Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add page to change user password #36

Merged
merged 1 commit into from
Oct 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion generators/client/files.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ const svelteFiles = {
'index.svelte',
'login.svelte',
'account/activate.svelte',
'account/password-reset.svelte',
'account/password.svelte',
'account/register.svelte',
'account/reset/finish.svelte',
'account/reset/init.svelte',
],
},
],
Expand All @@ -91,6 +92,7 @@ const svelteFiles = {
path: FRONTEND_COMPONENTS_DIR,
templates: [
'account/account-service.js',
'account/Password.svelte',
'account/PasswordConfirm.svelte',
'Alert.svelte',
'InputControl.svelte',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script>
import Icon from 'fa-svelte'
import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons/faExclamationCircle'

import InputControl from '../InputControl.svelte'

export let name = 'password'
export let label = 'Password'
export let value = ''
</script>

<InputControl
type="password"
label="{label}"
value="{value}"
name="{name}"
on:input
required
validations="{[{ type: 'required', message: 'Password is mandatory' }, { type: 'minlength', minlength: 4, message: 'Password is required to be at least 4 characters' }, { type: 'maxlength', maxlength: 50, message: 'Password cannot be longer than 50 characters' }]}"
on:validate
let:message
let:dirty
let:valid
{...$$restProps}
>
<slot message="{message}" dirty="{dirty}" valid="{valid}">
{#if dirty && !valid}
<div class="flex items-center">
<Icon class="fa-icon mr-2" icon="{faExclamationCircle}" />
{message}
</div>
{:else}&nbsp;{/if}
</slot>
</InputControl>
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import Icon from 'fa-svelte'
import { faExclamationCircle } from '@fortawesome/free-solid-svg-icons/faExclamationCircle'

import InputControl from '../InputControl.svelte'
import Password from './Password.svelte'

export let label='Password';
export let value = '';
export let label = 'Password'
export let name = 'password'
export let value = ''
const dispatch = createEventDispatcher()

let confirmPassword
Expand All @@ -19,59 +20,50 @@

function handlePassword(event) {
value = event.target.value
dispatch('input', {value})
dispatch('input', { value })
}

function handlePasswordValidation(event) {
validPassword = event.detail.valid
dispatch('validate', {'valid' : isValid()})
dispatch('validate', { valid: isValid() })
}

function handleConfirmPasswordValidation(event) {
validConfirmPassword = event.detail.valid
dispatch('validate', {'valid' : isValid()})
dispatch('validate', { valid: isValid() })
}
function isValid() {
return validPassword && validConfirmPassword && value === confirmPassword;
return (
validPassword && validConfirmPassword && value === confirmPassword
)
}
</script>

<InputControl
type="password"
<Password
name="{name}"
label="{label}"
name="password"
value="{value}"
on:input="{handlePassword}"
required
validations="{[{ type: 'required', message: 'Password is mandatory' }, { type: 'minlength', minlength: 4, message: 'Password is required to be at least 4 characters' }, { type: 'maxlength', maxlength: 50, message: 'Password cannot be longer than 50 characters' }]}"
on:validate="{handlePasswordValidation}"
/>
<InputControl
type="password"

<Password
label="Confirm {label}"
name="confirmPassword"
value="{confirmPassword}"
name="{name}Confirm"
on:input="{event => (confirmPassword = event.target.value)}"
required
validations="{[{ type: 'required', message: 'Password is mandatory' }, { type: 'minlength', minlength: 4, message: 'Password is required to be at least 4 characters' }, { type: 'maxlength', maxlength: 50, message: 'Password cannot be longer than 50 characters' }]}"
on:validate="{handleConfirmPasswordValidation}"
let:message
let:dirty
let:valid
>
<div class="flex items-center">
{#if confirmPasswordMismatch}
<Icon
class="fa-icon mr-2"
icon="{faExclamationCircle}"
/>
<Icon class="fa-icon mr-2" icon="{faExclamationCircle}" />
Password and its confirmation do not match
{:else if dirty && !valid}
<Icon
class="fa-icon mr-2"
icon="{faExclamationCircle}"
/>
<Icon class="fa-icon mr-2" icon="{faExclamationCircle}" />
{message}
{:else}&nbsp;{/if}
</div>
</InputControl>
</Password>
Original file line number Diff line number Diff line change
Expand Up @@ -71,4 +71,22 @@ export default {
return Promise.reject(err)
})
},
changeAccountPassword: (currentPassword, newPassword) => {
const body = JSON.stringify({ currentPassword, newPassword })
return fetch(
`${serverUrl}api/account/change-password`,
prepareRequest('POST', body, {
'Content-Type': 'application/json',
})
)
.then(response => {
if (response.ok) {
return Promise.resolve()
}
return response.json().then(Promise.reject.bind(Promise))
})
.catch(err => {
return Promise.reject(err)
})
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import Icon from 'fa-svelte'
import { goto } from '@sapper/app'
import { faSignOutAlt } from '@fortawesome/free-solid-svg-icons/faSignOutAlt'
import { faLock } from '@fortawesome/free-solid-svg-icons/faLock'
import { faCaretDown } from '@fortawesome/free-solid-svg-icons/faCaretDown'
import { faUser } from '@fortawesome/free-solid-svg-icons/faUser'

Expand All @@ -22,7 +23,7 @@
}
</script>

<div class="px-2 pt-2 pb-4 sm:p-0 relative sm:flex sm:mr-2">
<div class="px-2 pt-2 pb-4 sm:p-0 relative sm:flex sm:mr-2 sm:z-10">
<div
class="px-2 py-1 sm:py-0 flex justify-start items-center rounded
sm:rounded-none font-semibold hover:text-white hover:bg-gray-700
Expand Down Expand Up @@ -52,9 +53,17 @@
{/if}
<div
class:hidden="{!isOpen}"
class="sm:absolute sm:right-0 sm:mt-10 sm:w-40 py-2 sm:bg-white rounded
class="sm:absolute sm:right-0 sm:mt-10 sm:w-48 py-2 sm:bg-white rounded
sm:rounded-lg sm:shadow-lg"
>
<a
class="block px-2 sm:px-4 py-1 rounded sm:rounded-none font-semibold
sm:font-normal text-gray-500 hover:text-white hover:bg-gray-700
sm:text-gray-800 sm:hover:bg-indigo-500"
href="/account/password"
on:click="{() => (isOpen = false)}"
><Icon class="fa-icon sm:mr-1" icon="{faLock}" />
Change Password</a>
<a
class="block px-2 sm:px-4 py-1 rounded sm:rounded-none font-semibold
sm:font-normal text-gray-500 hover:text-white hover:bg-gray-700
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
class="flex flex-col text-gray-900 bg-gray-100 antialiased
min-h-screen font-sans"
>
<div class:hidden="{isLoginRouteActivated}">
<div class="z-10" class:hidden="{isLoginRouteActivated}">
<Navbar />
</div>
<main class="flex-grow">
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<script>
import accountService from './../../components/account/account-service'
import Alert from './../../components/Alert.svelte'
import Password from './../../components/account/Password.svelte'
import PasswordConfirm from './../../components/account/PasswordConfirm.svelte'

let error
let currentPassword
let newPassword
let validCurrentPassword = false
let validNewPassword = false
let passwordChanged = false

$: validForm = validCurrentPassword && validNewPassword

function changePassword() {
error = undefined
passwordChanged = false
accountService
.changeAccountPassword(currentPassword, newPassword)
.then(() => (passwordChanged = true), (currentPassword = ''))
.catch(err => ((currentPassword = ''), (error = err)))
}
</script>

<svelte:head>
<title>Change password</title>
</svelte:head>

<section class="m-3 relative bg-white shadow-md rounded p-4">
<div class="p-4 w-full sm:max-w-3xl sm:mx-auto">
<div class="px-4 w-full text-4xl text-center">Change password</div>
<Alert show="{passwordChanged}" closeable="{false}">
Password changed!
</Alert>
<Alert type="danger" show="{error}" closeable="{false}">
An error has occurred! The password could not be changed.
</Alert>
<form class="mt-4 flex flex-col">
<Password
name="currentPassword"
label="Current Password"
value="{currentPassword}"
on:input="{event => (currentPassword = event.target.value)}"
on:validate="{event => (validCurrentPassword = event.detail.valid)}"
/>

<PasswordConfirm
name="newPassword"
label="New Password"
value="{newPassword}"
on:input="{event => (newPassword = event.detail.value)}"
on:validate="{event => (validNewPassword = event.detail.valid)}"
/>
<button
type="submit"
on:click|preventDefault="{changePassword}"
class="my-4 w-64 m-auto btn btn-primary"
disabled="{!validForm}"
>Update password</button>
</form>
</div>
</section>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script>
import accountService from './../../components/account/account-service'
import Alert from './../../components/Alert.svelte'
import InputControl from '../../components/InputControl.svelte'
import accountService from './../../../components/account/account-service'
import Alert from './../../../components/Alert.svelte'
import InputControl from './../../../components/InputControl.svelte'

let error
let email
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@

<div class="mt-5 px-4 flex justify-between text-blue-600">
<div>
<a href="/account/password-reset" class="font-semibold">Forgot password?</a>
<a href="/account/reset/init" class="font-semibold">Forgot password?</a>
</div>
<div>
<a href="/account/register" class="font-semibold">Create an
Expand Down