import { useCallback, useEffect, useState, type ReactElement } from 'react'; import { SkeletonRow } from '../../components/skeleton.js'; import { createSource, deleteSource, getSources, updateSource } from '../../lib/api.js'; import { SourceForm } from './source-forms.js'; import { SOURCE_LABELS, type SourceConfig, type SourceType } from './source-types.js'; type DialogState = | { mode: 'add'; sourceType: SourceType } | { mode: 'edit'; source: SourceConfig } | { mode: 'confirm-delete'; source: SourceConfig } | null; export function SourcesTab(): ReactElement { const [sources, setSources] = useState([]); const [loading, setLoading] = useState(true); const [dialog, setDialog] = useState(null); const [error, setError] = useState(null); const [addType, setAddType] = useState('poalim'); const load = useCallback(async () => { setLoading(true); try { const list = await getSources(); setSources(list); } catch { setError('Failed to load sources'); } finally { setLoading(false); } }, []); useEffect(() => { void load(); }, [load]); async function handleAdd(data: Omit) { try { const list = await createSource({ ...data, type: (dialog as { mode: 'add'; sourceType: SourceType }).sourceType, }); setSources(list); setDialog(null); } catch { setError('Failed to add source'); } } async function handleEdit(data: Omit) { const source = (dialog as { mode: 'edit'; source: SourceConfig }).source; try { const list = await updateSource(source.id, data); setSources(list); setDialog(null); } catch { setError('Failed to update source'); } } async function handleDelete(id: string) { try { const list = await deleteSource(id); setSources(list); setDialog(null); } catch { setError('Failed to delete source'); } } function displayName(s: SourceConfig): string { if (s.nickname) return s.nickname; if (s.type === 'poalim') return `Poalim (${s.userCode})`; if (s.type === 'discount') return `Discount (${s.ID})`; if (s.type === 'isracard' || s.type === 'amex') return `${SOURCE_LABELS[s.type]} (${s.ownerId})`; if (s.type === 'cal' || s.type === 'max') return `${SOURCE_LABELS[s.type]} (${s.username})`; return ''; } return (

Sources

{error && (

{error}

)} {loading ? (
) : sources.length === 0 && !dialog ? (

No sources configured yet.

) : null}
    {sources.map(s => (
  • {SOURCE_LABELS[s.type]} — {displayName(s)}
  • ))}
{!dialog && (
)} {dialog && (
{dialog.mode === 'confirm-delete' ? ( <>

Delete source?

This will permanently remove{' '} {SOURCE_LABELS[dialog.source.type]} — {displayName(dialog.source)} {' '} and its stored credentials.

) : ( <>

{dialog.mode === 'add' ? `Add ${SOURCE_LABELS[dialog.sourceType]}` : `Edit ${SOURCE_LABELS[dialog.source.type]}`}

setDialog(null)} /> )}
)}
); }