photum/frontend/pages/Settings.tsx
João Vitor de5ceea1f3 feat: reestruturar página de equipe com sistema de profissionais multi-função
- Renomear 'Equipe & Fotógrafos' para 'Equipe' no título e navbar
- Adicionar suporte para 3 tipos de profissionais: Fotógrafo, Cinegrafista, Recepcionista
- Implementar cards estatísticos separados por função profissional
- Adicionar filtros por função (Fotógrafos, Cinegrafistas, Recepcionistas)
- Adicionar filtros por status (Disponível, Em Evento, Inativo)
- Transformar cards em tabela responsiva com colunas: Nome, Função Profissional, Disponibilidade
- Expandir interface Professional com campos completos do Excel:
  * Endereço completo (rua, número, complemento, bairro, cidade, UF)
  * Dados bancários (banco, agência, conta/pix, tipo cartão, titular)
  * Recursos (carro disponível, possui estúdio, quantidade)
  * Sistema de avaliações detalhado (6 critérios + média)
  * Valores (tabela free, extra no cachê)
  * Observações
- Redesenhar modal 'Adicionar Profissional' com formulário extenso organizado em seções
- Atualizar modal de detalhes com todas as novas informações
- Adicionar ícones específicos por função (Camera, Video, UserCheck)
- Remover fotos da tabela mantendo apenas informações essenciais
2025-12-08 03:12:45 -03:00

649 lines
29 KiB
TypeScript

import React, { useState } from "react";
import {
User,
Mail,
Phone,
MapPin,
Lock,
Bell,
Palette,
Globe,
Save,
Camera,
GraduationCap,
} from "lucide-react";
import { Button } from "../components/Button";
import { useAuth } from "../contexts/AuthContext";
import { UserRole } from "../types";
export const SettingsPage: React.FC = () => {
const { user } = useAuth();
const isAdmin =
user?.role === UserRole.SUPERADMIN ||
user?.role === UserRole.BUSINESS_OWNER;
const [activeTab, setActiveTab] = useState<
"profile" | "account" | "notifications" | "appearance" | "courses"
>("profile");
const [profileData, setProfileData] = useState({
name: "João Silva",
email: "joao.silva@photum.com",
phone: "(41) 99999-0000",
location: "Curitiba, PR",
bio: "Fotógrafo profissional especializado em eventos e formaturas há mais de 10 anos.",
avatar: "https://i.pravatar.cc/150?img=68",
});
const [notificationSettings, setNotificationSettings] = useState({
emailNotifications: true,
pushNotifications: true,
smsNotifications: false,
eventReminders: true,
paymentAlerts: true,
teamUpdates: false,
});
const [appearanceSettings, setAppearanceSettings] = useState({
theme: "light",
language: "pt-BR",
dateFormat: "DD/MM/YYYY",
currency: "BRL",
});
const handleSaveProfile = () => {
alert("Perfil atualizado com sucesso!");
};
const handleSaveNotifications = () => {
alert("Configurações de notificações salvas!");
};
const handleSaveAppearance = () => {
alert("Configurações de aparência salvas!");
};
return (
<div className="min-h-screen bg-gray-50 pt-20 sm:pt-24 md:pt-28 lg:pt-32 pb-8 sm:pb-12">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
{/* Header */}
<div className="mb-6 sm:mb-8">
<h1 className="text-2xl sm:text-3xl font-serif font-bold text-brand-black mb-2">
Configurações
</h1>
<p className="text-sm sm:text-base text-gray-600">
Gerencie suas preferências e informações da conta
</p>
</div>
<div className="grid grid-cols-1 lg:grid-cols-4 gap-4 sm:gap-6">
{/* Mobile Tabs - Horizontal */}
<div className="lg:hidden">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-2">
<nav className="flex overflow-x-auto gap-1 scrollbar-hide">
<button
onClick={() => setActiveTab("profile")}
className={`flex items-center gap-2 px-3 py-2 rounded-md transition-colors whitespace-nowrap text-sm ${
activeTab === "profile"
? "bg-brand-gold text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
<User size={18} />
<span className="font-medium">Perfil</span>
</button>
<button
onClick={() => setActiveTab("account")}
className={`flex items-center gap-2 px-3 py-2 rounded-md transition-colors whitespace-nowrap text-sm ${
activeTab === "account"
? "bg-brand-gold text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
<Lock size={18} />
<span className="font-medium">Conta</span>
</button>
<button
onClick={() => setActiveTab("notifications")}
className={`flex items-center gap-2 px-3 py-2 rounded-md transition-colors whitespace-nowrap text-sm ${
activeTab === "notifications"
? "bg-brand-gold text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
<Bell size={18} />
<span className="font-medium">Notificações</span>
</button>
<button
onClick={() => setActiveTab("appearance")}
className={`flex items-center gap-2 px-3 py-2 rounded-md transition-colors whitespace-nowrap text-sm ${
activeTab === "appearance"
? "bg-brand-gold text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
<Palette size={18} />
<span className="font-medium">Aparência</span>
</button>
</nav>
</div>
</div>
{/* Desktop Sidebar - Vertical */}
<div className="hidden lg:block lg:col-span-1">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4">
<nav className="space-y-1">
<button
onClick={() => setActiveTab("profile")}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-md transition-colors ${
activeTab === "profile"
? "bg-brand-gold text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
<User size={20} />
<span className="font-medium">Perfil</span>
</button>
<button
onClick={() => setActiveTab("account")}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-md transition-colors ${
activeTab === "account"
? "bg-brand-gold text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
<Lock size={20} />
<span className="font-medium">Conta</span>
</button>
<button
onClick={() => setActiveTab("notifications")}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-md transition-colors ${
activeTab === "notifications"
? "bg-brand-gold text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
<Bell size={20} />
<span className="font-medium">Notificações</span>
</button>
<button
onClick={() => setActiveTab("appearance")}
className={`w-full flex items-center gap-3 px-4 py-3 rounded-md transition-colors ${
activeTab === "appearance"
? "bg-brand-gold text-white"
: "text-gray-700 hover:bg-gray-100"
}`}
>
<Palette size={20} />
<span className="font-medium">Aparência</span>
</button>
</nav>
</div>
</div>
{/* Content */}
<div className="lg:col-span-3">
<div className="bg-white rounded-lg shadow-sm border border-gray-200 p-4 sm:p-6 md:p-8">
{/* Profile Tab */}
{activeTab === "profile" && (
<div>
<h2 className="text-xl sm:text-2xl font-semibold mb-4 sm:mb-6">
Informações do Perfil
</h2>
<div className="mb-6 sm:mb-8">
<div className="flex flex-col sm:flex-row items-center sm:items-start gap-4 sm:gap-6">
<div className="relative">
<img
src={profileData.avatar}
alt="Avatar"
className="w-20 h-20 sm:w-24 sm:h-24 rounded-full object-cover"
/>
<button className="absolute bottom-0 right-0 w-7 h-7 sm:w-8 sm:h-8 bg-brand-gold text-white rounded-full flex items-center justify-center hover:bg-[#a5bd2e] transition-colors">
<Camera size={14} className="sm:w-4 sm:h-4" />
</button>
</div>
<div className="text-center sm:text-left">
<h3 className="font-semibold text-base sm:text-lg">
{profileData.name}
</h3>
<p className="text-xs sm:text-sm text-gray-600">
{profileData.email}
</p>
<button className="text-xs sm:text-sm text-brand-gold hover:underline mt-1">
Alterar foto
</button>
</div>
</div>
</div>
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Nome Completo
</label>
<div className="relative">
<User
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
size={20}
/>
<input
type="text"
value={profileData.name}
onChange={(e) =>
setProfileData({
...profileData,
name: e.target.value,
})
}
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Email
</label>
<div className="relative">
<Mail
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
size={20}
/>
<input
type="email"
value={profileData.email}
onChange={(e) =>
setProfileData({
...profileData,
email: e.target.value,
})
}
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Telefone
</label>
<div className="relative">
<Phone
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
size={20}
/>
<input
type="tel"
value={profileData.phone}
onChange={(e) =>
setProfileData({
...profileData,
phone: e.target.value,
})
}
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Localização
</label>
<div className="relative">
<MapPin
className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400"
size={20}
/>
<input
type="text"
value={profileData.location}
onChange={(e) =>
setProfileData({
...profileData,
location: e.target.value,
})
}
className="w-full pl-10 pr-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Biografia
</label>
<textarea
value={profileData.bio}
onChange={(e) =>
setProfileData({
...profileData,
bio: e.target.value,
})
}
rows={4}
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
<div className="pt-4">
<Button
size="lg"
variant="secondary"
onClick={handleSaveProfile}
>
<Save size={20} className="mr-2" />
Salvar Alterações
</Button>
</div>
</div>
</div>
)}
{/* Account Tab */}
{activeTab === "account" && (
<div>
<h2 className="text-2xl font-semibold mb-6">
Segurança da Conta
</h2>
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Senha Atual
</label>
<input
type="password"
placeholder="Digite sua senha atual"
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Nova Senha
</label>
<input
type="password"
placeholder="Digite sua nova senha"
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Confirmar Nova Senha
</label>
<input
type="password"
placeholder="Confirme sua nova senha"
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
/>
</div>
<div className="pt-4">
<Button size="lg" variant="secondary">
<Lock size={20} className="mr-2" />
Atualizar Senha
</Button>
</div>
<div className="pt-8 border-t border-gray-200">
<h3 className="text-lg font-semibold mb-4">
Autenticação em Dois Fatores
</h3>
<p className="text-gray-600 mb-4">
Adicione uma camada extra de segurança à sua conta
</p>
<Button size="md" variant="outline">
Ativar 2FA
</Button>
</div>
</div>
</div>
)}
{/* Notifications Tab */}
{activeTab === "notifications" && (
<div>
<h2 className="text-2xl font-semibold mb-6">
Preferências de Notificações
</h2>
<div className="space-y-6">
<div className="flex items-center justify-between py-4 border-b border-gray-200">
<div>
<h3 className="font-medium">Notificações por Email</h3>
<p className="text-sm text-gray-600">
Receba atualizações por email
</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
checked={notificationSettings.emailNotifications}
onChange={(e) =>
setNotificationSettings({
...notificationSettings,
emailNotifications: e.target.checked,
})
}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand-gold/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-brand-gold"></div>
</label>
</div>
<div className="flex items-center justify-between py-4 border-b border-gray-200">
<div>
<h3 className="font-medium">Notificações Push</h3>
<p className="text-sm text-gray-600">
Receba notificações no navegador
</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
checked={notificationSettings.pushNotifications}
onChange={(e) =>
setNotificationSettings({
...notificationSettings,
pushNotifications: e.target.checked,
})
}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand-gold/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-brand-gold"></div>
</label>
</div>
<div className="flex items-center justify-between py-4 border-b border-gray-200">
<div>
<h3 className="font-medium">SMS</h3>
<p className="text-sm text-gray-600">
Receba mensagens de texto
</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
checked={notificationSettings.smsNotifications}
onChange={(e) =>
setNotificationSettings({
...notificationSettings,
smsNotifications: e.target.checked,
})
}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand-gold/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-brand-gold"></div>
</label>
</div>
<div className="flex items-center justify-between py-4 border-b border-gray-200">
<div>
<h3 className="font-medium">Lembretes de Eventos</h3>
<p className="text-sm text-gray-600">
Receba lembretes antes dos eventos
</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
checked={notificationSettings.eventReminders}
onChange={(e) =>
setNotificationSettings({
...notificationSettings,
eventReminders: e.target.checked,
})
}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand-gold/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-brand-gold"></div>
</label>
</div>
<div className="flex items-center justify-between py-4 border-b border-gray-200">
<div>
<h3 className="font-medium">Alertas de Pagamento</h3>
<p className="text-sm text-gray-600">
Notificações sobre pagamentos
</p>
</div>
<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
checked={notificationSettings.paymentAlerts}
onChange={(e) =>
setNotificationSettings({
...notificationSettings,
paymentAlerts: e.target.checked,
})
}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-brand-gold/20 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-brand-gold"></div>
</label>
</div>
<div className="pt-4">
<Button
size="lg"
variant="secondary"
onClick={handleSaveNotifications}
>
<Save size={20} className="mr-2" />
Salvar Preferências
</Button>
</div>
</div>
</div>
)}
{/* Appearance Tab */}
{activeTab === "appearance" && (
<div>
<h2 className="text-2xl font-semibold mb-6">
Aparência e Idioma
</h2>
<div className="space-y-6">
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Tema
</label>
<select
value={appearanceSettings.theme}
onChange={(e) =>
setAppearanceSettings({
...appearanceSettings,
theme: e.target.value,
})
}
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
>
<option value="light">Claro</option>
<option value="dark">Escuro</option>
<option value="auto">Automático</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Idioma
</label>
<select
value={appearanceSettings.language}
onChange={(e) =>
setAppearanceSettings({
...appearanceSettings,
language: e.target.value,
})
}
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
>
<option value="pt-BR">Português (Brasil)</option>
<option value="en-US">English (US)</option>
<option value="es-ES">Español</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Formato de Data
</label>
<select
value={appearanceSettings.dateFormat}
onChange={(e) =>
setAppearanceSettings({
...appearanceSettings,
dateFormat: e.target.value,
})
}
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
>
<option value="DD/MM/YYYY">DD/MM/YYYY</option>
<option value="MM/DD/YYYY">MM/DD/YYYY</option>
<option value="YYYY-MM-DD">YYYY-MM-DD</option>
</select>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-2">
Moeda
</label>
<select
value={appearanceSettings.currency}
onChange={(e) =>
setAppearanceSettings({
...appearanceSettings,
currency: e.target.value,
})
}
className="w-full px-4 py-3 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-brand-gold"
>
<option value="BRL">Real (R$)</option>
<option value="USD">Dólar ($)</option>
<option value="EUR">Euro ()</option>
</select>
</div>
<div className="pt-4">
<Button
size="lg"
variant="secondary"
onClick={handleSaveAppearance}
>
<Save size={20} className="mr-2" />
Salvar Configurações
</Button>
</div>
</div>
</div>
)}
</div>
</div>
</div>
</div>
</div>
);
};