feat(event-form): habilita seleção de empresa para business owners
- Atualiza o EventForm para buscar a lista de empresas via /api/empresas para usuários BUSINESS_OWNER e SUPERADMIN. - Adiciona campo de seleção de 'Empresa' antes do carregamento das FOTs (Turmas). - Implementa lógica em cascata: Seleção de Empresa -> Carrega Turmas -> Filtra Cursos -> Filtra Instituições. - Adiciona mensagem de aviso quando a empresa selecionada não possui turmas cadastradas. - Refatora o gerenciamento de estado para utilizar o ID da empresa ao invés do nome, garantindo maior integridade.
This commit is contained in:
parent
8515796ae9
commit
0e3e74eb59
1 changed files with 108 additions and 46 deletions
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import React, { useState, useEffect, useMemo } from "react";
|
||||
import { EventType, EventStatus, Address } from "../types";
|
||||
import { Input, Select } from "./Input";
|
||||
import { Button } from "./Button";
|
||||
|
|
@ -26,7 +26,7 @@ import { useData } from "../contexts/DataContext";
|
|||
import { UserRole } from "../types";
|
||||
import { InstitutionForm } from "./InstitutionForm";
|
||||
import { MapboxMap } from "./MapboxMap";
|
||||
import { getEventTypes, EventTypeResponse, getCadastroFot, createAgenda } from "../services/apiService";
|
||||
import { getEventTypes, EventTypeResponse, getCadastroFot, createAgenda, getCompanies } from "../services/apiService";
|
||||
|
||||
interface EventFormProps {
|
||||
onCancel: () => void;
|
||||
|
|
@ -121,48 +121,30 @@ export const EventForm: React.FC<EventFormProps> = ({
|
|||
fetchEventTypes();
|
||||
}, []);
|
||||
|
||||
// Fetch FOTs filtered by user company
|
||||
const [availableFots, setAvailableFots] = useState<any[]>([]);
|
||||
const [loadingFots, setLoadingFots] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const loadFots = async () => {
|
||||
// Allow FOT loading for Business Owners, Event Owners (Clients), and Superadmins
|
||||
if (user?.role === UserRole.BUSINESS_OWNER || user?.role === UserRole.EVENT_OWNER || user?.role === UserRole.SUPERADMIN) {
|
||||
// If user is not superadmin (admin generally has no empresaId but sees all or selects one, here we assume superadmin logic is separate or allowed)
|
||||
// Check if regular user has empresaId
|
||||
if (user?.role !== UserRole.SUPERADMIN && !user?.empresaId) {
|
||||
// If no company linked, do not load FOTs
|
||||
return;
|
||||
}
|
||||
|
||||
setLoadingFots(true);
|
||||
const token = localStorage.getItem("token") || "";
|
||||
// Use empresaId from user context if available
|
||||
const empresaId = user.empresaId;
|
||||
const response = await getCadastroFot(token, empresaId);
|
||||
|
||||
if (response.data) {
|
||||
// If we didn't filter by API (e.g. no empresaId), filter client side as fallback
|
||||
const myFots = (empresaId || user.companyName)
|
||||
? response.data.filter(f =>
|
||||
(empresaId && f.empresa_id === empresaId) ||
|
||||
(user.companyName && f.empresa_nome === user.companyName)
|
||||
)
|
||||
: response.data;
|
||||
|
||||
setAvailableFots(myFots);
|
||||
}
|
||||
setLoadingFots(false);
|
||||
}
|
||||
};
|
||||
loadFots();
|
||||
}, [user]);
|
||||
|
||||
// Derived state for dropdowns
|
||||
const [companies, setCompanies] = useState<any[]>([]); // New state for companies list
|
||||
const [selectedCompanyId, setSelectedCompanyId] = useState(""); // Changed from Name to ID
|
||||
|
||||
const [selectedCourseName, setSelectedCourseName] = useState("");
|
||||
const [selectedInstitutionName, setSelectedInstitutionName] = useState("");
|
||||
|
||||
// Load Companies for Business Owner / Superadmin
|
||||
useEffect(() => {
|
||||
if (user?.role === UserRole.BUSINESS_OWNER || user?.role === UserRole.SUPERADMIN) {
|
||||
const fetchCompanies = async () => {
|
||||
try {
|
||||
const response = await getCompanies();
|
||||
if (response.data) {
|
||||
setCompanies(response.data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to load companies", error);
|
||||
}
|
||||
};
|
||||
fetchCompanies();
|
||||
}
|
||||
}, [user]);
|
||||
|
||||
// Populate form with initialData
|
||||
useEffect(() => {
|
||||
if (initialData) {
|
||||
|
|
@ -171,11 +153,17 @@ export const EventForm: React.FC<EventFormProps> = ({
|
|||
...prev,
|
||||
...initialData,
|
||||
startTime: initialData.time || "00:00",
|
||||
locationName: (initialData as any).local_evento || (initialData as any).address?.mapLink?.includes('http') ? "" : (initialData as any).address?.mapLink || "", // Try to recover location name or clear if it's a link
|
||||
locationName: (initialData as any).local_evento || (initialData as any).address?.mapLink?.includes('http') ? "" : (initialData as any).address?.mapLink || "",
|
||||
fotId: initialData.fotId || "",
|
||||
}));
|
||||
|
||||
// 2. Populate derived dropdowns if data exists
|
||||
// Check for empresa_id or empresaId in initialData
|
||||
const initEmpresaId = (initialData as any).empresa_id || (initialData as any).empresaId;
|
||||
if (initEmpresaId && (user?.role === UserRole.BUSINESS_OWNER || user?.role === UserRole.SUPERADMIN)) {
|
||||
setSelectedCompanyId(initEmpresaId);
|
||||
}
|
||||
|
||||
if (initialData.curso) {
|
||||
setSelectedCourseName(initialData.curso);
|
||||
}
|
||||
|
|
@ -195,9 +183,47 @@ export const EventForm: React.FC<EventFormProps> = ({
|
|||
}));
|
||||
}
|
||||
}
|
||||
}, [initialData]);
|
||||
}, [initialData, user?.role]);
|
||||
|
||||
// Unique Courses
|
||||
// Fetch FOTs filtered by user company OR selected company
|
||||
const [availableFots, setAvailableFots] = useState<any[]>([]);
|
||||
const [loadingFots, setLoadingFots] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const loadFots = async () => {
|
||||
// Determine which company ID to use
|
||||
let targetEmpresaId = user?.empresaId;
|
||||
|
||||
if (user?.role === UserRole.BUSINESS_OWNER || user?.role === UserRole.SUPERADMIN) {
|
||||
// Must select a company first
|
||||
if (!selectedCompanyId) {
|
||||
setAvailableFots([]);
|
||||
return;
|
||||
}
|
||||
targetEmpresaId = selectedCompanyId;
|
||||
}
|
||||
|
||||
// If we have a target company (or user is linked), fetch FOTs
|
||||
if (targetEmpresaId || user?.role === UserRole.EVENT_OWNER) { // EventOwner might be linked differently or via getCadastroFot logic
|
||||
// Verify logic: EventOwner (client) usually has strict link.
|
||||
// If targetEmpresaId is still empty and user is NOT BusinessOwner/Superadmin, we might skip or let backend decide (if user has implicit link).
|
||||
// But let's assume valid flow.
|
||||
|
||||
setLoadingFots(true);
|
||||
const token = localStorage.getItem("token") || "";
|
||||
const response = await getCadastroFot(token, targetEmpresaId);
|
||||
|
||||
if (response.data) {
|
||||
setAvailableFots(response.data);
|
||||
}
|
||||
setLoadingFots(false);
|
||||
}
|
||||
};
|
||||
loadFots();
|
||||
}, [user, selectedCompanyId]);
|
||||
|
||||
|
||||
// Unique Courses (from availableFots - which are already specific to the company)
|
||||
const uniqueCourses = Array.from(new Set(availableFots.map(f => f.curso_nome))).sort();
|
||||
|
||||
// Filtered Institutions based on Course
|
||||
|
|
@ -611,7 +637,7 @@ export const EventForm: React.FC<EventFormProps> = ({
|
|||
<div className="bg-gray-50 p-4 rounded-md border border-gray-200">
|
||||
<h3 className="text-sm font-medium text-gray-700 mb-4 uppercase tracking-wider">Seleção da Turma</h3>
|
||||
|
||||
{!user?.empresaId && user?.role !== UserRole.SUPERADMIN ? (
|
||||
{!user?.empresaId && user?.role !== UserRole.SUPERADMIN && user?.role !== UserRole.BUSINESS_OWNER ? (
|
||||
<div className="bg-red-50 border-l-4 border-red-400 p-4 mb-4">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
|
|
@ -626,6 +652,42 @@ export const EventForm: React.FC<EventFormProps> = ({
|
|||
</div>
|
||||
) : (
|
||||
<>
|
||||
{/* 0. Empresa (Only for Business Owner / Superadmin) */}
|
||||
{(user?.role === UserRole.BUSINESS_OWNER || user?.role === UserRole.SUPERADMIN) && (
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm text-gray-600 mb-1">Empresa</label>
|
||||
<select
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded focus:ring-brand-gold focus:border-brand-gold"
|
||||
value={selectedCompanyId}
|
||||
onChange={e => {
|
||||
setSelectedCompanyId(e.target.value);
|
||||
setSelectedCourseName("");
|
||||
setSelectedInstitutionName("");
|
||||
setFormData({ ...formData, fotId: "" });
|
||||
}}
|
||||
>
|
||||
<option value="">Selecione a Empresa</option>
|
||||
{companies.map(c => <option key={c.id} value={c.id}>{c.nome}</option>)}
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Warning if Company Selected but No FOTs */}
|
||||
{selectedCompanyId && !loadingFots && availableFots.length === 0 && (user?.role === UserRole.BUSINESS_OWNER || user?.role === UserRole.SUPERADMIN) && (
|
||||
<div className="bg-yellow-50 border-l-4 border-yellow-400 p-4 mb-4">
|
||||
<div className="flex">
|
||||
<div className="flex-shrink-0">
|
||||
<AlertTriangle className="h-5 w-5 text-yellow-400" aria-hidden="true" />
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<p className="text-sm text-yellow-700">
|
||||
Esta empresa selecionada ainda não possui turmas, cursos ou FOTs cadastrados.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 1. Curso */}
|
||||
<div className="mb-4">
|
||||
<label className="block text-sm text-gray-600 mb-1">Curso</label>
|
||||
|
|
@ -637,7 +699,7 @@ export const EventForm: React.FC<EventFormProps> = ({
|
|||
setSelectedInstitutionName("");
|
||||
setFormData({ ...formData, fotId: "" });
|
||||
}}
|
||||
disabled={loadingFots}
|
||||
disabled={loadingFots || ((user?.role === UserRole.BUSINESS_OWNER || user?.role === UserRole.SUPERADMIN) && !selectedCompanyId)}
|
||||
>
|
||||
<option value="">Selecione o Curso</option>
|
||||
{uniqueCourses.map(c => <option key={c} value={c}>{c}</option>)}
|
||||
|
|
@ -685,7 +747,7 @@ export const EventForm: React.FC<EventFormProps> = ({
|
|||
<Button
|
||||
onClick={() => setActiveTab("location")}
|
||||
className="w-full sm:w-auto"
|
||||
disabled={(!user?.empresaId && user?.role !== UserRole.SUPERADMIN)}
|
||||
disabled={(!user?.empresaId && user?.role !== UserRole.SUPERADMIN && user?.role !== UserRole.BUSINESS_OWNER)}
|
||||
>
|
||||
Próximo: Localização
|
||||
</Button>
|
||||
|
|
|
|||
Loading…
Reference in a new issue