diff --git a/src/api/users.ts b/src/api/users.ts new file mode 100644 index 0000000..03b25e0 --- /dev/null +++ b/src/api/users.ts @@ -0,0 +1,10 @@ +import { apiClient } from '@/api/client' +import { extractErrorMessage } from '@/api/http' +import type { ChangePasswordPayload } from '@/types/auth' + +export async function changePasswordApi(payload: ChangePasswordPayload): Promise { + const response = await apiClient.post('/users/password', payload) + if (!response.ok) { + throw new Error(await extractErrorMessage(response, 'Failed to change password')) + } +} diff --git a/src/components/ChangePasswordModal.vue b/src/components/ChangePasswordModal.vue new file mode 100644 index 0000000..93dd060 --- /dev/null +++ b/src/components/ChangePasswordModal.vue @@ -0,0 +1,236 @@ + + + + + diff --git a/src/utils/jwt.ts b/src/utils/jwt.ts new file mode 100644 index 0000000..3db0d48 --- /dev/null +++ b/src/utils/jwt.ts @@ -0,0 +1,17 @@ +export function decodeJwtPayload(token: string): T | null { + const parts = token.split('.') + if (parts.length !== 3) return null + + try { + const base64 = parts[1]!.replace(/-/g, '+').replace(/_/g, '/') + const json = decodeURIComponent( + atob(base64) + .split('') + .map((c) => '%' + c.charCodeAt(0).toString(16).padStart(2, '0')) + .join(''), + ) + return JSON.parse(json) as T + } catch { + return null + } +}