344 lines
14 KiB
TypeScript
344 lines
14 KiB
TypeScript
import React, { useState } from 'react';
|
|
import { PageHeader } from '../../components/layout/PageHeader';
|
|
import { Card } from '../../components/layout/Card';
|
|
import { StepProgress } from '../../components/layout/StepProgress';
|
|
import { FormSection } from '../../components/forms/FormSection';
|
|
import { FormField } from '../../components/forms/FormField';
|
|
import { SelectField } from '../../components/forms/SelectField';
|
|
import { PhoneInput } from '../../components/forms/PhoneInput';
|
|
import { EINInput } from '../../components/forms/EINInput';
|
|
import { Button } from '../../components/shared/Button';
|
|
import { Toast } from '../../components/shared/Toast';
|
|
import { useMCPApp } from '../../hooks/useMCPApp';
|
|
import { useSmartAction } from '../../hooks/useSmartAction';
|
|
import type { RegistrationInput } from '../../../src/types';
|
|
|
|
const STEPS = [
|
|
{ label: 'Business Info', description: 'Basic details' },
|
|
{ label: 'Authorized Rep', description: 'Contact person' },
|
|
{ label: 'Address', description: 'Business location' },
|
|
{ label: 'Campaign', description: 'Use case & messages' },
|
|
{ label: 'Review', description: 'Confirm & submit' }
|
|
];
|
|
|
|
export default function RegistrationWizard() {
|
|
const { context, loading: contextLoading } = useMCPApp<{ prefillData?: RegistrationInput }>();
|
|
const { callTool, loading: submitting } = useSmartAction();
|
|
|
|
const [currentStep, setCurrentStep] = useState(0);
|
|
const [toast, setToast] = useState<{ message: string; type: 'success' | 'error' } | null>(null);
|
|
|
|
const [formData, setFormData] = useState<Partial<RegistrationInput>>(
|
|
context?.prefillData || {
|
|
business: {},
|
|
authorizedRep: {},
|
|
address: {},
|
|
campaign: { sampleMessages: [''], hasEmbeddedLinks: false, hasEmbeddedPhone: false },
|
|
phone: {}
|
|
} as any
|
|
);
|
|
|
|
const updateField = (section: keyof RegistrationInput, field: string, value: any) => {
|
|
setFormData(prev => ({
|
|
...prev,
|
|
[section]: {
|
|
...(prev[section] as any),
|
|
[field]: value
|
|
}
|
|
}));
|
|
};
|
|
|
|
const handleNext = () => {
|
|
if (currentStep < STEPS.length - 1) {
|
|
setCurrentStep(currentStep + 1);
|
|
}
|
|
};
|
|
|
|
const handlePrevious = () => {
|
|
if (currentStep > 0) {
|
|
setCurrentStep(currentStep - 1);
|
|
}
|
|
};
|
|
|
|
const handleSubmit = async () => {
|
|
try {
|
|
await callTool('a2p_submit_registration', formData);
|
|
setToast({ message: 'Registration submitted successfully!', type: 'success' });
|
|
setTimeout(() => {
|
|
// In production, this would close the app or navigate
|
|
window.location.reload();
|
|
}, 2000);
|
|
} catch (error) {
|
|
setToast({ message: 'Submission failed. Please try again.', type: 'error' });
|
|
}
|
|
};
|
|
|
|
if (contextLoading) {
|
|
return <div className="flex items-center justify-center h-screen">Loading...</div>;
|
|
}
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50">
|
|
<PageHeader
|
|
title="A2P Registration Wizard"
|
|
subtitle="Complete your brand and campaign registration"
|
|
/>
|
|
|
|
<div className="container mx-auto px-6 py-8">
|
|
<Card className="max-w-4xl mx-auto">
|
|
<div className="p-6 space-y-8">
|
|
{/* Step Progress */}
|
|
<StepProgress steps={STEPS} currentStep={currentStep} />
|
|
|
|
{/* Step Content */}
|
|
<div className="min-h-[500px]">
|
|
{currentStep === 0 && (
|
|
<FormSection title="Business Information" description="Enter your company details">
|
|
<FormField
|
|
label="Business Name"
|
|
value={(formData.business as any)?.businessName || ''}
|
|
onChange={(e) => updateField('business', 'businessName', e.target.value)}
|
|
required
|
|
/>
|
|
<SelectField
|
|
label="Business Type"
|
|
options={[
|
|
{ value: 'Corporation', label: 'Corporation' },
|
|
{ value: 'Limited Liability Corporation', label: 'LLC' },
|
|
{ value: 'Partnership', label: 'Partnership' },
|
|
{ value: 'Non-profit Corporation', label: 'Non-profit' }
|
|
]}
|
|
value={(formData.business as any)?.businessType || ''}
|
|
onChange={(e) => updateField('business', 'businessType', e.target.value)}
|
|
required
|
|
/>
|
|
<EINInput
|
|
label="EIN"
|
|
value={(formData.business as any)?.registrationNumber || ''}
|
|
onChange={(e) => updateField('business', 'registrationNumber', e.target.value)}
|
|
required
|
|
helpText="Format: XX-XXXXXXX"
|
|
/>
|
|
<FormField
|
|
label="Website URL"
|
|
type="url"
|
|
value={(formData.business as any)?.websiteUrl || ''}
|
|
onChange={(e) => updateField('business', 'websiteUrl', e.target.value)}
|
|
required
|
|
/>
|
|
<SelectField
|
|
label="Industry"
|
|
options={[
|
|
{ value: 'TECHNOLOGY', label: 'Technology' },
|
|
{ value: 'HEALTHCARE', label: 'Healthcare' },
|
|
{ value: 'FINANCIAL', label: 'Financial' },
|
|
{ value: 'RETAIL', label: 'Retail' },
|
|
{ value: 'EDUCATION', label: 'Education' }
|
|
]}
|
|
value={(formData.business as any)?.businessIndustry || ''}
|
|
onChange={(e) => updateField('business', 'businessIndustry', e.target.value)}
|
|
required
|
|
/>
|
|
<SelectField
|
|
label="Company Type"
|
|
options={[
|
|
{ value: 'private', label: 'Private' },
|
|
{ value: 'public', label: 'Public' },
|
|
{ value: 'non-profit', label: 'Non-profit' },
|
|
{ value: 'government', label: 'Government' }
|
|
]}
|
|
value={(formData.business as any)?.companyType || ''}
|
|
onChange={(e) => updateField('business', 'companyType', e.target.value)}
|
|
required
|
|
/>
|
|
</FormSection>
|
|
)}
|
|
|
|
{currentStep === 1 && (
|
|
<FormSection title="Authorized Representative" description="Primary contact for this registration">
|
|
<FormField
|
|
label="First Name"
|
|
value={(formData.authorizedRep as any)?.firstName || ''}
|
|
onChange={(e) => updateField('authorizedRep', 'firstName', e.target.value)}
|
|
required
|
|
/>
|
|
<FormField
|
|
label="Last Name"
|
|
value={(formData.authorizedRep as any)?.lastName || ''}
|
|
onChange={(e) => updateField('authorizedRep', 'lastName', e.target.value)}
|
|
required
|
|
/>
|
|
<FormField
|
|
label="Business Title"
|
|
value={(formData.authorizedRep as any)?.businessTitle || ''}
|
|
onChange={(e) => updateField('authorizedRep', 'businessTitle', e.target.value)}
|
|
required
|
|
/>
|
|
<SelectField
|
|
label="Job Position"
|
|
options={[
|
|
{ value: 'CEO', label: 'CEO' },
|
|
{ value: 'CFO', label: 'CFO' },
|
|
{ value: 'Director', label: 'Director' },
|
|
{ value: 'GM', label: 'General Manager' },
|
|
{ value: 'VP', label: 'Vice President' }
|
|
]}
|
|
value={(formData.authorizedRep as any)?.jobPosition || ''}
|
|
onChange={(e) => updateField('authorizedRep', 'jobPosition', e.target.value)}
|
|
required
|
|
/>
|
|
<PhoneInput
|
|
label="Phone Number"
|
|
value={(formData.authorizedRep as any)?.phoneNumber || ''}
|
|
onChange={(e) => updateField('authorizedRep', 'phoneNumber', e.target.value)}
|
|
required
|
|
/>
|
|
<FormField
|
|
label="Email"
|
|
type="email"
|
|
value={(formData.authorizedRep as any)?.email || ''}
|
|
onChange={(e) => updateField('authorizedRep', 'email', e.target.value)}
|
|
required
|
|
/>
|
|
</FormSection>
|
|
)}
|
|
|
|
{currentStep === 2 && (
|
|
<FormSection title="Business Address" description="Your primary business location">
|
|
<FormField
|
|
label="Street Address"
|
|
value={(formData.address as any)?.street || ''}
|
|
onChange={(e) => updateField('address', 'street', e.target.value)}
|
|
required
|
|
className="col-span-2"
|
|
/>
|
|
<FormField
|
|
label="City"
|
|
value={(formData.address as any)?.city || ''}
|
|
onChange={(e) => updateField('address', 'city', e.target.value)}
|
|
required
|
|
/>
|
|
<FormField
|
|
label="State"
|
|
value={(formData.address as any)?.region || ''}
|
|
onChange={(e) => updateField('address', 'region', e.target.value)}
|
|
required
|
|
maxLength={2}
|
|
placeholder="CA"
|
|
/>
|
|
<FormField
|
|
label="ZIP Code"
|
|
value={(formData.address as any)?.postalCode || ''}
|
|
onChange={(e) => updateField('address', 'postalCode', e.target.value)}
|
|
required
|
|
/>
|
|
<FormField
|
|
label="Country"
|
|
value={(formData.address as any)?.isoCountry || 'US'}
|
|
onChange={(e) => updateField('address', 'isoCountry', e.target.value)}
|
|
required
|
|
maxLength={2}
|
|
/>
|
|
</FormSection>
|
|
)}
|
|
|
|
{currentStep === 3 && (
|
|
<FormSection title="Campaign Information" description="Describe your messaging use case">
|
|
<SelectField
|
|
label="Use Case"
|
|
options={[
|
|
{ value: 'ACCOUNT_NOTIFICATION', label: 'Account Notifications' },
|
|
{ value: 'CUSTOMER_CARE', label: 'Customer Care' },
|
|
{ value: 'DELIVERY_NOTIFICATION', label: 'Delivery Notifications' },
|
|
{ value: 'FRAUD_ALERT', label: 'Fraud Alerts' },
|
|
{ value: 'MARKETING', label: 'Marketing' },
|
|
{ value: 'SECURITY_ALERT', label: 'Security Alerts' }
|
|
]}
|
|
value={(formData.campaign as any)?.useCase || ''}
|
|
onChange={(e) => updateField('campaign', 'useCase', e.target.value)}
|
|
required
|
|
className="col-span-2"
|
|
/>
|
|
<div className="col-span-2">
|
|
<label className="block text-sm font-medium text-gray-700 mb-1">
|
|
Description <span className="text-red-500">*</span>
|
|
</label>
|
|
<textarea
|
|
className="w-full px-3 py-2 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-[#667eea]"
|
|
rows={4}
|
|
value={(formData.campaign as any)?.description || ''}
|
|
onChange={(e) => updateField('campaign', 'description', e.target.value)}
|
|
placeholder="Explain what messages you send and why..."
|
|
/>
|
|
</div>
|
|
<SelectField
|
|
label="Opt-In Type"
|
|
options={[
|
|
{ value: 'WEB_FORM', label: 'Web Form' },
|
|
{ value: 'VERBAL', label: 'Verbal' },
|
|
{ value: 'VIA_TEXT', label: 'Via Text' },
|
|
{ value: 'PAPER_FORM', label: 'Paper Form' }
|
|
]}
|
|
value={(formData.campaign as any)?.optInType || ''}
|
|
onChange={(e) => updateField('campaign', 'optInType', e.target.value)}
|
|
required
|
|
/>
|
|
</FormSection>
|
|
)}
|
|
|
|
{currentStep === 4 && (
|
|
<div className="space-y-6">
|
|
<h3 className="text-xl font-semibold">Review & Submit</h3>
|
|
<div className="bg-gray-50 rounded-lg p-6 space-y-4">
|
|
<div>
|
|
<h4 className="font-semibold text-gray-700">Business</h4>
|
|
<p>{(formData.business as any)?.businessName}</p>
|
|
</div>
|
|
<div>
|
|
<h4 className="font-semibold text-gray-700">Authorized Rep</h4>
|
|
<p>{(formData.authorizedRep as any)?.firstName} {(formData.authorizedRep as any)?.lastName}</p>
|
|
</div>
|
|
<div>
|
|
<h4 className="font-semibold text-gray-700">Use Case</h4>
|
|
<p>{(formData.campaign as any)?.useCase}</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Navigation */}
|
|
<div className="flex items-center justify-between pt-6 border-t border-gray-200">
|
|
<Button
|
|
variant="ghost"
|
|
onClick={handlePrevious}
|
|
disabled={currentStep === 0}
|
|
>
|
|
Previous
|
|
</Button>
|
|
|
|
{currentStep < STEPS.length - 1 ? (
|
|
<Button onClick={handleNext}>
|
|
Next
|
|
</Button>
|
|
) : (
|
|
<Button onClick={handleSubmit} loading={submitting} variant="success">
|
|
Submit Registration
|
|
</Button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
</div>
|
|
|
|
{toast && (
|
|
<Toast
|
|
message={toast.message}
|
|
type={toast.type}
|
|
onClose={() => setToast(null)}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
}
|