fix: ajustado fluxo e geracao de codigos de acesso
This commit is contained in:
parent
5312945f7c
commit
cd00fb53f9
8 changed files with 175 additions and 9 deletions
|
|
@ -146,6 +146,7 @@ func main() {
|
|||
r.GET("/api/tipos-servicos", tiposServicosHandler.List)
|
||||
r.GET("/api/tipos-eventos", tiposEventosHandler.List)
|
||||
r.GET("/api/tipos-eventos/:id/precos", tiposEventosHandler.ListPrices)
|
||||
r.GET("/api/public/codigos-acesso/verificar", codigosHandler.Verify)
|
||||
|
||||
// Protected Routes
|
||||
api := r.Group("/api")
|
||||
|
|
|
|||
|
|
@ -2135,6 +2135,43 @@ const docTemplate = `{
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/public/codigos-acesso/verificar": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"codigos"
|
||||
],
|
||||
"summary": "Verify Access Code",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Code",
|
||||
"name": "code",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/tipos-eventos": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
|
|
|||
|
|
@ -2129,6 +2129,43 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"/api/public/codigos-acesso/verificar": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"codigos"
|
||||
],
|
||||
"summary": "Verify Access Code",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Code",
|
||||
"name": "code",
|
||||
"in": "query",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"400": {
|
||||
"description": "Bad Request",
|
||||
"schema": {
|
||||
"type": "object",
|
||||
"additionalProperties": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/tipos-eventos": {
|
||||
"get": {
|
||||
"security": [
|
||||
|
|
|
|||
|
|
@ -1874,6 +1874,30 @@ paths:
|
|||
summary: Update profissional
|
||||
tags:
|
||||
- profissionais
|
||||
/api/public/codigos-acesso/verificar:
|
||||
get:
|
||||
parameters:
|
||||
- description: Code
|
||||
in: query
|
||||
name: code
|
||||
required: true
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: boolean
|
||||
type: object
|
||||
"400":
|
||||
description: Bad Request
|
||||
schema:
|
||||
additionalProperties:
|
||||
type: string
|
||||
type: object
|
||||
summary: Verify Access Code
|
||||
tags:
|
||||
- codigos
|
||||
/api/tipos-eventos:
|
||||
get:
|
||||
consumes:
|
||||
|
|
|
|||
|
|
@ -88,3 +88,34 @@ func (h *Handler) Delete(c *gin.Context) {
|
|||
}
|
||||
c.JSON(http.StatusOK, gin.H{"message": "deleted"})
|
||||
}
|
||||
|
||||
// Verify godoc
|
||||
// @Summary Verify Access Code
|
||||
// @Tags codigos
|
||||
// @Param code query string true "Code"
|
||||
// @Success 200 {object} map[string]bool
|
||||
// @Failure 400 {object} map[string]string
|
||||
// @Router /api/public/codigos-acesso/verificar [get]
|
||||
func (h *Handler) Verify(c *gin.Context) {
|
||||
code := c.Query("code")
|
||||
if code == "" {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "code required"})
|
||||
return
|
||||
}
|
||||
|
||||
err := h.service.Verify(c.Request.Context(), code)
|
||||
if err != nil {
|
||||
// Distinguish validation error from DB error strictly?
|
||||
// For security, just say invalid.
|
||||
// But service returns specific AppError.
|
||||
if _, ok := err.(*AppError); ok {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"valid": false, "error": err.Error()})
|
||||
return
|
||||
}
|
||||
// If check failed (not found etc), return 404 or 400
|
||||
c.JSON(http.StatusBadRequest, gin.H{"valid": false, "error": "Código inválido"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"valid": true})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,3 +77,29 @@ func (s *Service) IncrementUse(ctx context.Context, id uuid.UUID) error {
|
|||
pgUUID.Valid = true
|
||||
return s.q.IncrementCodigoAcessoUso(ctx, pgUUID)
|
||||
}
|
||||
|
||||
// Custom error for validation
|
||||
type AppError struct {
|
||||
Message string
|
||||
}
|
||||
|
||||
func (e *AppError) Error() string {
|
||||
return e.Message
|
||||
}
|
||||
|
||||
func (s *Service) Verify(ctx context.Context, code string) error {
|
||||
c, err := s.q.GetCodigoAcesso(ctx, code)
|
||||
if err != nil {
|
||||
return err // Not found or DB error
|
||||
}
|
||||
|
||||
if !c.Ativo {
|
||||
return &AppError{Message: "Código inativo"}
|
||||
}
|
||||
|
||||
if time.Now().After(c.ExpiraEm.Time) {
|
||||
return &AppError{Message: "Código expirado"}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React, { useState } from "react";
|
||||
import { Button } from "../components/Button";
|
||||
import { X } from "lucide-react";
|
||||
import { verifyAccessCode } from "../services/apiService";
|
||||
|
||||
interface HomeProps {
|
||||
onEnter: () => void;
|
||||
|
|
@ -12,26 +13,28 @@ export const Home: React.FC<HomeProps> = ({ onEnter }) => {
|
|||
const [showProfessionalPrompt, setShowProfessionalPrompt] = useState(false);
|
||||
const [codeError, setCodeError] = useState("");
|
||||
|
||||
// Código mockado - em produção, verificar com o backend
|
||||
const MOCK_ACCESS_CODE = "PHOTUM2025";
|
||||
|
||||
const handleRegisterClick = () => {
|
||||
setShowProfessionalPrompt(true);
|
||||
setAccessCode("");
|
||||
setCodeError("");
|
||||
};
|
||||
|
||||
const handleVerifyCode = () => {
|
||||
const handleVerifyCode = async () => {
|
||||
if (accessCode.trim() === "") {
|
||||
setCodeError("Por favor, digite o código de acesso");
|
||||
return;
|
||||
}
|
||||
|
||||
if (accessCode.toUpperCase() === MOCK_ACCESS_CODE) {
|
||||
setShowAccessCodeModal(false);
|
||||
window.location.href = "/cadastro";
|
||||
} else {
|
||||
setCodeError("Código de acesso inválido ou expirado");
|
||||
try {
|
||||
const res = await verifyAccessCode(accessCode.toUpperCase());
|
||||
if (res.data && res.data.valid) {
|
||||
setShowAccessCodeModal(false);
|
||||
window.location.href = "/cadastro";
|
||||
} else {
|
||||
setCodeError(res.data?.error || "Código de acesso inválido ou expirado");
|
||||
}
|
||||
} catch (e) {
|
||||
setCodeError("Erro ao verificar código");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1059,3 +1059,10 @@ export async function listPassengers(carroId: string, token: string) {
|
|||
return { data, error: null };
|
||||
} catch (err: any) { return { data: null, error: err.message }; }
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifica se um código de acesso é válido
|
||||
*/
|
||||
export async function verifyAccessCode(code: string): Promise<ApiResponse<{ valid: boolean; error?: string }>> {
|
||||
return fetchFromBackend<{ valid: boolean; error?: string }>(`/api/public/codigos-acesso/verificar?code=${encodeURIComponent(code)}`);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue