Profiles, Giphy, uploads, settings UI
Backend: - Auth: split routes into RegisterPublicRoutes + RegisterProtectedRoutes - Auth: PATCH /me for profile updates (display_name, bio, accent_color, status_text) - Auth: Gravatar fallback for avatars on register - DB: users table now has bio, accent_color, status_text columns - giphy/client.go: Search() and GetTrending() against Giphy API - upload/handlers.go: MinIO file upload + serve - config: added GiphyConfig and MinIO config - cmd/server: wired giphy (/gifs/search, /gifs/trending), upload (/upload), files (/files/*) routes Frontend: - auth store: updated User interface with new profile fields, added updateProfile() - UserSettings.tsx: terminal-styled profile editor (display_name, bio, accent_color, status_text, avatar upload) - GiphyPicker.tsx: terminal-styled GIF picker with search + trending - ChatArea.tsx: integrated [GIF] button into message input - App.tsx: imports UserSettings, added /settings route
This commit is contained in:
+31
-5
@@ -6,10 +6,21 @@ export type UserStatus = 'online' | 'idle' | 'dnd' | 'offline';
|
||||
export interface User {
|
||||
id: string;
|
||||
username: string;
|
||||
displayName: string;
|
||||
display_name: string;
|
||||
email: string;
|
||||
avatar: string | null;
|
||||
avatar: string;
|
||||
bio: string;
|
||||
accent_color: string;
|
||||
status: UserStatus;
|
||||
status_text: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface UpdateProfilePayload {
|
||||
display_name?: string;
|
||||
bio?: string;
|
||||
accent_color?: string;
|
||||
status_text?: string;
|
||||
}
|
||||
|
||||
interface AuthState {
|
||||
@@ -18,9 +29,10 @@ interface AuthState {
|
||||
isLoading: boolean;
|
||||
error: string | null;
|
||||
login: (email: string, password: string) => Promise<void>;
|
||||
register: (email: string, username: 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>;
|
||||
clearError: () => void;
|
||||
}
|
||||
|
||||
@@ -45,10 +57,10 @@ export const useAuthStore = create<AuthState>((set) => ({
|
||||
}
|
||||
},
|
||||
|
||||
register: async (email, username, password) => {
|
||||
register: async (email, username, password, displayName) => {
|
||||
set({ isLoading: true, error: null });
|
||||
try {
|
||||
await api.post('/auth/register', { email, username, password });
|
||||
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) {
|
||||
@@ -89,5 +101,19 @@ export const useAuthStore = create<AuthState>((set) => ({
|
||||
}
|
||||
},
|
||||
|
||||
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;
|
||||
}
|
||||
},
|
||||
|
||||
clearError: () => set({ error: null }),
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user