diff --git a/backend-old/internal/domain/models.go b/backend-old/internal/domain/models.go
index 293d018..58df818 100644
--- a/backend-old/internal/domain/models.go
+++ b/backend-old/internal/domain/models.go
@@ -54,6 +54,9 @@ type User struct {
Email string `db:"email" json:"email"`
EmailVerified bool `db:"email_verified" json:"email_verified"`
PasswordHash string `db:"password_hash" json:"-"`
+ Superadmin bool `db:"superadmin" json:"superadmin"`
+ NomeSocial string `db:"nome_social" json:"nome_social"`
+ CPF string `db:"cpf" json:"cpf"`
CreatedAt time.Time `db:"created_at" json:"created_at"`
UpdatedAt time.Time `db:"updated_at" json:"updated_at"`
}
diff --git a/backend-old/internal/http/handler/dto.go b/backend-old/internal/http/handler/dto.go
index 9f8f24e..b7464d1 100644
--- a/backend-old/internal/http/handler/dto.go
+++ b/backend-old/internal/http/handler/dto.go
@@ -16,12 +16,15 @@ import (
// --- Request DTOs ---
type createUserRequest struct {
- CompanyID uuid.UUID `json:"company_id"`
- Role string `json:"role"`
- Name string `json:"name"`
- Username string `json:"username"`
- Email string `json:"email"`
- Password string `json:"password"`
+ CompanyID uuid.UUID `json:"company_id"`
+ Role string `json:"role"`
+ Name string `json:"name"`
+ Username string `json:"username"`
+ Email string `json:"email"`
+ Password string `json:"password"`
+ Superadmin bool `json:"superadmin"`
+ NomeSocial string `json:"nome-social"`
+ CPF string `json:"cpf"`
}
type registerAuthRequest struct {
diff --git a/backend-old/internal/http/handler/handler_test.go b/backend-old/internal/http/handler/handler_test.go
index 402b6bc..713d337 100644
--- a/backend-old/internal/http/handler/handler_test.go
+++ b/backend-old/internal/http/handler/handler_test.go
@@ -170,6 +170,10 @@ func (m *MockRepository) CreateInventoryItem(ctx context.Context, item *domain.I
return nil
}
+func (m *MockRepository) UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error {
+ return nil
+}
+
func (m *MockRepository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error) {
return []domain.InventoryItem{}, 0, nil
}
diff --git a/backend-old/internal/http/handler/product_handler.go b/backend-old/internal/http/handler/product_handler.go
index 9542e00..9b0993b 100644
--- a/backend-old/internal/http/handler/product_handler.go
+++ b/backend-old/internal/http/handler/product_handler.go
@@ -431,14 +431,59 @@ func (h *Handler) GetProductByEAN(w http.ResponseWriter, r *http.Request) {
}
type registerInventoryRequest struct {
- ProductID string `json:"product_id"`
- SellerID string `json:"seller_id"`
- SalePriceCents int64 `json:"sale_price_cents"`
- OriginalPriceCents int64 `json:"original_price_cents"` // Added to fix backend error
- FinalPriceCents int64 `json:"final_price_cents"` // Optional explicit field
- StockQuantity int64 `json:"stock_quantity"`
- ExpiresAt string `json:"expires_at"` // ISO8601
- Observations string `json:"observations"`
+ ProductID string `json:"product_id"`
+ SellerID string `json:"seller_id"`
+ SalePriceCents int64 `json:"sale_price_cents"`
+ StockQuantity int64 `json:"stock_quantity"`
+ ExpiresAt string `json:"expires_at"` // ISO8601
+ Observations string `json:"observations"`
+}
+
+type updateInventoryRequest struct {
+ StockQuantity int64 `json:"qtdade_estoque"`
+ SalePrice float64 `json:"preco_venda"`
+}
+
+// UpdateInventoryItem updates price and stock for an existing inventory item.
+func (h *Handler) UpdateInventoryItem(w http.ResponseWriter, r *http.Request) {
+ // Parse ID from path
+ idStr := r.PathValue("id")
+ if idStr == "" {
+ parts := splitPath(r.URL.Path)
+ if len(parts) > 0 {
+ idStr = parts[len(parts)-1]
+ }
+ }
+ if idStr == "" {
+ writeError(w, http.StatusBadRequest, errors.New("id is required"))
+ return
+ }
+ itemID, err := uuid.FromString(idStr)
+ if err != nil {
+ writeError(w, http.StatusBadRequest, errors.New("invalid id format"))
+ return
+ }
+
+ var req updateInventoryRequest
+ if err := decodeJSON(r.Context(), r, &req); err != nil {
+ writeError(w, http.StatusBadRequest, err)
+ return
+ }
+
+ claims, ok := middleware.GetClaims(r.Context())
+ if !ok || claims.CompanyID == nil {
+ writeError(w, http.StatusUnauthorized, errors.New("unauthorized"))
+ return
+ }
+
+ priceCents := int64(req.SalePrice * 100)
+ err = h.svc.UpdateInventoryItem(r.Context(), itemID, *claims.CompanyID, priceCents, req.StockQuantity)
+ if err != nil {
+ writeError(w, http.StatusInternalServerError, err)
+ return
+ }
+
+ writeJSON(w, http.StatusOK, map[string]string{"status": "updated"})
}
// CreateInventoryItem godoc
@@ -479,11 +524,8 @@ func (h *Handler) CreateInventoryItem(w http.ResponseWriter, r *http.Request) {
}
}
- // Logic: Use FinalPriceCents if provided, else SalePriceCents
+ // Logic: Use SalePriceCents
finalPrice := req.SalePriceCents
- if req.FinalPriceCents > 0 {
- finalPrice = req.FinalPriceCents
- }
item := &domain.InventoryItem{
ProductID: prodID,
diff --git a/backend-old/internal/http/handler/user_handler.go b/backend-old/internal/http/handler/user_handler.go
index a6a060f..3f80c9c 100644
--- a/backend-old/internal/http/handler/user_handler.go
+++ b/backend-old/internal/http/handler/user_handler.go
@@ -45,12 +45,23 @@ func (h *Handler) CreateUser(w http.ResponseWriter, r *http.Request) {
}
}
+ // Only Superadmin can create another Superadmin
+ if req.Superadmin {
+ if !strings.EqualFold(requester.Role, "super_admin") && !strings.EqualFold(requester.Role, "superadmin") { // Allow both variations just in case
+ writeError(w, http.StatusForbidden, errors.New("only superadmins can create superadmins"))
+ return
+ }
+ }
+
user := &domain.User{
- CompanyID: req.CompanyID,
- Role: req.Role,
- Name: req.Name,
- Username: req.Username,
- Email: req.Email,
+ CompanyID: req.CompanyID,
+ Role: req.Role,
+ Name: req.Name,
+ Username: req.Username,
+ Email: req.Email,
+ Superadmin: req.Superadmin,
+ NomeSocial: req.NomeSocial,
+ CPF: req.CPF,
}
if err := h.svc.CreateUser(r.Context(), user, req.Password); err != nil {
diff --git a/backend-old/internal/repository/postgres/migrations/0014_add_superadmin_fields.sql b/backend-old/internal/repository/postgres/migrations/0014_add_superadmin_fields.sql
new file mode 100644
index 0000000..8f18ca6
--- /dev/null
+++ b/backend-old/internal/repository/postgres/migrations/0014_add_superadmin_fields.sql
@@ -0,0 +1,3 @@
+ALTER TABLE users ADD COLUMN IF NOT EXISTS superadmin BOOLEAN NOT NULL DEFAULT FALSE;
+ALTER TABLE users ADD COLUMN IF NOT EXISTS nome_social TEXT;
+ALTER TABLE users ADD COLUMN IF NOT EXISTS cpf TEXT;
diff --git a/backend-old/internal/repository/postgres/postgres.go b/backend-old/internal/repository/postgres/postgres.go
index 3e7d263..baf2413 100644
--- a/backend-old/internal/repository/postgres/postgres.go
+++ b/backend-old/internal/repository/postgres/postgres.go
@@ -854,8 +854,8 @@ func (r *Repository) CreateUser(ctx context.Context, user *domain.User) error {
user.CreatedAt = now
user.UpdatedAt = now
- query := `INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, created_at, updated_at)
-VALUES (:id, :company_id, :role, :name, :username, :email, :email_verified, :password_hash, :created_at, :updated_at)`
+ query := `INSERT INTO users (id, company_id, role, name, username, email, email_verified, password_hash, superadmin, nome_social, cpf, created_at, updated_at)
+VALUES (:id, :company_id, :role, :name, :username, :email, :email_verified, :password_hash, :superadmin, :nome_social, :cpf, :created_at, :updated_at)`
_, err := r.db.NamedExecContext(ctx, query, user)
return err
@@ -1383,97 +1383,9 @@ func (r *Repository) CreateInventoryItem(ctx context.Context, item *domain.Inven
return err
}
-// ReplaceCart clears the cart and adds new items in a transaction.
-func (r *Repository) ReplaceCart(ctx context.Context, buyerID uuid.UUID, items []domain.CartItem) error {
- tx, err := r.db.BeginTxx(ctx, nil)
- if err != nil {
- return err
- }
- defer tx.Rollback()
-
- // 1. Clear Cart
- if _, err := tx.ExecContext(ctx, "DELETE FROM cart_items WHERE buyer_id = $1", buyerID); err != nil {
- return err
- }
-
- // 2. Add Items
- query := `INSERT INTO cart_items (id, buyer_id, product_id, quantity, unit_cents, batch, expires_at, created_at, updated_at)
-VALUES (:id, :buyer_id, :product_id, :quantity, :unit_cents, :batch, :expires_at, :created_at, :updated_at)`
-
- for _, item := range items {
- // Ensure IDs
- if item.ID == uuid.Nil {
- item.ID = uuid.Must(uuid.NewV7())
- }
- item.CreatedAt = time.Now().UTC()
- item.UpdatedAt = time.Now().UTC()
-
- if _, err := tx.NamedExecContext(ctx, query, item); err != nil {
- return err
- }
- }
-
- return tx.Commit()
-}
-
-// UpdateOrderItems replaces order items and updates total, handling stock accordingly.
-func (r *Repository) UpdateOrderItems(ctx context.Context, orderID uuid.UUID, items []domain.OrderItem, totalCents int64) error {
- tx, err := r.db.BeginTxx(ctx, nil)
- if err != nil {
- return err
- }
- defer tx.Rollback()
-
- // 1. Fetch existing items to restore stock
- var oldItems []domain.OrderItem
- if err := tx.SelectContext(ctx, &oldItems, "SELECT product_id, quantity FROM order_items WHERE order_id = $1", orderID); err != nil {
- return err
- }
-
- // 2. Restore stock for old items
- for _, item := range oldItems {
- if _, err := tx.ExecContext(ctx, "UPDATE products SET stock = stock + $1, updated_at = $2 WHERE id = $3", item.Quantity, time.Now().UTC(), item.ProductID); err != nil {
- return err
- }
- }
-
- // 3. Delete existing items
- if _, err := tx.ExecContext(ctx, "DELETE FROM order_items WHERE order_id = $1", orderID); err != nil {
- return err
- }
-
- // 4. Insert new items and consume stock
- itemQuery := `INSERT INTO order_items (id, order_id, product_id, quantity, unit_cents, batch, expires_at)
-VALUES (:id, :order_id, :product_id, :quantity, :unit_cents, :batch, :expires_at)`
-
- now := time.Now().UTC()
- for _, item := range items {
- if item.ID == uuid.Nil {
- item.ID = uuid.Must(uuid.NewV7())
- }
- item.OrderID = orderID
- if _, err := tx.NamedExecContext(ctx, itemQuery, item); err != nil {
- return err
- }
-
- // Reduce stock
- res, err := tx.ExecContext(ctx, `UPDATE products SET stock = stock - $1, updated_at = $2 WHERE id = $3 AND stock >= $1`, item.Quantity, now, item.ProductID)
- if err != nil {
- return err
- }
- rows, err := res.RowsAffected()
- if err != nil {
- return err
- }
- if rows == 0 {
- return fmt.Errorf("insufficient stock for product %s", item.ProductID)
- }
- }
-
- // 5. Update Order Total
- if _, err := tx.ExecContext(ctx, "UPDATE orders SET total_cents = $1, updated_at = $2 WHERE id = $3", totalCents, now, orderID); err != nil {
- return err
- }
-
- return tx.Commit()
+func (r *Repository) UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error {
+ query := `UPDATE inventory_items SET sale_price_cents = :sale_price_cents, stock_quantity = :stock_quantity, updated_at = :updated_at WHERE id = :id AND seller_id = :seller_id`
+ item.UpdatedAt = time.Now().UTC()
+ _, err := r.db.NamedExecContext(ctx, query, item)
+ return err
}
diff --git a/backend-old/internal/server/server.go b/backend-old/internal/server/server.go
index 970e8d2..aa862df 100644
--- a/backend-old/internal/server/server.go
+++ b/backend-old/internal/server/server.go
@@ -109,8 +109,8 @@ func New(cfg config.Config) (*Server, error) {
mux.Handle("GET /api/v1/inventory", chain(http.HandlerFunc(h.ListInventory), middleware.Logger, middleware.Gzip, auth))
mux.Handle("POST /api/v1/inventory", chain(http.HandlerFunc(h.CreateInventoryItem), middleware.Logger, middleware.Gzip, auth))
mux.Handle("POST /api/v1/produtos-venda", chain(http.HandlerFunc(h.CreateInventoryItem), middleware.Logger, middleware.Gzip, auth)) // Alias
- mux.Handle("PUT /api/v1/produtos-venda/{id}", chain(http.HandlerFunc(h.UpdateInventoryItem), middleware.Logger, middleware.Gzip, auth)) // Correct Handler
mux.Handle("GET /api/v1/produtos-venda", chain(http.HandlerFunc(h.ListInventory), middleware.Logger, middleware.Gzip, auth)) // Alias for list
+ mux.Handle("PUT /api/v1/produtos-venda/{id}", chain(http.HandlerFunc(h.UpdateInventoryItem), middleware.Logger, middleware.Gzip, auth)) // Update inventory
mux.Handle("POST /api/v1/inventory/adjust", chain(http.HandlerFunc(h.AdjustInventory), middleware.Logger, middleware.Gzip, auth))
mux.Handle("POST /api/v1/orders", chain(http.HandlerFunc(h.CreateOrder), middleware.Logger, middleware.Gzip, auth))
diff --git a/backend-old/internal/usecase/product_service.go b/backend-old/internal/usecase/product_service.go
index 8cb356c..9163983 100644
--- a/backend-old/internal/usecase/product_service.go
+++ b/backend-old/internal/usecase/product_service.go
@@ -129,10 +129,14 @@ func (s *Service) RegisterInventoryItem(ctx context.Context, item *domain.Invent
return s.repo.CreateInventoryItem(ctx, item)
}
-func (s *Service) GetInventoryItem(ctx context.Context, id uuid.UUID) (*domain.InventoryItem, error) {
- return s.repo.GetInventoryItem(ctx, id)
-}
-
-func (s *Service) UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error {
+func (s *Service) UpdateInventoryItem(ctx context.Context, itemID uuid.UUID, sellerID uuid.UUID, priceCents int64, stockQuantity int64) error {
+ // We construct a partial item just for update
+ item := &domain.InventoryItem{
+ ID: itemID,
+ SellerID: sellerID,
+ SalePriceCents: priceCents,
+ StockQuantity: stockQuantity,
+ }
+ // Future improvement: check if item exists and belongs to seller first, strict validation
return s.repo.UpdateInventoryItem(ctx, item)
}
diff --git a/backend-old/internal/usecase/usecase.go b/backend-old/internal/usecase/usecase.go
index 111045a..b56e86e 100644
--- a/backend-old/internal/usecase/usecase.go
+++ b/backend-old/internal/usecase/usecase.go
@@ -36,7 +36,6 @@ type Repository interface {
AdjustInventory(ctx context.Context, productID uuid.UUID, delta int64, reason string) (*domain.InventoryItem, error)
ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error)
CreateInventoryItem(ctx context.Context, item *domain.InventoryItem) error
- GetInventoryItem(ctx context.Context, id uuid.UUID) (*domain.InventoryItem, error)
UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error
CreateOrder(ctx context.Context, order *domain.Order) error
diff --git a/backend-old/internal/usecase/usecase_test.go b/backend-old/internal/usecase/usecase_test.go
index a7ab474..adfd1e6 100644
--- a/backend-old/internal/usecase/usecase_test.go
+++ b/backend-old/internal/usecase/usecase_test.go
@@ -183,6 +183,9 @@ func (m *MockRepository) AdjustInventory(ctx context.Context, productID uuid.UUI
func (m *MockRepository) CreateInventoryItem(ctx context.Context, item *domain.InventoryItem) error {
return nil
}
+func (m *MockRepository) UpdateInventoryItem(ctx context.Context, item *domain.InventoryItem) error {
+ return nil
+}
func (m *MockRepository) ListInventory(ctx context.Context, filter domain.InventoryFilter) ([]domain.InventoryItem, int64, error) {
return nil, 0, nil
}
diff --git a/saveinmed-frontend/src/app/dashboard/components/CadastroSuperadminModal.tsx b/saveinmed-frontend/src/app/dashboard/components/CadastroSuperadminModal.tsx
index 0d0a0ae..6f33fc6 100644
--- a/saveinmed-frontend/src/app/dashboard/components/CadastroSuperadminModal.tsx
+++ b/saveinmed-frontend/src/app/dashboard/components/CadastroSuperadminModal.tsx
@@ -1,12 +1,13 @@
"use client";
import { useState } from "react";
-import { X, AlertCircle, CheckCircle, Loader } from "lucide-react";
+import { X, AlertCircle, CheckCircle, Loader, Eye, EyeOff } from "lucide-react";
interface CadastroSuperadminModalProps {
isOpen: boolean;
onClose: () => void;
onSuccess?: () => void;
+ currentCompanyId?: string;
}
// Funções de máscara
@@ -31,10 +32,14 @@ export default function CadastroSuperadminModal({
isOpen,
onClose,
onSuccess,
+ currentCompanyId,
}: CadastroSuperadminModalProps) {
const [loading, setLoading] = useState(false);
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);
+
+ const [showPassword, setShowPassword] = useState(false);
+ const [showConfirmPassword, setShowConfirmPassword] = useState(false);
const [formData, setFormData] = useState({
nome: "",
@@ -117,24 +122,22 @@ export default function CadastroSuperadminModal({
const telefoneLimpo = formData.telefone.replace(/\D/g, "");
const payload = {
- identificador: formData.email,
- nome: formData.nome,
+ name: formData.nome,
+ username: formData.email,
email: formData.email,
- telefone: telefoneLimpo || null,
- senha: formData.senha,
+ password: formData.senha,
cpf: cpfLimpo,
- ativo: true,
superadmin: true,
- nivel: "admin",
- "registro-completo": true,
+ role: "superadmin",
"nome-social": formData.nomeSocial || null,
+ company_id: currentCompanyId || "00000000-0000-0000-0000-000000000000", // Fallback if no company provided, though might fail if foreign key invalid
};
// Obter token do localStorage para enviar autorização
const token = localStorage.getItem('access_token');
const response = await fetch(
- `${process.env.NEXT_PUBLIC_BFF_API_URL}/usuarios`,
+ `${process.env.NEXT_PUBLIC_BFF_API_URL}/users`,
{
method: "POST",
headers: {
@@ -168,6 +171,7 @@ export default function CadastroSuperadminModal({
const errorData = await response.json().catch(() => ({}));
setError(
errorData.message ||
+ errorData.error ||
`Erro ao criar superadmin (${response.status})`
);
}
@@ -308,15 +312,28 @@ export default function CadastroSuperadminModal({
-
+
+
+
+
{/* Confirmar Senha */}
@@ -324,15 +341,28 @@ export default function CadastroSuperadminModal({
-
+
+
+
+
{/* Botões */}
diff --git a/saveinmed-frontend/src/app/dashboard/page.tsx b/saveinmed-frontend/src/app/dashboard/page.tsx
index 25ec7b3..bffb99c 100644
--- a/saveinmed-frontend/src/app/dashboard/page.tsx
+++ b/saveinmed-frontend/src/app/dashboard/page.tsx
@@ -825,6 +825,7 @@ const Dashboard = () => {
onSuccess={() => {
setShowCadastroSuperadminModal(false);
}}
+ currentCompanyId={userData?.company_id || empresaId}
/>
);
diff --git a/saveinmed-frontend/src/app/usuarios-pendentes/page.tsx b/saveinmed-frontend/src/app/usuarios-pendentes/page.tsx
index 700111a..808b6ed 100644
--- a/saveinmed-frontend/src/app/usuarios-pendentes/page.tsx
+++ b/saveinmed-frontend/src/app/usuarios-pendentes/page.tsx
@@ -4,14 +4,29 @@ import { useEffect, useState } from "react";
import { EmpresaBff, empresaApiService } from "@/services/empresaApiService";
import { useRouter } from "next/navigation";
import Header from "@/components/Header";
-import { CheckCircleIcon, XCircleIcon, BuildingOfficeIcon } from "@heroicons/react/24/outline";
+import {
+ CheckCircleIcon,
+ XCircleIcon,
+ BuildingOfficeIcon,
+ MagnifyingGlassIcon,
+ ArrowPathIcon,
+ UserGroupIcon,
+ CalendarIcon,
+ EnvelopeIcon,
+ PhoneIcon,
+ IdentificationIcon,
+ ClockIcon
+} from "@heroicons/react/24/outline";
export default function UsuariosPendentesPage() {
const router = useRouter();
const [empresas, setEmpresas] = useState([]);
+ const [filteredEmpresas, setFilteredEmpresas] = useState([]);
const [loading, setLoading] = useState(true);
const [userData, setUserData] = useState(null);
const [error, setError] = useState("");
+ const [search, setSearch] = useState("");
+ const [approvingId, setApprovingId] = useState(null);
const fetchUserData = async () => {
try {
@@ -48,6 +63,7 @@ export default function UsuariosPendentesPage() {
try {
const data = await empresaApiService.listar({ is_verified: false });
setEmpresas(data);
+ setFilteredEmpresas(data);
} catch (err) {
console.error(err);
setError("Erro ao carregar usuários pendentes.");
@@ -61,8 +77,25 @@ export default function UsuariosPendentesPage() {
fetchPendentes();
}, []);
+ useEffect(() => {
+ if (!search.trim()) {
+ setFilteredEmpresas(empresas);
+ return;
+ }
+ const term = search.toLowerCase();
+ const filtered = empresas.filter(e =>
+ (e.razao_social || "").toLowerCase().includes(term) ||
+ (e.nome_fantasia || "").toLowerCase().includes(term) ||
+ (e.cnpj || "").includes(term) ||
+ (e.email || "").toLowerCase().includes(term)
+ );
+ setFilteredEmpresas(filtered);
+ }, [search, empresas]);
+
const handleAprovar = async (companyId: string) => {
if (!confirm("Tem certeza que deseja aprovar este cadastro?")) return;
+
+ setApprovingId(companyId);
try {
const sucesso = await empresaApiService.atualizar(companyId, {
@@ -70,17 +103,25 @@ export default function UsuariosPendentesPage() {
} as any);
if (sucesso) {
+ // Remove from list without full reload for better UX
+ setEmpresas(prev => prev.filter(e => e.id !== companyId));
alert("Cadastro aprovado com sucesso!");
- fetchPendentes();
} else {
alert("Erro ao aprovar cadastro.");
}
} catch (err) {
console.error(err);
alert("Erro ao processar aprovação.");
+ } finally {
+ setApprovingId(null);
}
};
+ const formatarData = (dataString?: string) => {
+ if (!dataString) return "N/A";
+ return new Date(dataString).toLocaleDateString('pt-BR');
+ };
+
if (!userData && loading) {
return (
@@ -103,6 +144,38 @@ export default function UsuariosPendentesPage() {
+ {/* Filtros e Busca */}
+
+
+
+
+
+
+
+
+
setSearch(e.target.value)}
+ className="block w-full pl-10 pr-3 py-2 border border-gray-300 rounded-md leading-5 bg-white placeholder-gray-500 focus:outline-none focus:placeholder-gray-400 focus:ring-1 focus:ring-blue-500 focus:border-blue-500"
+ placeholder="Razão Social, CNPJ ou Email..."
+ />
+
+
+
+
+
+
{error && (
@@ -114,59 +187,158 @@ export default function UsuariosPendentesPage() {
)}
- {loading ? (
-
-
-
Carregando solicitações...
+ {/* Stats Cards */}
+
+
+
+
+
+
+
+
+
+ - Total Pendentes
+ - {empresas.length}
+
+
+
+
- ) : empresas.length === 0 ? (
-
-
-
Nenhum cadastro pendente
-
Todas as solicitações foram processadas.
+
+
+
+
+
+
+
+
+ - Data Hoje
+ - {new Date().toLocaleDateString('pt-BR')}
+
+
+
+
- ) : (
-
- {empresas.map((empresa) => (
-
-
-
-
-
-
- {empresa.razao_social || empresa.nome_fantasia || "Sem Nome"}
-
-
- Pendente
-
-
-
-
-
CNPJ: {empresa.cnpj}
-
Email: {empresa.email}
-
Telefone: {empresa.telefone}
-
ID: {empresa.id}
-
-
+ {/* Placeholder for more stats if needed */}
+
-
-
-
+ {/* Lista */}
+
+
+
+ Solicitações ({filteredEmpresas.length})
+
+
+ {loading ? (
+
+
+
Carregando solicitações...
-
-
- ))}
-
- )}
+ ) : filteredEmpresas.length === 0 ? (
+
+
+
Nenhum cadastro encontrado
+
+ {search ? "Nenhum resultado para sua busca." : "Todas as solicitações foram processadas."}
+
+
+ ) : (
+
+ {filteredEmpresas.map((empresa) => (
+
+
+
+
+
+
+
+ {empresa.razao_social || empresa.nome_fantasia || "Sem Nome"}
+
+
+ Pendente
+
+
+
+ ID: {empresa.id}
+
+
+
+
+
+
+
+
+
+
+
+
+
CNPJ
+
{empresa.cnpj}
+
+
+
+
+
+
Email
+
{empresa.email}
+
+
+
+
+
+
Telefone
+
{empresa.telefone || "N/A"}
+
+
+
+
+
+
Data Cadastro
+
{formatarData(empresa.created_at)}
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+ )}
+
+
);
diff --git a/saveinmed-frontend/src/services/empresaApiService.ts b/saveinmed-frontend/src/services/empresaApiService.ts
index 28407fd..1b721fc 100644
--- a/saveinmed-frontend/src/services/empresaApiService.ts
+++ b/saveinmed-frontend/src/services/empresaApiService.ts
@@ -21,6 +21,8 @@ export interface EmpresaBff {
estado: string;
latitude?: string;
longitude?: string;
+ created_at?: string;
+ category?: string;
}
export const empresaApiService = {
@@ -97,6 +99,9 @@ export const empresaApiService = {
...item,
razao_social: item.corporate_name || item.razao_social, // Fallback
nome_fantasia: item.trade_name || item.nome_fantasia || "",
+ telefone: item.phone || item.telefone || "N/A",
+ created_at: item.created_at,
+ category: item.category,
}));
} catch (error) {
console.error('❌ Erro ao listar empresas:', error);