import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { FormGeneratorTable, type ColumnConfig } from '../../components/FormGenerator/FormGeneratorTable'; import { useAdminSubscriptions } from '../../hooks/useAdminSubscriptions'; import { useConfirm } from '../../hooks/useConfirm'; import { useApiRequest } from '../../hooks/useApi'; import { fetchAttributes } from '../../api/attributesApi'; import type { AttributeDefinition } from '../../api/attributesApi'; import { resolveColumnTypes } from '../../utils/columnTypeResolver'; import api from '../../api'; import styles from './Billing.module.css'; import { useLanguage } from '../../providers/language/LanguageContext'; const _TERMINAL_STATUSES = new Set(['EXPIRED']); const AdminSubscriptionsPage: React.FC = () => { const { t } = useLanguage(); const { request } = useApiRequest(); const [backendAttributes, setBackendAttributes] = useState([]); const { confirm, ConfirmDialog } = useConfirm(); const { data: subscriptions, pagination, loading, refetch } = useAdminSubscriptions(); useEffect(() => { fetchAttributes(request, 'MandateSubscriptionView') .then(setBackendAttributes) .catch(() => setBackendAttributes([])); }, [request]); const _rawColumns: ColumnConfig[] = useMemo(() => [ { key: 'mandateName', label: t('Mandant'), sortable: true, filterable: true, width: 180 }, { key: 'planTitle', label: t('Plan'), sortable: true, filterable: true, width: 180 }, { key: 'status', label: t('Status'), sortable: true, filterable: true, width: 110 }, { key: 'recurring', label: t('Wiederkehrend'), sortable: true, filterable: true, width: 120 }, { key: 'activeUsers', label: t('Benutzer'), sortable: true, width: 70 }, { key: 'activeInstances', label: t('Module'), sortable: true, width: 90 }, { key: 'monthlyRevenueCHF', label: t('Umsatz pro Monat'), sortable: true, width: 140 }, { key: 'startedAt', label: t('Gestartet'), sortable: true, filterable: true, width: 130 }, { key: 'currentPeriodEnd', label: t('Periodenende'), sortable: true, filterable: true, width: 130 }, { key: 'snapshotPricePerUserCHF', label: t('Preis pro Benutzer'), sortable: true, width: 100 }, { key: 'snapshotPricePerInstanceCHF', label: t('Preis pro Modul'), sortable: true, width: 110 }, ], [t]); const columns = useMemo( () => resolveColumnTypes(_rawColumns, backendAttributes), [_rawColumns, backendAttributes], ); const _handleForceCancel = useCallback(async (row: any) => { const ok = await confirm( t('Subscription «{plan}» für Mandant «{mandate}» sofort kündigen? Dies wird auch auf Stripe sofort storniert.', { plan: row.planTitle, mandate: row.mandateName }), { confirmLabel: t('Sofort kündigen'), cancelLabel: t('Abbrechen'), variant: 'danger' }, ); if (!ok) return; try { await api.post('/api/subscription/force-cancel', { subscriptionId: row.id }); await refetch(); } catch (err) { console.error('Force cancel failed:', err); } }, [confirm, refetch, t]); return (

{t('Abonnementübersicht')}

{t('Alle Abonnements aller Mandanten')}

_handleForceCancel(row), visible: (row: any) => !_TERMINAL_STATUSES.has(row._rawStatus), }, ]} emptyMessage={t('Keine Abonnements vorhanden')} />
); }; export default AdminSubscriptionsPage;