feat(app): add dashboard pages for settings, admin, and public user profiles
Introduce new pages for profile settings, admin dashboard (users, contents, categories), and public user profiles. Enhance profile functionality with avatar uploads and bio updates. Include help and improved content trends/recent pages. Streamline content display using `HomeContent`.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { Calendar, LogIn, LogOut, Settings } from "lucide-react";
|
||||
import { Calendar, Camera, LogIn, LogOut, Settings } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
import * as React from "react";
|
||||
@@ -19,11 +19,32 @@ import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
import { useAuth } from "@/providers/auth-provider";
|
||||
import { ContentService } from "@/services/content.service";
|
||||
import { FavoriteService } from "@/services/favorite.service";
|
||||
import { UserService } from "@/services/user.service";
|
||||
import { toast } from "sonner";
|
||||
|
||||
export default function ProfilePage() {
|
||||
const { user, isAuthenticated, isLoading, logout } = useAuth();
|
||||
const { user, isAuthenticated, isLoading, logout, refreshUser } = useAuth();
|
||||
const searchParams = useSearchParams();
|
||||
const tab = searchParams.get("tab") || "memes";
|
||||
const fileInputRef = React.useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleAvatarClick = () => {
|
||||
fileInputRef.current?.click();
|
||||
};
|
||||
|
||||
const handleFileChange = async (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
const file = event.target.files?.[0];
|
||||
if (!file) return;
|
||||
|
||||
try {
|
||||
await UserService.updateAvatar(file);
|
||||
toast.success("Avatar mis à jour avec succès !");
|
||||
await refreshUser?.();
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
toast.error("Erreur lors de la mise à jour de l'avatar.");
|
||||
}
|
||||
};
|
||||
|
||||
const fetchMyMemes = React.useCallback(
|
||||
(params: { limit: number; offset: number }) =>
|
||||
@@ -72,12 +93,28 @@ export default function ProfilePage() {
|
||||
<div className="max-w-4xl mx-auto py-8 px-4">
|
||||
<div className="bg-white dark:bg-zinc-900 rounded-2xl p-8 border shadow-sm mb-8">
|
||||
<div className="flex flex-col md:flex-row items-center gap-8">
|
||||
<Avatar className="h-32 w-32 border-4 border-primary/10">
|
||||
<AvatarImage src={user.avatarUrl} alt={user.username} />
|
||||
<AvatarFallback className="text-4xl">
|
||||
{user.username.slice(0, 2).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<div className="relative group">
|
||||
<Avatar className="h-32 w-32 border-4 border-primary/10">
|
||||
<AvatarImage src={user.avatarUrl} alt={user.username} />
|
||||
<AvatarFallback className="text-4xl">
|
||||
{user.username.slice(0, 2).toUpperCase()}
|
||||
</AvatarFallback>
|
||||
</Avatar>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleAvatarClick}
|
||||
className="absolute inset-0 flex items-center justify-center bg-black/40 text-white rounded-full opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
>
|
||||
<Camera className="h-8 w-8" />
|
||||
</button>
|
||||
<input
|
||||
type="file"
|
||||
ref={fileInputRef}
|
||||
onChange={handleFileChange}
|
||||
accept="image/*"
|
||||
className="hidden"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex-1 text-center md:text-left space-y-4">
|
||||
<div>
|
||||
<h1 className="text-3xl font-bold">
|
||||
@@ -85,6 +122,9 @@ export default function ProfilePage() {
|
||||
</h1>
|
||||
<p className="text-muted-foreground">@{user.username}</p>
|
||||
</div>
|
||||
{user.bio && (
|
||||
<p className="max-w-md text-sm leading-relaxed">{user.bio}</p>
|
||||
)}
|
||||
<div className="flex flex-wrap justify-center md:justify-start gap-4 text-sm text-muted-foreground">
|
||||
<span className="flex items-center gap-1">
|
||||
<Calendar className="h-4 w-4" />
|
||||
|
||||
Reference in New Issue
Block a user