diff --git a/src/app/quickaction-dashboard/register-sign-contract/company/page.tsx b/src/app/quickaction-dashboard/register-sign-contract/company/page.tsx index d353eeb..c177770 100644 --- a/src/app/quickaction-dashboard/register-sign-contract/company/page.tsx +++ b/src/app/quickaction-dashboard/register-sign-contract/company/page.tsx @@ -29,9 +29,12 @@ export default function CompanySignContractPage() { const [submitting, setSubmitting] = useState(false) const [success, setSuccess] = useState(false) const [error, setError] = useState('') - const [previewLoading, setPreviewLoading] = useState(false) - const [previewHtml, setPreviewHtml] = useState(null) - const [previewError, setPreviewError] = useState(null) + const [activeTab, setActiveTab] = useState<'contract' | 'gdpr'>('contract') + const [previewState, setPreviewState] = useState({ + contract: { loading: false, html: null as string | null, error: null as string | null }, + gdpr: { loading: false, html: null as string | null, error: null as string | null } + }) + const [previewsReady, setPreviewsReady] = useState(false) useEffect(() => { setDate(new Date().toISOString().slice(0, 10)) @@ -119,46 +122,82 @@ export default function CompanySignContractPage() { setSignatureDataUrl('') } - // Load latest contract preview for company user + const loadPreview = async (contractType: 'contract' | 'gdpr') => { + if (!accessToken) return + setPreviewState((prev) => ({ + ...prev, + [contractType]: { ...prev[contractType], loading: true, error: null } + })) + try { + const res = await fetch(`${API_BASE_URL}/api/contracts/preview/latest?contract_type=${contractType}`, { + method: 'GET', + headers: { Authorization: `Bearer ${accessToken}` }, + credentials: 'include' + }) + if (!res.ok) { + await res.text().catch(() => null) + throw new Error('No contract available at this moment, please contact us.') + } + const html = await res.text() + setPreviewState((prev) => ({ + ...prev, + [contractType]: { loading: false, html, error: null } + })) + } catch (e: unknown) { + console.error('CompanySignContractPage.loadPreview error:', e) + setPreviewState((prev) => ({ + ...prev, + [contractType]: { loading: false, html: null, error: 'No contract available at this moment, please contact us.' } + })) + } + } + + // Load latest contract + GDPR previews for company user useEffect(() => { - const loadPreview = async () => { - if (!accessToken) return - setPreviewLoading(true) - setPreviewError(null) - try { - const res = await fetch(`${API_BASE_URL}/api/contracts/preview/latest?contract_type=company`, { - method: 'GET', - headers: { Authorization: `Bearer ${accessToken}` }, - credentials: 'include' - }) - if (!res.ok) { - const text = await res.text().catch(() => '') - throw new Error(text || 'Failed to load contract preview') - } - const html = await res.text() - setPreviewHtml(html) - } catch (e: any) { - console.error('CompanySignContractPage.loadPreview error:', e) - setPreviewError(e?.message || 'Failed to load contract preview') - setPreviewHtml(null) - } finally { - setPreviewLoading(false) + if (!accessToken) return + loadPreview('contract') + loadPreview('gdpr') + }, [accessToken]) + + useEffect(() => { + const doneLoading = !previewState.contract.loading && !previewState.gdpr.loading + const anyAvailable = !!previewState.contract.html || !!previewState.gdpr.html + const blockingMsg = 'Temporarily unable to sign contracts. No active documents are available at this moment.' + if (doneLoading) { + setPreviewsReady(true) + // If one preview is missing, default to showing the available one + if (!previewState.contract.html && previewState.gdpr.html) { + setActiveTab('gdpr') + } else if (previewState.contract.html && !previewState.gdpr.html) { + setActiveTab('contract') } } - loadPreview() - }, [accessToken]) + // Only show a blocking error if BOTH are missing; clear it as soon as one exists. + if (doneLoading) { + if (anyAvailable) { + setError((prev) => (prev === blockingMsg ? '' : prev)) + } else { + setError(blockingMsg) + } + } + }, [previewState]) const valid = () => { const companyValid = companyName.trim().length >= 3 const repNameValid = repName.trim().length >= 3 const repTitleValid = repTitle.trim().length >= 2 const locationValid = location.trim().length >= 2 - const contractChecked = agreeContract - const dataChecked = agreeData + const contractAvailable = !!previewState.contract.html + const gdprAvailable = !!previewState.gdpr.html + + // Only require acknowledgements for documents that actually exist + const contractChecked = contractAvailable ? agreeContract : true + const dataChecked = gdprAvailable ? agreeData : true const signatureChecked = confirmSignature const signatureDrawn = !!signatureDataUrl - return companyValid && repNameValid && repTitleValid && locationValid && contractChecked && dataChecked && signatureChecked && signatureDrawn + const anyPreview = contractAvailable || gdprAvailable + return companyValid && repNameValid && repTitleValid && locationValid && contractChecked && dataChecked && signatureChecked && signatureDrawn && anyPreview } const handleSubmit = async (e: React.FormEvent) => { @@ -166,12 +205,26 @@ export default function CompanySignContractPage() { if (!valid()) { // Detailed error message to help debug const issues: string[] = [] + const contractAvailable = !!previewState.contract.html + const gdprAvailable = !!previewState.gdpr.html + + if (!contractAvailable && !gdprAvailable) { + const msg = 'Temporarily unable to sign contracts. No active documents are available at this moment.' + setError(msg) + showToast({ + variant: 'error', + title: 'No documents available', + message: msg, + }) + return + } + if (companyName.trim().length < 3) issues.push('Company name (min 3 characters)') if (repName.trim().length < 3) issues.push('Representative name (min 3 characters)') if (repTitle.trim().length < 2) issues.push('Representative title (min 2 characters)') if (location.trim().length < 2) issues.push('Location (min 2 characters)') - if (!agreeContract) issues.push('Contract read and understood') - if (!agreeData) issues.push('Privacy policy accepted') + if (contractAvailable && !agreeContract) issues.push('Contract read and understood') + if (gdprAvailable && !agreeData) issues.push('Privacy policy accepted') if (!confirmSignature) issues.push('Electronic signature confirmed') if (!signatureDataUrl) issues.push('Signature captured on pad') @@ -251,9 +304,9 @@ export default function CompanySignContractPage() { router.push('/dashboard') }, 2000) - } catch (error: any) { + } catch (error: unknown) { console.error('Contract signing error:', error) - const msg = error.message || 'Signature failed. Please try again.' + const msg = error instanceof Error ? (error.message || 'Signature failed. Please try again.') : 'Signature failed. Please try again.' setError(msg) showToast({ variant: 'error', @@ -332,13 +385,53 @@ export default function CompanySignContractPage() {
-

Contract Information

-
    -
  • Contract ID: COMP-2024-017
  • -
  • Version: 2.4 (valid from 01.11.2024)
  • -
  • Jurisdiction: EU / Germany
  • -
  • Language: DE (binding)
  • -
+
+

Document Information

+
+ {(['contract','gdpr'] as const).map((tab) => ( + + ))} +
+
+ {(() => { + const meta = activeTab === 'contract' + ? { + id: 'COMP-2025-001', + title: 'VERTRIEBSPARTNER / BUSINESSPARTNER / AFFILIATE - VERTRAG', + version: 'idF 21.05.2025', + jurisdiction: 'EU / Austria (Graz)', + language: 'DE (binding)', + issuer: 'Profit Planet GmbH', + address: 'Liebenauer Hauptstraße 82c, A-8041 Graz' + } + : { + id: 'COMP-GDPR-2025-001', + title: 'SUB-AUFTRAGSVERARBEITUNGS-VERTRAG', + version: 'Art. 28 Abs. 3 DSGVO', + jurisdiction: 'EU / Austria (Graz)', + language: 'DE (binding)', + issuer: 'Profit Planet GmbH', + address: 'Liebenauer Hauptstraße 82c, A-8041 Graz' + } + return ( +
    +
  • Document: {meta.title}
  • +
  • ID: {meta.id}
  • +
  • Version / Basis: {meta.version}
  • +
  • Jurisdiction: {meta.jurisdiction}
  • +
  • Language: {meta.language}
  • +
  • Issuer: {meta.issuer}
  • +
  • Address: {meta.address}
  • +
+ ) + })()}

Attention

@@ -350,60 +443,54 @@ export default function CompanySignContractPage() {
-

Company Contract Preview

+
+ Document Preview +
+ {(['contract','gdpr'] as const).map((tab) => ( + + ))} +
+
- {previewLoading ? ( + {previewState[activeTab].loading ? (
Loading preview…
- ) : previewError ? ( -
{previewError}
- ) : previewHtml ? ( -