refactor(ts): convert LoginModeCard + EmailNotifCard admin cards to TSX (B18)
LoginModeCard (AuthModeConfig; AdminUser[]) and EmailNotifCard (EmailConfig + keyed set(k,v)). typecheck 0, build green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
a9a58d8aa2
commit
c9b5f93569
|
|
@ -1,7 +1,8 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Eye, EyeOff } from 'lucide-react';
|
||||
import { toast } from 'sonner';
|
||||
import { api } from '@/api';
|
||||
import { errMessage } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
|
||||
|
|
@ -10,8 +11,21 @@ import {
|
|||
} from '@/components/ui/select';
|
||||
import { SectionHeading, FieldRow, Toggle } from './adminShared';
|
||||
|
||||
export default function EmailNotifCard() {
|
||||
const DEFAULTS = {
|
||||
interface EmailConfig {
|
||||
enabled: boolean;
|
||||
sender_name: string;
|
||||
sender_address: string;
|
||||
smtp_host: string;
|
||||
smtp_port: string;
|
||||
smtp_encryption: string;
|
||||
smtp_self_signed: boolean;
|
||||
smtp_username: string;
|
||||
smtp_password: string;
|
||||
allow_user_config: boolean;
|
||||
global_recipient: string;
|
||||
}
|
||||
|
||||
const DEFAULTS: EmailConfig = {
|
||||
enabled: false,
|
||||
sender_name: '', sender_address: '',
|
||||
smtp_host: '', smtp_port: '587', smtp_encryption: 'starttls',
|
||||
|
|
@ -19,9 +33,10 @@ export default function EmailNotifCard() {
|
|||
smtp_username: '', smtp_password: '',
|
||||
allow_user_config: false,
|
||||
global_recipient: '',
|
||||
};
|
||||
};
|
||||
|
||||
const [cfg, setCfg] = useState(DEFAULTS);
|
||||
export default function EmailNotifCard() {
|
||||
const [cfg, setCfg] = useState<EmailConfig>(DEFAULTS);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [loadError, setLoadError] = useState('');
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
|
@ -31,12 +46,12 @@ export default function EmailNotifCard() {
|
|||
|
||||
useEffect(() => {
|
||||
api.notifAdmin()
|
||||
.then(d => setCfg({ ...DEFAULTS, ...d }))
|
||||
.catch(err => setLoadError(err.message || 'Failed to load email settings'))
|
||||
.then(d => setCfg({ ...DEFAULTS, ...(d as Partial<EmailConfig>) }))
|
||||
.catch(err => setLoadError(errMessage(err, 'Failed to load email settings')))
|
||||
.finally(() => setLoading(false));
|
||||
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
||||
|
||||
const set = (k, v) => setCfg(p => ({ ...p, [k]: v }));
|
||||
const set = (k: keyof EmailConfig, v: string | boolean) => setCfg(p => ({ ...p, [k]: v }) as EmailConfig);
|
||||
|
||||
const handleSave = async () => {
|
||||
setSaving(true);
|
||||
|
|
@ -44,7 +59,7 @@ export default function EmailNotifCard() {
|
|||
await api.saveNotifAdmin(cfg);
|
||||
toast.success('Email settings saved.');
|
||||
} catch (err) {
|
||||
toast.error(err.message || 'Failed to save.');
|
||||
toast.error(errMessage(err, 'Failed to save.'));
|
||||
} finally {
|
||||
setSaving(false);
|
||||
}
|
||||
|
|
@ -57,7 +72,7 @@ export default function EmailNotifCard() {
|
|||
await api.testEmail({ to: testEmail });
|
||||
toast.success('Test email sent.');
|
||||
} catch (err) {
|
||||
toast.error(err.message || 'Failed to send test email.');
|
||||
toast.error(errMessage(err, 'Failed to send test email.'));
|
||||
} finally {
|
||||
setTesting(false);
|
||||
}
|
||||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { toast } from 'sonner';
|
||||
import { api } from '@/api';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { cn, errMessage } from '@/lib/utils';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Label } from '@/components/ui/label';
|
||||
|
|
@ -15,9 +15,15 @@ import {
|
|||
} from '@/components/ui/alert-dialog';
|
||||
import { LogIn, UserCheck, ShieldCheck } from 'lucide-react';
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
|
||||
import type { AdminUser } from './UsersTable';
|
||||
|
||||
export default function LoginModeCard({ users, onModeChange }) {
|
||||
const [modeData, setModeData] = useState(null);
|
||||
interface AuthModeConfig {
|
||||
auth_mode?: string;
|
||||
default_user_id?: number | null;
|
||||
}
|
||||
|
||||
export default function LoginModeCard({ users, onModeChange }: { users?: AdminUser[]; onModeChange?: (mode: string) => void }) {
|
||||
const [modeData, setModeData] = useState<AuthModeConfig | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [loadError, setLoadError] = useState('');
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
|
@ -27,25 +33,26 @@ export default function LoginModeCard({ users, onModeChange }) {
|
|||
|
||||
useEffect(() => {
|
||||
api.authModeConfig()
|
||||
.then(d => {
|
||||
.then(raw => {
|
||||
const d = raw as AuthModeConfig;
|
||||
setModeData(d);
|
||||
const mode = d.auth_mode === 'single' ? 'single' : 'multi';
|
||||
setSelected(mode);
|
||||
setSelectedUser(d.default_user_id?.toString() || '');
|
||||
onModeChange?.(mode);
|
||||
})
|
||||
.catch(err => setLoadError(err.message || 'Failed to load login mode config'))
|
||||
.catch(err => setLoadError(errMessage(err, 'Failed to load login mode config')))
|
||||
.finally(() => setLoading(false));
|
||||
}, []); // eslint-disable-line
|
||||
|
||||
const doSetMode = async (mode, userId) => {
|
||||
const doSetMode = async (mode: string, userId: string | null) => {
|
||||
setSaving(true);
|
||||
try {
|
||||
await api.setAuthMode({
|
||||
auth_mode: mode,
|
||||
default_user_id: mode === 'single' ? parseInt(userId, 10) : null,
|
||||
default_user_id: mode === 'single' ? parseInt(userId || '', 10) : null,
|
||||
});
|
||||
const d = await api.authModeConfig();
|
||||
const d = await api.authModeConfig() as AuthModeConfig;
|
||||
setModeData(d);
|
||||
const resolved = d.auth_mode === 'single' ? 'single' : 'multi';
|
||||
setSelected(resolved);
|
||||
|
|
@ -53,7 +60,7 @@ export default function LoginModeCard({ users, onModeChange }) {
|
|||
onModeChange?.(resolved);
|
||||
toast.success(mode === 'single' ? 'No Login mode enabled.' : 'Login requirement restored.');
|
||||
} catch (err) {
|
||||
toast.error(err.message || 'Failed to update login mode.');
|
||||
toast.error(errMessage(err, 'Failed to update login mode.'));
|
||||
// revert UI selection on error
|
||||
setSelected(modeData?.auth_mode === 'single' ? 'single' : 'multi');
|
||||
} finally {
|
||||
Loading…
Reference in New Issue