feat: add update password
This commit is contained in:
+5
-1
@@ -104,7 +104,9 @@ export interface UpdateUsername {
|
||||
username: string
|
||||
}
|
||||
|
||||
|
||||
export interface UpdatePassword {
|
||||
password: string
|
||||
}
|
||||
// --- Endpoints ---
|
||||
|
||||
export const api = {
|
||||
@@ -155,4 +157,6 @@ export const api = {
|
||||
request<DemoDetails>('POST', '/demos/details', { username }),
|
||||
updateUsername: (username: string) =>
|
||||
request<UpdateUsername>('POST', '/profile/username', { username }),
|
||||
updatePassword: (password: string) =>
|
||||
request<UpdatePassword>('POST', '/profile/password', { password })
|
||||
}
|
||||
|
||||
@@ -99,7 +99,8 @@ export function Profile() {
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [loggingOut, setLoggingOut] = useState(false)
|
||||
const [updatingUsername, setUpdatingUsername] = useState(false)
|
||||
|
||||
const [updatingPassword, setUpdatingPassword] = useState(false)
|
||||
const [passwordVersion, setPasswordVersion] = useState(0)
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
;(async () => {
|
||||
@@ -145,6 +146,36 @@ export function Profile() {
|
||||
}
|
||||
}
|
||||
|
||||
const handleUpdatePassword = async (newPassword: string) => {
|
||||
const trimmed = newPassword.trim()
|
||||
if (!me || trimmed.length < 8) {
|
||||
if (trimmed.length > 0) {
|
||||
toast({ status: 'warning', title: 'Le mot de passe doit contenir au moins 8 caractères' })
|
||||
}
|
||||
setPasswordVersion(v => v + 1) // reset le champ même en cas d'annulation
|
||||
return
|
||||
}
|
||||
|
||||
setUpdatingPassword(true)
|
||||
try {
|
||||
await api.updatePassword(trimmed)
|
||||
toast({ status: 'success', title: 'Mot de passe mis à jour' })
|
||||
} catch (err) {
|
||||
if (err instanceof ApiError && err.status === 401) {
|
||||
navigate('/login')
|
||||
return
|
||||
}
|
||||
toast({
|
||||
status: 'error',
|
||||
title: 'Impossible de mettre à jour le mot de passe',
|
||||
description: err instanceof ApiError ? err.message : undefined,
|
||||
})
|
||||
} finally {
|
||||
setUpdatingPassword(false)
|
||||
setPasswordVersion(v => v + 1) // vide le champ après tentative
|
||||
}
|
||||
}
|
||||
|
||||
const handleLogout = async () => {
|
||||
setLoggingOut(true)
|
||||
try {
|
||||
@@ -236,6 +267,25 @@ export function Profile() {
|
||||
<StatLabel>Type d'abonnement</StatLabel>
|
||||
<StatNumber fontSize="md">{me.type_abonnement || '—'}</StatNumber>
|
||||
</Stat>
|
||||
|
||||
<Stat>
|
||||
<StatLabel>Mot de passe</StatLabel>
|
||||
<Editable
|
||||
key={passwordVersion}
|
||||
defaultValue=""
|
||||
placeholder="••••••••"
|
||||
onSubmit={handleUpdatePassword}
|
||||
isDisabled={updatingPassword}
|
||||
submitOnBlur={false}
|
||||
>
|
||||
<HStack spacing={2}>
|
||||
<EditablePreview as={StatNumber} fontSize="md" fontFamily="mono" />
|
||||
<EditableInput type="password" fontSize="md" fontFamily="mono" />
|
||||
<EditableUsernameControls />
|
||||
</HStack>
|
||||
</Editable>
|
||||
</Stat>
|
||||
|
||||
<Stat>
|
||||
<StatLabel>Expire le</StatLabel>
|
||||
<StatNumber fontSize="md">{formatDate(me.expired_at)}</StatNumber>
|
||||
|
||||
Reference in New Issue
Block a user