parent
f5658e1980
commit
9a145cb785
3 changed files with 296 additions and 3 deletions
@ -0,0 +1,176 @@ |
||||
import { useState } from 'preact/hooks'; |
||||
import Cookies from 'js-cookie'; |
||||
import { TOKEN_COOKIE_NAME } from '../../lib/utils'; |
||||
|
||||
export default function ChangePasswordForm() { |
||||
const [currentPassword, setCurrentPassword] = useState(''); |
||||
const [newPassword, setNewPassword] = useState(''); |
||||
const [newPasswordConfirmation, setNewPasswordConfirmation] = useState(''); |
||||
const [error, setError] = useState(''); |
||||
const [successMessage, setSuccessMessage] = useState(''); |
||||
const [isLoading, setIsLoading] = useState(false); |
||||
|
||||
const handleSubmit = (e: Event) => { |
||||
e.preventDefault(); |
||||
setIsLoading(true); |
||||
|
||||
if (newPassword !== newPasswordConfirmation) { |
||||
setError('New password and confirmation do not match'); |
||||
setIsLoading(false); |
||||
return; |
||||
} |
||||
|
||||
const headers = new Headers(); |
||||
headers.append('Content-Type', 'application/json'); |
||||
headers.append( |
||||
'Cookie', |
||||
`${TOKEN_COOKIE_NAME}=${Cookies.get(TOKEN_COOKIE_NAME)}` |
||||
); |
||||
|
||||
fetch('http://localhost:8080/v1-update-password', { |
||||
method: 'POST', |
||||
credentials: 'include', |
||||
headers, |
||||
body: JSON.stringify({ |
||||
oldPassword: currentPassword, |
||||
password: newPassword, |
||||
confirmPassword: newPasswordConfirmation, |
||||
}), |
||||
}) |
||||
.then(async (res) => { |
||||
const json = await res.json(); |
||||
if (res.ok) { |
||||
return json; |
||||
} else { |
||||
throw new Error(json.message); |
||||
} |
||||
}) |
||||
.then((data) => { |
||||
setIsLoading(false); |
||||
setCurrentPassword(''); |
||||
setNewPassword(''); |
||||
setNewPasswordConfirmation(''); |
||||
setSuccessMessage('Password updated successfully'); |
||||
}) |
||||
.catch((err) => { |
||||
setIsLoading(false); |
||||
setError(err.message); |
||||
}); |
||||
}; |
||||
|
||||
console.log(currentPassword, newPassword, newPasswordConfirmation); |
||||
console.log(`${TOKEN_COOKIE_NAME}=${Cookies.get(TOKEN_COOKIE_NAME)}`); |
||||
|
||||
return ( |
||||
<form onSubmit={handleSubmit}> |
||||
<h2 className="text-3xl font-bold sm:text-4xl">Password</h2> |
||||
<p className="mt-2">Manage settings for your account passwords</p> |
||||
<div className="mt-8 space-y-4"> |
||||
<div className="flex w-full flex-col"> |
||||
<label |
||||
for="current-password" |
||||
className="text-sm leading-none text-slate-500" |
||||
> |
||||
Current Password |
||||
</label> |
||||
<input |
||||
type="password" |
||||
name="current-password" |
||||
id="current-password" |
||||
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" |
||||
required |
||||
minLength={6} |
||||
placeholder="Current password" |
||||
value={currentPassword} |
||||
onChange={(e) => |
||||
setCurrentPassword((e.target as HTMLInputElement).value) |
||||
} |
||||
/> |
||||
</div> |
||||
<div className="flex w-full flex-col"> |
||||
<label |
||||
for="new-password" |
||||
className="text-sm leading-none text-slate-500" |
||||
> |
||||
New Password |
||||
</label> |
||||
<input |
||||
type="password" |
||||
name="new-password" |
||||
id="new-password" |
||||
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" |
||||
required |
||||
minLength={6} |
||||
placeholder="New password" |
||||
value={newPassword} |
||||
onChange={(e) => |
||||
setNewPassword((e.target as HTMLInputElement).value) |
||||
} |
||||
/> |
||||
</div> |
||||
<div className="flex w-full flex-col"> |
||||
<label |
||||
for="new-password-confirmation" |
||||
className="text-sm leading-none text-slate-500" |
||||
> |
||||
New Password Confirm |
||||
</label> |
||||
<input |
||||
type="password" |
||||
name="new-password-confirmation" |
||||
id="new-password-confirmation" |
||||
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" |
||||
required |
||||
minLength={6} |
||||
placeholder="New password confirm" |
||||
value={newPasswordConfirmation} |
||||
onChange={(e) => |
||||
setNewPasswordConfirmation((e.target as HTMLInputElement).value) |
||||
} |
||||
/> |
||||
</div> |
||||
|
||||
{error && ( |
||||
<div className="text-sm font-medium text-red-500"> |
||||
<p>{error}</p> |
||||
</div> |
||||
)} |
||||
|
||||
{successMessage && ( |
||||
<div className="text-sm font-medium text-green-500"> |
||||
<p>{successMessage}</p> |
||||
</div> |
||||
)} |
||||
|
||||
<button |
||||
className="!mt-5 inline-flex h-10 min-w-[120px] items-center justify-center rounded-lg border border-slate-300 bg-black p-2 px-4 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:opacity-60" |
||||
type="submit" |
||||
> |
||||
{isLoading ? ( |
||||
<svg |
||||
class={`h-5 w-5 animate-spin text-white`} |
||||
xmlns="http://www.w3.org/2000/svg" |
||||
fill="none" |
||||
viewBox="0 0 24 24" |
||||
> |
||||
<circle |
||||
class="stroke-[4px] opacity-25" |
||||
cx="12" |
||||
cy="12" |
||||
r="10" |
||||
stroke="currentColor" |
||||
></circle> |
||||
<path |
||||
class="opacity-75" |
||||
fill="currentColor" |
||||
d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" |
||||
></path> |
||||
</svg> |
||||
) : ( |
||||
'Change' |
||||
)} |
||||
</button> |
||||
</div> |
||||
</form> |
||||
); |
||||
} |
@ -0,0 +1,117 @@ |
||||
import { useState } from 'preact/hooks'; |
||||
|
||||
export default function UpdateProfileForm() { |
||||
const [name, setName] = useState(''); |
||||
const [github, setGithub] = useState(''); |
||||
const [linkedin, setLinkedin] = useState(''); |
||||
const [website, setWebsite] = useState(''); |
||||
const [error, setError] = useState(''); |
||||
const [successMessage, setSuccessMessage] = useState(''); |
||||
const [isLoading, setIsLoading] = useState(false); |
||||
|
||||
const handleSubmit = (e: Event) => { |
||||
e.preventDefault(); |
||||
setIsLoading(true); |
||||
|
||||
fetch('http://localhost:8080/v1-update-profile', { |
||||
method: 'POST', |
||||
credentials: 'include', |
||||
headers: { |
||||
'Content-Type': 'application/json', |
||||
}, |
||||
body: JSON.stringify({ |
||||
name, |
||||
github, |
||||
linkedin, |
||||
website, |
||||
}), |
||||
}); |
||||
}; |
||||
|
||||
return ( |
||||
<form> |
||||
<h2 className="text-3xl font-bold sm:text-4xl">Update Profile</h2> |
||||
<p className="mt-2">Manage settings for your roadmap.sh profile</p> |
||||
<div className="mt-8 space-y-4"> |
||||
<div className="flex w-full flex-col"> |
||||
<label |
||||
for="name" |
||||
className='text-sm leading-none text-slate-500 after:text-red-400 after:content-["*"]' |
||||
> |
||||
Name |
||||
</label> |
||||
<input |
||||
type="text" |
||||
name="name" |
||||
id="name" |
||||
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" |
||||
required |
||||
placeholder="Arik Chakma" |
||||
/> |
||||
</div> |
||||
<div className="flex w-full flex-col"> |
||||
<label |
||||
for="email" |
||||
className='text-sm leading-none text-slate-500 after:text-red-400 after:content-["*"]' |
||||
> |
||||
Email |
||||
</label> |
||||
<input |
||||
type="email" |
||||
name="email" |
||||
id="email" |
||||
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" |
||||
required |
||||
disabled |
||||
placeholder="arik@roadmap.sh" |
||||
/> |
||||
</div> |
||||
|
||||
<div className="flex w-full flex-col"> |
||||
<label for="github" className="text-sm leading-none text-slate-500"> |
||||
Github Username |
||||
</label> |
||||
<input |
||||
type="text" |
||||
name="github" |
||||
id="github" |
||||
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" |
||||
placeholder="arikchakma" |
||||
/> |
||||
</div> |
||||
<div className="flex w-full flex-col"> |
||||
<label for="linkedin" className="text-sm leading-none text-slate-500"> |
||||
LinkedIn Url |
||||
</label> |
||||
<input |
||||
type="text" |
||||
name="linkedin" |
||||
id="linkedin" |
||||
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" |
||||
placeholder="https://www.linkedin.com/in/arikchakma/" |
||||
/> |
||||
</div> |
||||
|
||||
<div className="flex w-full flex-col"> |
||||
<label for="website" className="text-sm leading-none text-slate-500"> |
||||
Website |
||||
</label> |
||||
<input |
||||
type="text" |
||||
name="website" |
||||
id="website" |
||||
className="mt-2 block w-full appearance-none rounded-lg border border-gray-300 px-3 py-2 shadow-sm outline-none transition duration-150 ease-in-out placeholder:text-gray-400 focus:ring-2 focus:ring-black focus:ring-offset-1" |
||||
placeholder="https://arikko.dev" |
||||
/> |
||||
</div> |
||||
|
||||
<button |
||||
className="!mt-5 inline-flex h-10 items-center justify-center rounded-lg border border-slate-300 bg-black p-2 px-4 text-sm font-medium text-white outline-none transition duration-150 ease-in-out focus:ring-2 focus:ring-black focus:ring-offset-1 disabled:opacity-60" |
||||
type="button" |
||||
> |
||||
Update |
||||
</button> |
||||
</div> |
||||
</form> |
||||
); |
||||
} |
@ -1,11 +1,11 @@ |
||||
--- |
||||
import ChangePassword from '../../components/Setting/ChangePassword.astro'; |
||||
import ChangePasswordForm from '../../components/Setting/ChangePasswordForm'; |
||||
import SettingSidebar from '../../components/Setting/SettingSidebar.astro'; |
||||
import SettingLayout from '../../layouts/SettingLayout.astro'; |
||||
--- |
||||
|
||||
<SettingLayout title='Change Password' description=''> |
||||
<SettingSidebar pageUrl='change-password' name="Change Password"> |
||||
<ChangePassword /> |
||||
<SettingSidebar pageUrl='change-password' name='Change Password'> |
||||
<ChangePasswordForm client:load /> |
||||
</SettingSidebar> |
||||
</SettingLayout> |
||||
|
Loading…
Reference in new issue