books/frontend/src/pages/Eksport.tsx
Nicolaj Hartmann 381156ade7 Add frontend components, API mutations, and project config
Frontend:
- API mutations for accounts, bank connections, customers, invoices
- Document processing API
- Shared components (PageHeader, EmptyState, etc.)
- Pages: Admin, Fakturaer, Kunder, Ordrer, Produkter, etc.
- Hooks and stores

Config:
- CLAUDE.md project instructions
- Beads issue tracking config
- Git attributes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 22:20:03 +01:00

209 lines
6.4 KiB
TypeScript

import { useState } from 'react';
import {
Typography,
Card,
Row,
Col,
Form,
Select,
Button,
Tag,
Alert,
Spin,
} from 'antd';
import { showSuccess, showError } from '@/lib/errorHandling';
import { DownloadOutlined, FileTextOutlined } from '@ant-design/icons';
import { useCompany } from '@/hooks/useCompany';
import { useFiscalYears } from '@/api/queries/fiscalYearQueries';
import { useExportSaft, downloadSaftFile } from '@/api/mutations/saftMutations';
import { formatDate } from '@/lib/formatters';
import { spacing } from '@/styles/designTokens';
const { Title, Text, Paragraph } = Typography;
export default function Eksport() {
const { company } = useCompany();
const { data: fiscalYears, isLoading: fiscalYearsLoading } = useFiscalYears(company?.id);
const exportSaft = useExportSaft();
const [selectedFiscalYear, setSelectedFiscalYear] = useState<string>();
const handleExportSaft = async () => {
if (!company?.id || !selectedFiscalYear) {
showError('Vælg venligst et regnskabsår');
return;
}
try {
const result = await exportSaft.mutateAsync({
companyId: company.id,
fiscalYearId: selectedFiscalYear,
});
if (result.success) {
downloadSaftFile(result);
showSuccess(`SAF-T fil downloadet: ${result.fileName}`);
} else {
showError(result.errorMessage || 'Kunne ikke generere SAF-T fil');
}
} catch (error) {
showError('Der opstod en fejl under eksport');
console.error('SAF-T export error:', error);
}
};
if (fiscalYearsLoading) {
return (
<div style={{ textAlign: 'center', padding: spacing.xl }}>
<Spin size="large" />
</div>
);
}
const selectedYear = fiscalYears?.find(fy => fy.id === selectedFiscalYear);
return (
<div>
<Title level={4}>Eksporter data</Title>
<Paragraph type="secondary">
Eksporter regnskabsdata til forskellige formater for compliance og rapportering.
</Paragraph>
<Row gutter={[spacing.lg, spacing.lg]}>
{/* SAF-T Export Card */}
<Col xs={24} md={12}>
<Card
title={
<span>
<FileTextOutlined style={{ marginRight: 8 }} />
SAF-T (Standard Audit File for Tax)
</span>
}
>
<Paragraph type="secondary">
Eksporter regnskabsdata i SAF-T format til SKAT.
Dette er det danske standardformat for digital indberetning af regnskabsdata.
</Paragraph>
<Alert
message="Lovkrav fra 1. januar 2027"
description="SAF-T eksport bliver obligatorisk for alle virksomheder med omsætning over 300.000 DKK."
type="info"
showIcon
style={{ marginBottom: spacing.md }}
/>
<Form layout="vertical">
<Form.Item
label="Regnskabsår"
required
help={selectedYear ? `${formatDate(selectedYear.startDate)} - ${formatDate(selectedYear.endDate)}` : undefined}
>
<Select
placeholder="Vælg regnskabsår"
value={selectedFiscalYear}
onChange={setSelectedFiscalYear}
loading={fiscalYearsLoading}
options={fiscalYears?.map(fy => ({
value: fy.id,
label: (
<span>
{fy.name}
{fy.status === 'locked' && (
<Tag color="red" style={{ marginLeft: 8 }}>Låst</Tag>
)}
{fy.status === 'closed' && (
<Tag color="orange" style={{ marginLeft: 8 }}>Afsluttet</Tag>
)}
</span>
),
}))}
style={{ width: '100%' }}
/>
</Form.Item>
<Button
type="primary"
icon={<DownloadOutlined />}
onClick={handleExportSaft}
loading={exportSaft.isPending}
disabled={!selectedFiscalYear}
block
>
Download SAF-T XML
</Button>
</Form>
<div style={{ marginTop: spacing.md }}>
<Text type="secondary" style={{ fontSize: 12 }}>
Filen inkluderer: Kontoplan, kunder, leverandører og alle posteringer for perioden.
</Text>
</div>
</Card>
</Col>
{/* CSV Export Card (Coming Soon) */}
<Col xs={24} md={12}>
<Card
title={
<span>
<FileTextOutlined style={{ marginRight: 8 }} />
CSV Eksport
</span>
}
extra={<Tag>Kommer snart</Tag>}
>
<Paragraph type="secondary">
Eksporter kontoplan, posteringer eller kunder som CSV-filer til brug i regneark.
</Paragraph>
<Button disabled block>
Ikke tilgængelig endnu
</Button>
</Card>
</Col>
{/* PDF Report Card (Coming Soon) */}
<Col xs={24} md={12}>
<Card
title={
<span>
<FileTextOutlined style={{ marginRight: 8 }} />
Årsrapport (PDF)
</span>
}
extra={<Tag>Kommer snart</Tag>}
>
<Paragraph type="secondary">
Generér årsrapport i PDF format med resultatopgørelse og balance.
</Paragraph>
<Button disabled block>
Ikke tilgængelig endnu
</Button>
</Card>
</Col>
{/* Backup Card (Coming Soon) */}
<Col xs={24} md={12}>
<Card
title={
<span>
<FileTextOutlined style={{ marginRight: 8 }} />
Fuld backup
</span>
}
extra={<Tag>Kommer snart</Tag>}
>
<Paragraph type="secondary">
Download en komplet backup af alle virksomhedens data i JSON format.
</Paragraph>
<Button disabled block>
Ikke tilgængelig endnu
</Button>
</Card>
</Col>
</Row>
</div>
);
}