photum/frontend/components/ProfessionalDetailsModal.tsx
NANDO9322 434548c158 feat(staffing): implementa sistema de disponibilidade e escalonamento
- Adiciona tabela `disponibilidade_profissionais` no schema
- Adiciona coluna `posicao` para mapa de profissionais no evento
- Implementa Service e Handler para gerenciar Disponibilidade (Set/Get)
- Implementa lógica de Escalonamento: listar disponíveis e atribuir posição
- Atualiza rotas da API e serviço do frontend

feat(frontend): implementa modal de detalhes e updates otimistas na equipe

- Adiciona componente ProfessionalDetailsModal para exibir dados completos do profissional
- Implementa update otimista em DataContext para adição/removação instantânea da equipe
- Corrige bug crítico de sintaxe e estrutura na Dashboard.tsx
- Adiciona badges de status (Pendente/Confirmado/Rejeitado) na listagem de equipe
- Corrige erro de referência de variável (professionalId) no fluxo de atribuição
2025-12-23 17:29:40 -03:00

123 lines
6.3 KiB
TypeScript

import React from 'react';
import { Professional } from '../types';
import { Button } from './Button';
import { X, Mail, Phone, MapPin, Building, Star, Camera, DollarSign, Award } from 'lucide-react';
interface ProfessionalDetailsModalProps {
professional: Professional;
isOpen: boolean;
onClose: () => void;
}
export const ProfessionalDetailsModal: React.FC<ProfessionalDetailsModalProps> = ({
professional,
isOpen,
onClose,
}) => {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50 p-4 animate-fadeIn">
<div className="bg-white rounded-2xl shadow-2xl max-w-2xl w-full overflow-hidden flex flex-col relative animate-slideIn">
{/* Header com Capa/Avatar Style */}
<div className="h-32 bg-gradient-to-r from-brand-purple to-brand-purple/80 relative">
<button
onClick={onClose}
className="absolute top-4 right-4 text-white hover:bg-white/20 p-2 rounded-full transition-colors"
>
<X size={24} />
</button>
</div>
{/* Conteúdo Principal */}
<div className="px-8 pb-8 -mt-16 flex flex-col items-center sm:items-start relative z-10">
{/* Avatar Grande */}
<div
className="w-32 h-32 rounded-full border-4 border-white bg-white shadow-lg mb-4"
style={{
backgroundImage: `url(${professional.avatar || `https://ui-avatars.com/api/?name=${encodeURIComponent(professional.name)}&background=random`})`,
backgroundSize: 'cover',
backgroundPosition: 'center'
}}
/>
<div className="text-center sm:text-left w-full">
<h2 className="text-2xl font-serif font-bold text-brand-black">{professional.name}</h2>
<div className="flex flex-wrap justify-center sm:justify-start gap-2 mt-2">
<span className="px-3 py-1 bg-brand-gold/10 text-brand-black rounded-full text-sm font-medium border border-brand-gold/20">
{professional.role}
</span>
{/* Mock de Avaliação */}
<span className="px-3 py-1 bg-yellow-50 text-yellow-700 rounded-full text-sm font-medium border border-yellow-200 flex items-center gap-1">
<Star size={14} className="fill-yellow-500 text-yellow-500" /> 4.9
</span>
</div>
</div>
<div className="w-full grid grid-cols-1 md:grid-cols-2 gap-6 mt-8">
<div className="space-y-4">
<h3 className="font-bold text-gray-900 border-b pb-2 flex items-center gap-2">
<Building size={18} className="text-brand-gold" />
Dados Pessoais
</h3>
<div className="space-y-3 text-sm">
<div className="flex items-center gap-3 text-gray-700">
<Mail size={16} className="text-gray-400" />
<span>{professional.email}</span>
</div>
<div className="flex items-center gap-3 text-gray-700">
<Phone size={16} className="text-gray-400" />
<span>{professional.phone || "Não informado"}</span>
</div>
{/* Endereço Mockado se não tiver no tipo, ou usar campos extras do backend se mapeados */}
<div className="flex items-center gap-3 text-gray-700">
<MapPin size={16} className="text-gray-400" />
<span>São Paulo, SP</span>
</div>
</div>
</div>
<div className="space-y-4">
<h3 className="font-bold text-gray-900 border-b pb-2 flex items-center gap-2">
<Camera size={18} className="text-brand-gold" />
Equipamentos & Habilidades
</h3>
{/* Mock de Habilidades / Equipamentos (pois não está no type Professional simples ainda) */}
<div className="text-sm text-gray-600 space-y-2">
<p>Equipamento Profissional: <span className="text-gray-900">Canon R6, Lentes série L</span></p>
<div className="flex flex-wrap gap-2 mt-2">
{["Formatura", "Casamento", "Estúdio"].map(tag => (
<span key={tag} className="text-xs bg-gray-100 px-2 py-1 rounded text-gray-600">{tag}</span>
))}
</div>
</div>
</div>
</div>
<div className="w-full mt-8 bg-gray-50 p-4 rounded-lg border border-gray-100">
<div className="flex items-start gap-3">
<Award className="text-brand-gold mt-1" size={20} />
<div>
<h4 className="font-bold text-gray-900 text-sm">Performance</h4>
<p className="text-sm text-gray-600 mt-1">Este profissional tem mantido uma taxa de 100% de presença e alta satisfação nos últimos eventos.</p>
</div>
</div>
</div>
<div className="w-full mt-8 flex justify-end">
<Button variant="outline" onClick={onClose}>
Fechar
</Button>
</div>
</div>
</div>
</div>
);
};