diff --git a/index.html b/index.html index 072a57e..5f51e82 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - frontend + MangaMochi
diff --git a/package-lock.json b/package-lock.json index 58ad870..2926f70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", "@tailwindcss/vite": "^4.1.16", "@tanstack/react-query": "^5.90.5", "axios": "^1.13.1", @@ -2024,6 +2025,36 @@ } } }, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-use-callback-ref": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", diff --git a/package.json b/package.json index c0ba0c8..251e4a2 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@radix-ui/react-separator": "^1.1.7", "@radix-ui/react-slot": "^1.2.3", "@radix-ui/react-switch": "^1.2.6", + "@radix-ui/react-tabs": "^1.1.13", "@tailwindcss/vite": "^4.1.16", "@tanstack/react-query": "^5.90.5", "axios": "^1.13.1", diff --git a/src/components/ui/tabs.tsx b/src/components/ui/tabs.tsx new file mode 100644 index 0000000..be81ad8 --- /dev/null +++ b/src/components/ui/tabs.tsx @@ -0,0 +1,64 @@ +import * as TabsPrimitive from "@radix-ui/react-tabs"; +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Tabs({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function TabsList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function TabsTrigger({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function TabsContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Tabs, TabsList, TabsTrigger, TabsContent }; diff --git a/src/pages/Profile.tsx b/src/pages/Profile.tsx new file mode 100644 index 0000000..d1fa75a --- /dev/null +++ b/src/pages/Profile.tsx @@ -0,0 +1,210 @@ +import { LogOut, Settings, User } from "lucide-react"; +import { useState } from "react"; +import { useNavigate } from "react-router"; +import { Button } from "@/components/ui/button"; +import { + Card, + CardContent, + CardDescription, + CardHeader, + CardTitle, +} from "@/components/ui/card"; +import { Input } from "@/components/ui/input"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@/components/ui/tabs.tsx"; +import { useAuth } from "@/contexts/AuthContext.tsx"; + +const Profile = () => { + const navigate = useNavigate(); + const { user, logout } = useAuth(); + const [itemsPerPage, setItemsPerPage] = useState(12); + + if (!user) { + return ( +
+ + + Access Denied + + Please log in to view your profile + + + + + + +
+ ); + } + + const handleLogout = () => { + logout(); + navigate("/"); + }; + + const handleSavePreferences = () => { + // updatePreferences({ itemsPerPage }); + }; + + return ( +
+
+
+

Profile

+ +
+ + + + + + Account + + + + Preferences + + Stats + + + + + + Account Information + Your account details + + +
+ + +
+
+ + +
+
+
+
+ + + + + Preferences + Customize your experience + + +
+ + + setItemsPerPage(Number.parseInt(e.target.value)) + } + /> +

+ Number of manga to display per page (6-48) +

+
+ +
+
+
+ + + + + Reading Statistics + Your manga reading activity + + +
+
+

+ Favorite Manga +

+

+ {/*{user.favorites.length}*/} +

+
+
+

+ Manga Reading +

+

+ {/*{Object.keys(user.chaptersRead).length}*/} +

+
+
+ + {/*{user.favorites.length > 0 && (*/} + {/*
*/} + {/*

Favorite Manga IDs

*/} + {/*
*/} + {/* {user.favorites.map((id) => (*/} + {/* */} + {/* #{id}*/} + {/* */} + {/* ))}*/} + {/*
*/} + {/*
*/} + {/*)}*/} + + {/*{Object.keys(user.chaptersRead).length > 0 && (*/} + {/*
*/} + {/*

Reading Progress

*/} + {/*
*/} + {/* {Object.entries(user.chaptersRead).map(*/} + {/* ([mangaId, chapter]) => (*/} + {/*

*/} + {/* Manga #{mangaId}: Chapter {chapter}*/} + {/*

*/} + {/* ),*/} + {/* )}*/} + {/*
*/} + {/*
*/} + {/*)}*/} + + {/*{user.favorites.length === 0 &&*/} + {/* Object.keys(user.chaptersRead).length === 0 && (*/} + {/* */} + {/* */} + {/* No reading activity yet. Start adding favorites and*/} + {/* tracking chapters!*/} + {/* */} + {/* */} + {/* )}*/} +
+
+
+
+
+
+ ); +}; + +export default Profile; diff --git a/src/pages/Router.tsx b/src/pages/Router.tsx index 2e63c02..e96e2fd 100644 --- a/src/pages/Router.tsx +++ b/src/pages/Router.tsx @@ -8,6 +8,7 @@ const Manga = lazy(() => import("./Manga.tsx")); const Chapter = lazy(() => import("./Chapter.tsx")); const Login = lazy(() => import("./Login.tsx")); const Register = lazy(() => import("./Register.tsx")); +const Profile = lazy(() => import("./Profile.tsx")); export const Router = createBrowserRouter([ { @@ -29,6 +30,10 @@ export const Router = createBrowserRouter([ path: "/register", element: , }, + { + path: "/profile", + element: , + }, { path: "/import-review", element: ,