diff --git a/surfsense_web/app/dashboard/user/settings/components/ApiKeyContent.tsx b/surfsense_web/app/dashboard/user/settings/components/ApiKeyContent.tsx new file mode 100644 index 000000000..40e7b1d34 --- /dev/null +++ b/surfsense_web/app/dashboard/user/settings/components/ApiKeyContent.tsx @@ -0,0 +1,123 @@ +"use client"; + +import { Check, Copy, Key, Menu, Shield } from "lucide-react"; +import { AnimatePresence, motion } from "motion/react"; +import { useTranslations } from "next-intl"; +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; +import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; +import { useApiKey } from "@/hooks/use-api-key"; + +interface ApiKeyContentProps { + onMenuClick: () => void; +} + +export function ApiKeyContent({ onMenuClick }: ApiKeyContentProps) { + const t = useTranslations("userSettings"); + const { apiKey, isLoading, copied, copyToClipboard } = useApiKey(); + + return ( + +
+
+ + +
+ + + + +
+

+ {t("api_key_title")} +

+

{t("api_key_description")}

+
+
+
+
+ + + + + + {t("api_key_warning_title")} + {t("api_key_warning_description")} + + +
+

{t("your_api_key")}

+ {isLoading ? ( +
+ ) : apiKey ? ( +
+
+ {apiKey} +
+ + + + + + {copied ? t("copied") : t("copy")} + + +
+ ) : ( +

{t("no_api_key")}

+ )} +
+ +
+

{t("usage_title")}

+

{t("usage_description")}

+
+									Authorization: Bearer {apiKey || "YOUR_API_KEY"}
+								
+
+ + +
+
+ + ); +} + diff --git a/surfsense_web/app/dashboard/user/settings/components/ProfileContent.tsx b/surfsense_web/app/dashboard/user/settings/components/ProfileContent.tsx new file mode 100644 index 000000000..b0c5869f7 --- /dev/null +++ b/surfsense_web/app/dashboard/user/settings/components/ProfileContent.tsx @@ -0,0 +1,80 @@ +"use client"; + +import { Menu, User } from "lucide-react"; +import { AnimatePresence, motion } from "motion/react"; +import { useTranslations } from "next-intl"; +import { Button } from "@/components/ui/button"; + +interface ProfileContentProps { + onMenuClick: () => void; +} + +export function ProfileContent({ onMenuClick }: ProfileContentProps) { + const t = useTranslations("userSettings"); + + return ( + +
+
+ + +
+ + + + +
+

+ {t("profile_title")} +

+

{t("profile_description")}

+
+
+
+
+ + + + {/* Profile form will be added in Task 5 */} +
+

Profile settings coming soon...

+
+
+
+
+
+
+ ); +} + diff --git a/surfsense_web/app/dashboard/user/settings/components/UserSettingsSidebar.tsx b/surfsense_web/app/dashboard/user/settings/components/UserSettingsSidebar.tsx new file mode 100644 index 000000000..e25d318f3 --- /dev/null +++ b/surfsense_web/app/dashboard/user/settings/components/UserSettingsSidebar.tsx @@ -0,0 +1,155 @@ +"use client"; + +import { ArrowLeft, ChevronRight, X } from "lucide-react"; +import type { LucideIcon } from "lucide-react"; +import { AnimatePresence, motion } from "motion/react"; +import { useTranslations } from "next-intl"; +import { Button } from "@/components/ui/button"; +import { cn } from "@/lib/utils"; + +export interface SettingsNavItem { + id: string; + label: string; + description: string; + icon: LucideIcon; +} + +interface UserSettingsSidebarProps { + activeSection: string; + onSectionChange: (section: string) => void; + onBackToApp: () => void; + isOpen: boolean; + onClose: () => void; + navItems: SettingsNavItem[]; +} + +export function UserSettingsSidebar({ + activeSection, + onSectionChange, + onBackToApp, + isOpen, + onClose, + navItems, +}: UserSettingsSidebarProps) { + const t = useTranslations("userSettings"); + + const handleNavClick = (sectionId: string) => { + onSectionChange(sectionId); + onClose(); + }; + + return ( + <> + + {isOpen && ( + + )} + + + + + ); +} + diff --git a/surfsense_web/app/dashboard/user/settings/page.tsx b/surfsense_web/app/dashboard/user/settings/page.tsx index bf88e65e5..973b39076 100644 --- a/surfsense_web/app/dashboard/user/settings/page.tsx +++ b/surfsense_web/app/dashboard/user/settings/page.tsx @@ -1,286 +1,27 @@ "use client"; -import { - ArrowLeft, - Check, - ChevronRight, - Copy, - Key, - type LucideIcon, - Menu, - Shield, - X, -} from "lucide-react"; -import { AnimatePresence, motion } from "motion/react"; +import { Key, User } from "lucide-react"; +import { motion } from "motion/react"; import { useRouter } from "next/navigation"; import { useTranslations } from "next-intl"; import { useCallback, useState } from "react"; -import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; -import { useApiKey } from "@/hooks/use-api-key"; -import { cn } from "@/lib/utils"; - -interface SettingsNavItem { - id: string; - label: string; - description: string; - icon: LucideIcon; -} - -function UserSettingsSidebar({ - activeSection, - onSectionChange, - onBackToApp, - isOpen, - onClose, - navItems, -}: { - activeSection: string; - onSectionChange: (section: string) => void; - onBackToApp: () => void; - isOpen: boolean; - onClose: () => void; - navItems: SettingsNavItem[]; -}) { - const t = useTranslations("userSettings"); - - const handleNavClick = (sectionId: string) => { - onSectionChange(sectionId); - onClose(); - }; - - return ( - <> - - {isOpen && ( - - )} - - - - - ); -} - -function ApiKeyContent({ onMenuClick }: { onMenuClick: () => void }) { - const t = useTranslations("userSettings"); - const { apiKey, isLoading, copied, copyToClipboard } = useApiKey(); - - return ( - -
-
- - -
- - - - -
-

- {t("api_key_title")} -

-

{t("api_key_description")}

-
-
-
-
- - - - - - {t("api_key_warning_title")} - {t("api_key_warning_description")} - - -
-

{t("your_api_key")}

- {isLoading ? ( -
- ) : apiKey ? ( -
-
- {apiKey} -
- - - - - - {copied ? t("copied") : t("copy")} - - -
- ) : ( -

{t("no_api_key")}

- )} -
- -
-

{t("usage_title")}

-

{t("usage_description")}

-
-									Authorization: Bearer {apiKey || "YOUR_API_KEY"}
-								
-
- - -
-
- - ); -} +import { ApiKeyContent } from "./components/ApiKeyContent"; +import { ProfileContent } from "./components/ProfileContent"; +import { UserSettingsSidebar, type SettingsNavItem } from "./components/UserSettingsSidebar"; export default function UserSettingsPage() { const t = useTranslations("userSettings"); const router = useRouter(); - const [activeSection, setActiveSection] = useState("api-key"); + const [activeSection, setActiveSection] = useState("profile"); const [isSidebarOpen, setIsSidebarOpen] = useState(false); const navItems: SettingsNavItem[] = [ + { + id: "profile", + label: t("profile_nav_label"), + description: t("profile_nav_description"), + icon: User, + }, { id: "api-key", label: t("api_key_nav_label"), @@ -310,6 +51,9 @@ export default function UserSettingsPage() { onClose={() => setIsSidebarOpen(false)} navItems={navItems} /> + {activeSection === "profile" && ( + setIsSidebarOpen(true)} /> + )} {activeSection === "api-key" && ( setIsSidebarOpen(true)} /> )} diff --git a/surfsense_web/messages/en.json b/surfsense_web/messages/en.json index ae7f98843..131cbb360 100644 --- a/surfsense_web/messages/en.json +++ b/surfsense_web/messages/en.json @@ -109,6 +109,10 @@ "title": "User Settings", "description": "Manage your account settings and API access", "back_to_app": "Back to app", + "profile_nav_label": "Profile", + "profile_nav_description": "Manage your display name and avatar", + "profile_title": "Profile", + "profile_description": "Update your personal information", "api_key_nav_label": "API Key", "api_key_nav_description": "Manage your API access token", "api_key_title": "API Key",