Files
dumpsterChat/web/src/stores/auth.ts
T

195 lines
4.9 KiB
TypeScript

import { create } from "zustand";
import { api } from "../lib/api.ts";
export type UserStatus = "online" | "idle" | "dnd" | "offline";
export interface User {
id: string;
username: string;
display_name: string;
email: string;
avatar: string;
bio: string;
accent_color: string;
status: UserStatus;
status_text: string;
created_at: string;
banner_url?: string;
tagline?: string;
pronouns?: string;
social_links?: { platform: string; url: string }[];
}
export interface PublicProfile extends User {
badges: { id: string; name: string; icon: string; description?: string; server_id?: string }[];
}
export type BlockedUser = {
id: string;
username: string;
created_at: string;
};
export interface UpdateProfilePayload {
avatar_url?: string;
display_name?: string;
bio?: string;
accent_color?: string;
status_text?: string;
status?: UserStatus;
banner_url?: string;
tagline?: string;
pronouns?: string;
social_links?: { platform: string; url: string }[];
}
interface AuthState {
user: User | null;
isAuthenticated: boolean;
isLoading: boolean;
error: string | null;
login: (identifier: string, password: string) => Promise<void>;
register: (
email: string,
username: string,
password: string,
displayName?: string,
) => Promise<void>;
logout: () => Promise<void>;
fetchMe: () => Promise<void>;
updateProfile: (data: UpdateProfilePayload) => Promise<void>;
changePassword: (
currentPassword: string,
newPassword: string,
) => Promise<void>;
getPublicProfile: (userId: string) => Promise<PublicProfile>;
listBlocks: () => Promise<BlockedUser[]>;
blockUser: (userId: string) => Promise<void>;
unblockUser: (userId: string) => Promise<void>;
clearError: () => void;
}
export const useAuthStore = create<AuthState>((set) => ({
user: null,
isAuthenticated: false,
isLoading: false,
error: null,
login: async (identifier, password) => {
set({ isLoading: true, error: null });
try {
await api.post("/auth/login/password", {
email: identifier,
password,
});
const user = await api.get<User>("/auth/me");
set({ user, isAuthenticated: true, isLoading: false });
} catch (error) {
set({
isLoading: false,
error: error instanceof Error ? error.message : "Login failed",
});
throw error;
}
},
register: async (email, username, password, displayName) => {
set({ isLoading: true, error: null });
try {
await api.post("/auth/register", {
email,
username,
password,
display_name: displayName || username,
});
const user = await api.get<User>("/auth/me");
set({ user, isAuthenticated: true, isLoading: false });
} catch (error) {
set({
isLoading: false,
error:
error instanceof Error ? error.message : "Registration failed",
});
throw error;
}
},
logout: async () => {
set({ isLoading: true, error: null });
try {
await api.post("/auth/logout");
set({ user: null, isAuthenticated: false, isLoading: false });
} catch (error) {
set({
isLoading: false,
error: error instanceof Error ? error.message : "Logout failed",
});
throw error;
}
},
fetchMe: async () => {
set({ isLoading: true, error: null });
try {
const user = await api.get<User>(`/auth/me?t=${Date.now()}`);
set({ user, isAuthenticated: true, isLoading: false });
} catch (error) {
set({
user: null,
isAuthenticated: false,
isLoading: false,
error:
error instanceof Error ? error.message : "Failed to fetch user",
});
}
},
updateProfile: async (data) => {
set({ isLoading: true, error: null });
try {
const user = await api.patch<User>("/auth/me", data);
set({ user, isLoading: false });
} catch (error) {
set({
isLoading: false,
error: error instanceof Error ? error.message : "Update failed",
});
throw error;
}
},
changePassword: async (currentPassword, newPassword) => {
set({ isLoading: true, error: null });
try {
await api.put("/auth/me/password", {
current_password: currentPassword,
new_password: newPassword,
});
set({ isLoading: false });
} catch (error) {
set({
isLoading: false,
error:
error instanceof Error
? error.message
: "Password change failed",
});
throw error;
}
},
clearError: () => set({ error: null }),
getPublicProfile: async (userId) => api.get<PublicProfile>(`/users/${userId}/profile`),
listBlocks: async () => api.get<BlockedUser[]>('/users/me/blocks'),
blockUser: async (userId) => {
await api.post('/users/me/blocks', { user_id: userId });
},
unblockUser: async (userId) => {
await api.delete(`/users/me/blocks/${userId}`);
},
}));