diff --git a/src/app/admin/finance-management/page.tsx b/src/app/admin/finance-management/page.tsx index 9b559ba..96d72ae 100644 --- a/src/app/admin/finance-management/page.tsx +++ b/src/app/admin/finance-management/page.tsx @@ -18,10 +18,6 @@ export default function FinanceManagementPage() { const [diagData, setDiagData] = useState(null) const [selectedInvoice, setSelectedInvoice] = useState(null) const [detailModalOpen, setDetailModalOpen] = useState(false) - const [emailDialogOpen, setEmailDialogOpen] = useState(false) - const [reportEmail, setReportEmail] = useState('') - const [sendingReport, setSendingReport] = useState(false) - const [reportMsg, setReportMsg] = useState<{ type: 'success' | 'error'; text: string } | null>(null) // NEW: fetch invoices from backend const { @@ -120,66 +116,6 @@ export default function FinanceManagementPage() { URL.revokeObjectURL(url) } - const [pdfLoading, setPdfLoading] = useState(null) - - const viewInvoicePdf = async (inv: AdminInvoice) => { - setPdfLoading(inv.id) - try { - const base = process.env.NEXT_PUBLIC_API_BASE_URL || '' - const res = await fetch(`${base}/api/invoices/${inv.id}/pdf`, { - method: 'GET', - credentials: 'include', - headers: { - ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}), - }, - }) - if (!res.ok) { - const body = await res.json().catch(() => ({})) - throw new Error(body?.message || `Failed to load PDF (${res.status})`) - } - const blob = await res.blob() - const blobUrl = URL.createObjectURL(blob) - window.open(blobUrl, '_blank', 'noopener,noreferrer') - } catch (e: any) { - setReportMsg({ type: 'error', text: e?.message || 'Failed to load invoice PDF.' }) - } finally { - setPdfLoading(null) - } - } - - const sendEmailReport = async () => { - if (!reportEmail.trim()) return - setReportMsg(null) - setSendingReport(true) - try { - const base = process.env.NEXT_PUBLIC_API_BASE_URL || '' - const res = await fetch(`${base}/api/admin/invoices/email-report`, { - method: 'POST', - credentials: 'include', - headers: { - 'Content-Type': 'application/json', - ...(accessToken ? { Authorization: `Bearer ${accessToken}` } : {}), - }, - body: JSON.stringify({ - email: reportEmail.trim(), - from: billFilter.from || undefined, - to: billFilter.to || undefined, - }), - }) - const body = await res.json().catch(() => ({})) - if (!res.ok || body?.success === false) { - throw new Error(body?.message || `Request failed (${res.status})`) - } - setReportMsg({ type: 'success', text: `Report sent to ${reportEmail.trim()} (${body.data?.sentCount ?? 0} paid invoice(s)).` }) - setEmailDialogOpen(false) - setReportEmail('') - } catch (e: any) { - setReportMsg({ type: 'error', text: e?.message || 'Failed to send email report.' }) - } finally { - setSendingReport(false) - } - } - return (
@@ -246,7 +182,6 @@ export default function FinanceManagementPage() {

Invoices

- @@ -287,11 +222,6 @@ export default function FinanceManagementPage() {
- {reportMsg && ( -
- {reportMsg.text} -
- )} {invError && (
{invError} @@ -412,18 +342,11 @@ export default function FinanceManagementPage() { - @@ -443,47 +366,6 @@ export default function FinanceManagementPage() { onExport={(inv) => exportInvoice(inv)} /> )} - - {/* Email Report Dialog */} - {emailDialogOpen && ( -
-
-

Send Email Report

-
- Only paid invoices will be included in the report, regardless of the status filter. - {(billFilter.from || billFilter.to) && ( - The current date range filter ({billFilter.from || '…'} – {billFilter.to || '…'}) will be applied. - )} -
- - setReportEmail(e.target.value)} - placeholder="email@example.com" - className="w-full rounded-lg border border-gray-200 px-3 py-2 text-sm text-gray-900 placeholder:text-gray-400 focus:ring-2 focus:ring-blue-900 focus:border-transparent" - autoFocus - onKeyDown={e => { if (e.key === 'Enter' && !sendingReport) sendEmailReport() }} - /> -
- - -
-
-
- )}
diff --git a/src/app/coffee-abonnements/summary/components/SignaturePad.tsx b/src/app/coffee-abonnements/summary/components/SignaturePad.tsx index 7d743f8..c81c7d3 100644 --- a/src/app/coffee-abonnements/summary/components/SignaturePad.tsx +++ b/src/app/coffee-abonnements/summary/components/SignaturePad.tsx @@ -6,11 +6,9 @@ type Props = { value: string onChange: (dataUrl: string) => void className?: string - required?: boolean - error?: string | null } -export default function SignaturePad({ value, onChange, className, required = false, error = null }: Props) { +export default function SignaturePad({ value, onChange, className }: Props) { const canvasRef = useRef(null) const isDrawing = useRef(false) @@ -139,9 +137,7 @@ export default function SignaturePad({ value, onChange, className, required = fa return (
-

- Signature{required ? ' *' : ''} -

+

Signature

-
+
-

- {error || (value ? 'Signature captured.' : 'Draw your signature in the box.')} +

+ {value ? 'Signature captured.' : 'Draw your signature in the box.'}

) diff --git a/src/app/coffee-abonnements/summary/hooks/subscribeAbo.ts b/src/app/coffee-abonnements/summary/hooks/subscribeAbo.ts index 4f6537c..1b6637b 100644 --- a/src/app/coffee-abonnements/summary/hooks/subscribeAbo.ts +++ b/src/app/coffee-abonnements/summary/hooks/subscribeAbo.ts @@ -70,14 +70,6 @@ export async function subscribeAbo(input: SubscribeAboInput) { throw new Error(`Missing required fields: ${missing.join(', ')}`) } - if (typeof input.signingCity !== 'string' || input.signingCity.trim() === '') { - throw new Error('signingCity is required') - } - - if (typeof input.signatureDataUrl !== 'string' || input.signatureDataUrl.trim() === '') { - throw new Error('signatureDataUrl is required') - } - const body: any = { billing_interval: input.billing_interval ?? 'month', interval_count: input.interval_count ?? 1, diff --git a/src/app/coffee-abonnements/summary/page.tsx b/src/app/coffee-abonnements/summary/page.tsx index f87ad1c..5ed3dad 100644 --- a/src/app/coffee-abonnements/summary/page.tsx +++ b/src/app/coffee-abonnements/summary/page.tsx @@ -510,16 +510,12 @@ export default function SummaryPage() { const hasRequiredSelfFields = requiredSelfFields.every(k => String(form[k]).trim() !== '') const hasRequiredInvoiceFields = form.invoiceSameAsShipping || form.invoiceEmail.trim() !== '' - const hasSigningCity = form.signingCity.trim() !== '' - const hasSignature = signatureDataUrl.trim() !== '' const canSubmit = selectedEntries.length > 0 && totalPacks === requiredPacks && hasRequiredSelfFields && - hasRequiredInvoiceFields && - hasSigningCity && - hasSignature; + hasRequiredInvoiceFields; const backToSelection = () => router.push('/coffee-abonnements'); @@ -531,16 +527,6 @@ export default function SummaryPage() { return } - if (!hasSigningCity) { - setSubmitError('Signing city is required.') - return - } - - if (!hasSignature) { - setSubmitError('Signature is required.') - return - } - setSubmitError(null) setSubmitLoading(true) try { @@ -795,13 +781,10 @@ export default function SummaryPage() {
- - - {!hasSigningCity && submitError && ( -

Ort ist erforderlich.

- )} + +
- +
@@ -855,7 +838,7 @@ export default function SummaryPage() { {!canSubmit && (

- Please select coffees and fill all required buyer fields, signing city, and signature. + Please select coffees and fill all required buyer fields.

)}
diff --git a/src/app/profile/components/financeInvoices.tsx b/src/app/profile/components/financeInvoices.tsx index 22ca016..f055ba7 100644 --- a/src/app/profile/components/financeInvoices.tsx +++ b/src/app/profile/components/financeInvoices.tsx @@ -28,10 +28,8 @@ const isAbsUrl = (url: string) => /^https?:\/\//i.test(url) const resolveInvoiceUrl = (invoice: AboInvoice) => { const raw = invoice.pdfUrl || invoice.downloadUrl || invoice.htmlUrl || invoice.fileUrl - if (raw) return isAbsUrl(raw) ? raw : `${BASE_URL}${raw.startsWith('/') ? '' : '/'}${raw}` - // Fallback: use the backend PDF proxy endpoint if an id is available - if (invoice.id) return `${BASE_URL}/api/invoices/${invoice.id}/pdf` - return null + if (!raw) return null + return isAbsUrl(raw) ? raw : `${BASE_URL}${raw.startsWith('/') ? '' : '/'}${raw}` } type UiLifecycleStatus = 'issued' | 'ongoing' | 'finished' | 'pause' | 'cancelled' @@ -82,25 +80,14 @@ export default function FinanceInvoices({ abonementId }: Props) { const [busyId, setBusyId] = React.useState(null) const [actionError, setActionError] = React.useState(null) - const onView = async (invoice: AboInvoice) => { + const onView = (invoice: AboInvoice) => { setActionError(null) const url = resolveInvoiceUrl(invoice) if (!url) { setActionError('No view URL is available for this invoice.') return } - setBusyId(invoice.id) - try { - const res = await authFetch(url, { method: 'GET' }) - if (!res.ok) throw new Error(`Failed to load PDF: ${res.status}`) - const blob = await res.blob() - const blobUrl = URL.createObjectURL(blob) - window.open(blobUrl, '_blank', 'noopener,noreferrer') - } catch (e: any) { - setActionError(e?.message || 'Failed to load invoice PDF.') - } finally { - setBusyId(null) - } + window.open(url, '_blank', 'noopener,noreferrer') } const onDownload = async (invoice: AboInvoice) => {