191 lines
7.4 KiB
TypeScript
191 lines
7.4 KiB
TypeScript
import React from 'react';
|
|
import { Card } from '../../../components/layout/Card';
|
|
import { Section } from '../../../components/layout/Section';
|
|
import { Button } from '../../../components/shared/Button';
|
|
import { ComplianceChecklist } from '../../../components/shared/ComplianceChecklist';
|
|
|
|
interface ReviewStepProps {
|
|
formData: any;
|
|
onEdit: (step: number) => void;
|
|
onSubmit: () => void;
|
|
isLoading: boolean;
|
|
}
|
|
|
|
export function ReviewStep({ formData, onEdit, onSubmit, isLoading }: ReviewStepProps) {
|
|
const { business, authorizedRep, address, campaign } = formData;
|
|
|
|
// Auto-check compliance based on filled data
|
|
const complianceItems = [
|
|
{
|
|
label: 'Business details provided',
|
|
checked: !!business.businessName && !!business.businessType,
|
|
},
|
|
{
|
|
label: 'Valid EIN/registration number',
|
|
checked: business.registrationNumber.length === 9,
|
|
},
|
|
{
|
|
label: 'Authorized representative designated',
|
|
checked: !!authorizedRep.firstName && !!authorizedRep.email,
|
|
},
|
|
{
|
|
label: 'Physical business address provided',
|
|
checked: !!address.street && !!address.city,
|
|
},
|
|
{
|
|
label: 'Campaign use case defined',
|
|
checked: !!campaign.useCase,
|
|
},
|
|
{
|
|
label: 'Sample messages provided',
|
|
checked: campaign.sampleMessages.filter((m: string) => m.trim()).length > 0,
|
|
},
|
|
{
|
|
label: 'Opt-in process documented',
|
|
checked: !!campaign.messageFlow && !!campaign.optInType,
|
|
},
|
|
{
|
|
label: 'Opt-in confirmation message',
|
|
checked: !!campaign.optInMessage,
|
|
},
|
|
{
|
|
label: 'STOP instructions (opt-out)',
|
|
checked: !!campaign.optOutMessage && campaign.optOutMessage.toLowerCase().includes('stop'),
|
|
},
|
|
{
|
|
label: 'HELP instructions',
|
|
checked: !!campaign.helpMessage && campaign.helpMessage.toLowerCase().includes('help'),
|
|
},
|
|
];
|
|
|
|
const DataRow = ({ label, value }: { label: string; value: any }) => (
|
|
<div
|
|
style={{
|
|
display: 'grid',
|
|
gridTemplateColumns: '1fr 2fr',
|
|
gap: 'var(--spacing-4)',
|
|
padding: 'var(--spacing-3) 0',
|
|
borderBottom: `1px solid var(--color-border-secondary)`,
|
|
}}
|
|
>
|
|
<div style={{ fontSize: 'var(--font-size-sm)', fontWeight: 600, color: 'var(--color-text-secondary)' }}>
|
|
{label}
|
|
</div>
|
|
<div style={{ fontSize: 'var(--font-size-sm)', color: 'var(--color-text-primary)' }}>
|
|
{value || '—'}
|
|
</div>
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div>
|
|
<Section title="Business Information">
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 'var(--spacing-4)' }}>
|
|
<Button variant="secondary" size="sm" onClick={() => onEdit(0)}>
|
|
Edit
|
|
</Button>
|
|
</div>
|
|
<DataRow label="Business Name" value={business.businessName} />
|
|
<DataRow label="Business Type" value={business.businessType} />
|
|
<DataRow label="Industry" value={business.businessIndustry} />
|
|
<DataRow label="Company Type" value={business.companyType} />
|
|
<DataRow label="Registration ID" value={`${business.registrationIdentifier}: ${business.registrationNumber}`} />
|
|
<DataRow label="Website" value={business.websiteUrl} />
|
|
<DataRow label="Regions" value={business.regionsOfOperation.join(', ')} />
|
|
</Section>
|
|
|
|
<Section title="Authorized Representative">
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 'var(--spacing-4)' }}>
|
|
<Button variant="secondary" size="sm" onClick={() => onEdit(1)}>
|
|
Edit
|
|
</Button>
|
|
</div>
|
|
<DataRow label="Name" value={`${authorizedRep.firstName} ${authorizedRep.lastName}`} />
|
|
<DataRow label="Title" value={authorizedRep.businessTitle} />
|
|
<DataRow label="Position" value={authorizedRep.jobPosition} />
|
|
<DataRow label="Phone" value={authorizedRep.phoneNumber} />
|
|
<DataRow label="Email" value={authorizedRep.email} />
|
|
</Section>
|
|
|
|
<Section title="Business Address">
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 'var(--spacing-4)' }}>
|
|
<Button variant="secondary" size="sm" onClick={() => onEdit(2)}>
|
|
Edit
|
|
</Button>
|
|
</div>
|
|
<DataRow label="Customer Name" value={address.customerName} />
|
|
<DataRow
|
|
label="Address"
|
|
value={`${address.street}${address.streetSecondary ? ', ' + address.streetSecondary : ''}`}
|
|
/>
|
|
<DataRow label="City, State ZIP" value={`${address.city}, ${address.region} ${address.postalCode}`} />
|
|
<DataRow label="Country" value={address.isoCountry} />
|
|
</Section>
|
|
|
|
<Section title="Campaign Details">
|
|
<div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 'var(--spacing-4)' }}>
|
|
<Button variant="secondary" size="sm" onClick={() => onEdit(3)}>
|
|
Edit
|
|
</Button>
|
|
</div>
|
|
<DataRow label="Use Case" value={campaign.useCase} />
|
|
<DataRow label="Description" value={campaign.description} />
|
|
<DataRow
|
|
label="Sample Messages"
|
|
value={
|
|
<div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--spacing-2)' }}>
|
|
{campaign.sampleMessages
|
|
.filter((m: string) => m.trim())
|
|
.map((msg: string, i: number) => (
|
|
<div
|
|
key={i}
|
|
style={{
|
|
padding: 'var(--spacing-2)',
|
|
background: 'var(--color-background-secondary)',
|
|
borderRadius: 'var(--border-radius-md)',
|
|
fontSize: 'var(--font-size-xs)',
|
|
}}
|
|
>
|
|
{msg}
|
|
</div>
|
|
))}
|
|
</div>
|
|
}
|
|
/>
|
|
<DataRow label="Message Flow" value={campaign.messageFlow} />
|
|
<DataRow label="Opt-In Type" value={campaign.optInType} />
|
|
<DataRow label="Opt-In Message" value={campaign.optInMessage} />
|
|
<DataRow label="Opt-Out Message" value={campaign.optOutMessage} />
|
|
<DataRow label="Help Message" value={campaign.helpMessage} />
|
|
<DataRow
|
|
label="Content Flags"
|
|
value={`${campaign.hasEmbeddedLinks ? 'Links' : ''} ${campaign.hasEmbeddedPhone ? 'Phone Numbers' : ''} ${
|
|
!campaign.hasEmbeddedLinks && !campaign.hasEmbeddedPhone ? 'None' : ''
|
|
}`.trim()}
|
|
/>
|
|
</Section>
|
|
|
|
<div style={{ marginTop: 'var(--spacing-6)' }}>
|
|
<ComplianceChecklist items={complianceItems} />
|
|
</div>
|
|
|
|
<div style={{ marginTop: 'var(--spacing-6)' }}>
|
|
<Card padding="lg">
|
|
<div style={{ marginBottom: 'var(--spacing-4)' }}>
|
|
<h3 style={{ fontSize: 'var(--font-size-xl)', fontWeight: 600, marginBottom: 'var(--spacing-2)' }}>
|
|
Ready to Submit?
|
|
</h3>
|
|
<p style={{ fontSize: 'var(--font-size-sm)', color: 'var(--color-text-secondary)', margin: 0 }}>
|
|
Your registration will be submitted to Twilio's A2P Trust Registry. This process typically takes 2-5
|
|
business days. You'll receive a branded landing page URL once approved.
|
|
</p>
|
|
</div>
|
|
<Button onClick={onSubmit} loading={isLoading} fullWidth size="lg">
|
|
{isLoading ? 'Submitting...' : 'Submit Registration'}
|
|
</Button>
|
|
</Card>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|