Add i18 support
This commit is contained in:
@@ -0,0 +1,283 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { PageHeader } from '../../../../components/layout';
|
||||
import { Button } from '../../../../components/ui/Button';
|
||||
import { Card, CardHeader, CardBody } from '../../../../components/ui/Card';
|
||||
import { Badge } from '../../../../components/ui/Badge';
|
||||
import { Tooltip } from '../../../../components/ui/Tooltip';
|
||||
import { useTenant } from '../../../../stores/tenant.store';
|
||||
import { useAuthUser } from '../../../../stores/auth.store';
|
||||
import {
|
||||
Plus,
|
||||
Building2,
|
||||
Settings,
|
||||
Users,
|
||||
Calendar,
|
||||
MapPin,
|
||||
Phone,
|
||||
Mail,
|
||||
Globe,
|
||||
MoreHorizontal,
|
||||
ArrowRight,
|
||||
Crown,
|
||||
Shield,
|
||||
Eye
|
||||
} from 'lucide-react';
|
||||
|
||||
const OrganizationsPage: React.FC = () => {
|
||||
const navigate = useNavigate();
|
||||
const user = useAuthUser();
|
||||
const { currentTenant, availableTenants, switchTenant } = useTenant();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
|
||||
const handleAddNewOrganization = () => {
|
||||
navigate('/app/onboarding?new=true');
|
||||
};
|
||||
|
||||
const handleSwitchToTenant = async (tenantId: string) => {
|
||||
if (tenantId === currentTenant?.id) return;
|
||||
|
||||
setIsLoading(true);
|
||||
await switchTenant(tenantId);
|
||||
setIsLoading(false);
|
||||
};
|
||||
|
||||
const handleManageTenant = (tenantId: string) => {
|
||||
// Navigate to tenant settings
|
||||
navigate(`/app/database/bakery-config`);
|
||||
};
|
||||
|
||||
const handleManageTeam = (tenantId: string) => {
|
||||
// Navigate to team management
|
||||
navigate(`/app/database/team`);
|
||||
};
|
||||
|
||||
const getRoleIcon = (ownerId: string) => {
|
||||
if (user?.id === ownerId) {
|
||||
return <Crown className="w-4 h-4 text-[var(--color-warning)]" />;
|
||||
}
|
||||
return <Shield className="w-4 h-4 text-[var(--color-primary)]" />;
|
||||
};
|
||||
|
||||
const getRoleLabel = (ownerId: string) => {
|
||||
if (user?.id === ownerId) {
|
||||
return 'Propietario';
|
||||
}
|
||||
return 'Miembro';
|
||||
};
|
||||
|
||||
const formatDate = (dateString: string) => {
|
||||
return new Date(dateString).toLocaleDateString('es-ES', {
|
||||
year: 'numeric',
|
||||
month: 'long',
|
||||
day: 'numeric'
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6 p-4 sm:p-6">
|
||||
<PageHeader
|
||||
title="Mis Organizaciones"
|
||||
description="Gestiona tus panaderías y negocios"
|
||||
actions={
|
||||
<Button
|
||||
onClick={handleAddNewOrganization}
|
||||
variant="primary"
|
||||
size="lg"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Nueva Organización
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Statistics */}
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<Card>
|
||||
<CardBody className="text-center">
|
||||
<Building2 className="w-8 h-8 text-[var(--color-primary)] mx-auto mb-2" />
|
||||
<div className="text-2xl font-bold text-[var(--text-primary)]">
|
||||
{availableTenants?.length || 0}
|
||||
</div>
|
||||
<div className="text-sm text-[var(--text-secondary)]">Organizaciones Totales</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardBody className="text-center">
|
||||
<Crown className="w-8 h-8 text-[var(--color-warning)] mx-auto mb-2" />
|
||||
<div className="text-2xl font-bold text-[var(--text-primary)]">
|
||||
{availableTenants?.filter(t => t.owner_id === user?.id).length || 0}
|
||||
</div>
|
||||
<div className="text-sm text-[var(--text-secondary)]">Propietario</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
|
||||
<Card>
|
||||
<CardBody className="text-center">
|
||||
<Shield className="w-8 h-8 text-[var(--color-primary)] mx-auto mb-2" />
|
||||
<div className="text-2xl font-bold text-[var(--text-primary)]">
|
||||
{availableTenants?.filter(t => t.owner_id !== user?.id).length || 0}
|
||||
</div>
|
||||
<div className="text-sm text-[var(--text-secondary)]">Miembro</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
|
||||
{/* Organizations List */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-lg font-semibold text-[var(--text-primary)]">Tus Organizaciones</h3>
|
||||
|
||||
{availableTenants && availableTenants.length > 0 ? (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
||||
{availableTenants.map((tenant) => (
|
||||
<Card
|
||||
key={tenant.id}
|
||||
className={`transition-all duration-200 hover:shadow-lg ${
|
||||
currentTenant?.id === tenant.id
|
||||
? 'ring-2 ring-[var(--color-primary)]/20 bg-[var(--color-primary)]/5'
|
||||
: 'hover:border-[var(--color-primary)]/30'
|
||||
}`}
|
||||
>
|
||||
<CardHeader className="flex flex-row items-start justify-between space-y-0 pb-4">
|
||||
<div className="flex items-start gap-3 flex-1 min-w-0">
|
||||
<div className="w-12 h-12 bg-[var(--color-primary)]/10 rounded-lg flex items-center justify-center flex-shrink-0">
|
||||
<Building2 className="w-6 h-6 text-[var(--color-primary)]" />
|
||||
</div>
|
||||
<div className="flex-1 min-w-0">
|
||||
<div className="flex items-center gap-2 mb-1">
|
||||
<h4 className="font-semibold text-[var(--text-primary)] truncate">
|
||||
{tenant.name}
|
||||
</h4>
|
||||
{currentTenant?.id === tenant.id && (
|
||||
<Badge variant="primary" size="sm">Activa</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2 text-sm text-[var(--text-secondary)]">
|
||||
{getRoleIcon(tenant.owner_id)}
|
||||
<span>{getRoleLabel(tenant.owner_id)}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-1">
|
||||
<Tooltip content="Configurar organización">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleManageTenant(tenant.id)}
|
||||
className="w-8 h-8 p-0"
|
||||
>
|
||||
<Settings className="w-4 h-4" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
|
||||
{user?.id === tenant.owner_id && (
|
||||
<Tooltip content="Gestionar equipo">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
onClick={() => handleManageTeam(tenant.id)}
|
||||
className="w-8 h-8 p-0"
|
||||
>
|
||||
<Users className="w-4 h-4" />
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</CardHeader>
|
||||
|
||||
<CardBody className="pt-0">
|
||||
{/* Organization details */}
|
||||
<div className="space-y-2 mb-4">
|
||||
{tenant.business_type && (
|
||||
<div className="text-sm text-[var(--text-secondary)]">
|
||||
<Badge variant="outline" size="sm">{tenant.business_type}</Badge>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tenant.address && (
|
||||
<div className="flex items-center gap-2 text-sm text-[var(--text-secondary)]">
|
||||
<MapPin className="w-4 h-4 flex-shrink-0" />
|
||||
<span className="truncate">{tenant.address}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tenant.city && (
|
||||
<div className="flex items-center gap-2 text-sm text-[var(--text-secondary)]">
|
||||
<MapPin className="w-4 h-4 flex-shrink-0" />
|
||||
<span>{tenant.city}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{tenant.phone && (
|
||||
<div className="flex items-center gap-2 text-sm text-[var(--text-secondary)]">
|
||||
<Phone className="w-4 h-4 flex-shrink-0" />
|
||||
<span>{tenant.phone}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex items-center gap-2 text-sm text-[var(--text-secondary)]">
|
||||
<Calendar className="w-4 h-4 flex-shrink-0" />
|
||||
<span>Creada el {formatDate(tenant.created_at)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Actions */}
|
||||
<div className="flex gap-2">
|
||||
{currentTenant?.id !== tenant.id ? (
|
||||
<Button
|
||||
onClick={() => handleSwitchToTenant(tenant.id)}
|
||||
variant="primary"
|
||||
size="sm"
|
||||
disabled={isLoading}
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<ArrowRight className="w-4 h-4" />
|
||||
Cambiar a esta organización
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
onClick={() => navigate('/app/dashboard')}
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Eye className="w-4 h-4" />
|
||||
Ver dashboard
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</CardBody>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<Card>
|
||||
<CardBody className="text-center py-12">
|
||||
<Building2 className="w-16 h-16 text-[var(--text-tertiary)] mx-auto mb-4" />
|
||||
<h3 className="text-lg font-semibold text-[var(--text-primary)] mb-2">
|
||||
No tienes organizaciones
|
||||
</h3>
|
||||
<p className="text-[var(--text-secondary)] mb-6">
|
||||
Crea tu primera organización para comenzar a usar Bakery IA
|
||||
</p>
|
||||
<Button
|
||||
onClick={handleAddNewOrganization}
|
||||
variant="primary"
|
||||
size="lg"
|
||||
className="flex items-center gap-2"
|
||||
>
|
||||
<Plus className="w-4 h-4" />
|
||||
Crear Primera Organización
|
||||
</Button>
|
||||
</CardBody>
|
||||
</Card>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrganizationsPage;
|
||||
Reference in New Issue
Block a user