feat: conditionally display data management features in settings dialog based on user context

This commit is contained in:
2025-12-23 10:48:49 +01:00
parent b6d4f49fd9
commit 3a19995008
4 changed files with 70 additions and 66 deletions

View File

@@ -32,35 +32,35 @@ export function AppSidebar() {
return ( return (
<> <>
<Sidebar collapsible="icon"> <Sidebar collapsible="icon">
<SidebarContent> <SidebarContent>
<SidebarGroup> <SidebarGroup>
<SidebarGroupLabel>K-Notes</SidebarGroupLabel> <SidebarGroupLabel>K-Notes</SidebarGroupLabel>
<SidebarGroupContent> <SidebarGroupContent>
<SidebarMenu> <SidebarMenu>
{items.map((item) => ( {items.map((item) => (
<SidebarMenuItem key={item.title}> <SidebarMenuItem key={item.title}>
<SidebarMenuButton asChild isActive={location.pathname === item.url} tooltip={item.title}> <SidebarMenuButton asChild isActive={location.pathname === item.url} tooltip={item.title}>
<Link to={item.url}> <Link to={item.url}>
<item.icon /> <item.icon />
<span>{item.title}</span> <span>{item.title}</span>
</Link> </Link>
</SidebarMenuButton>
</SidebarMenuItem>
))}
<SidebarMenuItem>
<SidebarMenuButton onClick={() => setSettingsOpen(true)} tooltip="Settings">
<Settings />
<span>Settings</span>
</SidebarMenuButton> </SidebarMenuButton>
</SidebarMenuItem> </SidebarMenuItem>
))} </SidebarMenu>
</SidebarGroupContent>
<SidebarMenuItem> </SidebarGroup>
<SidebarMenuButton onClick={() => setSettingsOpen(true)} tooltip="Settings"> </SidebarContent>
<Settings /> </Sidebar>
<span>Settings</span> <SettingsDialog open={settingsOpen} onOpenChange={setSettingsOpen} dataManagementEnabled />
</SidebarMenuButton>
</SidebarMenuItem>
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>
</SidebarContent>
</Sidebar>
<SettingsDialog open={settingsOpen} onOpenChange={setSettingsOpen} />
</> </>
) )
} }

View File

@@ -10,9 +10,10 @@ import { Separator } from "@/components/ui/separator";
interface SettingsDialogProps { interface SettingsDialogProps {
open: boolean; open: boolean;
onOpenChange: (open: boolean) => void; onOpenChange: (open: boolean) => void;
dataManagementEnabled: boolean;
} }
export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) { export function SettingsDialog({ open, onOpenChange, dataManagementEnabled }: SettingsDialogProps) {
const [url, setUrl] = useState("http://localhost:3000"); const [url, setUrl] = useState("http://localhost:3000");
useEffect(() => { useEffect(() => {
@@ -31,7 +32,7 @@ export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
localStorage.setItem("k_notes_api_url", cleanUrl); localStorage.setItem("k_notes_api_url", cleanUrl);
toast.success("Settings saved. Please refresh the page."); toast.success("Settings saved. Please refresh the page.");
onOpenChange(false); onOpenChange(false);
window.location.reload(); window.location.reload();
} catch (e) { } catch (e) {
toast.error("Invalid URL"); toast.error("Invalid URL");
} }
@@ -97,31 +98,34 @@ export function SettingsDialog({ open, onOpenChange }: SettingsDialogProps) {
</div> </div>
</div> </div>
<Separator className="my-2" /> {dataManagementEnabled && <>
<Separator className="my-2" />
<div className="py-4 space-y-4"> <div className="py-4 space-y-4">
<div className="flex flex-col space-y-2"> <div className="flex flex-col space-y-2">
<h4 className="font-medium leading-none">Data Management</h4> <h4 className="font-medium leading-none">Data Management</h4>
<p className="text-sm text-muted-foreground"> <p className="text-sm text-muted-foreground">
Export your notes for backup or import from a JSON file. Export your notes for backup or import from a JSON file.
</p> </p>
</div>
<div className="flex gap-4">
<Button variant="outline" onClick={handleExport}>
Export Data
</Button>
<Button variant="outline" onClick={() => fileInputRef.current?.click()}>
Import Data
</Button>
<input
type="file"
ref={fileInputRef}
className="hidden"
accept=".json"
onChange={handleImport}
/>
</div>
</div> </div>
<div className="flex gap-4"> </>}
<Button variant="outline" onClick={handleExport}>
Export Data
</Button>
<Button variant="outline" onClick={() => fileInputRef.current?.click()}>
Import Data
</Button>
<input
type="file"
ref={fileInputRef}
className="hidden"
accept=".json"
onChange={handleImport}
/>
</div>
</div>
<DialogFooter> <DialogFooter>
<Button onClick={handleSave}>Save changes</Button> <Button onClick={handleSave}>Save changes</Button>
</DialogFooter> </DialogFooter>

View File

@@ -22,7 +22,7 @@ type LoginFormValues = z.infer<typeof loginSchema>;
export default function LoginPage() { export default function LoginPage() {
const { mutate: login, isPending } = useLogin(); const { mutate: login, isPending } = useLogin();
const form = useForm<LoginFormValues>({ const form = useForm<LoginFormValues>({
resolver: zodResolver(loginSchema), resolver: zodResolver(loginSchema),
defaultValues: { defaultValues: {
@@ -48,9 +48,9 @@ export default function LoginPage() {
return ( return (
<div className="flex min-h-screen items-center justify-center bg-gray-50 dark:bg-gray-950 p-4 relative"> <div className="flex min-h-screen items-center justify-center bg-gray-50 dark:bg-gray-950 p-4 relative">
<div className="absolute top-4 right-4"> <div className="absolute top-4 right-4">
<Button variant="ghost" size="icon" onClick={() => setSettingsOpen(true)}> <Button variant="ghost" size="icon" onClick={() => setSettingsOpen(true)}>
<Settings className="h-5 w-5" /> <Settings className="h-5 w-5" />
</Button> </Button>
</div> </div>
<Card className="w-full max-w-md"> <Card className="w-full max-w-md">
<CardHeader> <CardHeader>
@@ -103,7 +103,7 @@ export default function LoginPage() {
</p> </p>
</CardFooter> </CardFooter>
</Card> </Card>
<SettingsDialog open={settingsOpen} onOpenChange={setSettingsOpen} /> <SettingsDialog open={settingsOpen} onOpenChange={setSettingsOpen} dataManagementEnabled={false} />
</div> </div>
); );
} }

View File

@@ -26,7 +26,7 @@ type RegisterFormValues = z.infer<typeof registerSchema>;
export default function RegisterPage() { export default function RegisterPage() {
const { mutate: register, isPending } = useRegister(); const { mutate: register, isPending } = useRegister();
const form = useForm<RegisterFormValues>({ const form = useForm<RegisterFormValues>({
resolver: zodResolver(registerSchema), resolver: zodResolver(registerSchema),
defaultValues: { defaultValues: {
@@ -43,9 +43,9 @@ export default function RegisterPage() {
}, { }, {
onError: (error: any) => { onError: (error: any) => {
if (error instanceof ApiError) { if (error instanceof ApiError) {
toast.error(error.message); toast.error(error.message);
} else { } else {
toast.error("Failed to register"); toast.error("Failed to register");
} }
}, },
}); });
@@ -55,10 +55,10 @@ export default function RegisterPage() {
return ( return (
<div className="flex min-h-screen items-center justify-center bg-gray-50 dark:bg-gray-950 p-4 relative"> <div className="flex min-h-screen items-center justify-center bg-gray-50 dark:bg-gray-950 p-4 relative">
<div className="absolute top-4 right-4"> <div className="absolute top-4 right-4">
<Button variant="ghost" size="icon" onClick={() => setSettingsOpen(true)}> <Button variant="ghost" size="icon" onClick={() => setSettingsOpen(true)}>
<Settings className="h-5 w-5" /> <Settings className="h-5 w-5" />
</Button> </Button>
</div> </div>
<Card className="w-full max-w-md"> <Card className="w-full max-w-md">
<CardHeader> <CardHeader>
@@ -96,7 +96,7 @@ export default function RegisterPage() {
</FormItem> </FormItem>
)} )}
/> />
<FormField <FormField
control={form.control} control={form.control}
name="confirmPassword" name="confirmPassword"
render={({ field }) => ( render={({ field }) => (
@@ -124,7 +124,7 @@ export default function RegisterPage() {
</p> </p>
</CardFooter> </CardFooter>
</Card> </Card>
<SettingsDialog open={settingsOpen} onOpenChange={setSettingsOpen} /> <SettingsDialog open={settingsOpen} onOpenChange={setSettingsOpen} dataManagementEnabled={false} />
</div> </div>
); );
} }