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"`
|
||||
ParsedContacts []ContactInfo `json:"contacts"`
|
||||
ShadowFotFinalizada bool `json:"fot_finalizada"`
|
||||
ShadowFotPreVenda bool `json:"fot_pre_venda"`
|
||||
}
|
||||
|
||||
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,
|
||||
EmpresaID: r.EmpresaID,
|
||||
FotFinalizada: r.FotFinalizada,
|
||||
FotPreVenda: r.FotPreVenda,
|
||||
AnoSemestre: r.AnoSemestre,
|
||||
ObservacoesFot: r.ObservacoesFot,
|
||||
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
|
||||
for i, r := range rows {
|
||||
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,
|
||||
ParsedContacts: contacts,
|
||||
ShadowFotFinalizada: row.FotFinalizada.Bool,
|
||||
ShadowFotPreVenda: row.FotPreVenda.Bool,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -439,6 +439,7 @@ SELECT
|
|||
te.nome as tipo_evento_nome,
|
||||
cf.empresa_id,
|
||||
cf.finalizada as fot_finalizada,
|
||||
cf.pre_venda as fot_pre_venda,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'professional_id', ap.profissional_id,
|
||||
|
|
@ -502,6 +503,7 @@ type ListAgendasRow struct {
|
|||
TipoEventoNome string `json:"tipo_evento_nome"`
|
||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
||||
FotPreVenda pgtype.Bool `json:"fot_pre_venda"`
|
||||
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
||||
}
|
||||
|
||||
|
|
@ -555,6 +557,7 @@ func (q *Queries) ListAgendas(ctx context.Context, regiao pgtype.Text) ([]ListAg
|
|||
&i.TipoEventoNome,
|
||||
&i.EmpresaID,
|
||||
&i.FotFinalizada,
|
||||
&i.FotPreVenda,
|
||||
&i.AssignedProfessionals,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -579,6 +582,7 @@ SELECT
|
|||
te.nome as tipo_evento_nome,
|
||||
cf.empresa_id,
|
||||
cf.finalizada as fot_finalizada,
|
||||
cf.pre_venda as fot_pre_venda,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'professional_id', ap.profissional_id,
|
||||
|
|
@ -647,6 +651,7 @@ type ListAgendasByCompanyRow struct {
|
|||
TipoEventoNome string `json:"tipo_evento_nome"`
|
||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
||||
FotPreVenda pgtype.Bool `json:"fot_pre_venda"`
|
||||
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
||||
}
|
||||
|
||||
|
|
@ -700,6 +705,7 @@ func (q *Queries) ListAgendasByCompany(ctx context.Context, arg ListAgendasByCom
|
|||
&i.TipoEventoNome,
|
||||
&i.EmpresaID,
|
||||
&i.FotFinalizada,
|
||||
&i.FotPreVenda,
|
||||
&i.AssignedProfessionals,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
|
@ -827,6 +833,7 @@ SELECT
|
|||
te.nome as tipo_evento_nome,
|
||||
cf.empresa_id,
|
||||
cf.finalizada as fot_finalizada,
|
||||
cf.pre_venda as fot_pre_venda,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'professional_id', ap.profissional_id,
|
||||
|
|
@ -895,6 +902,7 @@ type ListAgendasByUserRow struct {
|
|||
TipoEventoNome string `json:"tipo_evento_nome"`
|
||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||
FotFinalizada pgtype.Bool `json:"fot_finalizada"`
|
||||
FotPreVenda pgtype.Bool `json:"fot_pre_venda"`
|
||||
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
||||
}
|
||||
|
||||
|
|
@ -948,6 +956,7 @@ func (q *Queries) ListAgendasByUser(ctx context.Context, arg ListAgendasByUserPa
|
|||
&i.TipoEventoNome,
|
||||
&i.EmpresaID,
|
||||
&i.FotFinalizada,
|
||||
&i.FotPreVenda,
|
||||
&i.AssignedProfessionals,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ SELECT
|
|||
te.nome as tipo_evento_nome,
|
||||
cf.empresa_id,
|
||||
cf.finalizada as fot_finalizada,
|
||||
cf.pre_venda as fot_pre_venda,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'professional_id', ap.profissional_id,
|
||||
|
|
@ -79,6 +80,7 @@ SELECT
|
|||
te.nome as tipo_evento_nome,
|
||||
cf.empresa_id,
|
||||
cf.finalizada as fot_finalizada,
|
||||
cf.pre_venda as fot_pre_venda,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'professional_id', ap.profissional_id,
|
||||
|
|
@ -228,6 +230,7 @@ SELECT
|
|||
te.nome as tipo_evento_nome,
|
||||
cf.empresa_id,
|
||||
cf.finalizada as fot_finalizada,
|
||||
cf.pre_venda as fot_pre_venda,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'professional_id', ap.profissional_id,
|
||||
|
|
|
|||
|
|
@ -541,7 +541,13 @@ export const EventTable: React.FC<EventTableProps> = ({
|
|||
<tr
|
||||
key={event.id}
|
||||
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">
|
||||
<span className="text-sm font-medium text-gray-900">
|
||||
|
|
|
|||
|
|
@ -724,6 +724,8 @@ export const DataProvider: React.FC<{ children: ReactNode }> = ({
|
|||
typeId: e.tipo_evento_id,
|
||||
local_evento: e.local_evento, // Added local_evento mapping
|
||||
fot_finalizada: e.fot_finalizada, // Mapped from backend
|
||||
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) => ({
|
||||
professionalId: a.professional_id,
|
||||
|
|
|
|||
|
|
@ -439,8 +439,15 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
|||
const matchesInstitution =
|
||||
!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 (
|
||||
matchesSearch && matchesStatus && matchesDate && matchesFot && matchesType && matchesCompany && matchesInstitution
|
||||
matchesSearch && matchesStatus && matchesDate && matchesFot && matchesType && matchesCompany && matchesInstitution && matchesFotStatus
|
||||
);
|
||||
});
|
||||
|
||||
|
|
@ -883,6 +890,20 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
|||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{/* 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">
|
||||
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]
|
||||
}`}
|
||||
|
|
@ -891,6 +912,7 @@ export const Dashboard: React.FC<DashboardProps> = ({
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="p-6">
|
||||
<div className="flex flex-wrap gap-2 mb-6 pb-4 border-b">
|
||||
|
|
|
|||
|
|
@ -151,6 +151,8 @@ export interface EventData {
|
|||
courseId?: string; // ID do curso/turma relacionado ao evento
|
||||
fotId?: string; // ID da Turma (FOT)
|
||||
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)
|
||||
|
||||
// Campos de gestão de equipe e recursos
|
||||
|
|
|
|||
Loading…
Reference in a new issue