La Cajita TV - Frontend Skill
Guía para desarrollo del frontend React + TypeScript + Tailwind CSS v4.
Stack Tecnológico
- •React 19.0.0 con TypeScript 5.7.2
- •Vite 6.3.5 como bundler
- •Tailwind CSS v4 (migrado desde Bootstrap)
- •React Router 7.x para navegación
- •Auth0 React SDK 2.x para autenticación
Estructura del Proyecto
code
/opt/adm-caja-unified/fastapi-playlists/Lacajita/Adm-Caj/ ├── src/ │ ├── components/ │ │ ├── ui/ # ⚠️ COMPONENTES AUTORIZADOS │ │ ├── common/ # Componentes compartidos │ │ └── Header/ # Componentes específicos │ ├── pages/ # Páginas/vistas │ ├── services/ # Servicios API │ ├── context/ # React Context │ ├── hooks/ # Custom hooks │ └── types/ # TypeScript types ├── dist/ # Build de producción └── vite.config.ts
⚠️ Regla Crítica: Componentes UI
SIEMPRE importar componentes desde /src/components/ui/:
typescript
// ✅ CORRECTO
import { Button, Card, Modal, Alert, Badge } from '@/components/ui';
import { Form, Table, Spinner, Tabs } from '../../components/ui';
// ❌ PROHIBIDO
import Button from '../ui/button/Button';
import { Modal } from 'react-bootstrap';
Componentes Disponibles
| Componente | Props principales |
|---|---|
Button | variant: 'primary' | 'secondary' | 'danger' | 'outline' |
Card, CardHeader, CardBody | className, children |
Alert | variant: 'info' | 'success' | 'warning' | 'danger' |
Modal | show, onClose, title, size |
Badge | variant, children |
Form.Group, Form.Label, Form.Control | - |
Table | striped, hover, responsive |
Spinner | size, variant |
Tabs, Tab | activeKey, onSelect |
Patrones de Código
Componente Funcional con Tipos
typescript
interface VideoCardProps {
video: Video;
onSelect?: (id: string) => void;
}
const VideoCard: React.FC<VideoCardProps> = ({ video, onSelect }) => {
return (
<Card>
<CardBody>
<h3>{video.title}</h3>
<Button variant="primary" onClick={() => onSelect?.(video.id)}>
Ver
</Button>
</CardBody>
</Card>
);
};
Servicio API
typescript
// src/services/videoService.ts
import { getApiUrl, getAuthHeaders } from './api';
export const fetchVideos = async (token: string): Promise<Video[]> => {
const response = await fetch(`${getApiUrl()}/videos`, {
headers: getAuthHeaders(token)
});
if (!response.ok) throw new Error('Error fetching videos');
return response.json();
};
Custom Hook
typescript
// src/hooks/useVideos.ts
export const useVideos = () => {
const { getAccessTokenSilently } = useAuth0();
const [videos, setVideos] = useState<Video[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const load = async () => {
try {
const token = await getAccessTokenSilently();
const data = await fetchVideos(token);
setVideos(data);
} finally {
setLoading(false);
}
};
load();
}, []);
return { videos, loading };
};
Comandos
bash
cd /opt/adm-caja-unified/fastapi-playlists/Lacajita/Adm-Caj # Desarrollo npm run dev # Inicia Vite + backend # Build producción npm run build # Genera /dist # Lint npm run lint
Configuración Auth0
Variables en .env:
code
VITE_AUTH0_DOMAIN=lacajita.us.auth0.com VITE_AUTH0_CLIENT_ID=... VITE_AUTH0_AUDIENCE=https://api.lacajita.tv VITE_API_URL=https://caja.segrd.com/api
Checklist Pre-Commit
- • Componentes UI importados desde
@/components/ui - • Tipos TypeScript definidos (sin
any) - •
npm run buildexitoso - • Sin errores de lint