BillTracker/client/components/admin/LoginModeCard.jsx

136 lines
5.3 KiB
React
Raw Normal View History

import React, { useState, useEffect } from 'react';
import { toast } from 'sonner';
import { api } from '@/api';
import { Button } from '@/components/ui/button';
import { Badge } from '@/components/ui/badge';
import { Label } from '@/components/ui/label';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
import {
Select, SelectTrigger, SelectValue, SelectContent, SelectItem,
} from '@/components/ui/select';
import {
AlertDialog, AlertDialogContent, AlertDialogHeader, AlertDialogTitle,
AlertDialogDescription, AlertDialogFooter, AlertDialogCancel, AlertDialogAction,
} from '@/components/ui/alert-dialog';
export default function LoginModeCard({ users }) {
const [modeData, setModeData] = useState(null);
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false);
const [selectedUser, setSelectedUser] = useState('');
const [confirmSingle, setConfirmSingle] = useState(false);
const [pendingUserId, setPendingUserId] = useState(null);
useEffect(() => {
api.authModeConfig()
.then(d => { setModeData(d); setSelectedUser(d.default_user_id?.toString() || ''); })
.catch(() => {})
.finally(() => setLoading(false));
}, []);
const doSetMode = async (mode, userId) => {
setSaving(true);
try {
await api.setAuthMode({
auth_mode: mode,
default_user_id: mode === 'single' ? parseInt(userId, 10) : null,
});
const d = await api.authModeConfig();
setModeData(d);
toast.success(mode === 'single' ? 'Single-user mode enabled.' : 'Login requirement restored.');
} catch (err) {
toast.error(err.message || 'Failed to update auth mode.');
} finally {
setSaving(false);
}
};
const handleRequestSingle = () => {
if (!selectedUser) { toast.error('Select a user first.'); return; }
setPendingUserId(selectedUser);
setConfirmSingle(true);
};
const handleConfirmSingle = () => {
setConfirmSingle(false);
doSetMode('single', pendingUserId);
};
if (loading) return <Card><CardContent className="py-8 text-center text-muted-foreground text-sm">Loading</CardContent></Card>;
const isMulti = !modeData || modeData.auth_mode === 'multi';
const activeUser = users?.find(u => u.id === modeData?.default_user_id);
const selectedUsername = users?.find(u => u.id.toString() === selectedUser)?.username ?? selectedUser;
return (
<>
<Card>
<CardHeader className="pb-4">
<div className="flex items-center justify-between">
<CardTitle>Login Mode</CardTitle>
<Badge className={isMulti ? 'bg-sky-500/15 text-sky-400 border-sky-500/20' : 'bg-amber-500/15 text-amber-400 border-amber-500/20'}>
{isMulti ? 'Multi-user' : 'Single-user'}
</Badge>
</div>
</CardHeader>
<CardContent className="space-y-4">
{isMulti ? (
<>
<p className="text-sm text-muted-foreground">
Single-user mode bypasses the login screen and automatically signs in as the selected user.
</p>
<div className="space-y-1.5">
<Label>Default user</Label>
<Select value={selectedUser} onValueChange={setSelectedUser}>
<SelectTrigger>
<SelectValue placeholder="Select a user…" />
</SelectTrigger>
<SelectContent>
{(users || []).filter(u => u.role === 'user').map(u => (
<SelectItem key={u.id} value={u.id.toString()}>{u.username}</SelectItem>
))}
</SelectContent>
</Select>
</div>
<Button onClick={handleRequestSingle} disabled={saving} className="w-full">
{saving ? 'Enabling…' : 'Enable Single-User Mode'}
</Button>
</>
) : (
<>
<p className="text-sm text-muted-foreground">
Currently auto-signing in as{' '}
<span className="font-medium text-foreground">{activeUser?.username ?? '—'}</span>.
Restoring login requirement will require all users to sign in manually.
</p>
<Button variant="outline" onClick={() => doSetMode('multi', null)} disabled={saving} className="w-full">
{saving ? 'Restoring…' : 'Restore Login Requirement'}
</Button>
</>
)}
</CardContent>
</Card>
<AlertDialog open={confirmSingle} onOpenChange={setConfirmSingle}>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Enable Single-User Mode?</AlertDialogTitle>
<AlertDialogDescription>
Anyone who opens the app will be automatically signed in as{' '}
<span className="font-medium text-foreground">{selectedUsername}</span>.
The admin login still requires a password.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Cancel</AlertDialogCancel>
<AlertDialogAction onClick={handleConfirmSingle}>
Enable Single-User Mode
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</>
);
}