"use client"; import { useActionState, useEffect, useRef, useState, useTransition } from "react"; import { useRouter } from "next/navigation"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { Plus, Trash2 } from "lucide-react"; import { addUser, deleteUser, sendTestEmail, type ActionResult } from "@/actions/settings"; import { updateDefaultPrice } from "@/actions/pricing"; import { toast } from "sonner"; import type { AppUser, FuelSettings } from "@/lib/types"; const initial: ActionResult = { ok: false, error: "" }; interface Props { currentUserId: string; settings: FuelSettings | null; users: AppUser[]; } export function SettingsForms({ currentUserId, settings, users }: Props) { const router = useRouter(); const [defaultPrice, setDefaultPrice] = useState(settings?.default_price_per_litre || 0); function onSaveDefault() { startTransition(async () => { const res = await updateDefaultPrice(defaultPrice); if (res.ok) { toast.success("Default price saved"); router.refresh(); } else { toast.error(res.error); } }); } const [, startTransition] = useTransition(); const [testEmail, setTestEmail] = useState(""); function onSendTest() { if (!testEmail) { toast.error("Enter a recipient email"); return; } startTransition(async () => { const res = await sendTestEmail(testEmail); if (res.ok) toast.success("Test email sent"); else toast.error(res.error); }); } return (

Settings

Fuel price, email, users, and price increase

Default fuel price Used when no per-customer rule applies
setDefaultPrice(Number(e.target.value))} />
Fuel price increase Quickly apply a cents increase to all customers (use Pricing page for details)
Email delivery Customer statements are sent through Gmail SMTP.

Configured sender

rjbulk01@gmail.com

Gmail credentials are managed by the deployment environment and are not stored in PocketBase.

setTestEmail(e.target.value)} />
); } function UsersSection({ currentUserId, users }: { currentUserId: string; users: AppUser[] }) { const router = useRouter(); const [open, setOpen] = useState(false); const [deletingId, setDeletingId] = useState(null); const [, startTransition] = useTransition(); function onDelete(id: string) { startTransition(async () => { const res = await deleteUser(id); if (res.ok) { toast.success("User deleted"); setDeletingId(null); router.refresh(); } else { toast.error(res.error); } }); } return (
Users {users.length} user{users.length !== 1 ? "s" : ""}
Name Email Verified {users.map((u) => ( {u.name || "—"} {u.email} {u.verified ? "Yes" : "No"} {u.id !== currentUserId && ( )} ))}
!v && setDeletingId(null)}> Delete this user? They will lose access immediately. This cannot be undone.
); } function AddUserDialog({ open, onOpenChange }: { open: boolean; onOpenChange: (v: boolean) => void }) { const router = useRouter(); const ref = useRef(null); const [pending, startTransition] = useTransition(); const [state, action] = useActionState(addUser, initial); useEffect(() => { if (state.ok) { toast.success("User created"); onOpenChange(false); ref.current?.reset(); router.refresh(); } else if (state.error) { toast.error(state.error); } }, [state, router, onOpenChange]); return ( Add user Create a new login for someone on your team.
); }