criando users

This commit is contained in:
Lucas Rodrigues 2025-10-10 20:04:48 -03:00
parent 612a70ee90
commit 1b477c10f0
2 changed files with 221 additions and 185 deletions

View File

@ -3,60 +3,57 @@
import { useState } from "react" import { useState } from "react"
import { useRouter } from "next/navigation" import { useRouter } from "next/navigation"
import Link from "next/link" import Link from "next/link"
import { Button } from "components/ui/button" import { Button } from "@/components/ui/button"
import { Input } from "components/ui/input" import { Input } from "@/components/ui/input"
import { Label } from "components/ui/label" import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "components/ui/select" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Save, Loader2 } from "lucide-react" import { Save, Loader2 } from "lucide-react"
import ManagerLayout from "components/manager-layout" import ManagerLayout from "@/components/manager-layout"
import { usersService } from "services/usersApi.mjs"; import { usersService } from "services/usersApi.mjs";
interface UserFormData { interface UserFormData {
email: string; email: string;
password: string; password: string;
nomeCompleto: string; nomeCompleto: string;
telefone: string; telefone: string;
cargo: string; papel: string;
} }
const defaultFormData: UserFormData = { const defaultFormData: UserFormData = {
email: '', email: '',
password: '', password: '',
nomeCompleto: '', nomeCompleto: '',
telefone: '', telefone: '',
cargo: '', papel: '',
}; };
// Remove todos os caracteres não numéricos
const cleanNumber = (value: string): string => value.replace(/\D/g, ''); const cleanNumber = (value: string): string => value.replace(/\D/g, '');
// Definição do requisito mínimo de senha
const MIN_PASSWORD_LENGTH = 8;
const formatPhone = (value: string): string => { const formatPhone = (value: string): string => {
const cleaned = cleanNumber(value).substring(0, 11); const cleaned = cleanNumber(value).substring(0, 11);
if (cleaned.length === 11) { if (cleaned.length === 11) {
return cleaned.replace(/(\d{2})(\d{5})(\d{4})/, '($1) $2-$3'); return cleaned.replace(/(\d{2})(\d{5})(\d{4})/, '($1) $2-$3');
} }
if (cleaned.length === 10) { if (cleaned.length === 10) {
return cleaned.replace(/(\d{2})(\d{4})(\d{4})/, '($1) $2-$3'); return cleaned.replace(/(\d{2})(\d{4})(\d{4})/, '($1) $2-$3');
} }
return cleaned; return cleaned;
}; };
export default function NovoUsuarioPage() { export default function NovoUsuarioPage() {
const router = useRouter(); const router = useRouter();
const [formData, setFormData] = useState<UserFormData>(defaultFormData); const [formData, setFormData] = useState<UserFormData>(defaultFormData);
const [isSaving, setIsSaving] = useState(false); const [isSaving, setIsSaving] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const handleInputChange = (key: keyof UserFormData, value: string) => { const handleInputChange = (key: keyof UserFormData, value: string) => {
const updatedValue = key === 'telefone' ? formatPhone(value) : value; const updatedValue = key === 'telefone' ? formatPhone(value) : value;
setFormData((prev) => ({ ...prev, [key]: updatedValue })); setFormData((prev) => ({ ...prev, [key]: updatedValue }));
@ -68,28 +65,49 @@ export default function NovoUsuarioPage() {
setError(null); setError(null);
// Basic validation // Basic validation
if (!formData.email || !formData.password || !formData.nomeCompleto || !formData.cargo) { if (!formData.email || !formData.password || !formData.nomeCompleto || !formData.papel) {
setError("Por favor, preencha todos os campos obrigatórios."); setError("Por favor, preencha todos os campos obrigatórios.");
return; return;
} }
// Validação de comprimento mínimo da senha
if (formData.password.length < MIN_PASSWORD_LENGTH) {
setError(`A senha deve ter no mínimo ${MIN_PASSWORD_LENGTH} caracteres.`);
return;
}
setIsSaving(true); setIsSaving(true);
// Prepare payload for the API // ----------------------------------------------------------------------
const payload = { // CORREÇÃO FINAL: Usa o formato de telefone que o mock API comprovadamente aceitou.
// ----------------------------------------------------------------------
const phoneValue = formData.telefone.trim();
// Prepara o payload com os campos obrigatórios
const payload: any = {
email: formData.email, email: formData.email,
password: formData.password, password: formData.password,
full_name: formData.nomeCompleto, full_name: formData.nomeCompleto,
phone: formData.telefone.trim() || null, role: formData.papel,
role: formData.cargo,
}; };
// Adiciona o telefone APENAS se estiver preenchido, enviando o formato FORMATADO.
if (phoneValue.length > 0) {
payload.phone = phoneValue;
}
// ----------------------------------------------------------------------
try { try {
await usersService.create_user(payload); await usersService.create_user(payload);
router.push("/manager/usuario"); router.push("/manager/usuario");
} catch (e: any) { } catch (e: any) {
console.error("Erro ao criar usuário:", e); console.error("Erro ao criar usuário:", e);
setError(e.message || "Ocorreu um erro inesperado. Tente novamente."); // Melhorando a mensagem de erro para o usuário final
const apiErrorMsg = e.message?.includes("500")
? "Erro interno do servidor. Verifique os logs do backend ou tente novamente mais tarde. (Possível problema: E-mail já em uso ou falha de conexão.)"
: e.message || "Ocorreu um erro inesperado. Tente novamente.";
setError(apiErrorMsg);
} finally { } finally {
setIsSaving(false); setIsSaving(false);
} }
@ -153,7 +171,10 @@ export default function NovoUsuarioPage() {
onChange={(e) => handleInputChange("password", e.target.value)} onChange={(e) => handleInputChange("password", e.target.value)}
placeholder="••••••••" placeholder="••••••••"
required required
minLength={MIN_PASSWORD_LENGTH} // Adiciona validação HTML
/> />
{/* MENSAGEM DE AJUDA PARA SENHA */}
<p className="text-xs text-gray-500">Mínimo de {MIN_PASSWORD_LENGTH} caracteres.</p>
</div> </div>
</div> </div>
@ -170,7 +191,7 @@ export default function NovoUsuarioPage() {
</div> </div>
<div className="space-y-2"> <div className="space-y-2">
<Label htmlFor="papel">Papel (Função) *</Label> <Label htmlFor="papel">Papel (Função) *</Label>
<Select value={formData.cargo} onValueChange={(v) => handleInputChange("cargo", v)} required> <Select value={formData.papel} onValueChange={(v) => handleInputChange("papel", v)} required>
<SelectTrigger id="papel"> <SelectTrigger id="papel">
<SelectValue placeholder="Selecione uma função" /> <SelectValue placeholder="Selecione uma função" />
</SelectTrigger> </SelectTrigger>

View File

@ -1,8 +1,23 @@
// services/usersApi.mjs (Versão Corrigida)
import { api } from "./api.mjs"; import { api } from "./api.mjs";
export const usersService = { export const usersService = {
create_user: (data) => api.post(`/functions/v1/create-user`), create_user: (data) => api.post(`/functions/v1/create-user`),
list_roles: () => api.get(`/rest/v1/user_roles`),
full_data: (id) => api.get(`/functions/v1/user-info?user_id=${id}`), // CORREÇÃO: Voltamos a pedir apenas os campos que sabemos que a view 'user_roles' tem
// (id ou user_id, e role), e usamos o endpoint 'full_data' para obter os detalhes de nome/telefone.
// SE a sua view 'user_roles' contiver uma coluna chamada 'user_id', tente a próxima linha:
// list_roles: () => api.get(`/rest/v1/user_roles?select=user_id,role,profiles(full_name,phone)`),
//
// PORÉM, VAMOS ASSUMIR QUE A RELAÇÃO ESTÁ REALMENTE QUEBRADA E SIMPLIFICAR A CHAMADA INICIAL:
list_roles: () => api.get(`/rest/v1/user_roles?select=id,user_id,email,role`),
// Se o email também não estiver em 'user_roles', apenas use 'id,user_id,role'.
// O importante é que esta chamada de API NÃO DÊ ERRO 400.
full_data: (id) => {
const endpoint = `/functions/v1/user-info?user_id=${id}`;
return api.get(endpoint);
},
summary_data: () => api.get(`/auth/v1/user`) summary_data: () => api.get(`/auth/v1/user`)
} }