ui-nyla/src/pages/views/trustee/TrusteeImportProcessView.tsx
2026-04-21 00:50:42 +02:00

115 lines
4.4 KiB
TypeScript

/**
* TrusteeImportProcessView
*
* Tab-based wrapper for the "Import & Verarbeitung" page. Consolidates the
* three import-related entry points under a single navigation item:
* - receipts : Belege verarbeiten (SharePoint -> Buchhaltung pipeline)
* - upload : Beleg hochladen (scan/manual upload)
* - sync : Daten einlesen (redirects to accounting settings,
* tab 'import-data' for the actual sync UI)
*
* The tab is controlled via the URL query parameter `?tab=...`, so
* QuickActions and deep links stay stable.
*/
import React, { useCallback, useEffect } from 'react';
import { useNavigate, useParams, useSearchParams } from 'react-router-dom';
import { useLanguage } from '../../../providers/language/LanguageContext';
import styles from './TrusteeViews.module.css';
import { TrusteeExpenseImportView } from './TrusteeExpenseImportView';
import { TrusteeScanUploadView } from './TrusteeScanUploadView';
interface TabDef {
id: string;
icon: string;
color: string;
}
const _TABS: TabDef[] = [
{ id: 'receipts', icon: '\uD83D\uDCC4', color: '#4CAF50' },
{ id: 'upload', icon: '\uD83D\uDCF7', color: '#607D8B' },
{ id: 'sync', icon: '\uD83D\uDD04', color: '#FF9800' },
];
function _tabLabel(tabId: string, t: (k: string) => string): string {
switch (tabId) {
case 'receipts': return t('Belege verarbeiten');
case 'upload': return t('Beleg hochladen');
case 'sync': return t('Daten einlesen');
default: return tabId;
}
}
function _tabDescription(tabId: string, t: (k: string) => string): string {
switch (tabId) {
case 'receipts': return t('Belege aus SharePoint importieren, klassifizieren und verbuchen.');
case 'upload': return t('Beleg scannen oder als Datei hochladen.');
case 'sync': return t('Buchhaltungsdaten aus dem externen System einlesen.');
default: return '';
}
}
export const TrusteeImportProcessView: React.FC = () => {
const { t } = useLanguage();
const navigate = useNavigate();
const { mandateId, featureCode, instanceId } = useParams<{ mandateId: string; featureCode: string; instanceId: string }>();
const [searchParams, setSearchParams] = useSearchParams();
const activeTab = searchParams.get('tab') || _TABS[0].id;
const _setActiveTab = useCallback((tab: string) => {
setSearchParams({ tab }, { replace: true });
}, [setSearchParams]);
useEffect(() => {
if (activeTab !== 'sync') return;
if (!mandateId || !featureCode || !instanceId) return;
const target = `/mandates/${mandateId}/${featureCode}/${instanceId}/settings?tab=import-data`;
navigate(target, { replace: true });
}, [activeTab, mandateId, featureCode, instanceId, navigate]);
return (
<div className={styles.listView}>
<div className={styles.expenseImportSection}>
<h3 className={styles.sectionTitle}>{t('Import & Verarbeitung')}</h3>
<div style={{ display: 'flex', gap: '0.25rem', marginBottom: '1.5rem', borderBottom: '2px solid var(--border-color, #e0e0e0)', paddingBottom: 0 }}>
{_TABS.map((tab) => (
<button
key={tab.id}
onClick={() => _setActiveTab(tab.id)}
style={{
padding: '0.625rem 1rem',
border: 'none',
borderBottom: activeTab === tab.id ? `3px solid ${tab.color}` : '3px solid transparent',
background: 'transparent',
color: activeTab === tab.id ? 'var(--text-primary, #1a1a1a)' : 'var(--text-secondary, #666)',
fontWeight: activeTab === tab.id ? 600 : 400,
fontSize: '0.875rem',
cursor: 'pointer',
transition: 'all 0.2s',
marginBottom: '-2px',
}}
>
<span style={{ marginRight: '0.375rem' }}>{tab.icon}</span>
{_tabLabel(tab.id, t)}
</button>
))}
</div>
<p className={styles.sectionDescription}>
{_tabDescription(activeTab, t)}
</p>
{activeTab === 'receipts' && <TrusteeExpenseImportView embedded />}
{activeTab === 'upload' && <TrusteeScanUploadView embedded />}
{activeTab === 'sync' && (
<div className={styles.infoBox}>
<p>{t('Weiterleitung zu den Buchhaltungs-Einstellungen…')}</p>
</div>
)}
</div>
</div>
);
};
export default TrusteeImportProcessView;