refactor(saveinmed): type legacy addresses and parameterize bootstrap admin
This commit is contained in:
parent
7e3604ed4a
commit
2829a3e87c
7 changed files with 219 additions and 230 deletions
|
|
@ -27,6 +27,8 @@ type Config struct {
|
|||
SwaggerSchemes []string
|
||||
MercadoPagoPublicKey string
|
||||
MapboxAccessToken string
|
||||
BootstrapAdminEmail string
|
||||
BootstrapAdminPassword string
|
||||
}
|
||||
|
||||
// Load reads configuration from environment variables and applies sane defaults
|
||||
|
|
@ -50,6 +52,8 @@ func Load() (*Config, error) {
|
|||
SwaggerSchemes: getEnvStringSlice("SWAGGER_SCHEMES", []string{"http"}),
|
||||
MercadoPagoPublicKey: getEnv("MERCADOPAGO_PUBLIC_KEY", "TEST-PUBLIC-KEY"),
|
||||
MapboxAccessToken: getEnv("MAPBOX_ACCESS_TOKEN", ""),
|
||||
BootstrapAdminEmail: getEnv("BOOTSTRAP_ADMIN_EMAIL", "admin@saveinmed.com.br"),
|
||||
BootstrapAdminPassword: getEnv("BOOTSTRAP_ADMIN_PASSWORD", "sim-admin"),
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ import (
|
|||
const (
|
||||
bootstrapAdminName = "SaveInMed Admin"
|
||||
bootstrapAdminUsername = "admin"
|
||||
bootstrapAdminEmail = "admin@saveinmed.com"
|
||||
bootstrapAdminPassword = "sim-admin"
|
||||
)
|
||||
|
||||
// Server wires the infrastructure and exposes HTTP handlers.
|
||||
|
|
@ -223,15 +221,16 @@ func (s *Server) Start(ctx context.Context) error {
|
|||
|
||||
// Seed platform admin automatically
|
||||
{
|
||||
existingUser, err := repo.GetUserByEmail(ctx, bootstrapAdminEmail)
|
||||
if err != nil {
|
||||
log.Printf("Seeding admin user: %s", bootstrapAdminEmail)
|
||||
adminEmail := s.cfg.BootstrapAdminEmail
|
||||
adminPassword := s.cfg.BootstrapAdminPassword
|
||||
|
||||
existingUser, err := repo.GetUserByEmail(ctx, adminEmail)
|
||||
if err != nil {
|
||||
log.Printf("Seeding admin user: %s", adminEmail)
|
||||
|
||||
// 1. Create/Get platform company
|
||||
adminCNPJ := "00000000000000"
|
||||
company := &domain.Company{
|
||||
ID: uuid.Nil,
|
||||
CNPJ: adminCNPJ,
|
||||
CNPJ: "00000000000000",
|
||||
CorporateName: "SaveInMed Platform",
|
||||
Category: "platform",
|
||||
LicenseNumber: "ADMIN",
|
||||
|
|
@ -240,46 +239,21 @@ func (s *Server) Start(ctx context.Context) error {
|
|||
UpdatedAt: time.Now().UTC(),
|
||||
}
|
||||
|
||||
// We need to check if company exists by CNPJ normally, but repo doesn't expose GetByCNPJ easily?
|
||||
// Let's rely on RegisterAccount handling it or check if we can query.
|
||||
// Actually RegisterAccount in Service handles creation if ID is Nil, but keys off ID.
|
||||
// We can try to create and ignore conflict, or use a known ID?
|
||||
// Let's use RegisterAccount logic.
|
||||
|
||||
// Because RegisterAccount expects us to pass a company, and tries to Get by ID if ID is set, or Create if not.
|
||||
// But duplicate CNPJ will fail at DB level.
|
||||
// Let's assume on fresh boot it doesn't exist.
|
||||
// Or better: Use svc.RegisterAccount. But wait, svc.RegisterAccount logic:
|
||||
/*
|
||||
if company != nil {
|
||||
if company.ID == uuid.Nil {
|
||||
// create
|
||||
} else {
|
||||
// get
|
||||
}
|
||||
}
|
||||
*/
|
||||
// If we re-run, GetUserByEmail would have found the user, so we skip.
|
||||
// The only edge case is if User was deleted but Company remains.
|
||||
// In that case, CreateCompany will fail on CNPJ constraint.
|
||||
|
||||
err := s.svc.RegisterAccount(ctx, company, &domain.User{
|
||||
Role: domain.RoleAdmin,
|
||||
Name: bootstrapAdminName,
|
||||
Username: bootstrapAdminUsername,
|
||||
Email: bootstrapAdminEmail,
|
||||
Email: adminEmail,
|
||||
Superadmin: false,
|
||||
}, bootstrapAdminPassword)
|
||||
}, adminPassword)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("Failed to seed admin: %v", err)
|
||||
} else {
|
||||
// FORCE VERIFY the platform company
|
||||
if _, err := s.svc.VerifyCompany(ctx, company.ID); err != nil {
|
||||
log.Printf("Failed to verify platform company: %v", err)
|
||||
}
|
||||
log.Printf("Admin user created successfully")
|
||||
log.Printf("Bootstrap admin credentials: email=%s password=%s", bootstrapAdminEmail, bootstrapAdminPassword)
|
||||
log.Printf("Admin user created: email=%s", adminEmail)
|
||||
}
|
||||
} else {
|
||||
existingUser.Role = domain.RoleAdmin
|
||||
|
|
@ -291,11 +265,10 @@ func (s *Server) Start(ctx context.Context) error {
|
|||
existingUser.Username = bootstrapAdminUsername
|
||||
}
|
||||
|
||||
if err := s.svc.UpdateUser(ctx, existingUser, bootstrapAdminPassword); err != nil {
|
||||
log.Printf("Failed to reconcile existing user %s as admin: %v", bootstrapAdminEmail, err)
|
||||
if err := s.svc.UpdateUser(ctx, existingUser, adminPassword); err != nil {
|
||||
log.Printf("Failed to reconcile existing user %s as admin: %v", adminEmail, err)
|
||||
} else {
|
||||
log.Printf("Existing user %s reconciled as admin with bootstrap password", bootstrapAdminEmail)
|
||||
log.Printf("Bootstrap admin credentials: email=%s password=%s", bootstrapAdminEmail, bootstrapAdminPassword)
|
||||
log.Printf("Admin user reconciled: email=%s", adminEmail)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
'use client';
|
||||
'use client';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { getCurrentUserWithRetry, account } from '@/lib/appwrite';
|
||||
import { Models } from '@/lib/appwrite';
|
||||
import { getCurrentUserWithRetry, Models } from '@/lib/appwrite';
|
||||
import Header from '@/components/Header';
|
||||
import { MapPin, Plus } from 'lucide-react';
|
||||
import EnderecoForm from '@/components/EnderecoForm';
|
||||
|
|
@ -11,13 +10,15 @@ import EnderecoList from '@/components/EnderecoList';
|
|||
import { useEnderecos, EnderecoData } from '@/hooks/useEnderecos';
|
||||
import { RoleGuard } from '@/components/auth/RoleGuard';
|
||||
import { UserRole } from '@/types/auth';
|
||||
import { EnderecoDocument } from '@/types/legacyEntities';
|
||||
|
||||
const GestaoEnderecos = () => {
|
||||
const router = useRouter();
|
||||
const [user, setUser] = useState<Models.User<Models.Preferences> | null>(null);
|
||||
const [editing, setEditing] = useState<Models.Document | null>(null);
|
||||
const [editing, setEditing] = useState<EnderecoDocument | null>(null);
|
||||
const [activeTab, setActiveTab] = useState<'lista' | 'cadastro'>('lista');
|
||||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const [checkingAuth, setCheckingAuth] = useState(true);
|
||||
|
||||
const {
|
||||
enderecos,
|
||||
|
|
@ -32,21 +33,27 @@ const GestaoEnderecos = () => {
|
|||
cadastrarEndereco,
|
||||
atualizarEndereco,
|
||||
deletarEndereco,
|
||||
setCurrentPage
|
||||
setCurrentPage,
|
||||
} = useEnderecos();
|
||||
|
||||
useEffect(() => {
|
||||
const initializeUser = async () => {
|
||||
try {
|
||||
const currentUser = await account.get();
|
||||
setUser(currentUser);
|
||||
const currentUser = await getCurrentUserWithRetry();
|
||||
if (!currentUser) {
|
||||
router.push('/');
|
||||
return;
|
||||
}
|
||||
|
||||
setUser(currentUser);
|
||||
if (activeTab === 'lista') {
|
||||
await listarEnderecos();
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('⌠Usuário não autenticado:', error);
|
||||
console.error('Usuario nao autenticado:', error);
|
||||
router.push('/');
|
||||
} finally {
|
||||
setCheckingAuth(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -61,16 +68,16 @@ const GestaoEnderecos = () => {
|
|||
setActiveTab('lista');
|
||||
}
|
||||
return success;
|
||||
} else {
|
||||
}
|
||||
|
||||
const success = await cadastrarEndereco(formData);
|
||||
if (success) {
|
||||
setTimeout(() => setActiveTab('lista'), 2000);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
};
|
||||
|
||||
const handleEdit = (endereco: Models.Document) => {
|
||||
const handleEdit = (endereco: EnderecoDocument) => {
|
||||
setEditing(endereco);
|
||||
setActiveTab('cadastro');
|
||||
};
|
||||
|
|
@ -90,9 +97,10 @@ const GestaoEnderecos = () => {
|
|||
setSearchTerm(term);
|
||||
if (term.trim()) {
|
||||
await buscarEnderecos(term, 1);
|
||||
} else {
|
||||
await listarEnderecos(1);
|
||||
return;
|
||||
}
|
||||
|
||||
await listarEnderecos(1);
|
||||
};
|
||||
|
||||
const handleNextPage = () => {
|
||||
|
|
@ -102,12 +110,12 @@ const GestaoEnderecos = () => {
|
|||
}
|
||||
};
|
||||
|
||||
if (!user) {
|
||||
if (checkingAuth || !user) {
|
||||
return (
|
||||
<div className="min-h-screen bg-gray-50 flex items-center justify-center">
|
||||
<div className="text-center">
|
||||
<div className="animate-spin rounded-full h-12 w-12 border-b-2 border-indigo-600 mx-auto mb-4"></div>
|
||||
<p className="text-gray-600">Verificando autenticação...</p>
|
||||
<p className="text-gray-600">Verificando autenticacao...</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
@ -118,8 +126,8 @@ const GestaoEnderecos = () => {
|
|||
<div className="min-h-screen bg-gray-50">
|
||||
<Header
|
||||
user={user}
|
||||
title="Gestão de Endereços"
|
||||
subtitle="Gerencie os endereços da plataforma SaveInMed"
|
||||
title="Gestao de Enderecos"
|
||||
subtitle="Gerencie os enderecos da plataforma SaveInMed"
|
||||
/>
|
||||
|
||||
<main className="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
|
||||
|
|
@ -136,7 +144,7 @@ const GestaoEnderecos = () => {
|
|||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<MapPin className="inline-block w-4 h-4 mr-1" /> Listar Endereços
|
||||
<MapPin className="inline-block w-4 h-4 mr-1" /> Listar Enderecos
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
|
|
@ -149,7 +157,7 @@ const GestaoEnderecos = () => {
|
|||
: 'border-transparent text-gray-500 hover:text-gray-700 hover:border-gray-300 hover:bg-gray-50'
|
||||
}`}
|
||||
>
|
||||
<Plus className="inline-block w-4 h-4 mr-1" /> Cadastrar Endereço
|
||||
<Plus className="inline-block w-4 h-4 mr-1" /> Cadastrar Endereco
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
|
|
@ -191,4 +199,3 @@ const GestaoEnderecos = () => {
|
|||
};
|
||||
|
||||
export default GestaoEnderecos;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,14 @@
|
|||
import React, { useEffect, useState } from 'react';
|
||||
import { Models } from '@/lib/appwrite';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { EnderecoData } from '@/services/enderecoService';
|
||||
import { EnderecoDocument } from '@/types/legacyEntities';
|
||||
|
||||
interface EnderecoFormProps {
|
||||
onSubmit: (data: EnderecoData) => Promise<boolean>;
|
||||
onCancel?: () => void;
|
||||
initialData?: Models.Document | null;
|
||||
initialData?: EnderecoDocument | null;
|
||||
loading?: boolean;
|
||||
}
|
||||
|
||||
type EnderecoDocument = Models.Document & EnderecoData;
|
||||
|
||||
const buildEmptyEndereco = (): EnderecoData => ({
|
||||
titulo: '',
|
||||
cep: '',
|
||||
|
|
@ -42,19 +40,18 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
return;
|
||||
}
|
||||
|
||||
const document = initialData as EnderecoDocument;
|
||||
setFormData({
|
||||
titulo: document.titulo || '',
|
||||
cep: document.cep || '',
|
||||
logradouro: document.logradouro || '',
|
||||
bairro: document.bairro || '',
|
||||
numero: document.numero || '',
|
||||
complemento: document.complemento || '',
|
||||
cidade: document.cidade || '',
|
||||
estado: document.estado || '',
|
||||
pais: document.pais || '',
|
||||
latitude: Number(document.latitude) || 0,
|
||||
longitude: Number(document.longitude) || 0,
|
||||
titulo: initialData.titulo || '',
|
||||
cep: initialData.cep || '',
|
||||
logradouro: initialData.logradouro || '',
|
||||
bairro: initialData.bairro || '',
|
||||
numero: initialData.numero || '',
|
||||
complemento: initialData.complemento || '',
|
||||
cidade: initialData.cidade || '',
|
||||
estado: initialData.estado || '',
|
||||
pais: initialData.pais || '',
|
||||
latitude: Number(initialData.latitude) || 0,
|
||||
longitude: Number(initialData.longitude) || 0,
|
||||
});
|
||||
}, [initialData]);
|
||||
|
||||
|
|
@ -68,7 +65,7 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
try {
|
||||
const res = await fetch(`https://lernu-backend-dev.rede5.com.br/viacep/${digits}`);
|
||||
if (!res.ok) {
|
||||
throw new Error('CEP inválido');
|
||||
throw new Error('CEP invalido');
|
||||
}
|
||||
|
||||
const data = (await res.json()) as Partial<EnderecoData>;
|
||||
|
|
@ -83,7 +80,7 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
setCepError(null);
|
||||
} catch (error) {
|
||||
console.error('Erro ao buscar CEP:', error);
|
||||
setCepError('CEP não encontrado.');
|
||||
setCepError('CEP nao encontrado.');
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -98,7 +95,7 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
if (success) {
|
||||
setMessage({
|
||||
type: 'success',
|
||||
text: initialData ? 'Endereço atualizado com sucesso!' : 'Endereço cadastrado com sucesso!',
|
||||
text: initialData ? 'Endereco atualizado com sucesso!' : 'Endereco cadastrado com sucesso!',
|
||||
});
|
||||
|
||||
if (!initialData) {
|
||||
|
|
@ -111,7 +108,7 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
|
||||
setMessage({
|
||||
type: 'error',
|
||||
text: initialData ? 'Erro ao atualizar endereço' : 'Erro ao cadastrar endereço',
|
||||
text: initialData ? 'Erro ao atualizar endereco' : 'Erro ao cadastrar endereco',
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -149,10 +146,10 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
<div className="bg-white rounded-lg shadow-md p-6">
|
||||
<div className="mb-6">
|
||||
<h2 className="text-2xl font-bold text-gray-900 mb-2">
|
||||
{initialData ? 'Editar Endereço' : 'Novo Endereço'}
|
||||
{initialData ? 'Editar Endereco' : 'Novo Endereco'}
|
||||
</h2>
|
||||
<p className="text-gray-600">
|
||||
{initialData ? 'Atualize os dados do endereço.' : 'Cadastre um novo endereço na plataforma SaveInMed.'}
|
||||
{initialData ? 'Atualize os dados do endereco.' : 'Cadastre um novo endereco na plataforma SaveInMed.'}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -170,7 +167,7 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label htmlFor="titulo" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
TÃtulo *
|
||||
Titulo *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
|
|
@ -237,7 +234,7 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
</div>
|
||||
<div>
|
||||
<label htmlFor="numero" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
Número *
|
||||
Numero *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
|
|
@ -301,7 +298,7 @@ const EnderecoForm: React.FC<EnderecoFormProps> = ({
|
|||
</div>
|
||||
<div>
|
||||
<label htmlFor="pais" className="block text-sm font-medium text-gray-700 mb-2">
|
||||
PaÃs *
|
||||
Pais *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
import React from 'react';
|
||||
import { Models } from '@/lib/appwrite';
|
||||
import React from 'react';
|
||||
import SearchBar from './SearchBar';
|
||||
import RefreshButton from './RefreshButton';
|
||||
import ListHeader from './ListHeader';
|
||||
import DataTable, { Column } from './DataTable';
|
||||
import Pagination from './Pagination';
|
||||
import TableActions from './TableActions';
|
||||
import { EnderecoDocument } from '@/types/legacyEntities';
|
||||
|
||||
interface EnderecoListProps {
|
||||
enderecos: Models.Document[];
|
||||
enderecos: EnderecoDocument[];
|
||||
loading: boolean;
|
||||
isChangingPage?: boolean;
|
||||
error: string | null;
|
||||
totalEnderecos: number;
|
||||
currentPage: number;
|
||||
pageSize: number;
|
||||
onEdit: (endereco: Models.Document) => void;
|
||||
onEdit: (endereco: EnderecoDocument) => void;
|
||||
onDelete: (id: string) => Promise<boolean>;
|
||||
onRefresh: () => void;
|
||||
onPrevPage: () => void;
|
||||
|
|
@ -23,6 +23,14 @@ interface EnderecoListProps {
|
|||
onSearch: (termo: string) => void;
|
||||
}
|
||||
|
||||
const columns: Column<EnderecoDocument>[] = [
|
||||
{ key: 'titulo', header: 'Titulo' },
|
||||
{ key: 'cep', header: 'CEP' },
|
||||
{ key: 'cidade', header: 'Cidade' },
|
||||
{ key: 'estado', header: 'Estado' },
|
||||
{ key: 'pais', header: 'Pais' },
|
||||
];
|
||||
|
||||
const EnderecoList: React.FC<EnderecoListProps> = ({
|
||||
enderecos,
|
||||
loading,
|
||||
|
|
@ -36,7 +44,7 @@ const EnderecoList: React.FC<EnderecoListProps> = ({
|
|||
onRefresh,
|
||||
onPrevPage,
|
||||
onNextPage,
|
||||
onSearch
|
||||
onSearch,
|
||||
}) => {
|
||||
const totalPages = Math.ceil(totalEnderecos / pageSize);
|
||||
const startItem = (currentPage - 1) * pageSize + 1;
|
||||
|
|
@ -49,27 +57,19 @@ const EnderecoList: React.FC<EnderecoListProps> = ({
|
|||
};
|
||||
|
||||
const handleDelete = async (id: string) => {
|
||||
if (confirm('Tem certeza que deseja deletar este endereço?')) {
|
||||
if (confirm('Tem certeza que deseja deletar este endereco?')) {
|
||||
await onDelete(id);
|
||||
}
|
||||
};
|
||||
|
||||
const columns: Column<Models.Document>[] = [
|
||||
{ key: 'titulo', header: 'TÃtulo' },
|
||||
{ key: 'cep', header: 'CEP' },
|
||||
{ key: 'cidade', header: 'Cidade' },
|
||||
{ key: 'estado', header: 'Estado' },
|
||||
{ key: 'pais', header: 'PaÃs' },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="container mx-auto px-4 py-8">
|
||||
<ListHeader title="Lista de Endereços">
|
||||
<ListHeader title="Lista de Enderecos">
|
||||
<SearchBar
|
||||
value={search}
|
||||
onChange={setSearch}
|
||||
onSearch={handleSearch}
|
||||
placeholder="Buscar tÃtulo, CEP ou cidade"
|
||||
placeholder="Buscar titulo, CEP ou cidade"
|
||||
/>
|
||||
<RefreshButton onClick={onRefresh} loading={loading} />
|
||||
</ListHeader>
|
||||
|
|
@ -84,24 +84,24 @@ const EnderecoList: React.FC<EnderecoListProps> = ({
|
|||
<div className="bg-blue-50 border border-blue-200 rounded-md p-3 mb-4">
|
||||
<div className="flex items-center">
|
||||
<div className="animate-spin rounded-full h-4 w-4 border-b-2 border-blue-600 mr-2"></div>
|
||||
<span className="text-blue-800 text-sm">Carregando página...</span>
|
||||
<span className="text-blue-800 text-sm">Carregando pagina...</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{loading ? (
|
||||
<div className="flex justify-center items-center min-h-screen">
|
||||
<div className="text-lg">Carregando endereços...</div>
|
||||
<div className="text-lg">Carregando enderecos...</div>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={enderecos}
|
||||
actions={(end) => (
|
||||
actions={(endereco) => (
|
||||
<TableActions
|
||||
onEdit={() => onEdit(end)}
|
||||
onDelete={() => handleDelete(end.$id)}
|
||||
onEdit={() => onEdit(endereco)}
|
||||
onDelete={() => handleDelete(endereco.$id)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
@ -109,9 +109,9 @@ const EnderecoList: React.FC<EnderecoListProps> = ({
|
|||
<div className="mt-4 flex justify-between items-center">
|
||||
<div className="text-sm text-gray-600">
|
||||
{totalEnderecos > 0 ? (
|
||||
<>Mostrando {startItem} - {endItem} de {totalEnderecos} endereços</>
|
||||
<>Mostrando {startItem} - {endItem} de {totalEnderecos} enderecos</>
|
||||
) : (
|
||||
'Total de endereços: 0'
|
||||
'Total de enderecos: 0'
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,10 @@
|
|||
// @ts-nocheck
|
||||
import { useState, useCallback, useRef, useEffect } from 'react';
|
||||
import { Models } from '@/lib/appwrite';
|
||||
import { enderecoService, EnderecoData } from '@/services/enderecoService';
|
||||
import { EnderecoDocument } from '@/types/legacyEntities';
|
||||
export type { EnderecoData };
|
||||
|
||||
export interface UseEnderecosReturn {
|
||||
enderecos: Models.Document[];
|
||||
enderecos: EnderecoDocument[];
|
||||
loading: boolean;
|
||||
isChangingPage: boolean;
|
||||
isCreating: boolean;
|
||||
|
|
@ -25,7 +24,7 @@ export interface UseEnderecosReturn {
|
|||
const PAGE_SIZE = 10;
|
||||
|
||||
export const useEnderecos = (): UseEnderecosReturn => {
|
||||
const [enderecos, setEnderecos] = useState<Models.Document[]>([]);
|
||||
const [enderecos, setEnderecos] = useState<EnderecoDocument[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [totalEnderecos, setTotalEnderecos] = useState(0);
|
||||
|
|
@ -35,8 +34,7 @@ export const useEnderecos = (): UseEnderecosReturn => {
|
|||
const [searchTerm, setSearchTerm] = useState('');
|
||||
const isInitialMount = useRef(true);
|
||||
|
||||
const listarEnderecos = useCallback(
|
||||
async (page = currentPage, search = searchTerm) => {
|
||||
const listarEnderecos = useCallback(async (page = currentPage, search = searchTerm) => {
|
||||
setIsChangingPage(true);
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
|
@ -47,51 +45,46 @@ export const useEnderecos = (): UseEnderecosReturn => {
|
|||
: await enderecoService.listar(page, PAGE_SIZE);
|
||||
|
||||
if (response.success) {
|
||||
setEnderecos(response.documents || []);
|
||||
setEnderecos((response.documents || []) as EnderecoDocument[]);
|
||||
setTotalEnderecos(response.total || 0);
|
||||
setCurrentPage(page);
|
||||
setSearchTerm(search);
|
||||
} else {
|
||||
setError(response.error || 'Erro ao carregar endereços');
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
setError('Erro de conexão ao carregar endereços');
|
||||
|
||||
setError(response.error || 'Erro ao carregar enderecos');
|
||||
} catch {
|
||||
setError('Erro de conexao ao carregar enderecos');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setIsChangingPage(false);
|
||||
}
|
||||
}, [currentPage, searchTerm]);
|
||||
|
||||
const buscarEnderecos = useCallback(
|
||||
async (termo: string, page = 1) => {
|
||||
const buscarEnderecos = useCallback(async (termo: string, page = 1) => {
|
||||
setIsChangingPage(true);
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
|
||||
try {
|
||||
const response = await enderecoService.buscar(
|
||||
termo,
|
||||
page,
|
||||
PAGE_SIZE
|
||||
);
|
||||
const response = await enderecoService.buscar(termo, page, PAGE_SIZE);
|
||||
|
||||
if (response.success) {
|
||||
setEnderecos(response.documents || []);
|
||||
setEnderecos((response.documents || []) as EnderecoDocument[]);
|
||||
setTotalEnderecos(response.total || 0);
|
||||
setCurrentPage(page);
|
||||
setSearchTerm(termo);
|
||||
} else {
|
||||
setError(response.error || 'Erro ao buscar enderecos');
|
||||
return;
|
||||
}
|
||||
} catch (err) {
|
||||
setError('Erro de conexão ao buscar enderecos');
|
||||
|
||||
setError(response.error || 'Erro ao buscar enderecos');
|
||||
} catch {
|
||||
setError('Erro de conexao ao buscar enderecos');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
setIsChangingPage(false);
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
}, []);
|
||||
|
||||
const cadastrarEndereco = useCallback(async (formData: EnderecoData): Promise<boolean> => {
|
||||
setIsCreating(true);
|
||||
|
|
@ -103,12 +96,12 @@ export const useEnderecos = (): UseEnderecosReturn => {
|
|||
if (response.success) {
|
||||
await listarEnderecos(1, searchTerm);
|
||||
return true;
|
||||
} else {
|
||||
setError(response.error || 'Erro ao cadastrar endereço');
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
setError('Erro de conexão ao cadastrar endereço');
|
||||
|
||||
setError(response.error || 'Erro ao cadastrar endereco');
|
||||
return false;
|
||||
} catch {
|
||||
setError('Erro de conexao ao cadastrar endereco');
|
||||
return false;
|
||||
} finally {
|
||||
setIsCreating(false);
|
||||
|
|
@ -125,17 +118,17 @@ export const useEnderecos = (): UseEnderecosReturn => {
|
|||
if (response.success) {
|
||||
await listarEnderecos(currentPage, searchTerm);
|
||||
return true;
|
||||
} else {
|
||||
setError(response.error || 'Erro ao atualizar endereço');
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
setError('Erro de conexão ao atualizar endereço');
|
||||
|
||||
setError(response.error || 'Erro ao atualizar endereco');
|
||||
return false;
|
||||
} catch {
|
||||
setError('Erro de conexao ao atualizar endereco');
|
||||
return false;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [currentPage, listarEnderecos]);
|
||||
}, [currentPage, listarEnderecos, searchTerm]);
|
||||
|
||||
const deletarEndereco = useCallback(async (id: string): Promise<boolean> => {
|
||||
setLoading(true);
|
||||
|
|
@ -147,17 +140,17 @@ export const useEnderecos = (): UseEnderecosReturn => {
|
|||
if (response.success) {
|
||||
await listarEnderecos(currentPage, searchTerm);
|
||||
return true;
|
||||
} else {
|
||||
setError(response.error || 'Erro ao deletar endereço');
|
||||
return false;
|
||||
}
|
||||
} catch (err) {
|
||||
setError('Erro de conexão ao deletar endereço');
|
||||
|
||||
setError(response.error || 'Erro ao deletar endereco');
|
||||
return false;
|
||||
} catch {
|
||||
setError('Erro de conexao ao deletar endereco');
|
||||
return false;
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [currentPage, listarEnderecos]);
|
||||
}, [currentPage, listarEnderecos, searchTerm]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isInitialMount.current) {
|
||||
|
|
@ -167,9 +160,10 @@ export const useEnderecos = (): UseEnderecosReturn => {
|
|||
|
||||
if (searchTerm.trim()) {
|
||||
buscarEnderecos(searchTerm, currentPage);
|
||||
} else {
|
||||
listarEnderecos(currentPage);
|
||||
return;
|
||||
}
|
||||
|
||||
listarEnderecos(currentPage);
|
||||
}, [currentPage, searchTerm, listarEnderecos, buscarEnderecos]);
|
||||
|
||||
return {
|
||||
|
|
@ -190,4 +184,3 @@ export const useEnderecos = (): UseEnderecosReturn => {
|
|||
setSearchTerm,
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,21 @@ export interface CarrinhoDocument extends LegacyDocument {
|
|||
quantidades?: number[] | number;
|
||||
}
|
||||
|
||||
export interface EnderecoDocument extends LegacyDocument {
|
||||
titulo?: string;
|
||||
cep?: string;
|
||||
logradouro?: string;
|
||||
bairro?: string;
|
||||
numero?: string;
|
||||
complemento?: string;
|
||||
cidade?: string;
|
||||
estado?: string;
|
||||
pais?: string;
|
||||
latitude?: number;
|
||||
longitude?: number;
|
||||
principal?: boolean;
|
||||
}
|
||||
|
||||
export interface ServiceResponse<TDocument> {
|
||||
success: boolean;
|
||||
data?: TDocument | null;
|
||||
|
|
|
|||
Loading…
Reference in a new issue