It's time to add the change password feature for our logged-in users. This lesson is even easier than the previous one since we won't need to retrieve anything from the server. Our change password form will have the following appearance.
Before we start implementing, let's first discuss why we can't have the password fields on the same profile page. While some websites or applications have this, it also brings up new issues:
Having a separate form specifically for changing passwords solves all of these problems and benefits both users and developers. With that in mind, let's implement the form.
src/hooks/usePassword.jsx
hook.import { useState } from 'react' export function usePassword() { const [errors, setErrors] = useState({}) const [loading, setLoading] = useState(false) const [status, setStatus] = useState('') async function updatePassword(data) { setLoading(true) setErrors({}) setStatus('') return axios.put('password', data) .then(() => setStatus('Password has been updated.')) .catch(error => { if (error.response.status === 422) { setErrors(error.response.data.errors) } }) .finally(() => setLoading(false)) } return { errors, loading, status, updatePassword }}
src/views/profile/ChangePassword.jsx
component.import { useState } from 'react'import { usePassword } from '@/hooks/usePassword'import ValidationError from '@/components/ValidationError'import IconSpinner from '@/components/IconSpinner' function ChangePassword() { const [currentPassword, setCurrentPassword] = useState('') const [password, setPassword] = useState('') const [passwordConfirmation, setPasswordConfirmation] = useState('') const { errors, loading, status, updatePassword } = usePassword() async function handleSubmit(event) { event.preventDefault() await updatePassword({ current_password: currentPassword, password, password_confirmation: passwordConfirmation, }) setCurrentPassword('') setPassword('') setPasswordConfirmation('') } return ( <form onSubmit={ handleSubmit } noValidate> <div className="flex flex-col mx-auto md:w-96 w-full"> <h1 className="heading">Change Password</h1> { status && <div className="alert alert-success mb-4" role="alert"> { status } </div> } <div className="flex flex-col gap-2 mb-4"> <label htmlFor="current_password" className="required">Current Password</label> <input id="current_password" name="current_password" type="password" value={ currentPassword } onChange={ event => setCurrentPassword(event.target.value) } className="form-input" autoComplete="current-password" disabled={ loading } /> <ValidationError errors={ errors } field="current_password" /> </div> <div className="flex flex-col gap-2 mb-4"> <label htmlFor="password" className="required">Password</label> <input id="password" name="password" type="password" value={ password } onChange={ event => setPassword(event.target.value) } className="form-input" autoComplete="new-password" disabled={ loading } /> <ValidationError errors={ errors } field="password" /> </div> <div className="flex flex-col gap-2"> <label htmlFor="password_confirmation" className="required">Confirm Password</label> <input id="password_confirmation" name="password_confirmation" type="password" value={ passwordConfirmation } onChange={ event => setPasswordConfirmation(event.target.value) } className="form-input" autoComplete="new-password" disabled={ loading } /> </div> <div className="border-t h-[1px] my-6"></div> <div className="flex flex-col gap-2 mb-4"> <button type="submit" className="btn btn-primary" disabled={ loading }> { loading && <IconSpinner /> } Update Password </button> </div> </div> </form> )} export default ChangePassword
profile.change-password
named route to the src/routes/index.jsx
file.const routeNames = { 'home': '/', 'register': '/register', 'login': '/login', 'profile.edit': '/profile', 'profile.change-password': '/profile/change-password', 'vehicles.index': '/vehicles', 'parkings.active': '/parkings/active',}
ChangePassword
component and bind the route in the src/main.jsx
file.import ChangePassword from '@/views/profile/ChangePassword'
<Route path={ route('profile.change-password') } element={<ChangePassword />} />
rightAuthLinks
function on the src/App.jsx
file.function rightAuthLinks() { return <> <NamedLink name="profile.edit"> Profile </NamedLink> <NamedLink name="profile.change-password"> Change Password </NamedLink> <button onClick={ logout } type="button" className="text-blue-600"> Logout </button> </>}