Merge branch 'dev' into hml
This commit is contained in:
commit
1bdb446709
5 changed files with 71 additions and 9 deletions
45
README.md
45
README.md
|
|
@ -24,7 +24,52 @@ O **Photum** é uma aplicação web full-stack desenvolvida com React + TypeScri
|
||||||
- ✅ **Backend Go**: API RESTful completa com PostgreSQL
|
- ✅ **Backend Go**: API RESTful completa com PostgreSQL
|
||||||
|
|
||||||
---
|
---
|
||||||
|
1. 📊 Status Report
|
||||||
|
|
||||||
|
Módulo / Perfil,Status,Detalhes Críticos (Blockers)
|
||||||
|
Superadmin,🔴 CRÍTICO,Cadastro FOT travado (sem Empresa/Curso/Ano). Dashboard quebra ao redimensionar. Modal de Novo Usuário trava a tela (scroll lock).
|
||||||
|
Empresa,🟠 PARCIAL,Equipe: Faltam funções e regiões. Filtros: Vazios.
|
||||||
|
Fotógrafo,🔴 CRÍTICO,Meus Pagamentos: Tela Branca (Crash). Região: Não editável.
|
||||||
|
Cliente,🟠 PARCIAL,"Solicitar Evento: Trava no ""Tipo de Evento"" (vazio). Upload e Mapas OK."
|
||||||
|
Geral (Backend),❌ OFF,A maioria dos formulários depende de GET /api/... que não está retornando dados.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
graph TD
|
||||||
|
%% Atores
|
||||||
|
SA((Superadmin))
|
||||||
|
EMP((Empresa))
|
||||||
|
FOTO((Fotógrafo))
|
||||||
|
CLI((Cliente))
|
||||||
|
|
||||||
|
%% Bloqueios do Superadmin
|
||||||
|
SA -->|Tenta Cadastrar| FOT[Cadastro FOT]
|
||||||
|
FOT -->|Erro| DropEmp[Select Empresa VAZIO]
|
||||||
|
FOT -->|Erro| DropCur[Select Curso VAZIO]
|
||||||
|
FOT -.->|Bloqueio| FimFOT(Não Salva)
|
||||||
|
|
||||||
|
SA -->|Visualiza| Dash[Dashboard]
|
||||||
|
Dash -->|Redimensiona| BugUI[Layout Quebra/Some]
|
||||||
|
|
||||||
|
SA -->|Gerenciar| Users[Aprovação Usuários]
|
||||||
|
Users -->|Novo Usuário| ModalLock[Modal Trava Scroll]
|
||||||
|
ModalLock -->|Refresh| Logout(Força Logout)
|
||||||
|
|
||||||
|
%% Bloqueios da Empresa/Equipe
|
||||||
|
EMP -->|Adicionar| Member[Novo Profissional]
|
||||||
|
Member -->|Erro| DropFunc[Funções VAZIAS]
|
||||||
|
Member -->|Erro| DropReg[Regiões INCOMPLETAS]
|
||||||
|
|
||||||
|
%% Bloqueios do Fotógrafo
|
||||||
|
FOTO -->|Acessa| Fin[Meus Pagamentos]
|
||||||
|
Fin -->|Erro| WS[TELA BRANCA / Crash]
|
||||||
|
|
||||||
|
%% Bloqueios do Cliente
|
||||||
|
CLI -->|Solicita| NewEvent[Novo Evento]
|
||||||
|
NewEvent -->|Erro| DropTipo[Tipo Evento VAZIO]
|
||||||
|
NewEvent -->|Sucesso| Maps[Localização/Mapbox OK]
|
||||||
|
NewEvent -->|Sucesso| Upload[Upload Inspirações OK]
|
||||||
|
```
|
||||||
|
---
|
||||||
## 🚀 Como Executar o Projeto
|
## 🚀 Como Executar o Projeto
|
||||||
|
|
||||||
### Pré-requisitos
|
### Pré-requisitos
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,12 @@ export const Navbar: React.FC<NavbarProps> = ({ onNavigate, currentPage }) => {
|
||||||
if (!user) return "";
|
if (!user) return "";
|
||||||
if (user.role === UserRole.BUSINESS_OWNER) return "Empresa";
|
if (user.role === UserRole.BUSINESS_OWNER) return "Empresa";
|
||||||
if (user.role === UserRole.EVENT_OWNER) return "Cliente";
|
if (user.role === UserRole.EVENT_OWNER) return "Cliente";
|
||||||
if (user.role === UserRole.PHOTOGRAPHER) return "Fotógrafo";
|
if (user.role === UserRole.PHOTOGRAPHER) {
|
||||||
|
if (user.functions && user.functions.length > 0) {
|
||||||
|
return user.functions[0].nome;
|
||||||
|
}
|
||||||
|
return "Profissional";
|
||||||
|
}
|
||||||
if (user.role === UserRole.SUPERADMIN) return "Super Admin";
|
if (user.role === UserRole.SUPERADMIN) return "Super Admin";
|
||||||
if (user.role === UserRole.AGENDA_VIEWER) return "Visualizador";
|
if (user.role === UserRole.AGENDA_VIEWER) return "Visualizador";
|
||||||
if (user.role === UserRole.RESEARCHER) return "Pesquisa";
|
if (user.role === UserRole.RESEARCHER) return "Pesquisa";
|
||||||
|
|
@ -440,7 +445,7 @@ export const Navbar: React.FC<NavbarProps> = ({ onNavigate, currentPage }) => {
|
||||||
user.role === UserRole.EVENT_OWNER) && (
|
user.role === UserRole.EVENT_OWNER) && (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setIsEditProfileModalOpen(true);
|
onNavigate("profile");
|
||||||
setIsAccountDropdownOpen(false);
|
setIsAccountDropdownOpen(false);
|
||||||
}}
|
}}
|
||||||
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white transition-colors text-left group"
|
className="w-full flex items-center gap-3 px-4 py-3 rounded-xl hover:bg-white transition-colors text-left group"
|
||||||
|
|
|
||||||
|
|
@ -120,6 +120,7 @@ export const AuthProvider: React.FC<{ children: ReactNode }> = ({ children }) =>
|
||||||
cidade: backendUser.cidade,
|
cidade: backendUser.cidade,
|
||||||
estado: backendUser.estado,
|
estado: backendUser.estado,
|
||||||
professionalId: data.profissional?.id, // Map professional ID
|
professionalId: data.profissional?.id, // Map professional ID
|
||||||
|
functions: data.profissional?.functions || [],
|
||||||
};
|
};
|
||||||
console.log("AuthContext: restoreSession mapped user:", mappedUser);
|
console.log("AuthContext: restoreSession mapped user:", mappedUser);
|
||||||
if (!backendUser.ativo) {
|
if (!backendUser.ativo) {
|
||||||
|
|
@ -221,6 +222,7 @@ const login = async (email: string, password?: string) => {
|
||||||
cidade: backendUser.cidade,
|
cidade: backendUser.cidade,
|
||||||
estado: backendUser.estado,
|
estado: backendUser.estado,
|
||||||
professionalId: data.profissional?.id, // Map professional ID
|
professionalId: data.profissional?.id, // Map professional ID
|
||||||
|
functions: data.profissional?.functions || [],
|
||||||
};
|
};
|
||||||
|
|
||||||
setUser(mappedUser);
|
setUser(mappedUser);
|
||||||
|
|
@ -338,6 +340,7 @@ const login = async (email: string, password?: string) => {
|
||||||
bairro: backendUser.bairro,
|
bairro: backendUser.bairro,
|
||||||
cidade: backendUser.cidade,
|
cidade: backendUser.cidade,
|
||||||
estado: backendUser.estado,
|
estado: backendUser.estado,
|
||||||
|
functions: backendUser.functions || [],
|
||||||
};
|
};
|
||||||
if (autoLogin) {
|
if (autoLogin) {
|
||||||
setUser(mappedUser);
|
setUser(mappedUser);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import {
|
||||||
rejectUser as apiRejectUser,
|
rejectUser as apiRejectUser,
|
||||||
updateUserRole,
|
updateUserRole,
|
||||||
getCompanies,
|
getCompanies,
|
||||||
|
getFunctions,
|
||||||
} from "../services/apiService";
|
} from "../services/apiService";
|
||||||
import { UserApprovalStatus, UserRole } from "../types";
|
import { UserApprovalStatus, UserRole } from "../types";
|
||||||
import {
|
import {
|
||||||
|
|
@ -62,7 +63,7 @@ const UserDetailsModal: React.FC<UserDetailsModalProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4 fade-in">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4 fade-in">
|
||||||
<div className="bg-white rounded-lg shadow-xl w-full max-w-lg overflow-hidden animate-slide-up">
|
<div className="bg-white rounded-lg shadow-xl w-full max-w-lg max-h-[95vh] overflow-y-auto animate-slide-up">
|
||||||
<div className="flex justify-between items-center p-6 border-b border-gray-100">
|
<div className="flex justify-between items-center p-6 border-b border-gray-100">
|
||||||
<h3 className="text-xl font-bold text-gray-900 font-serif">
|
<h3 className="text-xl font-bold text-gray-900 font-serif">
|
||||||
Detalhes do Cadastro
|
Detalhes do Cadastro
|
||||||
|
|
@ -196,20 +197,27 @@ const CreateUserModal: React.FC<CreateUserModalProps> = ({
|
||||||
formData,
|
formData,
|
||||||
setFormData
|
setFormData
|
||||||
}) => {
|
}) => {
|
||||||
// Fetch companies
|
// Fetch companies and functions
|
||||||
const [companies, setCompanies] = useState<any[]>([]);
|
const [companies, setCompanies] = useState<any[]>([]);
|
||||||
|
const [functions, setFunctions] = useState<any[]>([]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (formData.role === "EVENT_OWNER") {
|
if (formData.role === "EVENT_OWNER") {
|
||||||
getCompanies().then(res => {
|
getCompanies().then(res => {
|
||||||
if(res.data) setCompanies(res.data);
|
if(res.data) setCompanies(res.data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (formData.role === "PHOTOGRAPHER") {
|
||||||
|
getFunctions().then(res => {
|
||||||
|
if(res.data) setFunctions(res.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
}, [formData.role]);
|
}, [formData.role]);
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4 fade-in">
|
<div className="fixed inset-0 z-50 flex items-center justify-center bg-black bg-opacity-50 p-4 fade-in">
|
||||||
<div className="bg-white rounded-lg shadow-xl w-full max-w-md overflow-hidden animate-slide-up">
|
<div className="bg-white rounded-lg shadow-xl w-full max-w-md max-h-[95vh] overflow-y-auto animate-slide-up">
|
||||||
<div className="flex justify-between items-center p-6 border-b border-gray-100">
|
<div className="flex justify-between items-center p-6 border-b border-gray-100">
|
||||||
<h3 className="text-xl font-bold text-gray-900 font-serif">
|
<h3 className="text-xl font-bold text-gray-900 font-serif">
|
||||||
Novo Usuário
|
Novo Usuário
|
||||||
|
|
@ -259,7 +267,7 @@ const CreateUserModal: React.FC<CreateUserModalProps> = ({
|
||||||
onChange={(e) => setFormData({...formData, role: e.target.value})}
|
onChange={(e) => setFormData({...formData, role: e.target.value})}
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-photum-green focus:border-transparent outline-none transition-all"
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-photum-green focus:border-transparent outline-none transition-all"
|
||||||
>
|
>
|
||||||
<option value="PHOTOGRAPHER">Fotógrafo</option>
|
<option value="PHOTOGRAPHER">Profissional</option>
|
||||||
<option value="EVENT_OWNER">Cliente (Empresa)</option>
|
<option value="EVENT_OWNER">Cliente (Empresa)</option>
|
||||||
<option value="BUSINESS_OWNER">Dono de Negócio</option>
|
<option value="BUSINESS_OWNER">Dono de Negócio</option>
|
||||||
<option value="ADMIN">Administrador</option>
|
<option value="ADMIN">Administrador</option>
|
||||||
|
|
@ -451,9 +459,9 @@ const CreateUserModal: React.FC<CreateUserModalProps> = ({
|
||||||
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-photum-green focus:border-transparent outline-none transition-all"
|
className="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-photum-green focus:border-transparent outline-none transition-all"
|
||||||
>
|
>
|
||||||
<option value="">Selecione...</option>
|
<option value="">Selecione...</option>
|
||||||
<option value="Fotógrafo">Fotógrafo</option>
|
{functions.map(f => (
|
||||||
<option value="Cinegrafista">Cinegrafista</option>
|
<option key={f.id} value={f.nome}>{f.nome}</option>
|
||||||
<option value="Editor">Editor</option>
|
))}
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ export interface User {
|
||||||
companyName?: string; // Nome da empresa vinculada
|
companyName?: string; // Nome da empresa vinculada
|
||||||
allowedRegions?: string[]; // Regiões permitidas para o usuário
|
allowedRegions?: string[]; // Regiões permitidas para o usuário
|
||||||
professionalId?: string; // ID do profissional vinculado (se houver)
|
professionalId?: string; // ID do profissional vinculado (se houver)
|
||||||
|
functions?: { id: string; nome: string }[]; // Funções assumidas pelo profissional
|
||||||
|
|
||||||
// Client / Event Owner specific fields
|
// Client / Event Owner specific fields
|
||||||
cpf_cnpj?: string;
|
cpf_cnpj?: string;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue