Refactor Commerce module

This commit is contained in:
gpt-engineer-app[bot]
2025-10-11 02:26:41 +00:00
parent 1b9edcd0a5
commit 27b0e23a98
6 changed files with 652 additions and 116 deletions

View File

@@ -39,15 +39,13 @@ import Security from "./pages/dashboard/Security";
import VehicleManagement from "./pages/dashboard/VehicleManagement";
import Sustainability from "./pages/dashboard/Sustainability";
import Establishments from "./pages/dashboard/Establishments";
// Commerce pages
import CommerceEstablishments from "./pages/dashboard/commerce/Establishments";
// Commerce pages (for retail stores)
import CommerceStore from "./pages/dashboard/commerce/Store";
import CommercePOS from "./pages/dashboard/commerce/POSTerminal";
import CommerceOrders from "./pages/dashboard/commerce/Orders";
import CommerceMenu from "./pages/dashboard/commerce/Menu";
import CommerceHotel from "./pages/dashboard/commerce/Hotel";
import CommerceReservations from "./pages/dashboard/commerce/Reservations";
import CommerceCustomers from "./pages/dashboard/commerce/Customers";
import CommerceInventory from "./pages/dashboard/commerce/Inventory";
import CommerceStaff from "./pages/dashboard/commerce/Staff";
import CommerceCashier from "./pages/dashboard/commerce/Cashier";
import CommerceReports from "./pages/dashboard/commerce/Reports";
// Hotel pages
import HotelRooms from "./pages/dashboard/hotel/Rooms";
@@ -304,10 +302,10 @@ const AppRouter = () => (
} />
{/* Commerce Routes */}
<Route path="/dashboard/commerce/establishments" element={
<Route path="/dashboard/commerce/store" element={
<ProtectedRoute>
<DashboardLayout>
<CommerceEstablishments />
<CommerceStore />
</DashboardLayout>
</ProtectedRoute>
} />
@@ -320,34 +318,18 @@ const AppRouter = () => (
</ProtectedRoute>
} />
<Route path="/dashboard/commerce/orders" element={
<Route path="/dashboard/commerce/customers" element={
<ProtectedRoute>
<DashboardLayout>
<CommerceOrders />
<CommerceCustomers />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/commerce/menu" element={
<Route path="/dashboard/commerce/cashier" element={
<ProtectedRoute>
<DashboardLayout>
<CommerceMenu />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/commerce/hotel" element={
<ProtectedRoute>
<DashboardLayout>
<CommerceHotel />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/commerce/reservations" element={
<ProtectedRoute>
<DashboardLayout>
<CommerceReservations />
<CommerceCashier />
</DashboardLayout>
</ProtectedRoute>
} />
@@ -384,13 +366,6 @@ const AppRouter = () => (
</ProtectedRoute>
} />
<Route path="/dashboard/commerce/tables" element={
<ProtectedRoute>
<DashboardLayout>
<CommerceMenu />
</DashboardLayout>
</ProtectedRoute>
} />
<Route path="/dashboard/hotel-management" element={
<ProtectedRoute>

View File

@@ -165,15 +165,12 @@ const DashboardLayout = ({ children }: { children: React.ReactNode }) => {
label: 'Comercios',
path: '/dashboard/commerce',
subItems: [
{ icon: Store, label: 'Establecimientos', path: '/dashboard/commerce/establishments' },
{ icon: CreditCard, label: 'POS Terminal', path: '/dashboard/commerce/pos' },
{ icon: Receipt, label: 'Pedidos', path: '/dashboard/commerce/orders' },
{ icon: UtensilsCrossed, label: 'Menú', path: '/dashboard/commerce/menu' },
{ icon: Grid3x3, label: 'Mesas', path: '/dashboard/commerce/tables' },
{ icon: Hotel, label: 'Hotel', path: '/dashboard/commerce/hotel' },
{ icon: BookOpen, label: 'Reservaciones', path: '/dashboard/commerce/reservations' },
{ icon: Store, label: 'Mi Comercio', path: '/dashboard/commerce/store' },
{ icon: CreditCard, label: 'POS Ventas', path: '/dashboard/commerce/pos' },
{ icon: Package, label: 'Inventario', path: '/dashboard/commerce/inventory' },
{ icon: Users, label: 'Clientes', path: '/dashboard/commerce/customers' },
{ icon: Users, label: 'Personal', path: '/dashboard/commerce/staff' },
{ icon: Receipt, label: 'Caja', path: '/dashboard/commerce/cashier' },
{ icon: BarChart3, label: 'Reportes', path: '/dashboard/commerce/reports' },
{ icon: DollarSign, label: 'Ventas', path: '/dashboard/commerce/sales' }
]

View File

@@ -0,0 +1,172 @@
import React, { useState } from 'react';
import { Receipt, DollarSign, TrendingUp, TrendingDown, Clock } from 'lucide-react';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { useToast } from '@/hooks/use-toast';
const Cashier = () => {
const { toast } = useToast();
const [cashierData] = useState({
openingBalance: 1000.00,
currentBalance: 2450.50,
totalSales: 1450.50,
totalExpenses: 0,
transactionsCount: 25,
lastTransaction: new Date().toLocaleTimeString()
});
const [newTransaction, setNewTransaction] = useState({
type: 'sale',
amount: 0,
description: ''
});
const handleOpenCashier = () => {
toast({ title: 'Caja Abierta', description: 'Caja abierta con saldo inicial' });
};
const handleCloseCashier = () => {
toast({ title: 'Caja Cerrada', description: 'Caja cerrada. Generando reporte...' });
};
const handleAddTransaction = () => {
if (newTransaction.amount <= 0) {
toast({ title: 'Error', description: 'Ingresa un monto válido', variant: 'destructive' });
return;
}
toast({ title: 'Éxito', description: 'Transacción registrada' });
setNewTransaction({ type: 'sale', amount: 0, description: '' });
};
return (
<div className="min-h-screen bg-gray-50 p-6">
<div className="max-w-7xl mx-auto">
<div className="flex items-center justify-between mb-6">
<div className="flex items-center gap-3">
<Receipt className="w-8 h-8 text-orange-600" />
<div>
<h1 className="text-3xl font-bold text-gray-900">Control de Caja</h1>
<p className="text-gray-600">Gestiona el flujo de efectivo de tu tienda</p>
</div>
</div>
<div className="flex gap-2">
<Button onClick={handleOpenCashier}>Abrir Caja</Button>
<Button variant="outline" onClick={handleCloseCashier}>Cerrar Caja</Button>
</div>
</div>
<div className="grid gap-6 md:grid-cols-4 mb-6">
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Saldo Inicial</CardTitle>
<DollarSign className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">${cashierData.openingBalance.toFixed(2)}</div>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Saldo Actual</CardTitle>
<DollarSign className="h-4 w-4 text-muted-foreground" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-green-600">${cashierData.currentBalance.toFixed(2)}</div>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Ventas del Día</CardTitle>
<TrendingUp className="h-4 w-4 text-green-600" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold">${cashierData.totalSales.toFixed(2)}</div>
<p className="text-xs text-muted-foreground">{cashierData.transactionsCount} transacciones</p>
</CardContent>
</Card>
<Card>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Gastos</CardTitle>
<TrendingDown className="h-4 w-4 text-red-600" />
</CardHeader>
<CardContent>
<div className="text-2xl font-bold text-red-600">${cashierData.totalExpenses.toFixed(2)}</div>
</CardContent>
</Card>
</div>
<div className="grid gap-6 lg:grid-cols-2">
{/* Quick Transaction */}
<Card>
<CardHeader>
<CardTitle>Registrar Transacción</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-4">
<div>
<Label>Tipo de Transacción</Label>
<div className="grid grid-cols-2 gap-2 mt-2">
<Button
variant={newTransaction.type === 'sale' ? 'default' : 'outline'}
onClick={() => setNewTransaction({ ...newTransaction, type: 'sale' })}
>
Venta
</Button>
<Button
variant={newTransaction.type === 'expense' ? 'default' : 'outline'}
onClick={() => setNewTransaction({ ...newTransaction, type: 'expense' })}
>
Gasto
</Button>
</div>
</div>
<div>
<Label>Monto</Label>
<Input
type="number"
value={newTransaction.amount}
onChange={(e) => setNewTransaction({ ...newTransaction, amount: parseFloat(e.target.value) })}
placeholder="0.00"
/>
</div>
<div>
<Label>Descripción</Label>
<Input
value={newTransaction.description}
onChange={(e) => setNewTransaction({ ...newTransaction, description: e.target.value })}
placeholder="Detalle de la transacción"
/>
</div>
<Button className="w-full" onClick={handleAddTransaction}>
Registrar
</Button>
</div>
</CardContent>
</Card>
{/* Recent Transactions */}
<Card>
<CardHeader>
<CardTitle>Transacciones Recientes</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
<div className="text-center py-8 text-muted-foreground">
No hay transacciones registradas hoy
</div>
</div>
</CardContent>
</Card>
</div>
</div>
</div>
);
};
export default Cashier;

View File

@@ -0,0 +1,173 @@
import React, { useState } from 'react';
import { Users, Plus, Edit, Trash2, Mail, Phone, MapPin, DollarSign } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { useToast } from '@/hooks/use-toast';
const Customers = () => {
const [customers, setCustomers] = useState<any[]>([]);
const { toast } = useToast();
const [formData, setFormData] = useState({
firstName: '',
lastName: '',
email: '',
phone: '',
address: '',
notes: ''
});
const handleSubmit = async () => {
try {
toast({ title: 'Éxito', description: 'Cliente agregado correctamente' });
setFormData({
firstName: '',
lastName: '',
email: '',
phone: '',
address: '',
notes: ''
});
} catch (error: any) {
toast({ title: 'Error', description: error?.message || 'No se pudo agregar el cliente', variant: 'destructive' });
}
};
return (
<div className="min-h-screen bg-gray-50 p-6">
<div className="max-w-7xl mx-auto">
<div className="flex items-center gap-3 mb-6">
<Users className="w-8 h-8 text-orange-600" />
<div>
<h1 className="text-3xl font-bold text-gray-900">Gestión de Clientes</h1>
<p className="text-gray-600">Administra tu base de clientes</p>
</div>
</div>
<div className="flex justify-between items-center mb-4">
<Input
placeholder="Buscar clientes..."
className="max-w-sm"
/>
<Dialog>
<DialogTrigger asChild>
<Button>
<Plus className="w-4 h-4 mr-2" />
Nuevo Cliente
</Button>
</DialogTrigger>
<DialogContent>
<DialogHeader>
<DialogTitle>Agregar Cliente</DialogTitle>
</DialogHeader>
<div className="grid gap-4">
<div className="grid grid-cols-2 gap-4">
<div>
<Label>Nombre</Label>
<Input
value={formData.firstName}
onChange={(e) => setFormData({ ...formData, firstName: e.target.value })}
placeholder="Nombre"
/>
</div>
<div>
<Label>Apellido</Label>
<Input
value={formData.lastName}
onChange={(e) => setFormData({ ...formData, lastName: e.target.value })}
placeholder="Apellido"
/>
</div>
</div>
<div>
<Label>Email</Label>
<Input
type="email"
value={formData.email}
onChange={(e) => setFormData({ ...formData, email: e.target.value })}
placeholder="email@ejemplo.com"
/>
</div>
<div>
<Label>Teléfono</Label>
<Input
value={formData.phone}
onChange={(e) => setFormData({ ...formData, phone: e.target.value })}
placeholder="+1 809 123 4567"
/>
</div>
<div>
<Label>Dirección</Label>
<Input
value={formData.address}
onChange={(e) => setFormData({ ...formData, address: e.target.value })}
placeholder="Dirección del cliente"
/>
</div>
<Button onClick={handleSubmit}>Agregar Cliente</Button>
</div>
</DialogContent>
</Dialog>
</div>
<div className="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
{customers.length === 0 ? (
<div className="col-span-full text-center py-12 text-muted-foreground">
No hay clientes registrados. Agrega tu primer cliente.
</div>
) : (
customers.map((customer) => (
<Card key={customer.id}>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<div>
<CardTitle className="text-base">{customer.firstName} {customer.lastName}</CardTitle>
<p className="text-sm text-muted-foreground">Cliente desde {customer.createdAt}</p>
</div>
<div className="flex gap-1">
<Button variant="outline" size="sm">
<Edit className="w-4 h-4" />
</Button>
<Button variant="outline" size="sm">
<Trash2 className="w-4 h-4" />
</Button>
</div>
</CardHeader>
<CardContent>
<div className="space-y-2 text-sm">
<div className="flex items-center gap-2">
<Mail className="w-4 h-4 text-muted-foreground" />
<span>{customer.email}</span>
</div>
<div className="flex items-center gap-2">
<Phone className="w-4 h-4 text-muted-foreground" />
<span>{customer.phone}</span>
</div>
{customer.address && (
<div className="flex items-center gap-2">
<MapPin className="w-4 h-4 text-muted-foreground" />
<span className="truncate">{customer.address}</span>
</div>
)}
<div className="flex justify-between items-center pt-2 border-t">
<span className="text-muted-foreground">Total compras:</span>
<div className="flex items-center gap-1 font-bold">
<DollarSign className="w-4 h-4" />
{customer.totalPurchases || 0}
</div>
</div>
</div>
</CardContent>
</Card>
))
)}
</div>
</div>
</div>
);
};
export default Customers;

View File

@@ -1,46 +1,29 @@
import React, { useState, useEffect } from 'react';
import { CreditCard, Plus, Minus, Trash2, DollarSign } from 'lucide-react';
import { CreditCard, Plus, Minus, Trash2, DollarSign, Package, Barcode } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Badge } from '@/components/ui/badge';
import { useToast } from '@/hooks/use-toast';
import { apiClient } from '@/services/adminApi';
const POSTerminal = () => {
const [establishments, setEstablishments] = useState<any[]>([]);
const [selectedEstablishment, setSelectedEstablishment] = useState('');
const [menuItems, setMenuItems] = useState<any[]>([]);
const [products, setProducts] = useState<any[]>([]);
const [cart, setCart] = useState<any[]>([]);
const [tableNumber, setTableNumber] = useState('');
const [searchTerm, setSearchTerm] = useState('');
const { toast } = useToast();
useEffect(() => {
loadEstablishments();
loadProducts();
}, []);
useEffect(() => {
if (selectedEstablishment) {
loadMenu();
}
}, [selectedEstablishment]);
const loadEstablishments = async () => {
const loadProducts = async () => {
try {
const response = await apiClient.get('/commerce/establishments');
setEstablishments(Array.isArray(response) ? response : (response as any)?.establishments || []);
// Load inventory products for POS
// For now using mock data
setProducts([]);
} catch (error) {
console.error('Error loading establishments:', error);
}
};
const loadMenu = async () => {
try {
const response = await apiClient.get(`/restaurant/establishments/${selectedEstablishment}/menu`);
setMenuItems(Array.isArray(response) ? response : (response as any)?.items || []);
} catch (error) {
console.error('Error loading menu:', error);
console.error('Error loading products:', error);
}
};
@@ -74,30 +57,24 @@ const POSTerminal = () => {
};
const handleCheckout = async () => {
if (!tableNumber) {
toast({ title: 'Error', description: 'Ingresa el número de mesa', variant: 'destructive' });
if (cart.length === 0) {
toast({ title: 'Error', description: 'El carrito está vacío', variant: 'destructive' });
return;
}
try {
await apiClient.post('/restaurant/orders', {
establishmentId: parseInt(selectedEstablishment),
tableNumber,
items: cart.map(item => ({
menuItemId: item.id,
quantity: item.quantity,
price: item.price
})),
total: getTotal()
});
toast({ title: 'Éxito', description: 'Orden creada correctamente' });
toast({ title: 'Éxito', description: `Venta procesada: $${getTotal().toFixed(2)}` });
setCart([]);
setTableNumber('');
} catch (error: any) {
toast({ title: 'Error', description: error?.message || 'No se pudo crear la orden', variant: 'destructive' });
toast({ title: 'Error', description: error?.message || 'No se pudo procesar la venta', variant: 'destructive' });
}
};
const filteredProducts = products.filter(p =>
p.name?.toLowerCase().includes(searchTerm.toLowerCase()) ||
p.barcode?.includes(searchTerm)
);
return (
<div className="min-h-screen bg-gray-50 p-6">
<div className="max-w-7xl mx-auto">
@@ -110,57 +87,59 @@ const POSTerminal = () => {
</div>
<div className="mb-4">
<Select value={selectedEstablishment} onValueChange={setSelectedEstablishment}>
<SelectTrigger className="w-64">
<SelectValue placeholder="Selecciona establecimiento" />
</SelectTrigger>
<SelectContent>
{establishments.map((est) => (
<SelectItem key={est.id} value={est.id.toString()}>
{est.name}
</SelectItem>
))}
</SelectContent>
</Select>
<Input
placeholder="Buscar producto por nombre o escanear código de barras..."
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
className="max-w-md"
/>
</div>
{selectedEstablishment && (
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
{/* Menu Items */}
{/* Products */}
<div className="lg:col-span-2 grid gap-4 md:grid-cols-2">
{menuItems.map((item) => (
{filteredProducts.length === 0 ? (
<div className="col-span-2 text-center py-12">
<Package className="w-16 h-16 mx-auto text-muted-foreground mb-4" />
<p className="text-muted-foreground">No hay productos en el inventario</p>
<p className="text-sm text-muted-foreground">Agrega productos desde la sección de Inventario</p>
</div>
) : (
filteredProducts.map((item) => (
<Card key={item.id} className="cursor-pointer hover:shadow-lg transition-shadow" onClick={() => addToCart(item)}>
<CardHeader>
<CardTitle className="text-base">{item.name}</CardTitle>
</CardHeader>
<CardContent>
<p className="text-sm text-muted-foreground mb-2">{item.description}</p>
<div className="space-y-2">
{item.barcode && (
<div className="flex items-center gap-2 text-xs text-muted-foreground">
<Barcode className="w-3 h-3" />
{item.barcode}
</div>
)}
<div className="flex justify-between items-center">
<Badge variant="outline">{item.category}</Badge>
<span className="text-lg font-bold">${item.price}</span>
</div>
<p className="text-xs text-muted-foreground">Stock: {item.stock}</p>
</div>
</CardContent>
</Card>
))}
))
)}
</div>
{/* Cart */}
<div className="lg:col-span-1">
<Card className="sticky top-6">
<CardHeader>
<CardTitle>Orden Actual</CardTitle>
<div className="mt-2">
<Input
placeholder="Número de mesa"
value={tableNumber}
onChange={(e) => setTableNumber(e.target.value)}
/>
</div>
<CardTitle>Venta Actual</CardTitle>
</CardHeader>
<CardContent>
{cart.length === 0 ? (
<p className="text-sm text-muted-foreground text-center py-8">
No hay ítems en la orden
No hay productos en la venta
</p>
) : (
<>
@@ -202,7 +181,6 @@ const POSTerminal = () => {
</Card>
</div>
</div>
)}
</div>
</div>
);

View File

@@ -0,0 +1,241 @@
import React, { useState, useEffect } from 'react';
import { Store as StoreIcon, Edit, MapPin, Phone, Globe, Clock } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { Textarea } from '@/components/ui/textarea';
import { Label } from '@/components/ui/label';
import { Badge } from '@/components/ui/badge';
import { useToast } from '@/hooks/use-toast';
import { apiClient } from '@/services/adminApi';
const Store = () => {
const [editing, setEditing] = useState(false);
const [loading, setLoading] = useState(false);
const { toast } = useToast();
const [storeData, setStoreData] = useState<any>({
name: 'Mi Tienda',
description: 'Descripción de mi comercio',
type: 'store',
category: 'retail',
address: 'Dirección del comercio',
phone: '+1 809 123 4567',
email: 'contacto@mitienda.com',
website: '',
openingHours: {
monday: '9:00-18:00',
tuesday: '9:00-18:00',
wednesday: '9:00-18:00',
thursday: '9:00-18:00',
friday: '9:00-18:00',
saturday: '9:00-14:00',
sunday: 'Cerrado'
},
isActive: true
});
useEffect(() => {
loadStoreData();
}, []);
const loadStoreData = async () => {
setLoading(true);
try {
// Load the user's store data
const response = await apiClient.get('/commerce/establishments');
const stores = Array.isArray(response) ? response : (response as any)?.establishments || [];
if (stores.length > 0) {
setStoreData(stores[0]); // Load first store
}
} catch (error) {
console.error('Error loading store:', error);
} finally {
setLoading(false);
}
};
const handleSave = async () => {
try {
if (storeData.id) {
await apiClient.patch(`/commerce/establishments/${storeData.id}`, storeData);
} else {
await apiClient.post('/commerce/establishments', storeData);
}
toast({ title: 'Éxito', description: 'Información de la tienda actualizada' });
setEditing(false);
loadStoreData();
} catch (error: any) {
toast({ title: 'Error', description: error?.message || 'No se pudo guardar', variant: 'destructive' });
}
};
return (
<div className="min-h-screen bg-gray-50 p-6">
<div className="max-w-4xl mx-auto">
<div className="flex items-center justify-between mb-6">
<div className="flex items-center gap-3">
<StoreIcon className="w-8 h-8 text-orange-600" />
<div>
<h1 className="text-3xl font-bold text-gray-900">Mi Comercio</h1>
<p className="text-gray-600">Información y configuración de tu tienda</p>
</div>
</div>
<Button onClick={() => setEditing(!editing)} variant={editing ? 'outline' : 'default'}>
<Edit className="w-4 h-4 mr-2" />
{editing ? 'Cancelar' : 'Editar'}
</Button>
</div>
<div className="space-y-6">
{/* Store Status */}
<Card>
<CardHeader>
<div className="flex items-center justify-between">
<CardTitle>Estado del Comercio</CardTitle>
<Badge variant={storeData.isActive ? 'default' : 'secondary'}>
{storeData.isActive ? 'Activo' : 'Inactivo'}
</Badge>
</div>
</CardHeader>
</Card>
{/* Basic Information */}
<Card>
<CardHeader>
<CardTitle>Información Básica</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div>
<Label>Nombre del Comercio</Label>
<Input
value={storeData.name}
onChange={(e) => setStoreData({ ...storeData, name: e.target.value })}
disabled={!editing}
placeholder="Nombre de tu tienda"
/>
</div>
<div>
<Label>Descripción</Label>
<Textarea
value={storeData.description}
onChange={(e) => setStoreData({ ...storeData, description: e.target.value })}
disabled={!editing}
placeholder="Describe tu negocio..."
rows={3}
/>
</div>
<div>
<Label>Categoría</Label>
<Input
value={storeData.category}
onChange={(e) => setStoreData({ ...storeData, category: e.target.value })}
disabled={!editing}
placeholder="Ej: Boutique, Gift Shop, Electrónica"
/>
</div>
</CardContent>
</Card>
{/* Contact Information */}
<Card>
<CardHeader>
<CardTitle>Información de Contacto</CardTitle>
</CardHeader>
<CardContent className="space-y-4">
<div>
<Label className="flex items-center gap-2">
<MapPin className="w-4 h-4" />
Dirección
</Label>
<Input
value={storeData.address}
onChange={(e) => setStoreData({ ...storeData, address: e.target.value })}
disabled={!editing}
placeholder="Dirección completa"
/>
</div>
<div className="grid grid-cols-2 gap-4">
<div>
<Label className="flex items-center gap-2">
<Phone className="w-4 h-4" />
Teléfono
</Label>
<Input
value={storeData.phone}
onChange={(e) => setStoreData({ ...storeData, phone: e.target.value })}
disabled={!editing}
placeholder="+1 809 123 4567"
/>
</div>
<div>
<Label>Email</Label>
<Input
type="email"
value={storeData.email}
onChange={(e) => setStoreData({ ...storeData, email: e.target.value })}
disabled={!editing}
placeholder="contacto@tienda.com"
/>
</div>
</div>
<div>
<Label className="flex items-center gap-2">
<Globe className="w-4 h-4" />
Sitio Web (Opcional)
</Label>
<Input
value={storeData.website}
onChange={(e) => setStoreData({ ...storeData, website: e.target.value })}
disabled={!editing}
placeholder="https://..."
/>
</div>
</CardContent>
</Card>
{/* Opening Hours */}
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2">
<Clock className="w-5 h-5" />
Horario de Atención
</CardTitle>
</CardHeader>
<CardContent>
<div className="space-y-3">
{Object.entries(storeData.openingHours).map(([day, hours]) => (
<div key={day} className="grid grid-cols-2 gap-4 items-center">
<Label className="capitalize">{day === 'monday' ? 'Lunes' : day === 'tuesday' ? 'Martes' : day === 'wednesday' ? 'Miércoles' : day === 'thursday' ? 'Jueves' : day === 'friday' ? 'Viernes' : day === 'saturday' ? 'Sábado' : 'Domingo'}</Label>
<Input
value={hours as string}
onChange={(e) => setStoreData({
...storeData,
openingHours: { ...storeData.openingHours, [day]: e.target.value }
})}
disabled={!editing}
placeholder="9:00-18:00"
/>
</div>
))}
</div>
</CardContent>
</Card>
{editing && (
<div className="flex justify-end gap-2">
<Button variant="outline" onClick={() => setEditing(false)}>
Cancelar
</Button>
<Button onClick={handleSave}>
Guardar Cambios
</Button>
</div>
)}
</div>
</div>
</div>
);
};
export default Store;