"use client"; import { IconBrandGoogleFilled } from "@tabler/icons-react"; import { useAtom } from "jotai"; import { Clipboard, Eye, EyeOff, Keyboard, Sparkles } from "lucide-react"; import Image from "next/image"; import { useRouter } from "next/navigation"; import { useCallback, useEffect, useState } from "react"; import { toast } from "sonner"; import { loginMutationAtom } from "@/atoms/auth/auth-mutation.atoms"; import { DEFAULT_SHORTCUTS, ShortcutRecorder } from "@/components/desktop/shortcut-recorder"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Separator } from "@/components/ui/separator"; import { Spinner } from "@/components/ui/spinner"; import { useElectronAPI } from "@/hooks/use-platform"; import { AUTH_TYPE, BACKEND_URL } from "@/lib/env-config"; const isGoogleAuth = AUTH_TYPE === "GOOGLE"; export default function DesktopLoginPage() { const router = useRouter(); const api = useElectronAPI(); const [{ mutateAsync: login, isPending: isLoggingIn }] = useAtom(loginMutationAtom); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [showPassword, setShowPassword] = useState(false); const [loginError, setLoginError] = useState(null); const [shortcuts, setShortcuts] = useState(DEFAULT_SHORTCUTS); const [shortcutsLoaded, setShortcutsLoaded] = useState(false); useEffect(() => { if (!api?.getShortcuts) { setShortcutsLoaded(true); return; } api .getShortcuts() .then((config) => { if (config) setShortcuts(config); setShortcutsLoaded(true); }) .catch(() => setShortcutsLoaded(true)); }, [api]); const updateShortcut = useCallback( (key: "quickAsk" | "autocomplete", accelerator: string) => { setShortcuts((prev) => { const updated = { ...prev, [key]: accelerator }; api?.setShortcuts?.({ [key]: accelerator }).catch(() => { toast.error("Failed to update shortcut"); }); return updated; }); toast.success("Shortcut updated"); }, [api] ); const resetShortcut = useCallback( (key: "quickAsk" | "autocomplete") => { updateShortcut(key, DEFAULT_SHORTCUTS[key]); }, [updateShortcut] ); const handleGoogleLogin = () => { window.location.href = `${BACKEND_URL}/auth/google/authorize-redirect`; }; const handleLocalLogin = async (e: React.FormEvent) => { e.preventDefault(); setLoginError(null); try { const data = await login({ username: email, password, grant_type: "password", }); if (typeof window !== "undefined") { sessionStorage.setItem("login_success_tracked", "true"); } setTimeout(() => { router.push(`/auth/callback?token=${data.access_token}`); }, 300); } catch (err) { if (err instanceof Error) { setLoginError(err.message); } else { setLoginError("Login failed. Please check your credentials."); } } }; return (
SurfSense Welcome to SurfSense Desktop App Configure your shortcuts, then sign in to get started. {/* ---- Shortcuts Section (first) ---- */} {shortcutsLoaded ? (
Keyboard Shortcuts
updateShortcut("quickAsk", accel)} onReset={() => resetShortcut("quickAsk")} defaultValue={DEFAULT_SHORTCUTS.quickAsk} label="Quick Ask" description="Copy selected text and ask AI about it" icon={Clipboard} /> updateShortcut("autocomplete", accel)} onReset={() => resetShortcut("autocomplete")} defaultValue={DEFAULT_SHORTCUTS.autocomplete} label="Autocomplete" description="Get AI writing suggestions from a screenshot" icon={Sparkles} />

Click a shortcut and press a new key combination to change it.

) : (
)} {/* ---- Divider ---- */} {/* ---- Auth Section (second) ---- */} {isGoogleAuth ? ( ) : (
{loginError && (
{loginError}
)}
setEmail(e.target.value)} disabled={isLoggingIn} autoFocus />
setPassword(e.target.value)} disabled={isLoggingIn} className="pr-10" />
)}
); }