feat: destaca eventos de pré-venda e adiciona filtros de status da turma
- Destaque em azul para pré-venda na grid. - Filtros por status (Pré-venda/Finalizada) no Dashboard. - Badges de status nos detalhes do evento. - Ajustes no backend para expor campo `pre_venda` da FOT.
This commit is contained in:
parent
b49b0f31a6
commit
9906db8bc6
7 changed files with 56 additions and 9 deletions
|
|
@ -78,6 +78,7 @@ type AgendaResponse struct {
|
||||||
ParsedAssignments []Assignment `json:"assignments"`
|
ParsedAssignments []Assignment `json:"assignments"`
|
||||||
ParsedContacts []ContactInfo `json:"contacts"`
|
ParsedContacts []ContactInfo `json:"contacts"`
|
||||||
ShadowFotFinalizada bool `json:"fot_finalizada"`
|
ShadowFotFinalizada bool `json:"fot_finalizada"`
|
||||||
|
ShadowFotPreVenda bool `json:"fot_pre_venda"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) CalculateStatus(fotoFaltante, recepFaltante, cineFaltante int32) string {
|
func (s *Service) CalculateStatus(fotoFaltante, recepFaltante, cineFaltante int32) string {
|
||||||
|
|
@ -205,6 +206,7 @@ func (s *Service) List(ctx context.Context, userID uuid.UUID, role string, regia
|
||||||
EmpresaNome: r.EmpresaNome,
|
EmpresaNome: r.EmpresaNome,
|
||||||
EmpresaID: r.EmpresaID,
|
EmpresaID: r.EmpresaID,
|
||||||
FotFinalizada: r.FotFinalizada,
|
FotFinalizada: r.FotFinalizada,
|
||||||
|
FotPreVenda: r.FotPreVenda,
|
||||||
AnoSemestre: r.AnoSemestre,
|
AnoSemestre: r.AnoSemestre,
|
||||||
ObservacoesFot: r.ObservacoesFot,
|
ObservacoesFot: r.ObservacoesFot,
|
||||||
TipoEventoNome: r.TipoEventoNome,
|
TipoEventoNome: r.TipoEventoNome,
|
||||||
|
|
@ -220,7 +222,7 @@ func (s *Service) List(ctx context.Context, userID uuid.UUID, role string, regia
|
||||||
// DEBUG: Check first few rows
|
// DEBUG: Check first few rows
|
||||||
for i, r := range rows {
|
for i, r := range rows {
|
||||||
if i < 5 {
|
if i < 5 {
|
||||||
fmt.Printf("DEBUG SERVICE ADMIN PATH: Row %d ID=%s FotFinalizada=%v\n", i, r.ID.Bytes, r.FotFinalizada.Bool)
|
fmt.Printf("DEBUG SERVICE ADMIN PATH: Row %d ID=%s FotFinalizada=%v FotPreVenda=%v\n", i, r.ID.Bytes, r.FotFinalizada.Bool, r.FotPreVenda.Bool)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -251,6 +253,7 @@ func (s *Service) List(ctx context.Context, userID uuid.UUID, role string, regia
|
||||||
ParsedAssignments: assignments,
|
ParsedAssignments: assignments,
|
||||||
ParsedContacts: contacts,
|
ParsedContacts: contacts,
|
||||||
ShadowFotFinalizada: row.FotFinalizada.Bool,
|
ShadowFotFinalizada: row.FotFinalizada.Bool,
|
||||||
|
ShadowFotPreVenda: row.FotPreVenda.Bool,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -439,6 +439,7 @@ SELECT
|
||||||
te.nome as tipo_evento_nome,
|
te.nome as tipo_evento_nome,
|
||||||
cf.empresa_id,
|
cf.empresa_id,
|
||||||
cf.finalizada as fot_finalizada,
|
cf.finalizada as fot_finalizada,
|
||||||
|
cf.pre_venda as fot_pre_venda,
|
||||||
COALESCE(
|
COALESCE(
|
||||||
(SELECT json_agg(json_build_object(
|
(SELECT json_agg(json_build_object(
|
||||||
'professional_id', ap.profissional_id,
|
'professional_id', ap.profissional_id,
|
||||||
|
|
@ -502,6 +503,7 @@ type ListAgendasRow struct {
|
||||||
TipoEventoNome string `json:"tipo_evento_nome"`
|
TipoEventoNome string `json:"tipo_evento_nome"`
|
||||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||||
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
||||||
|
FotPreVenda pgtype.Bool `json:"fot_pre_venda"`
|
||||||
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -555,6 +557,7 @@ func (q *Queries) ListAgendas(ctx context.Context, regiao pgtype.Text) ([]ListAg
|
||||||
&i.TipoEventoNome,
|
&i.TipoEventoNome,
|
||||||
&i.EmpresaID,
|
&i.EmpresaID,
|
||||||
&i.FotFinalizada,
|
&i.FotFinalizada,
|
||||||
|
&i.FotPreVenda,
|
||||||
&i.AssignedProfessionals,
|
&i.AssignedProfessionals,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -579,6 +582,7 @@ SELECT
|
||||||
te.nome as tipo_evento_nome,
|
te.nome as tipo_evento_nome,
|
||||||
cf.empresa_id,
|
cf.empresa_id,
|
||||||
cf.finalizada as fot_finalizada,
|
cf.finalizada as fot_finalizada,
|
||||||
|
cf.pre_venda as fot_pre_venda,
|
||||||
COALESCE(
|
COALESCE(
|
||||||
(SELECT json_agg(json_build_object(
|
(SELECT json_agg(json_build_object(
|
||||||
'professional_id', ap.profissional_id,
|
'professional_id', ap.profissional_id,
|
||||||
|
|
@ -647,6 +651,7 @@ type ListAgendasByCompanyRow struct {
|
||||||
TipoEventoNome string `json:"tipo_evento_nome"`
|
TipoEventoNome string `json:"tipo_evento_nome"`
|
||||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||||
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
||||||
|
FotPreVenda pgtype.Bool `json:"fot_pre_venda"`
|
||||||
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -700,6 +705,7 @@ func (q *Queries) ListAgendasByCompany(ctx context.Context, arg ListAgendasByCom
|
||||||
&i.TipoEventoNome,
|
&i.TipoEventoNome,
|
||||||
&i.EmpresaID,
|
&i.EmpresaID,
|
||||||
&i.FotFinalizada,
|
&i.FotFinalizada,
|
||||||
|
&i.FotPreVenda,
|
||||||
&i.AssignedProfessionals,
|
&i.AssignedProfessionals,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -827,6 +833,7 @@ SELECT
|
||||||
te.nome as tipo_evento_nome,
|
te.nome as tipo_evento_nome,
|
||||||
cf.empresa_id,
|
cf.empresa_id,
|
||||||
cf.finalizada as fot_finalizada,
|
cf.finalizada as fot_finalizada,
|
||||||
|
cf.pre_venda as fot_pre_venda,
|
||||||
COALESCE(
|
COALESCE(
|
||||||
(SELECT json_agg(json_build_object(
|
(SELECT json_agg(json_build_object(
|
||||||
'professional_id', ap.profissional_id,
|
'professional_id', ap.profissional_id,
|
||||||
|
|
@ -895,6 +902,7 @@ type ListAgendasByUserRow struct {
|
||||||
TipoEventoNome string `json:"tipo_evento_nome"`
|
TipoEventoNome string `json:"tipo_evento_nome"`
|
||||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||||
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
||||||
|
FotPreVenda pgtype.Bool `json:"fot_pre_venda"`
|
||||||
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -948,6 +956,7 @@ func (q *Queries) ListAgendasByUser(ctx context.Context, arg ListAgendasByUserPa
|
||||||
&i.TipoEventoNome,
|
&i.TipoEventoNome,
|
||||||
&i.EmpresaID,
|
&i.EmpresaID,
|
||||||
&i.FotFinalizada,
|
&i.FotFinalizada,
|
||||||
|
&i.FotPreVenda,
|
||||||
&i.AssignedProfessionals,
|
&i.AssignedProfessionals,
|
||||||
); err != nil {
|
); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ SELECT
|
||||||
te.nome as tipo_evento_nome,
|
te.nome as tipo_evento_nome,
|
||||||
cf.empresa_id,
|
cf.empresa_id,
|
||||||
cf.finalizada as fot_finalizada,
|
cf.finalizada as fot_finalizada,
|
||||||
|
cf.pre_venda as fot_pre_venda,
|
||||||
COALESCE(
|
COALESCE(
|
||||||
(SELECT json_agg(json_build_object(
|
(SELECT json_agg(json_build_object(
|
||||||
'professional_id', ap.profissional_id,
|
'professional_id', ap.profissional_id,
|
||||||
|
|
@ -79,6 +80,7 @@ SELECT
|
||||||
te.nome as tipo_evento_nome,
|
te.nome as tipo_evento_nome,
|
||||||
cf.empresa_id,
|
cf.empresa_id,
|
||||||
cf.finalizada as fot_finalizada,
|
cf.finalizada as fot_finalizada,
|
||||||
|
cf.pre_venda as fot_pre_venda,
|
||||||
COALESCE(
|
COALESCE(
|
||||||
(SELECT json_agg(json_build_object(
|
(SELECT json_agg(json_build_object(
|
||||||
'professional_id', ap.profissional_id,
|
'professional_id', ap.profissional_id,
|
||||||
|
|
@ -228,6 +230,7 @@ SELECT
|
||||||
te.nome as tipo_evento_nome,
|
te.nome as tipo_evento_nome,
|
||||||
cf.empresa_id,
|
cf.empresa_id,
|
||||||
cf.finalizada as fot_finalizada,
|
cf.finalizada as fot_finalizada,
|
||||||
|
cf.pre_venda as fot_pre_venda,
|
||||||
COALESCE(
|
COALESCE(
|
||||||
(SELECT json_agg(json_build_object(
|
(SELECT json_agg(json_build_object(
|
||||||
'professional_id', ap.profissional_id,
|
'professional_id', ap.profissional_id,
|
||||||
|
|
|
||||||
|
|
@ -541,7 +541,13 @@ export const EventTable: React.FC<EventTableProps> = ({
|
||||||
<tr
|
<tr
|
||||||
key={event.id}
|
key={event.id}
|
||||||
onClick={() => onEventClick(event)}
|
onClick={() => onEventClick(event)}
|
||||||
className={`cursor-pointer transition-colors ${event.fot_finalizada ? "bg-red-50 hover:bg-red-100 border-l-4 border-l-red-500" : "hover:bg-gray-50"}`}
|
className={`cursor-pointer transition-colors border-l-4 ${
|
||||||
|
event.fot_finalizada
|
||||||
|
? "bg-red-50 hover:bg-red-100 border-l-red-500"
|
||||||
|
: ((event.fot_pre_venda || event.pre_venda) && (userRole === UserRole.SUPERADMIN || userRole === UserRole.BUSINESS_OWNER || userRole === UserRole.RESEARCHER))
|
||||||
|
? "bg-blue-50 hover:bg-blue-100 border-l-blue-500"
|
||||||
|
: "border-l-transparent hover:bg-gray-50"
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<td className="px-4 py-3">
|
<td className="px-4 py-3">
|
||||||
<span className="text-sm font-medium text-gray-900">
|
<span className="text-sm font-medium text-gray-900">
|
||||||
|
|
|
||||||
|
|
@ -724,7 +724,9 @@ export const DataProvider: React.FC<{ children: ReactNode }> = ({
|
||||||
typeId: e.tipo_evento_id,
|
typeId: e.tipo_evento_id,
|
||||||
local_evento: e.local_evento, // Added local_evento mapping
|
local_evento: e.local_evento, // Added local_evento mapping
|
||||||
fot_finalizada: e.fot_finalizada, // Mapped from backend
|
fot_finalizada: e.fot_finalizada, // Mapped from backend
|
||||||
assignments: Array.isArray(e.assigned_professionals)
|
fot_pre_venda: e.fot_pre_venda, // Mapped from backend
|
||||||
|
pre_venda: e.fot_pre_venda, // Fallback/Alias
|
||||||
|
assignments: Array.isArray(e.assigned_professionals)
|
||||||
? e.assigned_professionals.map((a: any) => ({
|
? e.assigned_professionals.map((a: any) => ({
|
||||||
professionalId: a.professional_id,
|
professionalId: a.professional_id,
|
||||||
status: a.status,
|
status: a.status,
|
||||||
|
|
|
||||||
|
|
@ -438,9 +438,16 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
||||||
!advancedFilters.company || e.empresa === advancedFilters.company;
|
!advancedFilters.company || e.empresa === advancedFilters.company;
|
||||||
const matchesInstitution =
|
const matchesInstitution =
|
||||||
!advancedFilters.institution || e.instituicao === advancedFilters.institution;
|
!advancedFilters.institution || e.instituicao === advancedFilters.institution;
|
||||||
|
|
||||||
|
// New FOT Status Filter
|
||||||
|
const matchesFotStatus =
|
||||||
|
!advancedFilters.fotStatus ||
|
||||||
|
(advancedFilters.fotStatus === 'finalizada' && e.fot_finalizada) ||
|
||||||
|
(advancedFilters.fotStatus === 'pre_venda' && (e.fot_pre_venda || e.pre_venda)) ||
|
||||||
|
(advancedFilters.fotStatus === 'normal' && !e.fot_finalizada && !e.fot_pre_venda && !e.pre_venda);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
matchesSearch && matchesStatus && matchesDate && matchesFot && matchesType && matchesCompany && matchesInstitution
|
matchesSearch && matchesStatus && matchesDate && matchesFot && matchesType && matchesCompany && matchesInstitution && matchesFotStatus
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -883,11 +890,26 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className="flex items-center gap-2">
|
||||||
className={`px-4 py-2 rounded text-sm font-semibold ${STATUS_COLORS[selectedEvent.status]
|
{/* Badge de Finalizada */}
|
||||||
}`}
|
{(selectedEvent.fot_finalizada) && (
|
||||||
>
|
<div className="px-4 py-2 rounded text-sm font-semibold bg-red-100 text-red-800 border border-red-200">
|
||||||
{selectedEvent.status}
|
Turma Finalizada
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{/* Badge de Pré-Venda */}
|
||||||
|
{((selectedEvent.fot_pre_venda || selectedEvent.pre_venda) && !selectedEvent.fot_finalizada) && (
|
||||||
|
<div className="px-4 py-2 rounded text-sm font-semibold bg-blue-100 text-blue-800 border border-blue-200">
|
||||||
|
Pré-Venda
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`px-4 py-2 rounded text-sm font-semibold ${STATUS_COLORS[selectedEvent.status]
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{selectedEvent.status}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,8 @@ export interface EventData {
|
||||||
courseId?: string; // ID do curso/turma relacionado ao evento
|
courseId?: string; // ID do curso/turma relacionado ao evento
|
||||||
fotId?: string; // ID da Turma (FOT)
|
fotId?: string; // ID da Turma (FOT)
|
||||||
fot_finalizada?: boolean; // Status da Turma (Visualizacao no Dashboard)
|
fot_finalizada?: boolean; // Status da Turma (Visualizacao no Dashboard)
|
||||||
|
fot_pre_venda?: boolean; // Status de Pré-Venda (vindo do FOT)
|
||||||
|
pre_venda?: boolean; // Status de Pré-Venda
|
||||||
typeId?: string; // ID do Tipo de Evento (UUID)
|
typeId?: string; // ID do Tipo de Evento (UUID)
|
||||||
|
|
||||||
// Campos de gestão de equipe e recursos
|
// Campos de gestão de equipe e recursos
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue