forked from wrenn/wrenn
Add settings page, forgot/reset password flows, and me API client
Adds /dashboard/settings route with profile/password/OAuth/account-deletion management. Adds /forgot-password and /reset-password routes. Enables sidebar settings link. Adds typed me.ts API client.
This commit is contained in:
42
frontend/src/lib/api/me.ts
Normal file
42
frontend/src/lib/api/me.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { apiFetch, type ApiResult } from '$lib/api/client';
|
||||
import type { AuthResponse } from '$lib/api/auth';
|
||||
|
||||
export type MeResponse = {
|
||||
name: string;
|
||||
email: string;
|
||||
has_password: boolean;
|
||||
providers: string[];
|
||||
};
|
||||
|
||||
export type ChangePasswordBody = {
|
||||
current_password?: string;
|
||||
new_password: string;
|
||||
confirm_password?: string;
|
||||
};
|
||||
|
||||
export const getMe = (): Promise<ApiResult<MeResponse>> =>
|
||||
apiFetch('GET', '/api/v1/me');
|
||||
|
||||
export const updateName = (name: string): Promise<ApiResult<AuthResponse>> =>
|
||||
apiFetch('PATCH', '/api/v1/me', { name });
|
||||
|
||||
export const changePassword = (body: ChangePasswordBody): Promise<ApiResult<void>> =>
|
||||
apiFetch('POST', '/api/v1/me/password', body);
|
||||
|
||||
export const requestPasswordReset = (email: string): Promise<ApiResult<void>> =>
|
||||
apiFetch('POST', '/api/v1/me/password/reset', { email });
|
||||
|
||||
export const confirmPasswordReset = (
|
||||
token: string,
|
||||
new_password: string
|
||||
): Promise<ApiResult<void>> =>
|
||||
apiFetch('POST', '/api/v1/me/password/reset/confirm', { token, new_password });
|
||||
|
||||
export const getProviderConnectURL = (provider: string): Promise<ApiResult<{ auth_url: string }>> =>
|
||||
apiFetch('GET', `/api/v1/me/providers/${provider}/connect`);
|
||||
|
||||
export const disconnectProvider = (provider: string): Promise<ApiResult<void>> =>
|
||||
apiFetch('DELETE', `/api/v1/me/providers/${provider}`);
|
||||
|
||||
export const deleteAccount = (confirmation: string): Promise<ApiResult<void>> =>
|
||||
apiFetch('DELETE', '/api/v1/me', { confirmation });
|
||||
@ -280,13 +280,21 @@
|
||||
<IconBell size={16} class="shrink-0" />
|
||||
{#if !collapsed}<span class="text-ui">Notifications</span>{/if}
|
||||
</div>
|
||||
<div
|
||||
class="flex cursor-not-allowed items-center rounded-[var(--radius-input)] px-2.5 py-2.5 opacity-35 {collapsed ? 'justify-center px-2' : 'gap-3'}"
|
||||
title={collapsed ? 'Settings (coming soon)' : 'Coming soon'}
|
||||
<a
|
||||
href="/dashboard/settings"
|
||||
class="group relative flex items-center rounded-[var(--radius-input)] px-2.5 py-2.5 transition-colors duration-150 hover:bg-[var(--color-bg-3)] {collapsed ? 'justify-center px-2' : 'gap-3'} {isActive('/dashboard/settings') ? (collapsed ? 'bg-[var(--color-accent-glow-mid)]' : 'bg-[var(--color-accent)]/[0.12]') : ''}"
|
||||
title={collapsed ? 'Settings' : undefined}
|
||||
>
|
||||
<IconSettings size={16} class="shrink-0" />
|
||||
{#if !collapsed}<span class="text-ui">Settings</span>{/if}
|
||||
</div>
|
||||
{#if isActive('/dashboard/settings') && !collapsed}
|
||||
<div class="absolute left-0 top-1/2 h-6 w-1 -translate-y-1/2 rounded-r-full bg-[var(--color-accent)]"></div>
|
||||
{/if}
|
||||
<IconSettings size={16} class="shrink-0 {isActive('/dashboard/settings') ? 'text-[var(--color-accent-bright)]' : 'opacity-50 transition-opacity duration-150 group-hover:opacity-100'}" />
|
||||
{#if !collapsed}
|
||||
<span class="text-ui transition-colors duration-150 {isActive('/dashboard/settings') ? 'font-semibold text-[var(--color-accent-bright)]' : 'text-[var(--color-text-primary)] group-hover:text-[var(--color-text-bright)]'}">
|
||||
Settings
|
||||
</span>
|
||||
{/if}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- User footer -->
|
||||
|
||||
Reference in New Issue
Block a user