Fix: Visibilidade da agenda para clientes e correções no filtro de códigos de acesso
- Backend: Implementada query `ListAgendasByCompany` e ajustada lógica do serviço de agenda para filtrar eventos pela empresa do usuário. - Backend: Adicionada migração segura (idempotente) para incluir coluna `empresa_id` em produção. - Frontend: Corrigido filtro [getEventsByRole] para exibir eventos importados (da empresa) para o cliente. - Frontend: Renomeada aba de aprovação para 'Cadastros Clientes'.
This commit is contained in:
parent
a35c8c27fa
commit
ec2d96333f
5 changed files with 184 additions and 6 deletions
|
|
@ -122,13 +122,24 @@ func (s *Service) List(ctx context.Context, userID uuid.UUID, role string) ([]Ag
|
|||
var rows []generated.ListAgendasRow
|
||||
var err error
|
||||
|
||||
// If role is CLIENT (cliente), filter by userID
|
||||
// If role is CLIENT (cliente) or EVENT_OWNER
|
||||
if role == "cliente" || role == "EVENT_OWNER" {
|
||||
listRows, err := s.queries.ListAgendasByUser(ctx, pgtype.UUID{Bytes: userID, Valid: true})
|
||||
// New Logic: Fetch User's Company
|
||||
user, err := s.queries.GetUsuarioByID(ctx, pgtype.UUID{Bytes: userID, Valid: true})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("erro ao buscar usuário para filtro de empresa: %v", err)
|
||||
}
|
||||
|
||||
if !user.EmpresaID.Valid {
|
||||
// If no company linked, return empty or error? Empty seems safer.
|
||||
return []AgendaResponse{}, nil
|
||||
}
|
||||
|
||||
listRows, err := s.queries.ListAgendasByCompany(ctx, user.EmpresaID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Convert ListAgendasByUserRow to ListAgendasRow manually
|
||||
// Convert ListAgendasByCompanyRow to ListAgendasRow manually
|
||||
for _, r := range listRows {
|
||||
rows = append(rows, generated.ListAgendasRow{
|
||||
ID: r.ID,
|
||||
|
|
|
|||
|
|
@ -518,6 +518,138 @@ func (q *Queries) ListAgendas(ctx context.Context) ([]ListAgendasRow, error) {
|
|||
return items, nil
|
||||
}
|
||||
|
||||
const listAgendasByCompany = `-- name: ListAgendasByCompany :many
|
||||
SELECT
|
||||
a.id, a.user_id, a.fot_id, a.data_evento, a.tipo_evento_id, a.observacoes_evento, a.local_evento, a.endereco, a.horario, a.qtd_formandos, a.qtd_fotografos, a.qtd_recepcionistas, a.qtd_cinegrafistas, a.qtd_estudios, a.qtd_ponto_foto, a.qtd_ponto_id, a.qtd_ponto_decorado, a.qtd_pontos_led, a.qtd_plataforma_360, a.status_profissionais, a.foto_faltante, a.recep_faltante, a.cine_faltante, a.logistica_observacoes, a.pre_venda, a.criado_em, a.atualizado_em, a.status, a.logistica_notificacao_enviada_em,
|
||||
cf.fot as fot_numero,
|
||||
cf.instituicao,
|
||||
c.nome as curso_nome,
|
||||
e.nome as empresa_nome,
|
||||
af.ano_semestre,
|
||||
cf.observacoes as observacoes_fot,
|
||||
te.nome as tipo_evento_nome,
|
||||
cf.empresa_id,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'professional_id', ap.profissional_id,
|
||||
'status', ap.status,
|
||||
'motivo_rejeicao', ap.motivo_rejeicao,
|
||||
'funcao_id', ap.funcao_id
|
||||
))
|
||||
FROM agenda_profissionais ap
|
||||
WHERE ap.agenda_id = a.id),
|
||||
'[]'::json
|
||||
) as assigned_professionals
|
||||
FROM agenda a
|
||||
JOIN cadastro_fot cf ON a.fot_id = cf.id
|
||||
JOIN cursos c ON cf.curso_id = c.id
|
||||
JOIN empresas e ON cf.empresa_id = e.id
|
||||
JOIN anos_formaturas af ON cf.ano_formatura_id = af.id
|
||||
JOIN tipos_eventos te ON a.tipo_evento_id = te.id
|
||||
WHERE cf.empresa_id = $1
|
||||
ORDER BY a.data_evento
|
||||
`
|
||||
|
||||
type ListAgendasByCompanyRow struct {
|
||||
ID pgtype.UUID `json:"id"`
|
||||
UserID pgtype.UUID `json:"user_id"`
|
||||
FotID pgtype.UUID `json:"fot_id"`
|
||||
DataEvento pgtype.Date `json:"data_evento"`
|
||||
TipoEventoID pgtype.UUID `json:"tipo_evento_id"`
|
||||
ObservacoesEvento pgtype.Text `json:"observacoes_evento"`
|
||||
LocalEvento pgtype.Text `json:"local_evento"`
|
||||
Endereco pgtype.Text `json:"endereco"`
|
||||
Horario pgtype.Text `json:"horario"`
|
||||
QtdFormandos pgtype.Int4 `json:"qtd_formandos"`
|
||||
QtdFotografos pgtype.Int4 `json:"qtd_fotografos"`
|
||||
QtdRecepcionistas pgtype.Int4 `json:"qtd_recepcionistas"`
|
||||
QtdCinegrafistas pgtype.Int4 `json:"qtd_cinegrafistas"`
|
||||
QtdEstudios pgtype.Int4 `json:"qtd_estudios"`
|
||||
QtdPontoFoto pgtype.Int4 `json:"qtd_ponto_foto"`
|
||||
QtdPontoID pgtype.Int4 `json:"qtd_ponto_id"`
|
||||
QtdPontoDecorado pgtype.Int4 `json:"qtd_ponto_decorado"`
|
||||
QtdPontosLed pgtype.Int4 `json:"qtd_pontos_led"`
|
||||
QtdPlataforma360 pgtype.Int4 `json:"qtd_plataforma_360"`
|
||||
StatusProfissionais pgtype.Text `json:"status_profissionais"`
|
||||
FotoFaltante pgtype.Int4 `json:"foto_faltante"`
|
||||
RecepFaltante pgtype.Int4 `json:"recep_faltante"`
|
||||
CineFaltante pgtype.Int4 `json:"cine_faltante"`
|
||||
LogisticaObservacoes pgtype.Text `json:"logistica_observacoes"`
|
||||
PreVenda pgtype.Bool `json:"pre_venda"`
|
||||
CriadoEm pgtype.Timestamptz `json:"criado_em"`
|
||||
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
|
||||
Status pgtype.Text `json:"status"`
|
||||
LogisticaNotificacaoEnviadaEm pgtype.Timestamp `json:"logistica_notificacao_enviada_em"`
|
||||
FotNumero string `json:"fot_numero"`
|
||||
Instituicao pgtype.Text `json:"instituicao"`
|
||||
CursoNome string `json:"curso_nome"`
|
||||
EmpresaNome string `json:"empresa_nome"`
|
||||
AnoSemestre string `json:"ano_semestre"`
|
||||
ObservacoesFot pgtype.Text `json:"observacoes_fot"`
|
||||
TipoEventoNome string `json:"tipo_evento_nome"`
|
||||
EmpresaID pgtype.UUID `json:"empresa_id"`
|
||||
AssignedProfessionals interface{} `json:"assigned_professionals"`
|
||||
}
|
||||
|
||||
func (q *Queries) ListAgendasByCompany(ctx context.Context, empresaID pgtype.UUID) ([]ListAgendasByCompanyRow, error) {
|
||||
rows, err := q.db.Query(ctx, listAgendasByCompany, empresaID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []ListAgendasByCompanyRow
|
||||
for rows.Next() {
|
||||
var i ListAgendasByCompanyRow
|
||||
if err := rows.Scan(
|
||||
&i.ID,
|
||||
&i.UserID,
|
||||
&i.FotID,
|
||||
&i.DataEvento,
|
||||
&i.TipoEventoID,
|
||||
&i.ObservacoesEvento,
|
||||
&i.LocalEvento,
|
||||
&i.Endereco,
|
||||
&i.Horario,
|
||||
&i.QtdFormandos,
|
||||
&i.QtdFotografos,
|
||||
&i.QtdRecepcionistas,
|
||||
&i.QtdCinegrafistas,
|
||||
&i.QtdEstudios,
|
||||
&i.QtdPontoFoto,
|
||||
&i.QtdPontoID,
|
||||
&i.QtdPontoDecorado,
|
||||
&i.QtdPontosLed,
|
||||
&i.QtdPlataforma360,
|
||||
&i.StatusProfissionais,
|
||||
&i.FotoFaltante,
|
||||
&i.RecepFaltante,
|
||||
&i.CineFaltante,
|
||||
&i.LogisticaObservacoes,
|
||||
&i.PreVenda,
|
||||
&i.CriadoEm,
|
||||
&i.AtualizadoEm,
|
||||
&i.Status,
|
||||
&i.LogisticaNotificacaoEnviadaEm,
|
||||
&i.FotNumero,
|
||||
&i.Instituicao,
|
||||
&i.CursoNome,
|
||||
&i.EmpresaNome,
|
||||
&i.AnoSemestre,
|
||||
&i.ObservacoesFot,
|
||||
&i.TipoEventoNome,
|
||||
&i.EmpresaID,
|
||||
&i.AssignedProfessionals,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, i)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const listAgendasByFot = `-- name: ListAgendasByFot :many
|
||||
SELECT
|
||||
a.id, a.user_id, a.fot_id, a.data_evento, a.tipo_evento_id, a.observacoes_evento, a.local_evento, a.endereco, a.horario, a.qtd_formandos, a.qtd_fotografos, a.qtd_recepcionistas, a.qtd_cinegrafistas, a.qtd_estudios, a.qtd_ponto_foto, a.qtd_ponto_id, a.qtd_ponto_decorado, a.qtd_pontos_led, a.qtd_plataforma_360, a.status_profissionais, a.foto_faltante, a.recep_faltante, a.cine_faltante, a.logistica_observacoes, a.pre_venda, a.criado_em, a.atualizado_em, a.status, a.logistica_notificacao_enviada_em,
|
||||
|
|
|
|||
|
|
@ -205,4 +205,35 @@ ORDER BY a.data_evento;
|
|||
-- name: GetAgendaByFotDataTipo :one
|
||||
SELECT * FROM agenda
|
||||
WHERE fot_id = $1 AND data_evento = $2 AND tipo_evento_id = $3
|
||||
LIMIT 1;
|
||||
LIMIT 1;
|
||||
|
||||
-- name: ListAgendasByCompany :many
|
||||
SELECT
|
||||
a.*,
|
||||
cf.fot as fot_numero,
|
||||
cf.instituicao,
|
||||
c.nome as curso_nome,
|
||||
e.nome as empresa_nome,
|
||||
af.ano_semestre,
|
||||
cf.observacoes as observacoes_fot,
|
||||
te.nome as tipo_evento_nome,
|
||||
cf.empresa_id,
|
||||
COALESCE(
|
||||
(SELECT json_agg(json_build_object(
|
||||
'professional_id', ap.profissional_id,
|
||||
'status', ap.status,
|
||||
'motivo_rejeicao', ap.motivo_rejeicao,
|
||||
'funcao_id', ap.funcao_id
|
||||
))
|
||||
FROM agenda_profissionais ap
|
||||
WHERE ap.agenda_id = a.id),
|
||||
'[]'::json
|
||||
) as assigned_professionals
|
||||
FROM agenda a
|
||||
JOIN cadastro_fot cf ON a.fot_id = cf.id
|
||||
JOIN cursos c ON cf.curso_id = c.id
|
||||
JOIN empresas e ON cf.empresa_id = e.id
|
||||
JOIN anos_formaturas af ON cf.ano_formatura_id = af.id
|
||||
JOIN tipos_eventos te ON a.tipo_evento_id = te.id
|
||||
WHERE cf.empresa_id = $1
|
||||
ORDER BY a.data_evento;
|
||||
|
|
@ -976,6 +976,10 @@ export const DataProvider: React.FC<{ children: ReactNode }> = ({
|
|||
return events;
|
||||
}
|
||||
if (role === "EVENT_OWNER") {
|
||||
// Check if logged user has company linked and matches requested user
|
||||
if (user && user.id === userId && user.empresaId) {
|
||||
return events.filter(e => e.empresaId === user.empresaId);
|
||||
}
|
||||
return events.filter((e) => e.ownerId === userId);
|
||||
}
|
||||
if (role === "PHOTOGRAPHER") {
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ export const UserApproval: React.FC<UserApprovalProps> = ({ onNavigate }) => {
|
|||
}`}
|
||||
>
|
||||
<Users className="w-5 h-5" />
|
||||
Cadastros Empresas
|
||||
Cadastros Clientes
|
||||
<span
|
||||
className={`ml-2 py-0.5 px-2.5 rounded-full text-xs ${activeTab === "cliente"
|
||||
? "bg-[#B9CF33] text-white"
|
||||
|
|
@ -271,7 +271,7 @@ export const UserApproval: React.FC<UserApprovalProps> = ({ onNavigate }) => {
|
|||
)}
|
||||
<p className="text-lg font-medium">
|
||||
{activeTab === "cliente"
|
||||
? "Nenhum cadastro de empresa encontrado"
|
||||
? "Nenhum cadastro de cliente encontrado"
|
||||
: "Nenhum cadastro profissional encontrado"}
|
||||
</p>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Reference in a new issue