mirror of
https://github.com/melgarafael/DeskcommCRM.git
synced 2026-10-02 01:28:34 +08:00
O CHECK de lgpd_requests aceita 'data_request' | 'redact' | 'store_redact'. A UI, as rotas, os webhooks da Nuvemshop e os workers usavam 'customer_data_request' | 'customer_redact' — palavras que o banco REJEITA. Provado com insert lado a lado: o vocabulário da UI viola a constraint, o do banco entra. O estrago era maior que o rótulo errado na tela: - criar pedido pelos caminhos que usam esse vocabulário estourava no INSERT (inclui os webhooks da Nuvemshop, que são obrigação de plataforma); - o filtro por tipo na tela nunca casava com nenhuma linha; - e os WORKERS descartavam pedido legítimo com "wrong_request_type" — o redact-worker aceitava store_redact e recusava 'redact', que é o caso comum (anonimizar um cliente). O banco tem uma linha 'redact' parada aí. Havia TRÊS declarações do tipo (lib/lgpd/types.ts, hooks/useLgpdRequests, hooks/useAdminLGPDRequests), todas com o vocabulário errado — três lugares para divergir. Agora os hooks reexportam o tipo canônico, e o rótulo em pt-BR sai de LGPD_REQUEST_TYPE_LABELS na mesma fonte, em vez de cinco mapas locais. typecheck 0, lint 0 errors, 848 unitários. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013dxBNZMjUzBx8xWs8DvGvP
70 lines
2.5 KiB
TypeScript
70 lines
2.5 KiB
TypeScript
"use client";
|
|
import { useInfiniteQuery } from "@tanstack/react-query";
|
|
import { apiClient } from "@/lib/api/client";
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Types
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export type AdminLgpdRiskLevel = "expired" | "at_risk" | "warning" | "ok";
|
|
export type AdminLgpdStatus = "received" | "processing" | "completed" | "failed" | "pending_review";
|
|
// Alias do tipo canônico (lib/lgpd/types.ts): o admin e o app falam o MESMO
|
|
// vocabulário do banco. Duas listas era como uma podia divergir sozinha.
|
|
import type { LgpdRequestType } from "@/lib/lgpd/types";
|
|
export type AdminLgpdRequestType = LgpdRequestType;
|
|
|
|
export interface AdminLgpdRequest {
|
|
id: string;
|
|
organization_id: string;
|
|
request_type: AdminLgpdRequestType;
|
|
status: AdminLgpdStatus;
|
|
received_at: string;
|
|
due_at: string | null;
|
|
completed_at: string | null;
|
|
contact_id: string | null;
|
|
external_customer_id: string | null;
|
|
attempts: number;
|
|
emergency: boolean;
|
|
scope: string;
|
|
error_message: string | null;
|
|
tenant_name: string | null;
|
|
tenant_slug: string | null;
|
|
risk_level: AdminLgpdRiskLevel;
|
|
}
|
|
|
|
export interface AdminLgpdFilters {
|
|
status?: AdminLgpdStatus;
|
|
request_type?: AdminLgpdRequestType;
|
|
risk_level?: AdminLgpdRiskLevel;
|
|
tenant_id?: string;
|
|
}
|
|
|
|
interface ListResponse {
|
|
data: AdminLgpdRequest[];
|
|
meta?: { cursor?: string | null; has_more?: boolean };
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Hook
|
|
// ---------------------------------------------------------------------------
|
|
|
|
export function useAdminLGPDRequests(filters: AdminLgpdFilters = {}) {
|
|
return useInfiniteQuery({
|
|
queryKey: ["admin", "lgpd", filters] as const,
|
|
initialPageParam: undefined as string | undefined,
|
|
queryFn: async ({ pageParam }) => {
|
|
const qs = new URLSearchParams();
|
|
if (filters.status) qs.set("status", filters.status);
|
|
if (filters.request_type) qs.set("request_type", filters.request_type);
|
|
if (filters.risk_level) qs.set("risk_level", filters.risk_level);
|
|
if (filters.tenant_id) qs.set("tenant_id", filters.tenant_id);
|
|
if (pageParam) qs.set("cursor", pageParam);
|
|
qs.set("limit", "50");
|
|
return apiClient.get<ListResponse>(`/api/v1/admin/lgpd/requests?${qs.toString()}`);
|
|
},
|
|
getNextPageParam: (last) =>
|
|
last.meta?.has_more && last.meta.cursor ? last.meta.cursor : undefined,
|
|
staleTime: 60_000,
|
|
});
|
|
}
|