Update: nueva version Horux Despachos
This commit is contained in:
@@ -0,0 +1,135 @@
|
||||
'use client';
|
||||
|
||||
import { Header } from '@/components/layouts/header';
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@horux/shared-ui';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
import {
|
||||
isGlobalAdminRfc,
|
||||
DESPACHO_PLAN_PRICES,
|
||||
DESPACHO_PLANS,
|
||||
DESPACHO_OVERAGE_PRICE_MENSUAL,
|
||||
type DespachoPaidPlan,
|
||||
} from '@horux/shared';
|
||||
import { Tags, ShieldAlert, Info, AlertTriangle } from 'lucide-react';
|
||||
|
||||
const PLAN_ORDER: DespachoPaidPlan[] = [
|
||||
'mi_empresa',
|
||||
'mi_empresa_plus',
|
||||
'business_control',
|
||||
'business_cloud',
|
||||
];
|
||||
|
||||
function fmtCurrency(n: number | null): string {
|
||||
if (n == null) return '—';
|
||||
return `$${n.toLocaleString('es-MX')}`;
|
||||
}
|
||||
|
||||
export default function PreciosSuscripcionPage() {
|
||||
const { user } = useAuthStore();
|
||||
const isGlobalAdmin = isGlobalAdminRfc(user?.tenantRfc, user?.role, user?.platformRoles);
|
||||
|
||||
if (!isGlobalAdmin) {
|
||||
return (
|
||||
<>
|
||||
<Header title="Precios de suscripciones" />
|
||||
<main className="p-6">
|
||||
<Card>
|
||||
<CardContent className="py-12 text-center">
|
||||
<ShieldAlert className="h-12 w-12 text-muted-foreground/40 mx-auto mb-3" />
|
||||
<p className="font-semibold">Acceso restringido</p>
|
||||
<p className="text-sm text-muted-foreground mt-1">Solo admin global puede consultar el catálogo de precios.</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Header title="Precios de suscripciones" />
|
||||
<main className="p-6 space-y-6">
|
||||
<Card className="bg-muted/30 border-dashed">
|
||||
<CardContent className="py-4 text-sm flex items-start gap-2">
|
||||
<Info className="h-4 w-4 text-blue-600 mt-0.5 flex-shrink-0" />
|
||||
<div>
|
||||
Los planes despacho están configurados en{' '}
|
||||
<code className="text-xs bg-muted px-1 py-0.5 rounded">packages/shared/src/constants/despacho-plans.ts</code>.
|
||||
Para modificar precios, edita ese archivo y redespliega — los cambios aplican
|
||||
a contrataciones nuevas y renovaciones; las suscripciones vigentes
|
||||
conservan su precio.
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2 text-base">
|
||||
<Tags className="h-5 w-5" />
|
||||
Planes despacho
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="overflow-x-auto">
|
||||
<table className="w-full text-sm">
|
||||
<thead>
|
||||
<tr className="border-b text-left text-muted-foreground">
|
||||
<th className="py-2 pr-4">Plan</th>
|
||||
<th className="py-2 pr-4 text-right">Mensual (MXN)</th>
|
||||
<th className="py-2 pr-4 text-right">Anual — primer año</th>
|
||||
<th className="py-2 pr-4 text-right">Anual — renovación</th>
|
||||
<th className="py-2 pr-4 text-right">RFCs incluidos</th>
|
||||
<th className="py-2 pr-4 text-right">Timbres/mes</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{PLAN_ORDER.map((plan) => {
|
||||
const price = DESPACHO_PLAN_PRICES[plan];
|
||||
const limits = DESPACHO_PLANS[plan];
|
||||
return (
|
||||
<tr key={plan} className="border-b last:border-0 hover:bg-muted/40">
|
||||
<td className="py-3 pr-4 font-medium">{limits.name}</td>
|
||||
<td className="py-3 pr-4 text-right">
|
||||
{price.permiteMonthly
|
||||
? <span className="font-medium">{fmtCurrency(price.monthly)}</span>
|
||||
: <span className="text-muted-foreground">No aplica</span>}
|
||||
</td>
|
||||
<td className="py-3 pr-4 text-right font-medium">{fmtCurrency(price.firstYear)}</td>
|
||||
<td className="py-3 pr-4 text-right">
|
||||
{price.firstYear !== price.renewal
|
||||
? <span className="font-medium">{fmtCurrency(price.renewal)}</span>
|
||||
: <span className="text-muted-foreground">{fmtCurrency(price.renewal)}</span>}
|
||||
</td>
|
||||
<td className="py-3 pr-4 text-right text-muted-foreground">{limits.maxRfcs}</td>
|
||||
<td className="py-3 pr-4 text-right text-muted-foreground">{limits.timbresIncluidosMes}</td>
|
||||
</tr>
|
||||
);
|
||||
})}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<Card className="bg-amber-50 dark:bg-amber-950/30 border-amber-200 dark:border-amber-900/50">
|
||||
<CardContent className="py-4 text-sm flex items-start gap-2">
|
||||
<AlertTriangle className="h-4 w-4 text-amber-600 mt-0.5 flex-shrink-0" />
|
||||
<div className="space-y-1">
|
||||
<p>
|
||||
<strong>Cobro adicional por RFC extra:</strong>{' '}
|
||||
<span className="font-mono">${DESPACHO_OVERAGE_PRICE_MENSUAL}/mes</span> por
|
||||
cada contribuyente que exceda los 100 incluidos. Solo aplica a
|
||||
<strong> Business Control</strong> y <strong>Enterprise</strong>; los planes
|
||||
Mi Empresa tienen límite duro de 1 RFC.
|
||||
</p>
|
||||
<p className="text-muted-foreground">
|
||||
Mi Empresa y Mi Empresa+ permiten facturación mensual o anual; al pagar
|
||||
anual se cobra el equivalente a 10 meses (descuento del 17%).
|
||||
</p>
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</main>
|
||||
</>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user