100 lines
3.2 KiB
React
100 lines
3.2 KiB
React
|
|
import React, { useState, useEffect } from 'react';
|
||
|
|
import { toast } from 'sonner';
|
||
|
|
import { api } from '@/api';
|
||
|
|
import { Button } from '@/components/ui/button';
|
||
|
|
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/card';
|
||
|
|
import { Toggle } from './adminShared';
|
||
|
|
|
||
|
|
export default function BankSyncAdminCard() {
|
||
|
|
const [config, setConfig] = useState(null);
|
||
|
|
const [loading, setLoading] = useState(true);
|
||
|
|
const [saving, setSaving] = useState(false);
|
||
|
|
const [enabled, setEnabled] = useState(false);
|
||
|
|
|
||
|
|
useEffect(() => {
|
||
|
|
api.bankSyncConfig()
|
||
|
|
.then(d => {
|
||
|
|
setConfig(d);
|
||
|
|
setEnabled(!!d.enabled);
|
||
|
|
})
|
||
|
|
.catch(() => {})
|
||
|
|
.finally(() => setLoading(false));
|
||
|
|
}, []);
|
||
|
|
|
||
|
|
const handleSave = async () => {
|
||
|
|
setSaving(true);
|
||
|
|
try {
|
||
|
|
const result = await api.setBankSyncConfig({ enabled });
|
||
|
|
setConfig(result);
|
||
|
|
setEnabled(!!result.enabled);
|
||
|
|
toast.success(enabled ? 'Bank sync enabled.' : 'Bank sync disabled.');
|
||
|
|
} catch (err) {
|
||
|
|
toast.error(err.message || 'Failed to update bank sync setting.');
|
||
|
|
} finally {
|
||
|
|
setSaving(false);
|
||
|
|
}
|
||
|
|
};
|
||
|
|
|
||
|
|
if (loading) {
|
||
|
|
return (
|
||
|
|
<Card>
|
||
|
|
<CardContent className="py-8 text-center text-muted-foreground text-sm">
|
||
|
|
Loading…
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
const keySet = config?.encryption_key_set;
|
||
|
|
const changed = enabled !== !!config?.enabled;
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Card>
|
||
|
|
<CardHeader className="pb-4">
|
||
|
|
<CardTitle>Bank Sync (SimpleFIN)</CardTitle>
|
||
|
|
<p className="text-sm text-muted-foreground mt-1">
|
||
|
|
Allow users to connect their own SimpleFIN Bridge account to sync
|
||
|
|
read-only bank transactions. Each user manages their own connection
|
||
|
|
from the Data page — no bank credentials are stored.
|
||
|
|
</p>
|
||
|
|
</CardHeader>
|
||
|
|
<CardContent className="space-y-5">
|
||
|
|
|
||
|
|
{/* Encryption key status */}
|
||
|
|
<div className={`rounded-lg border px-4 py-3 text-sm ${
|
||
|
|
keySet
|
||
|
|
? 'border-emerald-500/25 bg-emerald-500/10 text-emerald-700 dark:text-emerald-400'
|
||
|
|
: 'border-amber-500/25 bg-amber-500/10 text-amber-700 dark:text-amber-400'
|
||
|
|
}`}>
|
||
|
|
{keySet
|
||
|
|
? 'TOKEN_ENCRYPTION_KEY is configured. Bank sync can be enabled.'
|
||
|
|
: 'TOKEN_ENCRYPTION_KEY is not set. Add a 32+ character key to your environment before enabling bank sync.'}
|
||
|
|
</div>
|
||
|
|
|
||
|
|
{/* Enable toggle */}
|
||
|
|
<div className="flex items-center justify-between">
|
||
|
|
<div>
|
||
|
|
<p className="text-sm font-medium">Allow users to connect SimpleFIN</p>
|
||
|
|
<p className="text-xs text-muted-foreground mt-0.5">
|
||
|
|
When enabled, users see a Bank Sync section on their Data page.
|
||
|
|
</p>
|
||
|
|
</div>
|
||
|
|
<Toggle
|
||
|
|
checked={enabled}
|
||
|
|
onChange={v => setEnabled(v)}
|
||
|
|
disabled={!keySet}
|
||
|
|
label="Enable bank sync"
|
||
|
|
/>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className="flex justify-end pt-2">
|
||
|
|
<Button onClick={handleSave} disabled={saving || !changed || (!enabled ? false : !keySet)}>
|
||
|
|
{saving ? 'Saving…' : 'Save'}
|
||
|
|
</Button>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
</CardContent>
|
||
|
|
</Card>
|
||
|
|
);
|
||
|
|
}
|