feat(profissionais): melhorar a visualização de detalhes e persistência dos profissionais

- Adiciona a coluna `email` ao banco de dados para corrigir a persistência do e-mail de contato.
- Atualiza o `Team.tsx` para exibir todos os campos do profissional no modal de detalhes (Dados Financeiros, Detalhamento de Avaliações).
- Corrige o cálculo e a persistência de `media` (ajuste para valor nulo).
- Implementa integração com CEP para preenchimento automático de endereço.
- Adiciona validações para valores negativos e corrige problemas de layout.
This commit is contained in:
NANDO9322 2025-12-24 15:03:08 -03:00
parent 95d7906c28
commit 90841596c1
13 changed files with 997 additions and 1520 deletions

View file

@ -2997,6 +2997,9 @@ const docTemplate = `{
"educacao_simpatia": {
"type": "integer"
},
"email": {
"type": "string"
},
"endereco": {
"type": "string"
},
@ -3047,6 +3050,9 @@ const docTemplate = `{
"agencia": {
"type": "string"
},
"avatar_url": {
"type": "string"
},
"banco": {
"type": "string"
},
@ -3161,6 +3167,9 @@ const docTemplate = `{
"educacao_simpatia": {
"type": "integer"
},
"email": {
"type": "string"
},
"endereco": {
"type": "string"
},

View file

@ -2991,6 +2991,9 @@
"educacao_simpatia": {
"type": "integer"
},
"email": {
"type": "string"
},
"endereco": {
"type": "string"
},
@ -3041,6 +3044,9 @@
"agencia": {
"type": "string"
},
"avatar_url": {
"type": "string"
},
"banco": {
"type": "string"
},
@ -3155,6 +3161,9 @@
"educacao_simpatia": {
"type": "integer"
},
"email": {
"type": "string"
},
"endereco": {
"type": "string"
},

View file

@ -274,6 +274,8 @@ definitions:
type: integer
educacao_simpatia:
type: integer
email:
type: string
endereco:
type: string
equipamentos:
@ -307,6 +309,8 @@ definitions:
properties:
agencia:
type: string
avatar_url:
type: string
banco:
type: string
carro_disponivel:
@ -383,6 +387,8 @@ definitions:
type: integer
educacao_simpatia:
type: integer
email:
type: string
endereco:
type: string
equipamentos:

View file

@ -198,7 +198,7 @@ func (q *Queries) GetAgenda(ctx context.Context, id pgtype.UUID) (Agenda, error)
}
const getAgendaProfessionals = `-- name: GetAgendaProfessionals :many
SELECT p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.avatar_url, p.criado_em, p.atualizado_em, f.nome as funcao_nome, u.email
SELECT p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.email, p.avatar_url, p.criado_em, p.atualizado_em, f.nome as funcao_nome, u.email
FROM cadastro_profissionais p
JOIN agenda_profissionais ap ON p.id = ap.profissional_id
LEFT JOIN funcoes_profissionais f ON p.funcao_profissional_id = f.id
@ -232,11 +232,12 @@ type GetAgendaProfessionalsRow struct {
TabelaFree pgtype.Text `json:"tabela_free"`
ExtraPorEquipamento pgtype.Bool `json:"extra_por_equipamento"`
Equipamentos pgtype.Text `json:"equipamentos"`
Email pgtype.Text `json:"email"`
AvatarUrl pgtype.Text `json:"avatar_url"`
CriadoEm pgtype.Timestamptz `json:"criado_em"`
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
FuncaoNome pgtype.Text `json:"funcao_nome"`
Email pgtype.Text `json:"email"`
Email_2 pgtype.Text `json:"email_2"`
}
func (q *Queries) GetAgendaProfessionals(ctx context.Context, agendaID pgtype.UUID) ([]GetAgendaProfessionalsRow, error) {
@ -274,11 +275,12 @@ func (q *Queries) GetAgendaProfessionals(ctx context.Context, agendaID pgtype.UU
&i.TabelaFree,
&i.ExtraPorEquipamento,
&i.Equipamentos,
&i.Email,
&i.AvatarUrl,
&i.CriadoEm,
&i.AtualizadoEm,
&i.FuncaoNome,
&i.Email,
&i.Email_2,
); err != nil {
return nil, err
}
@ -543,7 +545,7 @@ func (q *Queries) ListAgendasByUser(ctx context.Context, userID pgtype.UUID) ([]
const listAvailableProfessionalsForDate = `-- name: ListAvailableProfessionalsForDate :many
SELECT
p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.avatar_url, p.criado_em, p.atualizado_em,
p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.email, p.avatar_url, p.criado_em, p.atualizado_em,
u.email,
f.nome as funcao_nome,
dp.status as status_disponibilidade
@ -589,10 +591,11 @@ type ListAvailableProfessionalsForDateRow struct {
TabelaFree pgtype.Text `json:"tabela_free"`
ExtraPorEquipamento pgtype.Bool `json:"extra_por_equipamento"`
Equipamentos pgtype.Text `json:"equipamentos"`
Email pgtype.Text `json:"email"`
AvatarUrl pgtype.Text `json:"avatar_url"`
CriadoEm pgtype.Timestamptz `json:"criado_em"`
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
Email string `json:"email"`
Email_2 string `json:"email_2"`
FuncaoNome string `json:"funcao_nome"`
StatusDisponibilidade string `json:"status_disponibilidade"`
}
@ -632,10 +635,11 @@ func (q *Queries) ListAvailableProfessionalsForDate(ctx context.Context, data pg
&i.TabelaFree,
&i.ExtraPorEquipamento,
&i.Equipamentos,
&i.Email,
&i.AvatarUrl,
&i.CriadoEm,
&i.AtualizadoEm,
&i.Email,
&i.Email_2,
&i.FuncaoNome,
&i.StatusDisponibilidade,
); err != nil {

View file

@ -107,6 +107,7 @@ type CadastroProfissionai struct {
TabelaFree pgtype.Text `json:"tabela_free"`
ExtraPorEquipamento pgtype.Bool `json:"extra_por_equipamento"`
Equipamentos pgtype.Text `json:"equipamentos"`
Email pgtype.Text `json:"email"`
AvatarUrl pgtype.Text `json:"avatar_url"`
CriadoEm pgtype.Timestamptz `json:"criado_em"`
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`

View file

@ -17,11 +17,11 @@ INSERT INTO cadastro_profissionais (
cpf_cnpj_titular, banco, agencia, conta_pix, carro_disponivel,
tem_estudio, qtd_estudio, tipo_cartao, observacao, qual_tec,
educacao_simpatia, desempenho_evento, disp_horario, media,
tabela_free, extra_por_equipamento, equipamentos, avatar_url
tabela_free, extra_por_equipamento, equipamentos, email, avatar_url
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15,
$16, $17, $18, $19, $20, $21, $22, $23, $24, $25
) RETURNING id, usuario_id, nome, funcao_profissional_id, endereco, cidade, uf, whatsapp, cpf_cnpj_titular, banco, agencia, conta_pix, carro_disponivel, tem_estudio, qtd_estudio, tipo_cartao, observacao, qual_tec, educacao_simpatia, desempenho_evento, disp_horario, media, tabela_free, extra_por_equipamento, equipamentos, avatar_url, criado_em, atualizado_em
$16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26
) RETURNING id, usuario_id, nome, funcao_profissional_id, endereco, cidade, uf, whatsapp, cpf_cnpj_titular, banco, agencia, conta_pix, carro_disponivel, tem_estudio, qtd_estudio, tipo_cartao, observacao, qual_tec, educacao_simpatia, desempenho_evento, disp_horario, media, tabela_free, extra_por_equipamento, equipamentos, email, avatar_url, criado_em, atualizado_em
`
type CreateProfissionalParams struct {
@ -49,6 +49,7 @@ type CreateProfissionalParams struct {
TabelaFree pgtype.Text `json:"tabela_free"`
ExtraPorEquipamento pgtype.Bool `json:"extra_por_equipamento"`
Equipamentos pgtype.Text `json:"equipamentos"`
Email pgtype.Text `json:"email"`
AvatarUrl pgtype.Text `json:"avatar_url"`
}
@ -78,6 +79,7 @@ func (q *Queries) CreateProfissional(ctx context.Context, arg CreateProfissional
arg.TabelaFree,
arg.ExtraPorEquipamento,
arg.Equipamentos,
arg.Email,
arg.AvatarUrl,
)
var i CadastroProfissionai
@ -107,6 +109,7 @@ func (q *Queries) CreateProfissional(ctx context.Context, arg CreateProfissional
&i.TabelaFree,
&i.ExtraPorEquipamento,
&i.Equipamentos,
&i.Email,
&i.AvatarUrl,
&i.CriadoEm,
&i.AtualizadoEm,
@ -125,7 +128,7 @@ func (q *Queries) DeleteProfissional(ctx context.Context, id pgtype.UUID) error
}
const getProfissionalByID = `-- name: GetProfissionalByID :one
SELECT p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.avatar_url, p.criado_em, p.atualizado_em, f.nome as funcao_nome
SELECT p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.email, p.avatar_url, p.criado_em, p.atualizado_em, f.nome as funcao_nome
FROM cadastro_profissionais p
LEFT JOIN funcoes_profissionais f ON p.funcao_profissional_id = f.id
WHERE p.id = $1 LIMIT 1
@ -157,6 +160,7 @@ type GetProfissionalByIDRow struct {
TabelaFree pgtype.Text `json:"tabela_free"`
ExtraPorEquipamento pgtype.Bool `json:"extra_por_equipamento"`
Equipamentos pgtype.Text `json:"equipamentos"`
Email pgtype.Text `json:"email"`
AvatarUrl pgtype.Text `json:"avatar_url"`
CriadoEm pgtype.Timestamptz `json:"criado_em"`
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
@ -192,6 +196,7 @@ func (q *Queries) GetProfissionalByID(ctx context.Context, id pgtype.UUID) (GetP
&i.TabelaFree,
&i.ExtraPorEquipamento,
&i.Equipamentos,
&i.Email,
&i.AvatarUrl,
&i.CriadoEm,
&i.AtualizadoEm,
@ -201,7 +206,7 @@ func (q *Queries) GetProfissionalByID(ctx context.Context, id pgtype.UUID) (GetP
}
const getProfissionalByUsuarioID = `-- name: GetProfissionalByUsuarioID :one
SELECT p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.avatar_url, p.criado_em, p.atualizado_em, f.nome as funcao_nome
SELECT p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.email, p.avatar_url, p.criado_em, p.atualizado_em, f.nome as funcao_nome
FROM cadastro_profissionais p
LEFT JOIN funcoes_profissionais f ON p.funcao_profissional_id = f.id
WHERE p.usuario_id = $1 LIMIT 1
@ -233,6 +238,7 @@ type GetProfissionalByUsuarioIDRow struct {
TabelaFree pgtype.Text `json:"tabela_free"`
ExtraPorEquipamento pgtype.Bool `json:"extra_por_equipamento"`
Equipamentos pgtype.Text `json:"equipamentos"`
Email pgtype.Text `json:"email"`
AvatarUrl pgtype.Text `json:"avatar_url"`
CriadoEm pgtype.Timestamptz `json:"criado_em"`
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
@ -268,6 +274,7 @@ func (q *Queries) GetProfissionalByUsuarioID(ctx context.Context, usuarioID pgty
&i.TabelaFree,
&i.ExtraPorEquipamento,
&i.Equipamentos,
&i.Email,
&i.AvatarUrl,
&i.CriadoEm,
&i.AtualizadoEm,
@ -277,7 +284,7 @@ func (q *Queries) GetProfissionalByUsuarioID(ctx context.Context, usuarioID pgty
}
const listProfissionais = `-- name: ListProfissionais :many
SELECT p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.avatar_url, p.criado_em, p.atualizado_em, f.nome as funcao_nome, u.email
SELECT p.id, p.usuario_id, p.nome, p.funcao_profissional_id, p.endereco, p.cidade, p.uf, p.whatsapp, p.cpf_cnpj_titular, p.banco, p.agencia, p.conta_pix, p.carro_disponivel, p.tem_estudio, p.qtd_estudio, p.tipo_cartao, p.observacao, p.qual_tec, p.educacao_simpatia, p.desempenho_evento, p.disp_horario, p.media, p.tabela_free, p.extra_por_equipamento, p.equipamentos, p.email, p.avatar_url, p.criado_em, p.atualizado_em, f.nome as funcao_nome, u.email as usuario_email
FROM cadastro_profissionais p
LEFT JOIN funcoes_profissionais f ON p.funcao_profissional_id = f.id
LEFT JOIN usuarios u ON p.usuario_id = u.id
@ -310,11 +317,12 @@ type ListProfissionaisRow struct {
TabelaFree pgtype.Text `json:"tabela_free"`
ExtraPorEquipamento pgtype.Bool `json:"extra_por_equipamento"`
Equipamentos pgtype.Text `json:"equipamentos"`
Email pgtype.Text `json:"email"`
AvatarUrl pgtype.Text `json:"avatar_url"`
CriadoEm pgtype.Timestamptz `json:"criado_em"`
AtualizadoEm pgtype.Timestamptz `json:"atualizado_em"`
FuncaoNome pgtype.Text `json:"funcao_nome"`
Email pgtype.Text `json:"email"`
UsuarioEmail pgtype.Text `json:"usuario_email"`
}
func (q *Queries) ListProfissionais(ctx context.Context) ([]ListProfissionaisRow, error) {
@ -352,11 +360,12 @@ func (q *Queries) ListProfissionais(ctx context.Context) ([]ListProfissionaisRow
&i.TabelaFree,
&i.ExtraPorEquipamento,
&i.Equipamentos,
&i.Email,
&i.AvatarUrl,
&i.CriadoEm,
&i.AtualizadoEm,
&i.FuncaoNome,
&i.Email,
&i.UsuarioEmail,
); err != nil {
return nil, err
}
@ -395,9 +404,10 @@ SET
extra_por_equipamento = $23,
equipamentos = $24,
avatar_url = $25,
email = $26,
atualizado_em = NOW()
WHERE id = $1
RETURNING id, usuario_id, nome, funcao_profissional_id, endereco, cidade, uf, whatsapp, cpf_cnpj_titular, banco, agencia, conta_pix, carro_disponivel, tem_estudio, qtd_estudio, tipo_cartao, observacao, qual_tec, educacao_simpatia, desempenho_evento, disp_horario, media, tabela_free, extra_por_equipamento, equipamentos, avatar_url, criado_em, atualizado_em
RETURNING id, usuario_id, nome, funcao_profissional_id, endereco, cidade, uf, whatsapp, cpf_cnpj_titular, banco, agencia, conta_pix, carro_disponivel, tem_estudio, qtd_estudio, tipo_cartao, observacao, qual_tec, educacao_simpatia, desempenho_evento, disp_horario, media, tabela_free, extra_por_equipamento, equipamentos, email, avatar_url, criado_em, atualizado_em
`
type UpdateProfissionalParams struct {
@ -426,6 +436,7 @@ type UpdateProfissionalParams struct {
ExtraPorEquipamento pgtype.Bool `json:"extra_por_equipamento"`
Equipamentos pgtype.Text `json:"equipamentos"`
AvatarUrl pgtype.Text `json:"avatar_url"`
Email pgtype.Text `json:"email"`
}
func (q *Queries) UpdateProfissional(ctx context.Context, arg UpdateProfissionalParams) (CadastroProfissionai, error) {
@ -455,6 +466,7 @@ func (q *Queries) UpdateProfissional(ctx context.Context, arg UpdateProfissional
arg.ExtraPorEquipamento,
arg.Equipamentos,
arg.AvatarUrl,
arg.Email,
)
var i CadastroProfissionai
err := row.Scan(
@ -483,6 +495,7 @@ func (q *Queries) UpdateProfissional(ctx context.Context, arg UpdateProfissional
&i.TabelaFree,
&i.ExtraPorEquipamento,
&i.Equipamentos,
&i.Email,
&i.AvatarUrl,
&i.CriadoEm,
&i.AtualizadoEm,

View file

@ -4,10 +4,10 @@ INSERT INTO cadastro_profissionais (
cpf_cnpj_titular, banco, agencia, conta_pix, carro_disponivel,
tem_estudio, qtd_estudio, tipo_cartao, observacao, qual_tec,
educacao_simpatia, desempenho_evento, disp_horario, media,
tabela_free, extra_por_equipamento, equipamentos, avatar_url
tabela_free, extra_por_equipamento, equipamentos, email, avatar_url
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15,
$16, $17, $18, $19, $20, $21, $22, $23, $24, $25
$16, $17, $18, $19, $20, $21, $22, $23, $24, $25, $26
) RETURNING *;
-- name: GetProfissionalByUsuarioID :one
@ -23,7 +23,7 @@ LEFT JOIN funcoes_profissionais f ON p.funcao_profissional_id = f.id
WHERE p.id = $1 LIMIT 1;
-- name: ListProfissionais :many
SELECT p.*, f.nome as funcao_nome, u.email
SELECT p.*, f.nome as funcao_nome, u.email as usuario_email
FROM cadastro_profissionais p
LEFT JOIN funcoes_profissionais f ON p.funcao_profissional_id = f.id
LEFT JOIN usuarios u ON p.usuario_id = u.id
@ -56,6 +56,7 @@ SET
extra_por_equipamento = $23,
equipamentos = $24,
avatar_url = $25,
email = $26,
atualizado_em = NOW()
WHERE id = $1
RETURNING *;

View file

@ -52,6 +52,7 @@ CREATE TABLE IF NOT EXISTS cadastro_profissionais (
tabela_free VARCHAR(50),
extra_por_equipamento BOOLEAN DEFAULT FALSE,
equipamentos TEXT,
email VARCHAR(255),
avatar_url VARCHAR(255),
criado_em TIMESTAMPTZ NOT NULL DEFAULT NOW(),
atualizado_em TIMESTAMPTZ NOT NULL DEFAULT NOW()

View file

@ -46,7 +46,8 @@ type ProfissionalResponse struct {
TabelaFree *string `json:"tabela_free"`
ExtraPorEquipamento *bool `json:"extra_por_equipamento"`
Equipamentos *string `json:"equipamentos"`
Email string `json:"email"`
Email *string `json:"email"`
AvatarURL *string `json:"avatar_url"`
}
func toResponse(p interface{}) ProfissionalResponse {
@ -84,6 +85,8 @@ func toResponse(p interface{}) ProfissionalResponse {
TabelaFree: fromPgText(v.TabelaFree),
ExtraPorEquipamento: fromPgBool(v.ExtraPorEquipamento),
Equipamentos: fromPgText(v.Equipamentos),
Email: fromPgText(v.Email),
AvatarURL: fromPgText(v.AvatarUrl),
}
case generated.ListProfissionaisRow:
return ProfissionalResponse{
@ -113,7 +116,8 @@ func toResponse(p interface{}) ProfissionalResponse {
TabelaFree: fromPgText(v.TabelaFree),
ExtraPorEquipamento: fromPgBool(v.ExtraPorEquipamento),
Equipamentos: fromPgText(v.Equipamentos),
Email: v.Email.String,
Email: fromPgText(v.Email),
AvatarURL: fromPgText(v.AvatarUrl),
}
case generated.GetProfissionalByIDRow:
return ProfissionalResponse{
@ -143,6 +147,7 @@ func toResponse(p interface{}) ProfissionalResponse {
TabelaFree: fromPgText(v.TabelaFree),
ExtraPorEquipamento: fromPgBool(v.ExtraPorEquipamento),
Equipamentos: fromPgText(v.Equipamentos),
AvatarURL: fromPgText(v.AvatarUrl),
}
default:
return ProfissionalResponse{}

View file

@ -3,6 +3,7 @@ package profissionais
import (
"context"
"errors"
"fmt"
"photum-backend/internal/db/generated"
@ -42,6 +43,7 @@ type CreateProfissionalInput struct {
TabelaFree *string `json:"tabela_free"`
ExtraPorEquipamento *bool `json:"extra_por_equipamento"`
Equipamentos *string `json:"equipamentos"`
Email *string `json:"email"`
AvatarURL *string `json:"avatar_url"`
}
@ -89,6 +91,7 @@ func (s *Service) Create(ctx context.Context, userID string, input CreateProfiss
TabelaFree: toPgText(input.TabelaFree),
ExtraPorEquipamento: toPgBool(input.ExtraPorEquipamento),
Equipamentos: toPgText(input.Equipamentos),
Email: toPgText(input.Email),
AvatarUrl: toPgText(input.AvatarURL),
}
@ -139,6 +142,7 @@ type UpdateProfissionalInput struct {
TabelaFree *string `json:"tabela_free"`
ExtraPorEquipamento *bool `json:"extra_por_equipamento"`
Equipamentos *string `json:"equipamentos"`
Email *string `json:"email"`
AvatarURL *string `json:"avatar_url"`
}
@ -178,6 +182,7 @@ func (s *Service) Update(ctx context.Context, id string, input UpdateProfissiona
TabelaFree: toPgText(input.TabelaFree),
ExtraPorEquipamento: toPgBool(input.ExtraPorEquipamento),
Equipamentos: toPgText(input.Equipamentos),
Email: toPgText(input.Email),
AvatarUrl: toPgText(input.AvatarURL),
}
@ -224,6 +229,8 @@ func toPgNumeric(f *float64) pgtype.Numeric {
return pgtype.Numeric{Valid: false}
}
var n pgtype.Numeric
n.Scan(f)
if err := n.Scan(fmt.Sprintf("%f", *f)); err != nil {
return pgtype.Numeric{Valid: false}
}
return n
}

File diff suppressed because it is too large Load diff

View file

@ -115,6 +115,108 @@ export async function createProfessional(data: any, token?: string): Promise<Api
}
}
/**
* Atualiza um profissional existente
*/
export async function updateProfessional(id: string, data: any, token: string): Promise<ApiResponse<any>> {
try {
const response = await fetch(`${API_BASE_URL}/api/profissionais/${id}`, {
method: "PUT",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
body: JSON.stringify(data),
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
}
const responseData = await response.json();
return {
data: responseData,
error: null,
isBackendDown: false,
};
} catch (error) {
console.error("Error updating professional:", error);
return {
data: null,
error: error instanceof Error ? error.message : "Erro desconhecido",
isBackendDown: true,
};
}
}
/**
* Remove um profissional
*/
export async function deleteProfessional(id: string, token: string): Promise<ApiResponse<void>> {
try {
const response = await fetch(`${API_BASE_URL}/api/profissionais/${id}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
});
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.error || `HTTP error! status: ${response.status}`);
}
return {
data: null,
error: null,
isBackendDown: false,
};
} catch (error) {
console.error("Error deleting professional:", error);
return {
data: null,
error: error instanceof Error ? error.message : "Erro desconhecido",
isBackendDown: true,
};
}
}
/**
* Busca um profissional pelo ID
*/
export async function getProfessionalById(id: string, token: string): Promise<ApiResponse<any>> {
try {
const response = await fetch(`${API_BASE_URL}/api/profissionais/${id}`, {
method: "GET",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return {
data,
error: null,
isBackendDown: false,
};
} catch (error) {
console.error("Error fetching professional by id:", error);
return {
data: null,
error: error instanceof Error ? error.message : "Erro desconhecido",
isBackendDown: true,
};
}
}
/**
* Busca a lista de profissionais
*/

View file

@ -144,13 +144,75 @@ export interface EventData {
assignments?: Assignment[]; // Lista de status de atribuições
}
export interface Professional {
id: string;
usuarioId: string;
name: string;
email: string; // Added via JOIN
role: string; // Funcao nome
avatar?: string;
usuario_id?: string;
nome: string;
email?: string;
funcao_profissional_id: string;
role?: string; // Optional, for UI display if needed (e.g. from join)
avatar?: string; // Legacy/UI
avatar_url?: string; // Backend field
phone?: string;
availability: { [date: string]: boolean }; // Mocked or fetched? For now let's keep compatibility with mock structure
// Detailed fields matching backend
endereco?: string;
cidade?: string;
uf?: string;
cep?: string;
whatsapp?: string;
cpf_cnpj_titular?: string;
banco?: string;
agencia?: string;
conta_pix?: string;
carro_disponivel?: boolean;
tem_estudio?: boolean;
qtd_estudio?: number;
tipo_cartao?: string;
observacao?: string;
// Ratings
qual_tec?: number;
educacao_simpatia?: number;
desempenho_evento?: number;
disp_horario?: number;
media?: number;
tabela_free?: string;
extra_por_equipamento?: boolean;
equipamentos?: string;
// Availability (kept for compatibility, though might not be in main payload)
availability?: { [date: string]: boolean };
}
export interface CreateProfessionalDTO {
nome: string;
funcao_profissional_id: string;
email?: string;
endereco?: string;
cidade?: string;
uf?: string;
cep?: string;
whatsapp?: string;
cpf_cnpj_titular?: string;
banco?: string;
agencia?: string;
conta_pix?: string;
carro_disponivel?: boolean;
tem_estudio?: boolean;
qtd_estudio?: number;
tipo_cartao?: string;
observacao?: string;
qual_tec?: number;
educacao_simpatia?: number;
desempenho_evento?: number;
disp_horario?: number;
media?: number;
tabela_free?: string;
extra_por_equipamento?: boolean;
equipamentos?: string;
avatar_url?: string;
}