- Backend: Migrations para tabelas 'escalas' e 'logistica' (transporte) - Backend: Handlers e Services completos para gestão de escalas e logística - Backend: Suporte a auth vinculado a perfil profissional - Frontend: Nova página de Detalhes Operacionais (/agenda/:id) - Frontend: Componente EventScheduler com verificação robusta de conflitos - Frontend: Componente EventLogistics para gestão de motoristas e caronas - Frontend: Modal de Detalhes de Profissional unificado (Admin + Self-view) - Frontend: Dashboard com modal de gestão de equipe e filtros avançados - Fix: Correção crítica de timezone (UTC) em horários de agendamento - Fix: Tratamento de URLs no campo de local do evento - Fix: Filtros de profissional com carro na logística
164 lines
4.6 KiB
Go
164 lines
4.6 KiB
Go
package logistica
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
type Handler struct {
|
|
service *Service
|
|
}
|
|
|
|
func NewHandler(service *Service) *Handler {
|
|
return &Handler{service: service}
|
|
}
|
|
|
|
// CreateCarro
|
|
func (h *Handler) CreateCarro(c *gin.Context) {
|
|
var req CreateCarroInput
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
carro, err := h.service.CreateCarro(c.Request.Context(), req)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
c.JSON(http.StatusCreated, gin.H{"id": uuid.UUID(carro.ID.Bytes).String()})
|
|
}
|
|
|
|
// ListCarros
|
|
func (h *Handler) ListCarros(c *gin.Context) {
|
|
agendaID := c.Query("agenda_id")
|
|
if agendaID == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "agenda_id is required"})
|
|
return
|
|
}
|
|
|
|
carros, err := h.service.ListCarros(c.Request.Context(), agendaID)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
// Fetch passengers for each car? Or let frontend do it on demand?
|
|
// For main list, efficient to just list cars, or maybe passengers embedded.
|
|
// For simplicity, let's embed passengers if possible, but list returns row.
|
|
// We will return list of cars. The frontend can fetch passengers per car or we should use a transaction/composite query.
|
|
// MVP: Check if we can just return the cars now.
|
|
|
|
resp := make([]map[string]interface{}, len(carros))
|
|
for i, car := range carros {
|
|
var driverName string
|
|
// Logic: if system driver name exists, use it. Else use custom name.
|
|
if car.MotoristaNomeSistema.String != "" {
|
|
driverName = car.MotoristaNomeSistema.String
|
|
} else {
|
|
driverName = car.NomeMotorista.String
|
|
}
|
|
|
|
var avatar string
|
|
if car.MotoristaAvatar.Valid {
|
|
avatar = car.MotoristaAvatar.String
|
|
}
|
|
|
|
resp[i] = map[string]interface{}{
|
|
"id": uuid.UUID(car.ID.Bytes).String(),
|
|
"agenda_id": uuid.UUID(car.AgendaID.Bytes).String(),
|
|
"driver_id": uuid.UUID(car.MotoristaID.Bytes).String(), // May be empty UUID or nil representation
|
|
"driver_name": driverName,
|
|
"driver_avatar": avatar,
|
|
"arrival_time": car.HorarioChegada.String,
|
|
"notes": car.Observacoes.String,
|
|
}
|
|
}
|
|
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|
|
|
|
// DeleteCarro
|
|
func (h *Handler) DeleteCarro(c *gin.Context) {
|
|
id := c.Param("id")
|
|
if id == "" {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": "id required"})
|
|
return
|
|
}
|
|
if err := h.service.DeleteCarro(c.Request.Context(), id); err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "deleted"})
|
|
}
|
|
|
|
// UpdateCarro
|
|
func (h *Handler) UpdateCarro(c *gin.Context) {
|
|
id := c.Param("id")
|
|
var req UpdateCarroInput
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
_, err := h.service.UpdateCarro(c.Request.Context(), id, req)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "updated"})
|
|
}
|
|
|
|
// Passengers
|
|
type AddPassengerInput struct {
|
|
ProfissionalID string `json:"profissional_id"`
|
|
}
|
|
|
|
func (h *Handler) AddPassenger(c *gin.Context) {
|
|
carID := c.Param("id")
|
|
var req AddPassengerInput
|
|
if err := c.ShouldBindJSON(&req); err != nil {
|
|
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
err := h.service.AddPassageiro(c.Request.Context(), carID, req.ProfissionalID)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "passenger added"})
|
|
}
|
|
|
|
func (h *Handler) RemovePassenger(c *gin.Context) {
|
|
carID := c.Param("id")
|
|
profID := c.Param("profID")
|
|
err := h.service.RemovePassageiro(c.Request.Context(), carID, profID)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
c.JSON(http.StatusOK, gin.H{"message": "passenger removed"})
|
|
}
|
|
|
|
func (h *Handler) ListPassengers(c *gin.Context) {
|
|
carID := c.Param("id")
|
|
passengers, err := h.service.ListPassageiros(c.Request.Context(), carID)
|
|
if err != nil {
|
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
|
return
|
|
}
|
|
|
|
resp := make([]map[string]interface{}, len(passengers))
|
|
for i, p := range passengers {
|
|
resp[i] = map[string]interface{}{
|
|
"id": uuid.UUID(p.ID.Bytes).String(),
|
|
"profissional_id": uuid.UUID(p.ProfissionalID.Bytes).String(),
|
|
"name": p.Nome,
|
|
"avatar_url": p.AvatarUrl.String,
|
|
"role": p.FuncaoNome.String,
|
|
}
|
|
}
|
|
c.JSON(http.StatusOK, resp)
|
|
}
|