feat(registro): agrega Mi Empresa y Mi Empresa+ a pagina de registro
This commit is contained in:
@@ -10,7 +10,8 @@ const signupSchema = z.object({
|
||||
regimenFiscal: z.string().optional(),
|
||||
codigoPostal: z.string().regex(/^\d{5}$/, 'Código postal inválido').optional(),
|
||||
verticalProfile: z.enum(['CONTABLE', 'JURIDICO', 'ARQUITECTURA']),
|
||||
plan: z.enum(['trial', 'business_control', 'business_cloud']).optional().default('trial'),
|
||||
plan: z.enum(['trial', 'business_control', 'business_cloud', 'mi_empresa', 'mi_empresa_plus']).optional().default('trial'),
|
||||
frequency: z.enum(['monthly', 'annual']).optional().default('annual'),
|
||||
}),
|
||||
owner: z.object({
|
||||
nombre: z.string().min(2, 'Nombre del owner requerido'),
|
||||
|
||||
@@ -23,7 +23,7 @@ export async function signupDespacho(data: DespachoSignupRequest) {
|
||||
data: {
|
||||
nombre: despacho.nombre,
|
||||
rfc: tenantSlug.toUpperCase(),
|
||||
plan: 'enterprise',
|
||||
plan: (despacho.plan === 'trial' ? 'enterprise' : despacho.plan) as any,
|
||||
databaseName: databaseName,
|
||||
cfdiLimit: -1,
|
||||
usersLimit: -1,
|
||||
@@ -103,7 +103,7 @@ export async function signupDespacho(data: DespachoSignupRequest) {
|
||||
const result2 = await subscriptionService.subscribe({
|
||||
tenantId: result.tenant.id,
|
||||
plan: data.despacho.plan as any,
|
||||
frequency: 'annual',
|
||||
frequency: data.despacho.frequency ?? 'annual',
|
||||
payerEmail: owner.email,
|
||||
});
|
||||
paymentUrl = result2.paymentUrl;
|
||||
|
||||
@@ -6,10 +6,11 @@ import Link from 'next/link';
|
||||
import { Button, Input, Label, Card, CardContent, CardHeader, CardTitle, cn } from '@horux/shared-ui';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import { apiClient } from '@/lib/api/client';
|
||||
import { CheckCircle2, Server, Cloud, ArrowLeft, Clock } from 'lucide-react';
|
||||
import { CheckCircle2, Server, Cloud, ArrowLeft, Clock, Zap } from 'lucide-react';
|
||||
|
||||
type VerticalProfile = 'CONTABLE' | 'JURIDICO' | 'ARQUITECTURA';
|
||||
type PlanType = 'trial' | 'business_control' | 'business_cloud';
|
||||
type PlanType = 'trial' | 'business_control' | 'business_cloud' | 'mi_empresa' | 'mi_empresa_plus';
|
||||
type Frequency = 'monthly' | 'annual';
|
||||
|
||||
export default function RegisterDespachoPage() {
|
||||
const router = useRouter();
|
||||
@@ -17,6 +18,8 @@ export default function RegisterDespachoPage() {
|
||||
const [step, setStep] = useState(1);
|
||||
const [verticalProfile, setVerticalProfile] = useState<VerticalProfile | null>(null);
|
||||
const [selectedPlan, setSelectedPlan] = useState<PlanType | null>(null);
|
||||
const [meFreq, setMeFreq] = useState<Frequency>('monthly');
|
||||
const [mePlusFreq, setMePlusFreq] = useState<Frequency>('monthly');
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState('');
|
||||
const [form, setForm] = useState({
|
||||
@@ -38,11 +41,16 @@ export default function RegisterDespachoPage() {
|
||||
setLoading(true);
|
||||
setError('');
|
||||
try {
|
||||
const frequency: Frequency | undefined =
|
||||
selectedPlan === 'mi_empresa' ? meFreq :
|
||||
selectedPlan === 'mi_empresa_plus' ? mePlusFreq :
|
||||
undefined;
|
||||
const { data } = await apiClient.post('/despachos/signup', {
|
||||
despacho: {
|
||||
nombre: form.despachoNombre,
|
||||
verticalProfile,
|
||||
plan: selectedPlan,
|
||||
frequency,
|
||||
},
|
||||
owner: {
|
||||
nombre: form.ownerNombre,
|
||||
@@ -168,10 +176,10 @@ export default function RegisterDespachoPage() {
|
||||
<span className="bg-primary text-primary-foreground rounded-full w-6 h-6 flex items-center justify-center font-bold">3</span>
|
||||
</div>
|
||||
<h1 className="text-3xl font-bold">Elige tu plan</h1>
|
||||
<p className="text-muted-foreground mt-2">Todos los planes incluyen las mismas funcionalidades.</p>
|
||||
<p className="text-muted-foreground mt-2">Mi Empresa para individuales, Business para despachos.</p>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-5 gap-6">
|
||||
{/* Trial Gratuito */}
|
||||
<Card
|
||||
className={cn(
|
||||
@@ -202,6 +210,99 @@ export default function RegisterDespachoPage() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Mi Empresa */}
|
||||
<Card
|
||||
className={cn(
|
||||
'cursor-pointer transition-all hover:shadow-lg',
|
||||
selectedPlan === 'mi_empresa' && 'border-primary ring-2 ring-primary/20'
|
||||
)}
|
||||
onClick={() => setSelectedPlan('mi_empresa')}
|
||||
>
|
||||
<CardHeader className="text-center pb-2">
|
||||
<div className="mx-auto bg-emerald-100 dark:bg-emerald-900 rounded-full p-3 w-fit mb-2">
|
||||
<Cloud className="h-6 w-6 text-emerald-600 dark:text-emerald-400" />
|
||||
</div>
|
||||
<CardTitle className="text-xl">Mi Empresa</CardTitle>
|
||||
<p className="text-sm text-muted-foreground">Para una sola empresa</p>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex bg-muted rounded-lg p-1 text-xs font-medium">
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); setMeFreq('monthly'); }}
|
||||
className={`flex-1 py-1.5 rounded-md transition-colors ${meFreq === 'monthly' ? 'bg-background shadow-sm text-foreground' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>Mensual</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); setMeFreq('annual'); }}
|
||||
className={`flex-1 py-1.5 rounded-md transition-colors flex items-center justify-center gap-1 ${meFreq === 'annual' ? 'bg-background shadow-sm text-foreground' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>Anual <span className="text-emerald-600 dark:text-emerald-400 text-[10px] font-bold">−17%</span></button>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold">${meFreq === 'monthly' ? '580' : '5,800'}</div>
|
||||
<p className="text-sm text-muted-foreground">{meFreq === 'monthly' ? 'por mes (IVA incluido)' : 'por año (IVA incluido)'}</p>
|
||||
{meFreq === 'monthly' && <p className="text-xs text-muted-foreground mt-1">o $5,800/año (ahorras 17%)</p>}
|
||||
</div>
|
||||
<div className="space-y-2 text-sm">
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>1 RFC</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>3 usuarios</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Hasta 1,000,000 CFDIs</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Base de datos en la nube</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Dashboard, CFDI, IVA/ISR, alertas</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>50 timbres/mes incluidos</span></div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Mi Empresa + */}
|
||||
<Card
|
||||
className={cn(
|
||||
'cursor-pointer transition-all hover:shadow-lg relative',
|
||||
selectedPlan === 'mi_empresa_plus' && 'border-primary ring-2 ring-primary/20'
|
||||
)}
|
||||
onClick={() => setSelectedPlan('mi_empresa_plus')}
|
||||
>
|
||||
<div className="absolute -top-3 left-1/2 -translate-x-1/2 bg-primary text-primary-foreground text-xs px-3 py-1 rounded-full">
|
||||
Más popular
|
||||
</div>
|
||||
<CardHeader className="text-center pb-2">
|
||||
<div className="mx-auto bg-teal-100 dark:bg-teal-900 rounded-full p-3 w-fit mb-2">
|
||||
<Zap className="h-6 w-6 text-teal-600 dark:text-teal-400" />
|
||||
</div>
|
||||
<CardTitle className="text-xl">Mi Empresa +</CardTitle>
|
||||
<p className="text-sm text-muted-foreground">Con API y Lolita IA</p>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="flex bg-muted rounded-lg p-1 text-xs font-medium">
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); setMePlusFreq('monthly'); }}
|
||||
className={`flex-1 py-1.5 rounded-md transition-colors ${mePlusFreq === 'monthly' ? 'bg-background shadow-sm text-foreground' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>Mensual</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={(e) => { e.stopPropagation(); setMePlusFreq('annual'); }}
|
||||
className={`flex-1 py-1.5 rounded-md transition-colors flex items-center justify-center gap-1 ${mePlusFreq === 'annual' ? 'bg-background shadow-sm text-foreground' : 'text-muted-foreground hover:text-foreground'}`}
|
||||
>Anual <span className="text-emerald-600 dark:text-emerald-400 text-[10px] font-bold">−17%</span></button>
|
||||
</div>
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold">${mePlusFreq === 'monthly' ? '900' : '9,000'}</div>
|
||||
<p className="text-sm text-muted-foreground">{mePlusFreq === 'monthly' ? 'por mes (IVA incluido)' : 'por año (IVA incluido)'}</p>
|
||||
{mePlusFreq === 'monthly' && <p className="text-xs text-muted-foreground mt-1">o $9,000/año (ahorras 17%)</p>}
|
||||
</div>
|
||||
<div className="space-y-2 text-sm">
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>1 RFC</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>3 usuarios</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Hasta 1,000,000 CFDIs</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Base de datos en la nube</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Dashboard, CFDI, IVA/ISR, alertas</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>50 timbres/mes incluidos</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span><strong>API REST</strong> incluida</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span><strong>Lolita IA</strong> agente fiscal</span></div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Business Control */}
|
||||
<Card
|
||||
className={cn(
|
||||
@@ -219,21 +320,23 @@ export default function RegisterDespachoPage() {
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold">$21,000</div>
|
||||
<p className="text-sm text-muted-foreground">primer año (IVA incluido)</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">$15,000/año a partir del 2do año</p>
|
||||
<div className="text-3xl font-bold">$25,850</div>
|
||||
<p className="text-sm text-muted-foreground">por año (IVA incluido)</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">+ $45/mes por cada RFC adicional sobre 100</p>
|
||||
</div>
|
||||
<div className="space-y-2 text-sm">
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Base de datos en tu servidor</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>RFCs ilimitados</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Hasta 100 RFCs</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Usuarios ilimitados</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Hasta 1,000,000 CFDIs por contribuyente</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Servidor local con backup</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Control total de tus datos</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Requiere Docker en tu servidor</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Dashboard, CFDI, IVA/ISR, alertas, calendario</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Reportes, conciliación, documentos, facturación, API</span></div>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
{/* Business Cloud */}
|
||||
{/* Enterprise (business_cloud) */}
|
||||
<Card
|
||||
className={cn(
|
||||
'cursor-pointer transition-all hover:shadow-lg relative',
|
||||
@@ -241,27 +344,27 @@ export default function RegisterDespachoPage() {
|
||||
)}
|
||||
onClick={() => setSelectedPlan('business_cloud')}
|
||||
>
|
||||
<div className="absolute -top-3 left-1/2 -translate-x-1/2 bg-primary text-primary-foreground text-xs px-3 py-1 rounded-full">
|
||||
Más popular
|
||||
</div>
|
||||
<CardHeader className="text-center pb-2">
|
||||
<div className="mx-auto bg-purple-100 dark:bg-purple-900 rounded-full p-3 w-fit mb-2">
|
||||
<Cloud className="h-6 w-6 text-purple-600 dark:text-purple-400" />
|
||||
</div>
|
||||
<CardTitle className="text-xl">Business Cloud</CardTitle>
|
||||
<p className="text-sm text-muted-foreground">Nosotros lo operamos por ti</p>
|
||||
<CardTitle className="text-xl">Enterprise</CardTitle>
|
||||
<p className="text-sm text-muted-foreground">Despachos grandes con alto volumen</p>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="text-center">
|
||||
<div className="text-3xl font-bold">$15,000</div>
|
||||
<p className="text-sm text-muted-foreground">por año (fijo)</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">+ $45/mes por cada RFC gestionado</p>
|
||||
<div className="text-3xl font-bold">$43,000</div>
|
||||
<p className="text-sm text-muted-foreground">por año (IVA incluido)</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">+ $45/mes por cada RFC adicional sobre 100</p>
|
||||
</div>
|
||||
<div className="space-y-2 text-sm">
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Base de datos en la nube (Horux)</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Sin infraestructura propia</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Hasta 100 RFCs</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Usuarios ilimitados</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Backups automáticos</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Hasta 3,000,000 CFDIs por contribuyente</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Servidor local con backup</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Backups automáticos en la nube</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Dashboard, CFDI, IVA/ISR, alertas, calendario</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Reportes, conciliación, documentos, facturación, API</span></div>
|
||||
<div className="flex items-center gap-2"><CheckCircle2 className="h-4 w-4 text-green-500 flex-shrink-0" /><span>Soporte prioritario</span></div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user