import React, { useState, useEffect } from "react"; import { Users, Camera, Mail, Phone, MapPin, Star, Plus, Search, Filter, User, Upload, X, Video, UserCheck, Car, Building, CreditCard, TrendingUp, AlertTriangle, } from "lucide-react"; import { Button } from "../components/Button"; import { getProfessionalRoles } from "../services/apiService"; type ProfessionalRole = "Fotógrafo" | "Cinegrafista" | "Recepcionista"; interface Professional { id: string; name: string; role: ProfessionalRole; address: { street: string; number: string; complement?: string; neighborhood: string; city: string; state: string; }; whatsapp: string; cpfCnpj: string; bankInfo: { bank: string; agency: string; accountPix: string; }; hasCar: boolean; hasStudio: boolean; studioQuantity?: number; cardType: string; accountHolder: string; observations?: string; ratings: { technicalQuality: number; appearance: number; education: number; sympathy: number; eventPerformance: number; scheduleAvailability: number; average: number; }; freeTable: string; extraFee: string; email: string; specialties: string[]; eventsCompleted: number; status: "active" | "inactive" | "busy"; avatar: string; joinDate: string; } const MOCK_PROFESSIONALS: Professional[] = [ { id: "1", name: "Carlos Silva", role: "Fotógrafo", address: { street: "Rua das Flores", number: "123", complement: "Apto 301", neighborhood: "Centro", city: "Curitiba", state: "PR", }, whatsapp: "(41) 99999-1111", cpfCnpj: "123.456.789-00", bankInfo: { bank: "Banco do Brasil", agency: "1234-5", accountPix: "carlos.silva@email.com", }, hasCar: true, hasStudio: false, cardType: "Débito/Crédito", accountHolder: "Carlos Silva", ratings: { technicalQuality: 4.8, appearance: 4.7, education: 4.9, sympathy: 4.8, eventPerformance: 4.9, scheduleAvailability: 4.6, average: 4.8, }, freeTable: "R$ 800,00", extraFee: "R$ 150,00 por equipamento extra", email: "carlos.silva@photum.com", specialties: ["Formaturas", "Eventos Corporativos"], eventsCompleted: 45, status: "active", avatar: "https://i.pravatar.cc/150?img=12", joinDate: "2023-01-15", }, { id: "2", name: "Ana Paula Mendes", role: "Cinegrafista", address: { street: "Av. Sete de Setembro", number: "456", neighborhood: "Batel", city: "Curitiba", state: "PR", }, whatsapp: "(41) 99999-2222", cpfCnpj: "987.654.321-00", bankInfo: { bank: "Caixa Econômica", agency: "0987", accountPix: "(41) 99999-2222", }, hasCar: true, hasStudio: true, studioQuantity: 1, cardType: "Crédito", accountHolder: "Ana Paula Mendes", ratings: { technicalQuality: 4.9, appearance: 5.0, education: 4.8, sympathy: 4.9, eventPerformance: 4.9, scheduleAvailability: 4.7, average: 4.9, }, freeTable: "R$ 1.200,00", extraFee: "R$ 200,00 por hora extra", email: "ana.mendes@photum.com", specialties: ["Casamentos", "Formaturas"], eventsCompleted: 62, status: "busy", avatar: "https://i.pravatar.cc/150?img=5", joinDate: "2022-08-20", }, { id: "3", name: "Mariana Alves", role: "Recepcionista", address: { street: "Rua Comendador Araújo", number: "321", complement: "Sala 12", neighborhood: "Centro", city: "Curitiba", state: "PR", }, whatsapp: "(41) 99999-4444", cpfCnpj: "321.654.987-00", bankInfo: { bank: "Bradesco", agency: "4321", accountPix: "mariana.alves@email.com", }, hasCar: false, hasStudio: false, cardType: "Débito", accountHolder: "Mariana Alves Santos", ratings: { technicalQuality: 0, appearance: 4.9, education: 5.0, sympathy: 5.0, eventPerformance: 4.8, scheduleAvailability: 4.9, average: 4.9, }, freeTable: "R$ 400,00", extraFee: "R$ 50,00 por hora extra", email: "mariana.alves@photum.com", specialties: ["Recepção", "Atendimento"], eventsCompleted: 71, status: "active", avatar: "https://i.pravatar.cc/150?img=9", joinDate: "2022-05-12", }, ]; export const TeamPage: React.FC = () => { const [searchTerm, setSearchTerm] = useState(""); const [roleFilter, setRoleFilter] = useState("all"); const [statusFilter, setStatusFilter] = useState< "all" | "active" | "busy" | "inactive" >("all"); const [selectedProfessional, setSelectedProfessional] = useState(null); const [showAddModal, setShowAddModal] = useState(false); const [showEditModal, setShowEditModal] = useState(false); const [editingProfessional, setEditingProfessional] = useState(null); const [professionalRoles, setProfessionalRoles] = useState([]); const [isBackendDown, setIsBackendDown] = useState(false); const [isLoadingRoles, setIsLoadingRoles] = useState(true); const [newProfessional, setNewProfessional] = useState>( { name: "", role: "Fotógrafo", address: { street: "", number: "", complement: "", neighborhood: "", city: "", state: "", }, whatsapp: "", cpfCnpj: "", bankInfo: { bank: "", agency: "", accountPix: "", }, hasCar: false, hasStudio: false, studioQuantity: 0, cardType: "", accountHolder: "", observations: "", ratings: { technicalQuality: 0, appearance: 0, education: 0, sympathy: 0, eventPerformance: 0, scheduleAvailability: 0, average: 0, }, freeTable: "", extraFee: "", email: "", specialties: [], avatar: "", } ); const [avatarFile, setAvatarFile] = useState(null); const [avatarPreview, setAvatarPreview] = useState(""); // Buscar funções profissionais do backend useEffect(() => { const fetchRoles = async () => { setIsLoadingRoles(true); const response = await getProfessionalRoles(); if (response.isBackendDown) { setIsBackendDown(true); setProfessionalRoles([]); } else if (response.data) { setIsBackendDown(false); setProfessionalRoles(response.data); } setIsLoadingRoles(false); }; fetchRoles(); }, []); const handleAvatarChange = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { setAvatarFile(file); const reader = new FileReader(); reader.onloadend = () => { setAvatarPreview(reader.result as string); }; reader.readAsDataURL(file); } }; const removeAvatar = () => { setAvatarFile(null); setAvatarPreview(""); }; const handleEditProfessional = (professional: Professional) => { setEditingProfessional(professional); setNewProfessional(professional); setAvatarPreview(professional.avatar); setSelectedProfessional(null); setShowEditModal(true); }; const handleUpdateProfessional = () => { // Aqui você implementaria a lógica de atualização // Por exemplo, chamada à API para atualizar os dados console.log('Atualizando profissional:', newProfessional); // Simulando atualização setShowEditModal(false); setEditingProfessional(null); setNewProfessional({ name: "", role: "Fotógrafo", address: { street: "", number: "", complement: "", neighborhood: "", city: "", state: "", }, whatsapp: "", cpfCnpj: "", bankInfo: { bank: "", agency: "", accountPix: "", }, hasCar: false, hasStudio: false, studioQuantity: 0, cardType: "", accountHolder: "", observations: "", ratings: { technicalQuality: 0, appearance: 0, education: 0, sympathy: 0, eventPerformance: 0, scheduleAvailability: 0, average: 0, }, freeTable: "", extraFee: "", email: "", specialties: [], avatar: "", }); removeAvatar(); }; const getStatusColor = (status: Professional["status"]) => { switch (status) { case "active": return "bg-green-100 text-green-800"; case "busy": return "bg-yellow-100 text-yellow-800"; case "inactive": return "bg-gray-100 text-gray-800"; } }; const getStatusLabel = (status: Professional["status"]) => { switch (status) { case "active": return "Disponível"; case "busy": return "Em Evento"; case "inactive": return "Inativo"; } }; const getRoleIcon = (role: ProfessionalRole) => { switch (role) { case "Fotógrafo": return Camera; case "Cinegrafista": return Video; case "Recepcionista": return UserCheck; } }; const filteredProfessionals = MOCK_PROFESSIONALS.filter((professional) => { const matchesSearch = professional.name.toLowerCase().includes(searchTerm.toLowerCase()) || professional.email.toLowerCase().includes(searchTerm.toLowerCase()); const matchesRole = roleFilter === "all" || professional.role === roleFilter; const matchesStatus = statusFilter === "all" || professional.status === statusFilter; return matchesSearch && matchesRole && matchesStatus; }); const stats = { photographers: MOCK_PROFESSIONALS.filter((p) => p.role === "Fotógrafo") .length, cinematographers: MOCK_PROFESSIONALS.filter( (p) => p.role === "Cinegrafista" ).length, receptionists: MOCK_PROFESSIONALS.filter((p) => p.role === "Recepcionista") .length, total: MOCK_PROFESSIONALS.length, }; return (
{/* Header */}

Equipe

Gerencie sua equipe de profissionais

{/* Stats */}

Total de Fotógrafos

{stats.photographers}

Total de Cinegrafistas

{stats.cinematographers}

Total de Recepcionistas

{stats.receptionists}

{/* Filters and Search */}
setSearchTerm(e.target.value)} className="w-full pl-10 pr-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
{/* Status Filters */}
{/* Professionals Table */}
{filteredProfessionals.length === 0 ? (

Nenhum profissional encontrado

) : (
{filteredProfessionals.map((professional) => { const RoleIcon = getRoleIcon(professional.role); return ( setSelectedProfessional(professional)} > ); })}
Nome Função Profissional Disponibilidade
{professional.name}
{professional.ratings.average.toFixed(1)} ({professional.eventsCompleted} eventos)
{professional.role}
{getStatusLabel(professional.status)}
)}
{/* Edit Professional Modal */} {showEditModal && (
setShowEditModal(false)} >
e.stopPropagation()} >

Editar Profissional

Atualize as informações do profissional

{ e.preventDefault(); handleUpdateProfessional(); alert("Profissional atualizado com sucesso!"); }} > {/* Reutilizar o mesmo conteúdo do formulário de adicionar */} {/* Avatar Upload */}
{avatarPreview ? (
Preview
) : (
)}
{/* Botões de Ação */}
)} {/* Add Professional Modal - com todos os campos da planilha */} {showAddModal && (
setShowAddModal(false)} >
e.stopPropagation()} >

Adicionar Novo Profissional

{ e.preventDefault(); alert("Profissional adicionado com sucesso!"); setShowAddModal(false); }} > {/* Dados Básicos */}

Dados Básicos

setNewProfessional({ ...newProfessional, name: e.target.value, }) } placeholder="Nome completo" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
{isBackendDown && (
Backend não está rodando. Não é possível carregar as funções profissionais.
)} {isLoadingRoles && !isBackendDown && (
Carregando funções profissionais...
)}
setNewProfessional({ ...newProfessional, email: e.target.value, }) } placeholder="email@exemplo.com" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, whatsapp: e.target.value, }) } placeholder="(00) 00000-0000" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, cpfCnpj: e.target.value, }) } placeholder="000.000.000-00 ou 00.000.000/0000-00" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
{/* Endereço */}

Endereço

setNewProfessional({ ...newProfessional, address: { ...newProfessional.address!, street: e.target.value, }, }) } placeholder="Nome da rua" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, address: { ...newProfessional.address!, number: e.target.value, }, }) } placeholder="123" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, address: { ...newProfessional.address!, complement: e.target.value, }, }) } placeholder="Apto, Sala, etc" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, address: { ...newProfessional.address!, neighborhood: e.target.value, }, }) } placeholder="Nome do bairro" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, address: { ...newProfessional.address!, city: e.target.value, }, }) } placeholder="Nome da cidade" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, address: { ...newProfessional.address!, state: e.target.value.toUpperCase(), }, }) } placeholder="SP" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
{/* Dados Bancários */}

Dados Bancários

setNewProfessional({ ...newProfessional, bankInfo: { ...newProfessional.bankInfo!, bank: e.target.value, }, }) } placeholder="Nome do banco" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, bankInfo: { ...newProfessional.bankInfo!, agency: e.target.value, }, }) } placeholder="0000-0" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, bankInfo: { ...newProfessional.bankInfo!, accountPix: e.target.value, }, }) } placeholder="Conta ou chave Pix" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, cardType: e.target.value, }) } placeholder="Débito, Crédito, Pix, etc" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, accountHolder: e.target.value, }) } placeholder="Nome do titular" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
{/* Recursos e Equipamentos */}

Recursos e Equipamentos

{newProfessional.hasStudio && (
setNewProfessional({ ...newProfessional, studioQuantity: parseInt(e.target.value), }) } placeholder="0" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
)}
setNewProfessional({ ...newProfessional, cardType: e.target.value, }) } placeholder="Ex: SD, CF, XQD, etc." className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
{/* Avaliações */}

Avaliações (0 a 5)

setNewProfessional({ ...newProfessional, ratings: { ...newProfessional.ratings!, technicalQuality: parseFloat(e.target.value), }, }) } placeholder="0.0" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, ratings: { ...newProfessional.ratings!, sympathy: parseFloat(e.target.value), }, }) } placeholder="0.0" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, ratings: { ...newProfessional.ratings!, eventPerformance: parseFloat(e.target.value), }, }) } placeholder="0.0" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, ratings: { ...newProfessional.ratings!, scheduleAvailability: parseFloat(e.target.value), }, }) } placeholder="0.0" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
{/* Valores */}

Valores

setNewProfessional({ ...newProfessional, freeTable: e.target.value, }) } placeholder="R$ 800,00" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
setNewProfessional({ ...newProfessional, extraFee: e.target.value, }) } placeholder="R$ 150,00" className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold" />
{/* Observações */}