onSaved("resourceId", id)}
/>
diff --git a/modules/companies/src/web/certificate-configurations/list/types/certificate-configurations-page-props.ts b/modules/companies/src/web/certificate-configurations/list/types/certificate-configurations-page-props.ts
index f987e19..fac4f73 100644
--- a/modules/companies/src/web/certificate-configurations/list/types/certificate-configurations-page-props.ts
+++ b/modules/companies/src/web/certificate-configurations/list/types/certificate-configurations-page-props.ts
@@ -2,6 +2,5 @@ import type { CompanyDTO } from "../../../../common";
export type CertificateConfigurationsPageProps = {
company: CompanyDTO;
- csrfToken: string;
initialProfileId?: string;
};
diff --git a/modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx b/modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx
index c12ef3f..c6d8b20 100644
--- a/modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx
+++ b/modules/companies/src/web/certificate-configurations/list/ui/certificate-configurations-page.tsx
@@ -16,7 +16,7 @@ import { useCertificateConfigurationsPageController } from "../controllers";
import type { CertificateConfigurationsPageProps } from "../types";
export function CertificateConfigurationsPage(props: CertificateConfigurationsPageProps) {
- const { company, csrfToken, initialProfileId } = props;
+ const { company, initialProfileId } = props;
const {
editor,
setEditor,
@@ -42,7 +42,6 @@ export function CertificateConfigurationsPage(props: CertificateConfigurationsPa
setDeleteId(undefined)}
path={
deleteId ? `/api/certificate-configurations/${company.id}/${deleteId}/delete` : undefined
@@ -177,7 +176,6 @@ export function CertificateConfigurationsPage(props: CertificateConfigurationsPa
setEditor(undefined)}
/>
diff --git a/modules/companies/src/web/certificate-configurations/shared/api/certificate-api.ts b/modules/companies/src/web/certificate-configurations/shared/api/certificate-api.ts
index 54e09fb..f9a7a33 100644
--- a/modules/companies/src/web/certificate-configurations/shared/api/certificate-api.ts
+++ b/modules/companies/src/web/certificate-configurations/shared/api/certificate-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { CertificateConfigurationInput } from "../../../../common/certificate-configurations";
@@ -14,18 +15,13 @@ export class CertificateApiError extends Error {
}
}
-async function request(
- companyId: string,
- values?: CertificateConfigurationInput,
- token?: string,
- id?: string
-) {
- const response = await fetch(
+async function request(companyId: string, values?: CertificateConfigurationInput, id?: string) {
+ const response = await csrfFetch(
`/api/certificate-configurations/${companyId}${id ? `/${id}/update` : ""}`,
{
method: values ? "POST" : "GET",
credentials: "same-origin",
- headers: values ? { "content-type": "application/json", "x-csrf-token": token ?? "" } : {},
+ headers: values ? { "content-type": "application/json" } : {},
...(values ? { body: JSON.stringify({ values }) } : {}),
}
);
@@ -44,9 +40,7 @@ export const certificateApi = {
async get(companyId: string) {
return CertificateConfigurationsResponseSchema.parse(await request(companyId));
},
- async save(companyId: string, values: CertificateConfigurationInput, token: string, id?: string) {
- return CertificateConfigurationResponseSchema.parse(
- await request(companyId, values, token, id)
- );
+ async save(companyId: string, values: CertificateConfigurationInput, id?: string) {
+ return CertificateConfigurationResponseSchema.parse(await request(companyId, values, id));
},
};
diff --git a/modules/companies/src/web/certificate-configurations/shared/certificate.test.tsx b/modules/companies/src/web/certificate-configurations/shared/certificate.test.tsx
index c0c7814..f3c4e74 100644
--- a/modules/companies/src/web/certificate-configurations/shared/certificate.test.tsx
+++ b/modules/companies/src/web/certificate-configurations/shared/certificate.test.tsx
@@ -65,7 +65,7 @@ test("certificados: listado sin formularios, alta en cabecera y traducciones", a
]) {
const html = await render(
language ?? "es",
-
+
);
assert.ok(html.includes(title ?? ""));
@@ -78,7 +78,7 @@ test("certificados: selectores con alta rápida y ayuda inferior antes de guarda
for (const language of ["es", "en"]) {
const html = await render(
language,
- undefined} />
+ undefined} />
);
const text = language === "es" ? companiesSpanish : companiesEnglish;
diff --git a/modules/companies/src/web/certificate-configurations/shared/controllers/use-certificate-configuration-form-controller.ts b/modules/companies/src/web/certificate-configurations/shared/controllers/use-certificate-configuration-form-controller.ts
index 6124322..c3e0613 100644
--- a/modules/companies/src/web/certificate-configurations/shared/controllers/use-certificate-configuration-form-controller.ts
+++ b/modules/companies/src/web/certificate-configurations/shared/controllers/use-certificate-configuration-form-controller.ts
@@ -27,7 +27,6 @@ function certificateStates(
export function useCertificateConfigurationFormController({
company,
- csrfToken,
configuration,
initialProfileId = "",
onSaved,
@@ -65,7 +64,7 @@ export function useCertificateConfigurationFormController({
const states = certificateStates(configuration);
const mutation = useMutation({
mutationFn: (input: CertificateConfigurationInput) =>
- certificateApi.save(company.id, input, csrfToken, configuration?.id),
+ certificateApi.save(company.id, input, configuration?.id),
onSuccess: async () => {
await client.invalidateQueries({ queryKey: certificateKeys.company(company.id) });
if (mounted.current) {
diff --git a/modules/companies/src/web/certificate-configurations/shared/types/certificate-configuration-form-props.ts b/modules/companies/src/web/certificate-configurations/shared/types/certificate-configuration-form-props.ts
index a9b02b5..4707db2 100644
--- a/modules/companies/src/web/certificate-configurations/shared/types/certificate-configuration-form-props.ts
+++ b/modules/companies/src/web/certificate-configurations/shared/types/certificate-configuration-form-props.ts
@@ -3,7 +3,6 @@ import type { CertificateConfigurationDTO } from "../../../../common/certificate
export type CertificateConfigurationFormProps = {
company: CompanyDTO;
- csrfToken: string;
configuration?: CertificateConfigurationDTO | undefined;
initialProfileId?: string;
onSaved: () => void;
diff --git a/modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-editor-dialog.tsx b/modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-editor-dialog.tsx
index 07e75ed..464c8a2 100644
--- a/modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-editor-dialog.tsx
+++ b/modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-editor-dialog.tsx
@@ -9,13 +9,11 @@ import { CertificateConfigurationForm } from "./certificate-configuration-form";
export function CertificateConfigurationEditorDialog({
configuration,
company,
- csrfToken,
initialProfileId,
onClose,
}: {
configuration: ComponentProps["configuration"];
company: CompanyDTO;
- csrfToken: string;
initialProfileId: ComponentProps["initialProfileId"];
onClose: () => void;
}) {
@@ -37,7 +35,6 @@ export function CertificateConfigurationEditorDialog({
onClose()}
/>
diff --git a/modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-form.tsx b/modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-form.tsx
index 7730396..99c44ca 100644
--- a/modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-form.tsx
+++ b/modules/companies/src/web/certificate-configurations/shared/ui/certificate-configuration-form.tsx
@@ -23,7 +23,7 @@ function certificateProfiles(selected: string, profiles: readonly WorkProfileDTO
}
export function CertificateConfigurationForm(props: CertificateConfigurationFormProps) {
- const { company, csrfToken, configuration } = props;
+ const { company, configuration } = props;
const {
quick,
setQuick,
@@ -154,7 +154,6 @@ export function CertificateConfigurationForm(props: CertificateConfigurationForm
{quick && (
setQuick(undefined)}
onSaved={quickCreated}
diff --git a/modules/companies/src/web/companies/change-logo/api/company-logo-api.ts b/modules/companies/src/web/companies/change-logo/api/company-logo-api.ts
index d47aa0d..b10782d 100644
--- a/modules/companies/src/web/companies/change-logo/api/company-logo-api.ts
+++ b/modules/companies/src/web/companies/change-logo/api/company-logo-api.ts
@@ -1,12 +1,13 @@
+import { csrfFetch } from "@metis/core/client";
+
import { CompanyErrorResponseSchema, CompanyLogoResponseSchema } from "../../../../common";
import { CompanyApiError } from "../../shared/api/company-api-error";
-export async function saveCompanyLogo(companyId: string, logo: File | null, csrfToken: string) {
- const response = await fetch(`/api/companies/${companyId}/logo${logo ? "" : "/remove"}`, {
+export async function saveCompanyLogo(companyId: string, logo: File | null) {
+ const response = await csrfFetch(`/api/companies/${companyId}/logo${logo ? "" : "/remove"}`, {
method: "POST",
credentials: "same-origin",
headers: {
- "x-csrf-token": csrfToken,
"content-type": logo ? "application/octet-stream" : "application/json",
},
body: logo ?? "{}",
diff --git a/modules/companies/src/web/companies/detail/types/company-detail-props.ts b/modules/companies/src/web/companies/detail/types/company-detail-props.ts
index 00bbe72..edb72df 100644
--- a/modules/companies/src/web/companies/detail/types/company-detail-props.ts
+++ b/modules/companies/src/web/companies/detail/types/company-detail-props.ts
@@ -2,7 +2,6 @@ import type { CompanyTab } from "../../shared/types";
export type CompanyDetailProps = {
id: string;
- csrfToken: string;
onBack: () => void;
embedded?: boolean;
initialSection?: CompanyTab;
diff --git a/modules/companies/src/web/companies/detail/ui/company-detail.tsx b/modules/companies/src/web/companies/detail/ui/company-detail.tsx
index 4ddcfb2..5edfd33 100644
--- a/modules/companies/src/web/companies/detail/ui/company-detail.tsx
+++ b/modules/companies/src/web/companies/detail/ui/company-detail.tsx
@@ -28,7 +28,6 @@ import { CompanySection } from "./company-section";
export function CompanyDetail(props: CompanyDetailProps) {
const {
- csrfToken,
onBack,
embedded = false,
initialSection,
@@ -100,7 +99,6 @@ export function CompanyDetail(props: CompanyDetailProps) {
setEditOpen(false)}
open={editOpen}
@@ -188,7 +186,6 @@ export function CompanyDetail(props: CompanyDetailProps) {
)}
setQuick(undefined)}
onCreated={quick.onCreated}
diff --git a/modules/companies/src/web/companies/detail/ui/company-overview.tsx b/modules/companies/src/web/companies/detail/ui/company-overview.tsx
index 02bad3c..90aad46 100644
--- a/modules/companies/src/web/companies/detail/ui/company-overview.tsx
+++ b/modules/companies/src/web/companies/detail/ui/company-overview.tsx
@@ -16,13 +16,7 @@ import { workspaceHref } from "../../../workspace/shared/helpers";
import { CompanyOverviewStatistics } from "./company-overview-statistics";
/** Composición propia de compañía; comparte bloques y consultas, no la pantalla Inicio. */
-export function CompanyOverview({
- company,
- csrfToken,
-}: {
- company: CompanyDTO;
- csrfToken: string;
-}) {
+export function CompanyOverview({ company }: { company: CompanyDTO }) {
const { t } = useTranslation("companies");
const { summary, details, setDetails, quick, setQuick } = useDashboardPageController(company.id);
@@ -93,7 +87,6 @@ export function CompanyOverview({
{quick && (
setQuick(undefined)}
onNavigate={onNavigate}
diff --git a/modules/companies/src/web/companies/detail/ui/company-section.tsx b/modules/companies/src/web/companies/detail/ui/company-section.tsx
index 10208fd..9208bc8 100644
--- a/modules/companies/src/web/companies/detail/ui/company-section.tsx
+++ b/modules/companies/src/web/companies/detail/ui/company-section.tsx
@@ -28,14 +28,12 @@ import { CompanyOverview } from "./company-overview";
export function CompanySection({
company,
- csrfToken,
tab,
initialEntityId,
initialCreate,
initialConfiguration,
}: {
company: CompanyDTO;
- csrfToken: string;
tab: CompanyTab;
initialEntityId?: string | undefined;
initialCreate?: boolean | undefined;
@@ -54,52 +52,33 @@ export function CompanySection({
switch (tab) {
case "overview":
- return ;
+ return ;
case "catalogs":
return ;
case "intervention-templates":
- return ;
+ return ;
case "interventions":
- return (
-
- );
+ return ;
case "tickets":
- return (
-
- );
+ return ;
case "processes":
- return ;
+ return ;
case "remote":
- return (
-
- );
+ return ;
case "telework":
- return (
-
- );
+ return ;
case "people":
- return ;
+ return ;
case "departments":
- return ;
+ return ;
case "sites":
- return ;
+ return ;
case "access":
- return (
-
- );
+ return ;
case "profiles":
return (
@@ -108,7 +87,6 @@ export function CompanySection({
return (
);
@@ -116,7 +94,6 @@ export function CompanySection({
return (
);
@@ -124,7 +101,6 @@ export function CompanySection({
return (
);
@@ -132,7 +108,6 @@ export function CompanySection({
return (
);
@@ -140,38 +115,31 @@ export function CompanySection({
return (
);
case "workstations":
- return ;
+ return ;
case "inventory":
return (
-
+
);
case "resources":
return (
resource.values.integration?.kind === "mailbox" ? (
-
+
) : null
}
/>
);
case "resource-catalog":
- return ;
+ return ;
case "assets":
- return ;
+ return ;
}
}
diff --git a/modules/companies/src/web/companies/detail/ui/inventory-quick-create-dialog.tsx b/modules/companies/src/web/companies/detail/ui/inventory-quick-create-dialog.tsx
index a1ff8df..f490d18 100644
--- a/modules/companies/src/web/companies/detail/ui/inventory-quick-create-dialog.tsx
+++ b/modules/companies/src/web/companies/detail/ui/inventory-quick-create-dialog.tsx
@@ -6,13 +6,11 @@ import { SiteForm } from "../../../sites";
export function InventoryQuickCreateDialog({
companyId,
- csrfToken,
kind,
onCreated,
onClose,
}: {
companyId: string;
- csrfToken: string;
kind: "site" | "person";
onCreated: (id: string) => void;
onClose: () => void;
@@ -36,7 +34,6 @@ export function InventoryQuickCreateDialog({
{kind === "site" ? (
{
onCreated(id);
onClose();
@@ -46,7 +43,6 @@ export function InventoryQuickCreateDialog({
) : (
{
onCreated(id);
onClose();
diff --git a/modules/companies/src/web/companies/list/types/companies-page-props.ts b/modules/companies/src/web/companies/list/types/companies-page-props.ts
index 8536ff5..478f09a 100644
--- a/modules/companies/src/web/companies/list/types/companies-page-props.ts
+++ b/modules/companies/src/web/companies/list/types/companies-page-props.ts
@@ -1,5 +1,4 @@
export type CompaniesPageProps = {
- csrfToken: string;
onSelectCompany?: (id: string) => void;
initialActiveOnly?: boolean | undefined;
initialCompanyId?: string | undefined;
diff --git a/modules/companies/src/web/companies/list/ui/companies-page.tsx b/modules/companies/src/web/companies/list/ui/companies-page.tsx
index c106338..8d8480f 100644
--- a/modules/companies/src/web/companies/list/ui/companies-page.tsx
+++ b/modules/companies/src/web/companies/list/ui/companies-page.tsx
@@ -16,7 +16,7 @@ import { useCompaniesPageController } from "../controllers";
import type { CompaniesPageProps } from "../types";
export function CompaniesPage(props: CompaniesPageProps) {
- const { csrfToken, onSelectCompany } = props;
+ const { onSelectCompany } = props;
const {
query,
selectedId,
@@ -36,12 +36,7 @@ export function CompaniesPage(props: CompaniesPageProps) {
if (selectedId && !onSelectCompany) {
return (
- setSelectedId(undefined)}
- />
+ setSelectedId(undefined)} />
);
}
const companies = table
@@ -153,7 +148,6 @@ export function CompaniesPage(props: CompaniesPageProps) {
/>
)}
{
setCreateOpen(false);
selectCompany(companyId);
diff --git a/modules/companies/src/web/companies/shared/api/company-request.ts b/modules/companies/src/web/companies/shared/api/company-request.ts
index 81492aa..3bc74ff 100644
--- a/modules/companies/src/web/companies/shared/api/company-request.ts
+++ b/modules/companies/src/web/companies/shared/api/company-request.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import type { z } from "zod/v4";
import { CompanyErrorResponseSchema } from "../../../../common";
@@ -7,16 +8,12 @@ import { CompanyApiError } from "./company-api-error";
export async function companyRequest(
path: string,
schema: z.ZodType,
- body?: unknown,
- csrfToken?: string
+ body?: unknown
): Promise {
- const response = await fetch(`/api/companies${path}`, {
+ const response = await csrfFetch(`/api/companies${path}`, {
method: body === undefined ? "GET" : "POST",
credentials: "same-origin",
- headers:
- body === undefined
- ? {}
- : { "content-type": "application/json", "x-csrf-token": csrfToken ?? "" },
+ headers: body === undefined ? {} : { "content-type": "application/json" },
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
const json: unknown = await response.json();
diff --git a/modules/companies/src/web/companies/shared/api/save-company.api.ts b/modules/companies/src/web/companies/shared/api/save-company.api.ts
index 66b12c6..211cb81 100644
--- a/modules/companies/src/web/companies/shared/api/save-company.api.ts
+++ b/modules/companies/src/web/companies/shared/api/save-company.api.ts
@@ -2,5 +2,5 @@ import { CompanyResponseSchema } from "../../../../common";
import { companyRequest } from "./company-request";
-export const saveCompany = (id: string | undefined, body: unknown, token: string) =>
- companyRequest(id ? `/${id}/update` : "", CompanyResponseSchema, body, token);
+export const saveCompany = (id: string | undefined, body: unknown) =>
+ companyRequest(id ? `/${id}/update` : "", CompanyResponseSchema, body);
diff --git a/modules/companies/src/web/companies/shared/companies-page.test.tsx b/modules/companies/src/web/companies/shared/companies-page.test.tsx
index dc5b320..6addb0e 100644
--- a/modules/companies/src/web/companies/shared/companies-page.test.tsx
+++ b/modules/companies/src/web/companies/shared/companies-page.test.tsx
@@ -60,11 +60,7 @@ test("el dashboard no ofrece selector de compañía y conserva las métricas de
for (const scope of [undefined, companyId]) {
const markup = await renderPage(
language,
- undefined}
- />,
+ undefined} />,
(client) => {
for (const summaryScope of [undefined, companyId]) {
client.setQueryData(dashboardKeys.block("summary", summaryScope), {
@@ -89,7 +85,7 @@ test("el resumen de compañía es la entrada por defecto y ofrece destinos reale
for (const language of ["es", "en"]) {
const markup = await renderPage(
language,
- undefined} />,
+ undefined} />,
(client) =>
client.setQueryData(companyKeys.detail(companyId), {
company: {
@@ -145,7 +141,7 @@ test("el listado presenta estado vacío y acceso al alta sin formularios visible
["es", "Compañías", "Todavía no hay compañías"],
["en", "Companies", "No companies yet"],
] as const) {
- const markup = await renderPage(language, , (client) =>
+ const markup = await renderPage(language, , (client) =>
client.setQueryData(companyKeys.list, { companies: [] })
);
@@ -159,12 +155,7 @@ test("el listado presenta estado vacío y acceso al alta sin formularios visible
test("la ficha presenta datos de la compañía, contactos y acceso a sedes", async () => {
const markup = await renderPage(
"es",
- undefined}
- />,
+ undefined} />,
(client) =>
client.setQueryData(companyKeys.detail(companyId), {
company: {
@@ -200,11 +191,7 @@ test("la ficha presenta datos de la compañía, contactos y acceso a sedes", asy
assert.equal(markup.includes("
setQuick(undefined)}
onCompany={(id) => {
@@ -181,7 +179,6 @@ export function InterventionForm(props: InterventionFormProps) {
{
if (!open) {
setQuick(undefined);
@@ -202,7 +199,6 @@ export function InterventionForm(props: InterventionFormProps) {
/>
{
if (!open) {
setQuick(undefined);
diff --git a/modules/companies/src/web/mail-configurations/create/ui/mail-quick-editor.tsx b/modules/companies/src/web/mail-configurations/create/ui/mail-quick-editor.tsx
index 58f1258..cb2e060 100644
--- a/modules/companies/src/web/mail-configurations/create/ui/mail-quick-editor.tsx
+++ b/modules/companies/src/web/mail-configurations/create/ui/mail-quick-editor.tsx
@@ -11,7 +11,6 @@ import { WorkProfileForm } from "../../../work-profiles/shared";
export function MailQuickEditor({
kind,
company,
- csrfToken,
profile,
mailbox,
initialAddress,
@@ -20,7 +19,6 @@ export function MailQuickEditor({
}: {
kind: "profile" | "mailbox" | "use";
company: CompanyDTO;
- csrfToken: string;
profile: WorkProfileDTO | undefined;
mailbox: MailboxDTO | undefined;
initialAddress: string;
@@ -47,7 +45,6 @@ export function MailQuickEditor({
onCreated("mailboxId", id)}
/>
@@ -56,7 +53,6 @@ export function MailQuickEditor({
onCreated("profileId", id)}
/>
)}
@@ -64,7 +60,6 @@ export function MailQuickEditor({
setDeleteId(undefined)}
path={deleteId ? `/api/mail-configurations/${company.id}/${deleteId}/delete` : undefined}
queryKey={["mail-configurations", company.id]}
@@ -167,7 +166,6 @@ export function MailConfigurationsPage(props: MailConfigurationsPageProps) {
setEditor(undefined)}
/>
diff --git a/modules/companies/src/web/mail-configurations/shared/api/mail-api.ts b/modules/companies/src/web/mail-configurations/shared/api/mail-api.ts
index 2c652d1..bf69623 100644
--- a/modules/companies/src/web/mail-configurations/shared/api/mail-api.ts
+++ b/modules/companies/src/web/mail-configurations/shared/api/mail-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { MailConfigurationInput } from "../../../../common/mail-configurations";
@@ -14,18 +15,13 @@ export class MailApiError extends Error {
}
}
-async function request(
- companyId: string,
- values?: MailConfigurationInput,
- token?: string,
- id?: string
-) {
- const response = await fetch(
+async function request(companyId: string, values?: MailConfigurationInput, id?: string) {
+ const response = await csrfFetch(
`/api/mail-configurations/${companyId}${id ? `/${id}/update` : ""}`,
{
method: values ? "POST" : "GET",
credentials: "same-origin",
- headers: values ? { "content-type": "application/json", "x-csrf-token": token ?? "" } : {},
+ headers: values ? { "content-type": "application/json" } : {},
...(values ? { body: JSON.stringify({ values }) } : {}),
}
);
@@ -44,7 +40,7 @@ export const mailApi = {
async get(companyId: string) {
return MailConfigurationsResponseSchema.parse(await request(companyId));
},
- async save(companyId: string, values: MailConfigurationInput, token: string, id?: string) {
- return MailConfigurationResponseSchema.parse(await request(companyId, values, token, id));
+ async save(companyId: string, values: MailConfigurationInput, id?: string) {
+ return MailConfigurationResponseSchema.parse(await request(companyId, values, id));
},
};
diff --git a/modules/companies/src/web/mail-configurations/shared/controllers/use-mail-configuration-form-controller.ts b/modules/companies/src/web/mail-configurations/shared/controllers/use-mail-configuration-form-controller.ts
index e1b5f91..d56b148 100644
--- a/modules/companies/src/web/mail-configurations/shared/controllers/use-mail-configuration-form-controller.ts
+++ b/modules/companies/src/web/mail-configurations/shared/controllers/use-mail-configuration-form-controller.ts
@@ -27,7 +27,6 @@ function configurationStates(configuration: MailConfigurationDTO | undefined) {
export function useMailConfigurationFormController({
company,
- csrfToken,
configuration,
onSaved,
initialProfileId = "",
@@ -73,7 +72,7 @@ export function useMailConfigurationFormController({
);
const mutation = useMutation({
mutationFn: (input: MailConfigurationInput) =>
- mailApi.save(company.id, input, csrfToken, configuration?.id),
+ mailApi.save(company.id, input, configuration?.id),
onSuccess: async () => {
await client.invalidateQueries({ queryKey: mailKeys.company(company.id) });
if (mounted.current) {
diff --git a/modules/companies/src/web/mail-configurations/shared/mail.test.tsx b/modules/companies/src/web/mail-configurations/shared/mail.test.tsx
index 7dcd1a4..3d939ed 100644
--- a/modules/companies/src/web/mail-configurations/shared/mail.test.tsx
+++ b/modules/companies/src/web/mail-configurations/shared/mail.test.tsx
@@ -104,10 +104,7 @@ async function render(language: string, node: ReactNode) {
test("correo: listado traducido, alta en cabecera y formularios ocultos", async () => {
for (const language of ["es", "en"]) {
- const html = await render(
- language,
-
- );
+ const html = await render(language, );
assert.equal(html.includes(" {
const html = await render(
"es",
- undefined} />
+ undefined} />
);
for (const label of ["Nuevo perfil", "Nuevo buzón"]) {
@@ -138,20 +135,13 @@ test("Buzones: alta en modal, cuenta opcional y ayuda al final", async () => {
for (const language of ["es", "en"]) {
const page = await render(
language,
-
+
);
assert.equal(page.includes(" undefined} />
- );
+ const form = await render("es", undefined} />);
assert.ok(form.includes("Cuenta relacionada (opcional)"));
assert.ok(form.indexOf("¿Qué es y para qué sirve?") < form.indexOf("Guardar"));
diff --git a/modules/companies/src/web/mail-configurations/shared/types/mail-configuration-form-props.ts b/modules/companies/src/web/mail-configurations/shared/types/mail-configuration-form-props.ts
index 7454a68..4dccd2e 100644
--- a/modules/companies/src/web/mail-configurations/shared/types/mail-configuration-form-props.ts
+++ b/modules/companies/src/web/mail-configurations/shared/types/mail-configuration-form-props.ts
@@ -3,7 +3,6 @@ import type { MailConfigurationDTO } from "../../../../common/mail-configuration
export type MailConfigurationFormProps = {
company: CompanyDTO;
- csrfToken: string;
configuration?: MailConfigurationDTO | undefined;
onSaved: () => void;
initialProfileId?: string;
diff --git a/modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-editor-dialog.tsx b/modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-editor-dialog.tsx
index 3a5e2a8..e84a5d1 100644
--- a/modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-editor-dialog.tsx
+++ b/modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-editor-dialog.tsx
@@ -9,13 +9,11 @@ import { MailConfigurationForm } from "./mail-configuration-form";
export function MailConfigurationEditorDialog({
configuration,
company,
- csrfToken,
initialProfileId,
onClose,
}: {
configuration: ComponentProps["configuration"];
company: CompanyDTO;
- csrfToken: string;
initialProfileId: ComponentProps["initialProfileId"];
onClose: () => void;
}) {
@@ -37,7 +35,6 @@ export function MailConfigurationEditorDialog({
onClose()}
/>
diff --git a/modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-form.tsx b/modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-form.tsx
index 1cfda7e..0cc64ba 100644
--- a/modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-form.tsx
+++ b/modules/companies/src/web/mail-configurations/shared/ui/mail-configuration-form.tsx
@@ -16,7 +16,7 @@ import { MailConfigurationTargets } from "./mail-configuration-targets";
import { MailFeedback } from "./mail-feedback";
export function MailConfigurationForm(props: MailConfigurationFormProps) {
- const { company, csrfToken, initialProfileId = "" } = props;
+ const { company, initialProfileId = "" } = props;
const {
quick,
setQuick,
@@ -121,7 +121,6 @@ export function MailConfigurationForm(props: MailConfigurationFormProps) {
{quick && (
saveMailboxUse(company.id, input, csrfToken, use?.id),
+ mutationFn: (input: MailboxUseInput) => saveMailboxUse(company.id, input, use?.id),
onSuccess: async () => {
await Promise.all([
client.invalidateQueries({ queryKey: mailboxKeys.company(company.id) }),
diff --git a/modules/companies/src/web/mailbox-uses/shared/types/mailbox-use-form-props.ts b/modules/companies/src/web/mailbox-uses/shared/types/mailbox-use-form-props.ts
index 360fad1..c9b209a 100644
--- a/modules/companies/src/web/mailbox-uses/shared/types/mailbox-use-form-props.ts
+++ b/modules/companies/src/web/mailbox-uses/shared/types/mailbox-use-form-props.ts
@@ -3,7 +3,6 @@ import type { MailboxUseDTO } from "../../../../common/mailboxes";
export type MailboxUseFormProps = {
company: CompanyDTO;
- csrfToken: string;
use?: MailboxUseDTO | undefined;
initialMailboxId?: string;
initialPersonId?: string;
diff --git a/modules/companies/src/web/mailbox-uses/shared/ui/mailbox-use-editor-dialog.tsx b/modules/companies/src/web/mailbox-uses/shared/ui/mailbox-use-editor-dialog.tsx
index dacc5e7..4fa7e09 100644
--- a/modules/companies/src/web/mailbox-uses/shared/ui/mailbox-use-editor-dialog.tsx
+++ b/modules/companies/src/web/mailbox-uses/shared/ui/mailbox-use-editor-dialog.tsx
@@ -9,14 +9,12 @@ import { MailboxUseForm } from "./mailbox-use-form";
export function MailboxUseEditorDialog({
use,
company,
- csrfToken,
mailboxId,
onSaved,
onOpenChange,
}: {
use: ComponentProps["use"];
company: CompanyDTO;
- csrfToken: string;
mailboxId: string;
onSaved: () => void;
onOpenChange: (open: boolean) => void;
@@ -34,7 +32,6 @@ export function MailboxUseEditorDialog({
{
if (!open) {
setQuick(undefined);
@@ -134,7 +132,6 @@ export function MailboxUseForm(props: MailboxUseFormProps) {
{quick === "mailbox" && (
{
if (!open) {
setQuick(undefined);
diff --git a/modules/companies/src/web/mailboxes/create/ui/mailbox-create-dialog.tsx b/modules/companies/src/web/mailboxes/create/ui/mailbox-create-dialog.tsx
index f41d98e..f802f03 100644
--- a/modules/companies/src/web/mailboxes/create/ui/mailbox-create-dialog.tsx
+++ b/modules/companies/src/web/mailboxes/create/ui/mailbox-create-dialog.tsx
@@ -6,12 +6,10 @@ import { MailboxForm } from "../../shared/ui/mailbox-form";
export function MailboxCreateDialog({
company,
- csrfToken,
onSaved,
onOpenChange,
}: {
company: CompanyDTO;
- csrfToken: string;
onSaved: (id: string) => void;
onOpenChange: (open: boolean) => void;
}) {
@@ -25,12 +23,7 @@ export function MailboxCreateDialog({
open
title={t("mailbox.new")}
>
-
+
);
}
diff --git a/modules/companies/src/web/mailboxes/shared/api/mailbox-request.ts b/modules/companies/src/web/mailboxes/shared/api/mailbox-request.ts
index f8ba873..4dc365c 100644
--- a/modules/companies/src/web/mailboxes/shared/api/mailbox-request.ts
+++ b/modules/companies/src/web/mailboxes/shared/api/mailbox-request.ts
@@ -1,21 +1,17 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { MailboxUseInput } from "../../../../common/mailboxes";
import { MailboxesResponseSchema } from "../../../../common/mailboxes";
import { MailApiError } from "../../../mail-configurations/shared/api/mail-api";
-export async function mailboxRequest(
- companyId: string,
- values?: MailboxUseInput,
- token?: string,
- id?: string
-) {
- const response = await fetch(
+export async function mailboxRequest(companyId: string, values?: MailboxUseInput, id?: string) {
+ const response = await csrfFetch(
`/api/mailboxes/${companyId}${values ? "/uses" : ""}${id ? `/${id}/update` : ""}`,
{
method: values ? "POST" : "GET",
credentials: "same-origin",
- headers: values ? { "content-type": "application/json", "x-csrf-token": token ?? "" } : {},
+ headers: values ? { "content-type": "application/json" } : {},
...(values ? { body: JSON.stringify({ values }) } : {}),
}
);
diff --git a/modules/companies/src/web/mailboxes/shared/types/mailbox-relations-props.ts b/modules/companies/src/web/mailboxes/shared/types/mailbox-relations-props.ts
index 378404d..49b6a25 100644
--- a/modules/companies/src/web/mailboxes/shared/types/mailbox-relations-props.ts
+++ b/modules/companies/src/web/mailboxes/shared/types/mailbox-relations-props.ts
@@ -2,6 +2,5 @@ import type { CompanyDTO } from "../../../../common";
export type MailboxRelationsProps = {
company: CompanyDTO;
- csrfToken: string;
mailboxId: string;
};
diff --git a/modules/companies/src/web/mailboxes/shared/ui/mailbox-form.tsx b/modules/companies/src/web/mailboxes/shared/ui/mailbox-form.tsx
index ed44428..16720d9 100644
--- a/modules/companies/src/web/mailboxes/shared/ui/mailbox-form.tsx
+++ b/modules/companies/src/web/mailboxes/shared/ui/mailbox-form.tsx
@@ -6,14 +6,12 @@ import type { MailboxDTO } from "../../../../common/mailboxes";
/** El alta rápida de correo utiliza la misma ficha y persistencia que Recursos. */
export function MailboxForm({
company,
- csrfToken,
mailbox,
onSaved,
allowQuickCreate = true,
initialAddress = "",
}: {
company: CompanyDTO;
- csrfToken: string;
mailbox?: MailboxDTO | undefined;
onSaved: (id: string) => void;
allowQuickCreate?: boolean;
@@ -23,7 +21,6 @@ export function MailboxForm({
{
if (!open) {
diff --git a/modules/companies/src/web/people/detail/ui/person-details.tsx b/modules/companies/src/web/people/detail/ui/person-details.tsx
index 27f202d..7f5243b 100644
--- a/modules/companies/src/web/people/detail/ui/person-details.tsx
+++ b/modules/companies/src/web/people/detail/ui/person-details.tsx
@@ -24,13 +24,11 @@ import { deletePerson } from "../../shared/api";
export function PersonDetails({
company,
person,
- csrfToken,
onBack,
onEdit,
}: {
company: CompanyDTO;
person: PersonDTO;
- csrfToken: string;
onBack: () => void;
onEdit: () => void;
}) {
@@ -121,7 +119,7 @@ export function PersonDetails({
}
setDeleting(true);
try {
- await deletePerson(company.id, person.id, csrfToken);
+ await deletePerson(company.id, person.id);
onBack();
} catch {
window.alert(t("deletePersonError"));
@@ -214,7 +212,7 @@ export function PersonDetails({
}
setDeletingAssignment(item.id);
try {
- await deleteAssignment(company.id, person.id, item.id, csrfToken);
+ await deleteAssignment(company.id, person.id, item.id);
window.location.reload();
} catch {
window.alert(t("deleteAssignmentError"));
@@ -243,7 +241,6 @@ export function PersonDetails({
{
if (!open) {
diff --git a/modules/companies/src/web/people/list/ui/people-section.tsx b/modules/companies/src/web/people/list/ui/people-section.tsx
index f89794b..c5908f7 100644
--- a/modules/companies/src/web/people/list/ui/people-section.tsx
+++ b/modules/companies/src/web/people/list/ui/people-section.tsx
@@ -19,11 +19,9 @@ import { PersonAvatar, PersonEditorDialog } from "../../shared";
export function PeopleSection({
company,
- csrfToken,
initialId,
}: {
company: CompanyDTO;
- csrfToken: string;
initialId?: string | undefined;
}) {
const { t, i18n } = useTranslation("companies");
@@ -41,7 +39,6 @@ export function PeopleSection({
const personEditor = (
{
if (!open) {
setSelection(selected ? { mode: "detail", id: selected.id } : undefined);
@@ -65,7 +62,6 @@ export function PeopleSection({
{personEditor}
{
setSelection(undefined);
diff --git a/modules/companies/src/web/people/shared/api/save-person.api.ts b/modules/companies/src/web/people/shared/api/save-person.api.ts
index 3eb2daf..90e565f 100644
--- a/modules/companies/src/web/people/shared/api/save-person.api.ts
+++ b/modules/companies/src/web/people/shared/api/save-person.api.ts
@@ -1,47 +1,38 @@
+import { csrfFetch } from "@metis/core/client";
+
import { CompanyResponseSchema } from "../../../../common";
import { companyRequest } from "../../../companies/shared/api/company-request";
-export const savePerson = (
- companyId: string,
- id: string | undefined,
- body: unknown,
- token: string
-) =>
- companyRequest(
- `/${companyId}/people${id ? `/${id}/update` : ""}`,
- CompanyResponseSchema,
- body,
- token
- );
+export const savePerson = (companyId: string, id: string | undefined, body: unknown) =>
+ companyRequest(`/${companyId}/people${id ? `/${id}/update` : ""}`, CompanyResponseSchema, body);
-export const deletePerson = (companyId: string, id: string, token: string) =>
- companyRequest(`/${companyId}/people/${id}/delete`, CompanyResponseSchema, {}, token);
+export const deletePerson = (companyId: string, id: string) =>
+ companyRequest(`/${companyId}/people/${id}/delete`, CompanyResponseSchema, {});
-export async function savePersonPhoto(
- companyId: string,
- personId: string,
- file: File,
- token: string
-) {
- const response = await fetch(`/api/companies/${companyId}/people/${personId}/photo`, {
+export async function savePersonPhoto(companyId: string, personId: string, file: File) {
+ const response = await csrfFetch(`/api/companies/${companyId}/people/${personId}/photo`, {
method: "POST",
- headers: { "Content-Type": "application/octet-stream", "X-CSRF-Token": token },
+ headers: { "Content-Type": "application/octet-stream" },
body: file,
});
- if (!response.ok) throw new Error("PHOTO_UPLOAD_FAILED");
+ if (!response.ok) {
+ throw new Error("PHOTO_UPLOAD_FAILED");
+ }
return response.json() as Promise<{ photoVersion: string }>;
}
-export async function removePersonPhoto(companyId: string, personId: string, token: string) {
- const response = await fetch(`/api/companies/${companyId}/people/${personId}/photo/remove`, {
+export async function removePersonPhoto(companyId: string, personId: string) {
+ const response = await csrfFetch(`/api/companies/${companyId}/people/${personId}/photo/remove`, {
method: "POST",
- headers: { "Content-Type": "application/json", "X-CSRF-Token": token },
+ headers: { "Content-Type": "application/json" },
body: "{}",
});
- if (!response.ok) throw new Error("PHOTO_REMOVE_FAILED");
+ if (!response.ok) {
+ throw new Error("PHOTO_REMOVE_FAILED");
+ }
return response.json() as Promise<{ photoVersion: null }>;
}
diff --git a/modules/companies/src/web/people/shared/controllers/use-person-form-controller.ts b/modules/companies/src/web/people/shared/controllers/use-person-form-controller.ts
index faea73c..3ffd39d 100644
--- a/modules/companies/src/web/people/shared/controllers/use-person-form-controller.ts
+++ b/modules/companies/src/web/people/shared/controllers/use-person-form-controller.ts
@@ -1,7 +1,7 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { useMutation, useQueryClient } from "@tanstack/react-query";
-import { useForm } from "react-hook-form";
import { useState } from "react";
+import { useForm } from "react-hook-form";
import { accessKeys } from "../../../access/shared/queries";
import { companyKeys } from "../../../companies/shared/queries";
@@ -12,12 +12,7 @@ import { savePerson, savePersonPhoto } from "../api";
import { PersonFormSchema } from "../schemas";
import type { PersonFormProps, PersonFormValues } from "../types";
-export function usePersonFormController({
- person,
- companyId,
- csrfToken,
- onSaved,
-}: PersonFormProps) {
+export function usePersonFormController({ person, companyId, onSaved }: PersonFormProps) {
const client = useQueryClient();
const [photoFile, setPhotoFile] = useState(null);
const form = useForm({
@@ -33,7 +28,7 @@ export function usePersonFormController({
});
const mutation = useMutation({
mutationFn: (values: PersonFormValues) =>
- savePerson(companyId, person?.id, buildPersonRequest(values), csrfToken),
+ savePerson(companyId, person?.id, buildPersonRequest(values)),
onSuccess: async (response) => {
await Promise.all([
client.invalidateQueries({ queryKey: accessKeys.scope(companyId) }),
@@ -47,7 +42,9 @@ export function usePersonFormController({
: response.company.people.at(-1);
if (saved) {
- if (photoFile) await savePersonPhoto(companyId, saved.id, photoFile, csrfToken);
+ if (photoFile) {
+ await savePersonPhoto(companyId, saved.id, photoFile);
+ }
onSaved(saved.id);
}
},
diff --git a/modules/companies/src/web/people/shared/types/person-form-props.ts b/modules/companies/src/web/people/shared/types/person-form-props.ts
index 2d48066..8f9b5d9 100644
--- a/modules/companies/src/web/people/shared/types/person-form-props.ts
+++ b/modules/companies/src/web/people/shared/types/person-form-props.ts
@@ -8,7 +8,6 @@ export type PersonFormValues = z.infer;
export type PersonFormProps = {
person?: PersonDTO | undefined;
companyId: string;
- csrfToken: string;
onSaved: (id: string) => void;
requireActive?: boolean;
};
diff --git a/modules/companies/src/web/printer-configurations/create/ui/printer-profile-create-dialog.tsx b/modules/companies/src/web/printer-configurations/create/ui/printer-profile-create-dialog.tsx
index 489bc2e..7e16046 100644
--- a/modules/companies/src/web/printer-configurations/create/ui/printer-profile-create-dialog.tsx
+++ b/modules/companies/src/web/printer-configurations/create/ui/printer-profile-create-dialog.tsx
@@ -6,12 +6,10 @@ import { WorkProfileForm } from "../../../work-profiles/shared";
export function PrinterProfileCreateDialog({
company,
- csrfToken,
onSaved,
onOpenChange,
}: {
company: CompanyDTO;
- csrfToken: string;
onSaved: (id: string) => void;
onOpenChange: (open: boolean) => void;
}) {
@@ -26,12 +24,7 @@ export function PrinterProfileCreateDialog({
title={t("profiles.new")}
wide
>
-
+
);
}
diff --git a/modules/companies/src/web/printer-configurations/list/types/printer-configurations-page-props.ts b/modules/companies/src/web/printer-configurations/list/types/printer-configurations-page-props.ts
index 5bd2dcb..c3d0fdc 100644
--- a/modules/companies/src/web/printer-configurations/list/types/printer-configurations-page-props.ts
+++ b/modules/companies/src/web/printer-configurations/list/types/printer-configurations-page-props.ts
@@ -2,6 +2,5 @@ import type { CompanyDTO } from "../../../../common";
export type PrinterConfigurationsPageProps = {
company: CompanyDTO;
- csrfToken: string;
initialProfileId?: string;
};
diff --git a/modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx b/modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx
index 4f3bff6..7742052 100644
--- a/modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx
+++ b/modules/companies/src/web/printer-configurations/list/ui/printer-configurations-page.tsx
@@ -16,7 +16,7 @@ import { usePrinterConfigurationsPageController } from "../controllers";
import type { PrinterConfigurationsPageProps } from "../types";
export function PrinterConfigurationsPage(props: PrinterConfigurationsPageProps) {
- const { company, csrfToken, initialProfileId } = props;
+ const { company, initialProfileId } = props;
const {
editor,
setEditor,
@@ -41,7 +41,6 @@ export function PrinterConfigurationsPage(props: PrinterConfigurationsPageProps)
setDeleteId(undefined)}
path={deleteId ? `/api/printer-configurations/${company.id}/${deleteId}/delete` : undefined}
queryKey={["printer-configurations", company.id]}
@@ -162,7 +161,6 @@ export function PrinterConfigurationsPage(props: PrinterConfigurationsPageProps)
setEditor(undefined)}
/>
diff --git a/modules/companies/src/web/printer-configurations/shared/api/printer-api.ts b/modules/companies/src/web/printer-configurations/shared/api/printer-api.ts
index d544bd5..7267d3d 100644
--- a/modules/companies/src/web/printer-configurations/shared/api/printer-api.ts
+++ b/modules/companies/src/web/printer-configurations/shared/api/printer-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { PrinterConfigurationInput } from "../../../../common/printer-configurations";
@@ -14,18 +15,13 @@ export class PrinterApiError extends Error {
}
}
-async function request(
- companyId: string,
- values?: PrinterConfigurationInput,
- token?: string,
- id?: string
-) {
- const response = await fetch(
+async function request(companyId: string, values?: PrinterConfigurationInput, id?: string) {
+ const response = await csrfFetch(
`/api/printer-configurations/${companyId}${id ? `/${id}/update` : ""}`,
{
method: values ? "POST" : "GET",
credentials: "same-origin",
- headers: values ? { "content-type": "application/json", "x-csrf-token": token ?? "" } : {},
+ headers: values ? { "content-type": "application/json" } : {},
...(values ? { body: JSON.stringify({ values }) } : {}),
}
);
@@ -44,7 +40,7 @@ export const printerApi = {
async get(companyId: string) {
return PrinterConfigurationsResponseSchema.parse(await request(companyId));
},
- async save(companyId: string, values: PrinterConfigurationInput, token: string, id?: string) {
- return PrinterConfigurationResponseSchema.parse(await request(companyId, values, token, id));
+ async save(companyId: string, values: PrinterConfigurationInput, id?: string) {
+ return PrinterConfigurationResponseSchema.parse(await request(companyId, values, id));
},
};
diff --git a/modules/companies/src/web/printer-configurations/shared/controllers/use-printer-configuration-form-controller.ts b/modules/companies/src/web/printer-configurations/shared/controllers/use-printer-configuration-form-controller.ts
index 6c96ad7..1ecb7a3 100644
--- a/modules/companies/src/web/printer-configurations/shared/controllers/use-printer-configuration-form-controller.ts
+++ b/modules/companies/src/web/printer-configurations/shared/controllers/use-printer-configuration-form-controller.ts
@@ -27,7 +27,6 @@ function availablePrinterStates(
export function usePrinterConfigurationFormController({
company,
- csrfToken,
configuration,
initialProfileId = "",
onSaved,
@@ -62,7 +61,7 @@ export function usePrinterConfigurationFormController({
const ready = [profiles.data, inventory.data].every(Boolean);
const mutation = useMutation({
mutationFn: (input: PrinterConfigurationInput) =>
- printerApi.save(company.id, input, csrfToken, configuration?.id),
+ printerApi.save(company.id, input, configuration?.id),
onSuccess: async () => {
await client.invalidateQueries({ queryKey: printerKeys.company(company.id) });
if (mounted.current) {
diff --git a/modules/companies/src/web/printer-configurations/shared/printer.test.tsx b/modules/companies/src/web/printer-configurations/shared/printer.test.tsx
index 720f292..0966428 100644
--- a/modules/companies/src/web/printer-configurations/shared/printer.test.tsx
+++ b/modules/companies/src/web/printer-configurations/shared/printer.test.tsx
@@ -60,10 +60,7 @@ test("impresoras: listado sin formularios, alta en cabecera y traducciones", asy
["es", "Impresoras del perfil", "Configurar impresora"],
["en", "Profile printers", "Configure printer"],
]) {
- const html = await render(
- language ?? "es",
-
- );
+ const html = await render(language ?? "es", );
assert.ok(html.includes(title ?? ""));
assert.ok(html.includes(action ?? ""));
@@ -75,7 +72,7 @@ test("impresoras: selectores con alta rápida y ayuda inferior antes de guardar"
for (const language of ["es", "en"]) {
const html = await render(
language,
- undefined} />
+ undefined} />
);
const text = language === "es" ? companiesSpanish : companiesEnglish;
diff --git a/modules/companies/src/web/printer-configurations/shared/types/printer-configuration-form-props.ts b/modules/companies/src/web/printer-configurations/shared/types/printer-configuration-form-props.ts
index aedc2bd..424768a 100644
--- a/modules/companies/src/web/printer-configurations/shared/types/printer-configuration-form-props.ts
+++ b/modules/companies/src/web/printer-configurations/shared/types/printer-configuration-form-props.ts
@@ -3,7 +3,6 @@ import type { PrinterConfigurationDTO } from "../../../../common/printer-configu
export type PrinterConfigurationFormProps = {
company: CompanyDTO;
- csrfToken: string;
configuration?: PrinterConfigurationDTO | undefined;
initialProfileId?: string;
onSaved: () => void;
diff --git a/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-editor-dialog.tsx b/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-editor-dialog.tsx
index 0694170..10dd588 100644
--- a/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-editor-dialog.tsx
+++ b/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-editor-dialog.tsx
@@ -9,13 +9,11 @@ import { PrinterConfigurationForm } from "./printer-configuration-form";
export function PrinterConfigurationEditorDialog({
configuration,
company,
- csrfToken,
initialProfileId,
onClose,
}: {
configuration: ComponentProps["configuration"];
company: CompanyDTO;
- csrfToken: string;
initialProfileId: ComponentProps["initialProfileId"];
onClose: () => void;
}) {
@@ -37,7 +35,6 @@ export function PrinterConfigurationEditorDialog({
onClose()}
/>
diff --git a/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-form.tsx b/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-form.tsx
index 10ca759..5348db7 100644
--- a/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-form.tsx
+++ b/modules/companies/src/web/printer-configurations/shared/ui/printer-configuration-form.tsx
@@ -25,7 +25,7 @@ function profileOptions(profiles: readonly WorkProfileDTO[], selected: string) {
}
export function PrinterConfigurationForm(props: PrinterConfigurationFormProps) {
- const { company, csrfToken, configuration } = props;
+ const { company, configuration } = props;
const {
quick,
setQuick,
@@ -173,7 +173,6 @@ export function PrinterConfigurationForm(props: PrinterConfigurationFormProps) {
{quick === "profile" && (
{
if (!open) {
setQuick(undefined);
@@ -185,7 +184,6 @@ export function PrinterConfigurationForm(props: PrinterConfigurationFormProps) {
{quick === "printer" && (
setQuick(undefined)}
diff --git a/modules/companies/src/web/process-templates/list/types/index.ts b/modules/companies/src/web/process-templates/list/types/index.ts
deleted file mode 100644
index d48266b..0000000
--- a/modules/companies/src/web/process-templates/list/types/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type { ProcessTemplatesPageProps } from "./process-templates-page-props";
diff --git a/modules/companies/src/web/process-templates/list/types/process-templates-page-props.ts b/modules/companies/src/web/process-templates/list/types/process-templates-page-props.ts
deleted file mode 100644
index 6bce299..0000000
--- a/modules/companies/src/web/process-templates/list/types/process-templates-page-props.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export type ProcessTemplatesPageProps = {
- csrfToken: string;
-};
diff --git a/modules/companies/src/web/process-templates/list/ui/process-templates-page.tsx b/modules/companies/src/web/process-templates/list/ui/process-templates-page.tsx
index 9c0c593..70f4adf 100644
--- a/modules/companies/src/web/process-templates/list/ui/process-templates-page.tsx
+++ b/modules/companies/src/web/process-templates/list/ui/process-templates-page.tsx
@@ -11,10 +11,8 @@ import { useTranslation } from "react-i18next";
import { ProcessFeedback } from "../../../processes/shared";
import { ProcessTemplateEditorDialog } from "../../shared";
import { useProcessTemplatesPageController } from "../controllers";
-import type { ProcessTemplatesPageProps } from "../types";
-export function ProcessTemplatesPage(props: ProcessTemplatesPageProps) {
- const { csrfToken } = props;
+export function ProcessTemplatesPage() {
const { query, editor, setEditor, copy, setCopy, templates, selected, copied, close } =
useProcessTemplatesPageController();
const { t, i18n } = useTranslation("companies");
@@ -144,7 +142,6 @@ export function ProcessTemplatesPage(props: ProcessTemplatesPageProps) {
{
if (!open) {
diff --git a/modules/companies/src/web/process-templates/shared/api/save-process-template.api.ts b/modules/companies/src/web/process-templates/shared/api/save-process-template.api.ts
index 81fa916..4de418a 100644
--- a/modules/companies/src/web/process-templates/shared/api/save-process-template.api.ts
+++ b/modules/companies/src/web/process-templates/shared/api/save-process-template.api.ts
@@ -2,12 +2,8 @@ import type { ProcessTemplateInput } from "../../../../common/processes";
import { ProcessTemplateResponseSchema } from "../../../../common/processes";
import { processRequest } from "../../../processes/shared/api/process-request";
-export async function saveProcessTemplate(
- values: ProcessTemplateInput,
- token: string,
- id?: string
-) {
+export async function saveProcessTemplate(values: ProcessTemplateInput, id?: string) {
return ProcessTemplateResponseSchema.parse(
- await processRequest(`templates${id ? `/${id}/update` : ""}`, { values }, token)
+ await processRequest(`templates${id ? `/${id}/update` : ""}`, { values })
);
}
diff --git a/modules/companies/src/web/process-templates/shared/controllers/use-process-template-form-controller.ts b/modules/companies/src/web/process-templates/shared/controllers/use-process-template-form-controller.ts
index 29b2e02..de56780 100644
--- a/modules/companies/src/web/process-templates/shared/controllers/use-process-template-form-controller.ts
+++ b/modules/companies/src/web/process-templates/shared/controllers/use-process-template-form-controller.ts
@@ -12,7 +12,6 @@ import type { ProcessTemplateFormProps, Values } from "../types";
export function useProcessTemplateFormController({
template,
initialValues,
- csrfToken,
onSaved,
}: ProcessTemplateFormProps) {
const client = useQueryClient();
@@ -37,8 +36,7 @@ export function useProcessTemplateFormController({
},
});
const mutation = useMutation({
- mutationFn: (v: Values) =>
- saveProcessTemplate(buildProcessTemplateInput(v), csrfToken, template?.id),
+ mutationFn: (v: Values) => saveProcessTemplate(buildProcessTemplateInput(v), template?.id),
onSuccess: async (response) => {
await client.invalidateQueries({ queryKey: processKeys.catalog() });
if (mounted.current) {
diff --git a/modules/companies/src/web/process-templates/shared/types/process-template-form-props.ts b/modules/companies/src/web/process-templates/shared/types/process-template-form-props.ts
index d97f666..06a9220 100644
--- a/modules/companies/src/web/process-templates/shared/types/process-template-form-props.ts
+++ b/modules/companies/src/web/process-templates/shared/types/process-template-form-props.ts
@@ -8,6 +8,5 @@ export type Values = z.infer;
export type ProcessTemplateFormProps = {
template?: ProcessTemplateDTO | undefined;
initialValues?: ProcessTemplateInput | undefined;
- csrfToken: string;
onSaved: (id: string) => void;
};
diff --git a/modules/companies/src/web/process-templates/shared/ui/process-template-editor-dialog.tsx b/modules/companies/src/web/process-templates/shared/ui/process-template-editor-dialog.tsx
index ce82c2e..b7a03a2 100644
--- a/modules/companies/src/web/process-templates/shared/ui/process-template-editor-dialog.tsx
+++ b/modules/companies/src/web/process-templates/shared/ui/process-template-editor-dialog.tsx
@@ -9,7 +9,6 @@ export function ProcessTemplateEditorDialog({
copy,
selected,
copied,
- csrfToken,
onSaved,
onOpenChange,
}: {
@@ -17,7 +16,6 @@ export function ProcessTemplateEditorDialog({
copy: string | undefined;
selected: ComponentProps["template"];
copied: ComponentProps["template"];
- csrfToken: string;
onSaved: () => void;
onOpenChange: (open: boolean) => void;
}) {
@@ -34,7 +32,6 @@ export function ProcessTemplateEditorDialog({
>
{editor && (
void;
onOpenChange: (open: boolean) => void;
}) {
@@ -29,9 +27,9 @@ export function ProcessQuickCreateDialog({
wide
>
{quick === "person" ? (
-
+
) : (
-
+
)}
);
diff --git a/modules/companies/src/web/processes/detail/controllers/use-process-detail-controller.ts b/modules/companies/src/web/processes/detail/controllers/use-process-detail-controller.ts
index 06f5a5a..4eb5f8b 100644
--- a/modules/companies/src/web/processes/detail/controllers/use-process-detail-controller.ts
+++ b/modules/companies/src/web/processes/detail/controllers/use-process-detail-controller.ts
@@ -5,12 +5,12 @@ import { refreshProcess } from "../../refresh/api";
import { processKeys } from "../../shared/queries";
import type { ProcessDetailProps } from "../types";
-export function useProcessDetailController({ process, csrfToken }: ProcessDetailProps) {
+export function useProcessDetailController({ process }: ProcessDetailProps) {
const [edit, setEdit] = useState(false);
const client = useQueryClient();
const refresh = useMutation({
mutationFn: () =>
- refreshProcess(process.companyId, process.id, process.history.at(-1)?.id ?? "", csrfToken),
+ refreshProcess(process.companyId, process.id, process.history.at(-1)?.id ?? ""),
onSuccess: async () => {
await client.invalidateQueries({ queryKey: processKeys.company(process.companyId) });
},
diff --git a/modules/companies/src/web/processes/detail/types/process-detail-props.ts b/modules/companies/src/web/processes/detail/types/process-detail-props.ts
index ee26dab..d0df9c1 100644
--- a/modules/companies/src/web/processes/detail/types/process-detail-props.ts
+++ b/modules/companies/src/web/processes/detail/types/process-detail-props.ts
@@ -3,7 +3,6 @@ import type { PersonProcessDTO } from "../../../../common/processes";
export type ProcessDetailProps = {
process: PersonProcessDTO;
person: string;
- csrfToken: string;
onDelete?: (id: string) => void;
onDeleted?: () => void;
};
diff --git a/modules/companies/src/web/processes/detail/ui/process-detail.tsx b/modules/companies/src/web/processes/detail/ui/process-detail.tsx
index e056983..edc3e24 100644
--- a/modules/companies/src/web/processes/detail/ui/process-detail.tsx
+++ b/modules/companies/src/web/processes/detail/ui/process-detail.tsx
@@ -1,6 +1,6 @@
import { Button } from "@repo/shadcn-ui/components/button";
-import { useState } from "react";
import { Card, CardContent } from "@repo/shadcn-ui/components/card";
+import { useState } from "react";
import { useTranslation } from "react-i18next";
import { ProcessFeedback } from "../../shared";
@@ -10,7 +10,7 @@ import { useProcessDetailController } from "../controllers";
import type { ProcessDetailProps } from "../types";
export function ProcessDetail(props: ProcessDetailProps) {
- const { process, person, csrfToken, onDelete, onDeleted } = props;
+ const { process, person, onDelete, onDeleted } = props;
const { edit, setEdit, refresh, open, resolved } = useProcessDetailController(props);
const { t, i18n } = useTranslation("companies");
const [deleting, setDeleting] = useState(false);
@@ -44,14 +44,15 @@ export function ProcessDetail(props: ProcessDetailProps) {
{
- if (!window.confirm(t("processes.deleteConfirm", { name: process.values.name })))
+ if (!window.confirm(t("processes.deleteConfirm", { name: process.values.name }))) {
return;
+ }
setDeleting(true);
onDelete?.(process.id);
onDeleted?.();
}}
+ variant="destructive"
>
{t("processes.delete")}
@@ -130,7 +131,6 @@ export function ProcessDetail(props: ProcessDetailProps) {
setEdit(false)}
open={edit}
diff --git a/modules/companies/src/web/processes/list/api/get-processes.api.ts b/modules/companies/src/web/processes/list/api/get-processes.api.ts
index e9e7a4a..0ca5b67 100644
--- a/modules/companies/src/web/processes/list/api/get-processes.api.ts
+++ b/modules/companies/src/web/processes/list/api/get-processes.api.ts
@@ -5,6 +5,6 @@ export async function getProcesses(company: string) {
return ProcessesResponseSchema.parse(await processRequest(company));
}
-export async function deleteProcess(company: string, id: string, token: string) {
- await processRequest(`${company}/${id}/delete`, {}, token);
+export async function deleteProcess(company: string, id: string) {
+ await processRequest(`${company}/${id}/delete`, {});
}
diff --git a/modules/companies/src/web/processes/list/controllers/use-processes-page-controller.ts b/modules/companies/src/web/processes/list/controllers/use-processes-page-controller.ts
index 48125ef..8601361 100644
--- a/modules/companies/src/web/processes/list/controllers/use-processes-page-controller.ts
+++ b/modules/companies/src/web/processes/list/controllers/use-processes-page-controller.ts
@@ -38,8 +38,7 @@ export function useProcessesPageController({ company }: ProcessesPageProps) {
});
const remove = useMutation({
- mutationFn: ({ id, token }: { id: string; token: string }) =>
- deleteProcess(company.id, id, token),
+ mutationFn: (id: string) => deleteProcess(company.id, id),
onSuccess: async () => {
await client.invalidateQueries({ queryKey: processKeys.company(company.id) });
setSelected(undefined);
diff --git a/modules/companies/src/web/processes/list/types/processes-page-props.ts b/modules/companies/src/web/processes/list/types/processes-page-props.ts
index 1609a65..6991dc6 100644
--- a/modules/companies/src/web/processes/list/types/processes-page-props.ts
+++ b/modules/companies/src/web/processes/list/types/processes-page-props.ts
@@ -2,5 +2,4 @@ import type { CompanyDTO } from "../../../../common";
export type ProcessesPageProps = {
company: CompanyDTO;
- csrfToken: string;
};
diff --git a/modules/companies/src/web/processes/list/ui/processes-page.tsx b/modules/companies/src/web/processes/list/ui/processes-page.tsx
index 2b0721a..f0801a7 100644
--- a/modules/companies/src/web/processes/list/ui/processes-page.tsx
+++ b/modules/companies/src/web/processes/list/ui/processes-page.tsx
@@ -17,7 +17,7 @@ import { useProcessesPageController } from "../controllers";
import type { ProcessesPageProps } from "../types";
export function ProcessesPage(props: ProcessesPageProps) {
- const { company, csrfToken } = props;
+ const { company } = props;
const {
create,
setCreate,
@@ -66,11 +66,10 @@ export function ProcessesPage(props: ProcessesPageProps) {
)}
{current && !query.isError ? (
remove.mutate(id)}
+ onDeleted={() => setSelected(undefined)}
person={person(current.values.personId)}
process={current}
- onDeleted={() => setSelected(undefined)}
- onDelete={(id) => remove.mutate({ id, token: csrfToken })}
/>
) : (
!selected && (
@@ -163,7 +162,7 @@ export function ProcessesPage(props: ProcessesPageProps) {
if (
window.confirm(t("processes.deleteConfirm", { name: p.values.name }))
) {
- remove.mutate({ id: p.id, token: csrfToken });
+ remove.mutate(p.id);
}
}}
>
@@ -200,7 +199,6 @@ export function ProcessesPage(props: ProcessesPageProps) {
)}
{
setCreate(false);
diff --git a/modules/companies/src/web/processes/refresh/api/refresh-process.api.ts b/modules/companies/src/web/processes/refresh/api/refresh-process.api.ts
index a83a274..0eb130a 100644
--- a/modules/companies/src/web/processes/refresh/api/refresh-process.api.ts
+++ b/modules/companies/src/web/processes/refresh/api/refresh-process.api.ts
@@ -1,13 +1,8 @@
import { ProcessResponseSchema } from "../../../../common/processes";
import { processRequest } from "../../shared/api/process-request";
-export async function refreshProcess(
- company: string,
- id: string,
- revisionId: string,
- token: string
-) {
+export async function refreshProcess(company: string, id: string, revisionId: string) {
return ProcessResponseSchema.parse(
- await processRequest(`${company}/${id}/refresh`, { revisionId }, token)
+ await processRequest(`${company}/${id}/refresh`, { revisionId })
);
}
diff --git a/modules/companies/src/web/processes/shared/api/process-request.ts b/modules/companies/src/web/processes/shared/api/process-request.ts
index 2f1f5ce..810f41f 100644
--- a/modules/companies/src/web/processes/shared/api/process-request.ts
+++ b/modules/companies/src/web/processes/shared/api/process-request.ts
@@ -1,13 +1,13 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import { ProcessApiError } from "./process-api-error";
-export async function processRequest(path: string, body?: unknown, token?: string) {
- const response = await fetch(`/api/processes/${path}`, {
+export async function processRequest(path: string, body?: unknown) {
+ const response = await csrfFetch(`/api/processes/${path}`, {
method: body === undefined ? "GET" : "POST",
credentials: "same-origin",
- headers:
- body === undefined ? {} : { "content-type": "application/json", "x-csrf-token": token ?? "" },
+ headers: body === undefined ? {} : { "content-type": "application/json" },
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
const data: unknown = response.status === 204 ? undefined : await response.json();
diff --git a/modules/companies/src/web/processes/shared/processes.test.tsx b/modules/companies/src/web/processes/shared/processes.test.tsx
index e62354d..e14fe2a 100644
--- a/modules/companies/src/web/processes/shared/processes.test.tsx
+++ b/modules/companies/src/web/processes/shared/processes.test.tsx
@@ -55,11 +55,11 @@ async function render(language: string, node: ReactNode) {
test("procesos: listados es/en sin formularios junto a los datos", async () => {
for (const language of ["es", "en"]) {
const text = language === "es" ? companiesSpanish : companiesEnglish;
- const html = await render(language, );
+ const html = await render(language, );
assert.ok(html.includes(text.processes.new) && html.includes(text.processes.templates));
assert.ok(!html.includes(" );
+ const templates = await render(language, );
assert.ok(templates.includes(text.processes.globalTemplates));
assert.ok(!templates.includes(" {
const text = language === "es" ? companiesSpanish : companiesEnglish;
const html = await render(
language,
- undefined} />
+ undefined} />
);
assert.ok(html.includes(text.newPerson) && html.includes(text.processes.newTemplate));
@@ -81,10 +81,7 @@ test("procesos: alta rápida y ayuda inferior antes del pie", async () => {
test("plantillas: instrucciones, desactivación y ayuda global es/en sin datos de compañía", async () => {
for (const language of ["es", "en"]) {
const text = language === "es" ? companiesSpanish : companiesEnglish;
- const html = await render(
- language,
- undefined} />
- );
+ const html = await render(language, undefined} />);
assert.ok(html.includes(text.processes.instructionsHelp));
assert.ok(html.includes(text.processes.templateHelp.scope));
@@ -135,10 +132,7 @@ test("seguimiento: origen personal, revisión actual y edición sin afirmar reti
for (const language of ["es", "en"]) {
const text = language === "es" ? companiesSpanish : companiesEnglish;
- const html = await render(
- language,
-
- );
+ const html = await render(language, );
assert.ok(html.includes(text.remote.personal_mobile));
assert.ok(html.includes(text.processes.stillRecorded));
@@ -148,7 +142,7 @@ test("seguimiento: origen personal, revisión actual y edición sin afirmar reti
assert.ok(!html.includes(" undefined} process={process} />
+ undefined} process={process} />
);
assert.ok(editor.includes(text.processes.taskNotes));
@@ -157,7 +151,6 @@ test("seguimiento: origen personal, revisión actual y edición sin afirmar reti
const closed = await render(
language,
diff --git a/modules/companies/src/web/processes/start/api/start-process.api.ts b/modules/companies/src/web/processes/start/api/start-process.api.ts
index f362567..d6de362 100644
--- a/modules/companies/src/web/processes/start/api/start-process.api.ts
+++ b/modules/companies/src/web/processes/start/api/start-process.api.ts
@@ -2,6 +2,6 @@ import type { StartProcessInput } from "../../../../common/processes";
import { ProcessResponseSchema } from "../../../../common/processes";
import { processRequest } from "../../shared/api/process-request";
-export async function startProcess(company: string, values: StartProcessInput, token: string) {
- return ProcessResponseSchema.parse(await processRequest(company, { values }, token));
+export async function startProcess(company: string, values: StartProcessInput) {
+ return ProcessResponseSchema.parse(await processRequest(company, { values }));
}
diff --git a/modules/companies/src/web/processes/start/controllers/use-process-start-form-controller.ts b/modules/companies/src/web/processes/start/controllers/use-process-start-form-controller.ts
index 9d7b8df..de8fa3f 100644
--- a/modules/companies/src/web/processes/start/controllers/use-process-start-form-controller.ts
+++ b/modules/companies/src/web/processes/start/controllers/use-process-start-form-controller.ts
@@ -10,11 +10,7 @@ import { processKeys } from "../../shared/queries";
import { getProcessReview, startProcess } from "../api";
import type { ProcessStartFormProps } from "../types";
-export function useProcessStartFormController({
- company,
- csrfToken,
- onSaved,
-}: ProcessStartFormProps) {
+export function useProcessStartFormController({ company, onSaved }: ProcessStartFormProps) {
const client = useQueryClient();
const [quick, setQuick] = useState<"person" | "template">();
const mounted = useRef(true);
@@ -39,7 +35,7 @@ export function useProcessStartFormController({
enabled: Boolean(values.personId),
});
const mutation = useMutation({
- mutationFn: (input: StartProcessInput) => startProcess(company.id, input, csrfToken),
+ mutationFn: (input: StartProcessInput) => startProcess(company.id, input),
onSuccess: async (response) => {
await client.invalidateQueries({ queryKey: processKeys.company(company.id) });
if (mounted.current) {
diff --git a/modules/companies/src/web/processes/start/types/process-start-form-props.ts b/modules/companies/src/web/processes/start/types/process-start-form-props.ts
index 27ea6d7..abb6fb5 100644
--- a/modules/companies/src/web/processes/start/types/process-start-form-props.ts
+++ b/modules/companies/src/web/processes/start/types/process-start-form-props.ts
@@ -2,6 +2,5 @@ import type { CompanyDTO } from "../../../../common";
export type ProcessStartFormProps = {
company: CompanyDTO;
- csrfToken: string;
onSaved: (id: string) => void;
};
diff --git a/modules/companies/src/web/processes/start/ui/process-start-dialog.tsx b/modules/companies/src/web/processes/start/ui/process-start-dialog.tsx
index a4a6d65..6e3aa07 100644
--- a/modules/companies/src/web/processes/start/ui/process-start-dialog.tsx
+++ b/modules/companies/src/web/processes/start/ui/process-start-dialog.tsx
@@ -9,13 +9,11 @@ import { ProcessStartForm } from "./process-start-form";
export function ProcessStartDialog({
open,
company,
- csrfToken,
onSaved,
onOpenChange,
}: {
open: boolean;
company: CompanyDTO;
- csrfToken: string;
onSaved: ComponentProps["onSaved"];
onOpenChange: (open: boolean) => void;
}) {
@@ -30,7 +28,7 @@ export function ProcessStartDialog({
title={t("processes.new")}
wide
>
- {open && }
+ {open && }
);
}
diff --git a/modules/companies/src/web/processes/start/ui/process-start-form.tsx b/modules/companies/src/web/processes/start/ui/process-start-form.tsx
index 1d1ea0c..ab07186 100644
--- a/modules/companies/src/web/processes/start/ui/process-start-form.tsx
+++ b/modules/companies/src/web/processes/start/ui/process-start-form.tsx
@@ -13,7 +13,7 @@ import { useProcessStartFormController } from "../controllers";
import type { ProcessStartFormProps } from "../types";
export function ProcessStartForm(props: ProcessStartFormProps) {
- const { company, csrfToken } = props;
+ const { company } = props;
const { quick, setQuick, query, form, values, template, review, mutation, onCreated, submit } =
useProcessStartFormController(props);
const { t } = useTranslation("companies");
@@ -108,7 +108,6 @@ export function ProcessStartForm(props: ProcessStartFormProps) {
{quick && (
{
if (!open) {
diff --git a/modules/companies/src/web/processes/update/api/update-process.api.ts b/modules/companies/src/web/processes/update/api/update-process.api.ts
index 8b6ccc6..b3a82f4 100644
--- a/modules/companies/src/web/processes/update/api/update-process.api.ts
+++ b/modules/companies/src/web/processes/update/api/update-process.api.ts
@@ -2,13 +2,6 @@ import type { UpdateProcessInput } from "../../../../common/processes";
import { ProcessResponseSchema } from "../../../../common/processes";
import { processRequest } from "../../shared/api/process-request";
-export async function updateProcess(
- company: string,
- id: string,
- values: UpdateProcessInput,
- token: string
-) {
- return ProcessResponseSchema.parse(
- await processRequest(`${company}/${id}/update`, { values }, token)
- );
+export async function updateProcess(company: string, id: string, values: UpdateProcessInput) {
+ return ProcessResponseSchema.parse(await processRequest(`${company}/${id}/update`, { values }));
}
diff --git a/modules/companies/src/web/processes/update/controllers/use-process-edit-form-controller.ts b/modules/companies/src/web/processes/update/controllers/use-process-edit-form-controller.ts
index 6e92dd8..407f3e6 100644
--- a/modules/companies/src/web/processes/update/controllers/use-process-edit-form-controller.ts
+++ b/modules/companies/src/web/processes/update/controllers/use-process-edit-form-controller.ts
@@ -9,11 +9,7 @@ import { processKeys } from "../../shared/queries";
import { updateProcess } from "../api";
import type { ProcessEditFormProps } from "../types";
-export function useProcessEditFormController({
- process,
- csrfToken,
- onSaved,
-}: ProcessEditFormProps) {
+export function useProcessEditFormController({ process, onSaved }: ProcessEditFormProps) {
const client = useQueryClient();
const mounted = useRef(true);
@@ -39,8 +35,7 @@ export function useProcessEditFormController({
},
});
const mutation = useMutation({
- mutationFn: (input: UpdateProcessInput) =>
- updateProcess(process.companyId, process.id, input, csrfToken),
+ mutationFn: (input: UpdateProcessInput) => updateProcess(process.companyId, process.id, input),
onSuccess: async () => {
await client.invalidateQueries({ queryKey: processKeys.company(process.companyId) });
if (mounted.current) {
diff --git a/modules/companies/src/web/processes/update/types/process-edit-form-props.ts b/modules/companies/src/web/processes/update/types/process-edit-form-props.ts
index aba5844..f303f36 100644
--- a/modules/companies/src/web/processes/update/types/process-edit-form-props.ts
+++ b/modules/companies/src/web/processes/update/types/process-edit-form-props.ts
@@ -2,6 +2,5 @@ import type { PersonProcessDTO } from "../../../../common/processes";
export type ProcessEditFormProps = {
process: PersonProcessDTO;
- csrfToken: string;
onSaved: () => void;
};
diff --git a/modules/companies/src/web/processes/update/ui/process-edit-dialog.tsx b/modules/companies/src/web/processes/update/ui/process-edit-dialog.tsx
index d345bd0..2449111 100644
--- a/modules/companies/src/web/processes/update/ui/process-edit-dialog.tsx
+++ b/modules/companies/src/web/processes/update/ui/process-edit-dialog.tsx
@@ -7,13 +7,11 @@ import { ProcessEditForm } from "./process-edit-form";
export function ProcessEditDialog({
open,
process,
- csrfToken,
onSaved,
onOpenChange,
}: {
open: boolean;
process: ComponentProps["process"];
- csrfToken: string;
onSaved: () => void;
onOpenChange: (open: boolean) => void;
}) {
@@ -28,7 +26,7 @@ export function ProcessEditDialog({
title={t("processes.update")}
wide
>
- {open && }
+ {open && }
);
}
diff --git a/modules/companies/src/web/remote-connections/create/ui/remote-quick-editor.tsx b/modules/companies/src/web/remote-connections/create/ui/remote-quick-editor.tsx
index 2db42bb..8b11337 100644
--- a/modules/companies/src/web/remote-connections/create/ui/remote-quick-editor.tsx
+++ b/modules/companies/src/web/remote-connections/create/ui/remote-quick-editor.tsx
@@ -11,14 +11,12 @@ export type RemoteQuickKind = "person" | "source" | "target" | "resource" | "sit
export function RemoteQuickEditor({
kind,
company,
- csrfToken,
personId,
onSaved,
onClose,
}: {
kind: RemoteQuickKind;
company: CompanyDTO;
- csrfToken: string;
personId: string;
onSaved: (id: string) => void;
onClose: () => void;
@@ -29,7 +27,6 @@ export function RemoteQuickEditor({
return (
{kind === "site" ? (
-
+
) : (
-
+
)}
);
diff --git a/modules/companies/src/web/remote-connections/list/types/remote-connections-page-props.ts b/modules/companies/src/web/remote-connections/list/types/remote-connections-page-props.ts
index c6b87ae..58311ab 100644
--- a/modules/companies/src/web/remote-connections/list/types/remote-connections-page-props.ts
+++ b/modules/companies/src/web/remote-connections/list/types/remote-connections-page-props.ts
@@ -2,6 +2,5 @@ import type { CompanyDTO } from "../../../../common";
export type RemoteConnectionsPageProps = {
company: CompanyDTO;
- csrfToken: string;
initialPersonId?: string | undefined;
};
diff --git a/modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx b/modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx
index 5dbccda..e2e75f4 100644
--- a/modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx
+++ b/modules/companies/src/web/remote-connections/list/ui/remote-connections-page.tsx
@@ -15,7 +15,7 @@ import { useRemoteConnectionsPageController } from "../controllers";
import type { RemoteConnectionsPageProps } from "../types";
export function RemoteConnectionsPage(props: RemoteConnectionsPageProps) {
- const { company, csrfToken, initialPersonId } = props;
+ const { company, initialPersonId } = props;
const {
editor,
setEditor,
@@ -160,7 +160,6 @@ export function RemoteConnectionsPage(props: RemoteConnectionsPageProps) {
setEditor(undefined)}
/>
diff --git a/modules/companies/src/web/remote-connections/shared/api/remote-api.ts b/modules/companies/src/web/remote-connections/shared/api/remote-api.ts
index abf3ba6..239b1d2 100644
--- a/modules/companies/src/web/remote-connections/shared/api/remote-api.ts
+++ b/modules/companies/src/web/remote-connections/shared/api/remote-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { RemoteConnectionInput } from "../../../../common/remote-connections";
@@ -14,18 +15,16 @@ export class RemoteApiError extends Error {
}
}
-async function request(
- companyId: string,
- values?: RemoteConnectionInput,
- token?: string,
- id?: string
-) {
- const response = await fetch(`/api/remote-connections/${companyId}${id ? `/${id}/update` : ""}`, {
- method: values ? "POST" : "GET",
- credentials: "same-origin",
- headers: values ? { "content-type": "application/json", "x-csrf-token": token ?? "" } : {},
- ...(values ? { body: JSON.stringify({ values }) } : {}),
- });
+async function request(companyId: string, values?: RemoteConnectionInput, id?: string) {
+ const response = await csrfFetch(
+ `/api/remote-connections/${companyId}${id ? `/${id}/update` : ""}`,
+ {
+ method: values ? "POST" : "GET",
+ credentials: "same-origin",
+ headers: values ? { "content-type": "application/json" } : {},
+ ...(values ? { body: JSON.stringify({ values }) } : {}),
+ }
+ );
const body: unknown = await response.json();
if (!response.ok) {
@@ -41,7 +40,7 @@ export const remoteApi = {
async get(companyId: string) {
return RemoteConnectionsResponseSchema.parse(await request(companyId));
},
- async save(companyId: string, values: RemoteConnectionInput, token: string, id?: string) {
- return RemoteConnectionResponseSchema.parse(await request(companyId, values, token, id));
+ async save(companyId: string, values: RemoteConnectionInput, id?: string) {
+ return RemoteConnectionResponseSchema.parse(await request(companyId, values, id));
},
};
diff --git a/modules/companies/src/web/remote-connections/shared/controllers/use-remote-connection-form-controller.ts b/modules/companies/src/web/remote-connections/shared/controllers/use-remote-connection-form-controller.ts
index d79be8b..4c4fc63 100644
--- a/modules/companies/src/web/remote-connections/shared/controllers/use-remote-connection-form-controller.ts
+++ b/modules/companies/src/web/remote-connections/shared/controllers/use-remote-connection-form-controller.ts
@@ -27,7 +27,6 @@ const QUICK_FIELDS = {
export function useRemoteConnectionFormController({
company,
- csrfToken,
connection,
initialPersonId,
onSaved,
@@ -75,7 +74,7 @@ export function useRemoteConnectionFormController({
: ["pending", "configured"];
const mutation = useMutation({
mutationFn: (values: RemoteConnectionInput) =>
- remoteApi.save(company.id, values, csrfToken, connection?.id),
+ remoteApi.save(company.id, values, connection?.id),
onSuccess: async () => {
await client.invalidateQueries({ queryKey: remoteKeys.company(company.id) });
if (mounted.current) {
diff --git a/modules/companies/src/web/remote-connections/shared/remote.test.tsx b/modules/companies/src/web/remote-connections/shared/remote.test.tsx
index 1e15583..00abbc0 100644
--- a/modules/companies/src/web/remote-connections/shared/remote.test.tsx
+++ b/modules/companies/src/web/remote-connections/shared/remote.test.tsx
@@ -59,10 +59,7 @@ async function render(language: string, node: ReactNode) {
test("remotos: consulta sin formularios y traducciones", async () => {
for (const language of ["es", "en"]) {
- const html = await render(
- language,
-
- );
+ const html = await render(language, );
const text = language === "es" ? companiesSpanish : companiesEnglish;
assert.ok(html.includes(text.remote.title));
@@ -74,7 +71,7 @@ test("remotos: formulario, altas rápidas y ayuda antes del pie", async () => {
for (const language of ["es", "en"]) {
const html = await render(
language,
- undefined} />
+ undefined} />
);
const text = language === "es" ? companiesSpanish : companiesEnglish;
diff --git a/modules/companies/src/web/remote-connections/shared/types/remote-connection-form-props.ts b/modules/companies/src/web/remote-connections/shared/types/remote-connection-form-props.ts
index 69366d9..c260538 100644
--- a/modules/companies/src/web/remote-connections/shared/types/remote-connection-form-props.ts
+++ b/modules/companies/src/web/remote-connections/shared/types/remote-connection-form-props.ts
@@ -3,7 +3,6 @@ import type { RemoteConnectionDTO } from "../../../../common/remote-connections"
export type RemoteConnectionFormProps = {
company: CompanyDTO;
- csrfToken: string;
connection?: RemoteConnectionDTO | undefined;
initialPersonId?: string | undefined;
onSaved: () => void;
diff --git a/modules/companies/src/web/remote-connections/shared/ui/remote-connection-editor-dialog.tsx b/modules/companies/src/web/remote-connections/shared/ui/remote-connection-editor-dialog.tsx
index 621e926..a845b4a 100644
--- a/modules/companies/src/web/remote-connections/shared/ui/remote-connection-editor-dialog.tsx
+++ b/modules/companies/src/web/remote-connections/shared/ui/remote-connection-editor-dialog.tsx
@@ -9,13 +9,11 @@ import { RemoteConnectionForm } from "./remote-connection-form";
export function RemoteConnectionEditorDialog({
connection,
company,
- csrfToken,
initialPersonId,
onClose,
}: {
connection: ComponentProps["connection"];
company: CompanyDTO;
- csrfToken: string;
initialPersonId: ComponentProps["initialPersonId"];
onClose: () => void;
}) {
@@ -37,7 +35,6 @@ export function RemoteConnectionEditorDialog({
onClose()}
/>
diff --git a/modules/companies/src/web/remote-connections/shared/ui/remote-connection-form.tsx b/modules/companies/src/web/remote-connections/shared/ui/remote-connection-form.tsx
index 088a8cc..ba5073d 100644
--- a/modules/companies/src/web/remote-connections/shared/ui/remote-connection-form.tsx
+++ b/modules/companies/src/web/remote-connections/shared/ui/remote-connection-form.tsx
@@ -18,7 +18,7 @@ import { RemoteEndpointFields } from "./remote-endpoint-fields";
import { RemoteFeedback } from "./remote-feedback";
export function RemoteConnectionForm(props: RemoteConnectionFormProps) {
- const { company, csrfToken } = props;
+ const { company } = props;
const {
quick,
setQuick,
@@ -148,7 +148,6 @@ export function RemoteConnectionForm(props: RemoteConnectionFormProps) {
{quick && (
setQuick(undefined)}
onSaved={quickCreated}
diff --git a/modules/companies/src/web/shared/api/delete-record.api.ts b/modules/companies/src/web/shared/api/delete-record.api.ts
index fa88214..5be1e42 100644
--- a/modules/companies/src/web/shared/api/delete-record.api.ts
+++ b/modules/companies/src/web/shared/api/delete-record.api.ts
@@ -1,10 +1,11 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
-export async function deleteRecord(path: string, token: string) {
- const response = await fetch(path, {
+export async function deleteRecord(path: string) {
+ const response = await csrfFetch(path, {
method: "POST",
credentials: "same-origin",
- headers: { "content-type": "application/json", "x-csrf-token": token },
+ headers: { "content-type": "application/json" },
body: "{}",
});
diff --git a/modules/companies/src/web/shared/client-contracts.test.ts b/modules/companies/src/web/shared/client-contracts.test.ts
index 2f9dcf9..0a0943d 100644
--- a/modules/companies/src/web/shared/client-contracts.test.ts
+++ b/modules/companies/src/web/shared/client-contracts.test.ts
@@ -1,6 +1,8 @@
import assert from "node:assert/strict";
import { test } from "node:test";
+import { configureCsrfTokenReader } from "@metis/core/client";
+
import { COMPANY_LOGO_LIMITS, COMPANY_LOGO_TYPES } from "../../common";
import { getAccess } from "../access/list/api";
import { saveAccess } from "../access/shared/api";
@@ -16,6 +18,7 @@ import { buildSiteRequest } from "../sites/shared/adapters";
const COMPANY_ID = "e0420eb9-2aab-4368-96a0-2ce83dd23eb4";
test("las consultas de compañías conservan sus rutas y rechazan respuestas inválidas", async (context) => {
+ context.after(configureCsrfTokenReader(() => "a".repeat(64)));
context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => {
assert.equal(options.method, "GET");
if (url === "/api/companies") {
@@ -30,6 +33,7 @@ test("las consultas de compañías conservan sus rutas y rechazan respuestas inv
});
test("lectura y guardado de accesos están separados sin cambiar el contrato HTTP", async (context) => {
+ context.after(configureCsrfTokenReader(() => "a".repeat(64)));
const calls: { url: unknown; options: RequestInit }[] = [];
context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => {
@@ -40,7 +44,7 @@ test("lectura y guardado de accesos están separados sin cambiar el contrato HTT
await getAccess("global");
const values = { kind: "system", name: "Directory", active: true } as const;
- await saveAccess("global", values, COMPANY_ID, "csrf");
+ await saveAccess("global", values, COMPANY_ID);
assert.deepEqual(
calls.map((call) => call.url),
["/api/access/global", `/api/access/global/${COMPANY_ID}/update`]
@@ -51,10 +55,11 @@ test("lectura y guardado de accesos están separados sin cambiar el contrato HTT
assert.ok(save);
assert.equal(save.method, "POST");
assert.equal(save.body, JSON.stringify({ values }));
- assert.equal(new Headers(save.headers).get("x-csrf-token"), "csrf");
+ assert.equal(new Headers(save.headers).get("x-csrf-token"), "a".repeat(64));
});
test("el guardado de usos de buzón mantiene su endpoint y no se confunde con la consulta", async (context) => {
+ context.after(configureCsrfTokenReader(() => "a".repeat(64)));
const calls: { url: unknown; options: RequestInit }[] = [];
context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => {
@@ -70,7 +75,7 @@ test("el guardado de usos de buzón mantiene su endpoint y no se confunde con la
endDate: null,
};
- await saveMailboxUse(COMPANY_ID, values, "csrf", COMPANY_ID);
+ await saveMailboxUse(COMPANY_ID, values, COMPANY_ID);
assert.deepEqual(
calls.map((call) => call.url),
[`/api/mailboxes/${COMPANY_ID}`, `/api/mailboxes/${COMPANY_ID}/uses/${COMPANY_ID}/update`]
diff --git a/modules/companies/src/web/shared/types/configuration-quick-editor-props.ts b/modules/companies/src/web/shared/types/configuration-quick-editor-props.ts
index 89d0c5f..abccafa 100644
--- a/modules/companies/src/web/shared/types/configuration-quick-editor-props.ts
+++ b/modules/companies/src/web/shared/types/configuration-quick-editor-props.ts
@@ -6,7 +6,6 @@ export type ConfigurationQuickEditorProps = {
kind: ConfigurationQuickKind;
title?: string;
company: CompanyDTO;
- csrfToken: string;
values: Readonly<{
personId: string;
accountId: string;
diff --git a/modules/companies/src/web/shared/ui/configuration-quick-editor.tsx b/modules/companies/src/web/shared/ui/configuration-quick-editor.tsx
index 8feed05..f306072 100644
--- a/modules/companies/src/web/shared/ui/configuration-quick-editor.tsx
+++ b/modules/companies/src/web/shared/ui/configuration-quick-editor.tsx
@@ -16,7 +16,7 @@ const titles = {
} as const;
export function ConfigurationQuickEditor(props: ConfigurationQuickEditorProps) {
- const { kind, title, company, csrfToken, values, data } = props;
+ const { kind, title, company, values, data } = props;
const { created, close, catalog } = useConfigurationQuickEditorController(props);
const { t } = useTranslation("companies");
@@ -36,7 +36,6 @@ export function ConfigurationQuickEditor(props: ConfigurationQuickEditorProps) {
{kind === "person" && (
created("personId", id)}
requireActive
/>
@@ -44,7 +43,6 @@ export function ConfigurationQuickEditor(props: ConfigurationQuickEditorProps) {
{(kind === "account" || kind === "authorization") && data && (
void;
companyId: string;
@@ -30,7 +28,7 @@ export function DeleteRecordDialog({
if (!path) {
return;
}
- await deleteRecord(path, csrfToken);
+ await deleteRecord(path);
await Promise.all([
client.invalidateQueries({ queryKey }),
client.invalidateQueries({ queryKey: ["person-processes", companyId] }),
diff --git a/modules/companies/src/web/sites/list/ui/site-section.tsx b/modules/companies/src/web/sites/list/ui/site-section.tsx
index 8a55b8d..4f73592 100644
--- a/modules/companies/src/web/sites/list/ui/site-section.tsx
+++ b/modules/companies/src/web/sites/list/ui/site-section.tsx
@@ -11,7 +11,7 @@ import { useTranslation } from "react-i18next";
import type { CompanyDTO } from "../../../../common";
import { SiteEditorDialog } from "../../shared";
-export function SiteSection({ company, csrfToken }: { company: CompanyDTO; csrfToken: string }) {
+export function SiteSection({ company }: { company: CompanyDTO }) {
const { t, i18n } = useTranslation("companies");
const [createOpen, setCreateOpen] = useState(false);
const [selectedId, setSelectedId] = useState();
@@ -59,14 +59,12 @@ export function SiteSection({ company, csrfToken }: { company: CompanyDTO; csrfT
/>
setCreateOpen(false)}
open={createOpen}
/>
{
if (!open) {
setSelectedId(undefined);
diff --git a/modules/companies/src/web/sites/shared/api/save-site.api.ts b/modules/companies/src/web/sites/shared/api/save-site.api.ts
index edd881d..f2ee594 100644
--- a/modules/companies/src/web/sites/shared/api/save-site.api.ts
+++ b/modules/companies/src/web/sites/shared/api/save-site.api.ts
@@ -1,10 +1,5 @@
import { CompanyResponseSchema } from "../../../../common";
import { companyRequest } from "../../../companies/shared/api/company-request";
-export const saveSite = (companyId: string, id: string | undefined, body: unknown, token: string) =>
- companyRequest(
- `/${companyId}/sites${id ? `/${id}/update` : ""}`,
- CompanyResponseSchema,
- body,
- token
- );
+export const saveSite = (companyId: string, id: string | undefined, body: unknown) =>
+ companyRequest(`/${companyId}/sites${id ? `/${id}/update` : ""}`, CompanyResponseSchema, body);
diff --git a/modules/companies/src/web/sites/shared/controllers/use-site-form-controller.ts b/modules/companies/src/web/sites/shared/controllers/use-site-form-controller.ts
index d98dfdb..909514d 100644
--- a/modules/companies/src/web/sites/shared/controllers/use-site-form-controller.ts
+++ b/modules/companies/src/web/sites/shared/controllers/use-site-form-controller.ts
@@ -9,15 +9,14 @@ import { buildSiteRequest } from "../adapters";
import { saveSite } from "../api";
import type { SiteFormProps } from "../types";
-export function useSiteFormController({ site, companyId, csrfToken, onSaved }: SiteFormProps) {
+export function useSiteFormController({ site, companyId, onSaved }: SiteFormProps) {
const client = useQueryClient();
const form = useForm({
resolver: zodResolver(SiteRequestSchema),
defaultValues: { name: site?.name ?? "", address: site?.address ?? "" },
});
const mutation = useMutation({
- mutationFn: (values: SiteRequestDTO) =>
- saveSite(companyId, site?.id, buildSiteRequest(values), csrfToken),
+ mutationFn: (values: SiteRequestDTO) => saveSite(companyId, site?.id, buildSiteRequest(values)),
onSuccess: (response) => {
client.setQueryData(companyKeys.detail(companyId), response);
if (!site) {
diff --git a/modules/companies/src/web/sites/shared/types/site-form-props.ts b/modules/companies/src/web/sites/shared/types/site-form-props.ts
index 9721aa0..5671b0c 100644
--- a/modules/companies/src/web/sites/shared/types/site-form-props.ts
+++ b/modules/companies/src/web/sites/shared/types/site-form-props.ts
@@ -3,7 +3,6 @@ import type { SiteDTO } from "../../../../common";
export type SiteFormProps = {
site?: SiteDTO;
companyId: string;
- csrfToken: string;
onSaved?: (id: string) => void;
showTitle?: boolean;
};
diff --git a/modules/companies/src/web/telework-authorizations/list/types/telework-authorizations-page-props.ts b/modules/companies/src/web/telework-authorizations/list/types/telework-authorizations-page-props.ts
index 20644cd..ffb97c2 100644
--- a/modules/companies/src/web/telework-authorizations/list/types/telework-authorizations-page-props.ts
+++ b/modules/companies/src/web/telework-authorizations/list/types/telework-authorizations-page-props.ts
@@ -2,6 +2,5 @@ import type { CompanyDTO } from "../../../../common";
export type TeleworkAuthorizationsPageProps = {
company: CompanyDTO;
- csrfToken: string;
initialPersonId?: string | undefined;
};
diff --git a/modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx b/modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx
index 5cf743c..e53ee0e 100644
--- a/modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx
+++ b/modules/companies/src/web/telework-authorizations/list/ui/telework-authorizations-page.tsx
@@ -15,7 +15,7 @@ import { useTeleworkAuthorizationsPageController } from "../controllers";
import type { TeleworkAuthorizationsPageProps } from "../types";
export function TeleworkAuthorizationsPage(props: TeleworkAuthorizationsPageProps) {
- const { company, csrfToken, initialPersonId } = props;
+ const { company, initialPersonId } = props;
const {
editor,
setEditor,
@@ -143,7 +143,6 @@ export function TeleworkAuthorizationsPage(props: TeleworkAuthorizationsPageProp
authorization={edited}
authorizations={authorizations}
company={company}
- csrfToken={csrfToken}
initialPersonId={initialPersonId}
onClose={() => setEditor(undefined)}
/>
diff --git a/modules/companies/src/web/telework-authorizations/shared/api/telework-api.ts b/modules/companies/src/web/telework-authorizations/shared/api/telework-api.ts
index ee1bc96..cc5ffec 100644
--- a/modules/companies/src/web/telework-authorizations/shared/api/telework-api.ts
+++ b/modules/companies/src/web/telework-authorizations/shared/api/telework-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { TeleworkAuthorizationInput } from "../../../../common/telework-authorizations";
@@ -14,18 +15,13 @@ export class TeleworkApiError extends Error {
}
}
-async function request(
- companyId: string,
- values?: TeleworkAuthorizationInput,
- token?: string,
- id?: string
-) {
- const response = await fetch(
+async function request(companyId: string, values?: TeleworkAuthorizationInput, id?: string) {
+ const response = await csrfFetch(
`/api/telework-authorizations/${companyId}${id ? `/${id}/update` : ""}`,
{
method: values ? "POST" : "GET",
credentials: "same-origin",
- headers: values ? { "content-type": "application/json", "x-csrf-token": token ?? "" } : {},
+ headers: values ? { "content-type": "application/json" } : {},
...(values ? { body: JSON.stringify({ values }) } : {}),
}
);
@@ -44,7 +40,7 @@ export const teleworkApi = {
async get(companyId: string) {
return TeleworkAuthorizationsResponseSchema.parse(await request(companyId));
},
- async save(companyId: string, values: TeleworkAuthorizationInput, token: string, id?: string) {
- return TeleworkAuthorizationResponseSchema.parse(await request(companyId, values, token, id));
+ async save(companyId: string, values: TeleworkAuthorizationInput, id?: string) {
+ return TeleworkAuthorizationResponseSchema.parse(await request(companyId, values, id));
},
};
diff --git a/modules/companies/src/web/telework-authorizations/shared/controllers/use-telework-authorization-form-controller.ts b/modules/companies/src/web/telework-authorizations/shared/controllers/use-telework-authorization-form-controller.ts
index d8c804d..33cf52f 100644
--- a/modules/companies/src/web/telework-authorizations/shared/controllers/use-telework-authorization-form-controller.ts
+++ b/modules/companies/src/web/telework-authorizations/shared/controllers/use-telework-authorization-form-controller.ts
@@ -11,7 +11,6 @@ import type { TeleworkAuthorizationFormProps } from "../types";
export function useTeleworkAuthorizationFormController({
company,
- csrfToken,
authorization,
authorizations,
initialPersonId,
@@ -42,7 +41,7 @@ export function useTeleworkAuthorizationFormController({
const fixed = Boolean(authorization || initialPersonId);
const mutation = useMutation({
mutationFn: (input: TeleworkAuthorizationInput) =>
- teleworkApi.save(company.id, input, csrfToken, authorization?.id),
+ teleworkApi.save(company.id, input, authorization?.id),
onSuccess: async () => {
await Promise.all([
client.invalidateQueries({ queryKey: teleworkKeys.company(company.id) }),
diff --git a/modules/companies/src/web/telework-authorizations/shared/telework.test.tsx b/modules/companies/src/web/telework-authorizations/shared/telework.test.tsx
index 6cdb2d9..7935181 100644
--- a/modules/companies/src/web/telework-authorizations/shared/telework.test.tsx
+++ b/modules/companies/src/web/telework-authorizations/shared/telework.test.tsx
@@ -51,10 +51,7 @@ async function render(language: string, node: ReactNode) {
test("teletrabajo: consulta sin formularios y traducciones", async () => {
for (const language of ["es", "en"]) {
- const html = await render(
- language,
-
- );
+ const html = await render(language, );
const text = language === "es" ? companiesSpanish : companiesEnglish;
assert.ok(html.includes(text.telework.title));
@@ -67,12 +64,7 @@ test("teletrabajo: formulario con alta rápida de persona, fechas opcionales y a
for (const language of ["es", "en"]) {
const html = await render(
language,
- undefined}
- />
+ undefined} />
);
const text = language === "es" ? companiesSpanish : companiesEnglish;
@@ -123,7 +115,6 @@ test("teletrabajo: alta desde un perfil fija la persona y no abre otra alta ráp
undefined}
/>
diff --git a/modules/companies/src/web/telework-authorizations/shared/types/telework-authorization-form-props.ts b/modules/companies/src/web/telework-authorizations/shared/types/telework-authorization-form-props.ts
index 2b530ce..31d127b 100644
--- a/modules/companies/src/web/telework-authorizations/shared/types/telework-authorization-form-props.ts
+++ b/modules/companies/src/web/telework-authorizations/shared/types/telework-authorization-form-props.ts
@@ -3,7 +3,6 @@ import type { TeleworkAuthorizationDTO } from "../../../../common/telework-autho
export type TeleworkAuthorizationFormProps = {
company: CompanyDTO;
- csrfToken: string;
authorization?: TeleworkAuthorizationDTO | undefined;
authorizations: readonly TeleworkAuthorizationDTO[];
initialPersonId?: string | undefined;
diff --git a/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-editor-dialog.tsx b/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-editor-dialog.tsx
index 28c10c1..e209e9d 100644
--- a/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-editor-dialog.tsx
+++ b/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-editor-dialog.tsx
@@ -9,14 +9,12 @@ import { TeleworkAuthorizationForm } from "./telework-authorization-form";
export function TeleworkAuthorizationEditorDialog({
authorization,
company,
- csrfToken,
authorizations,
initialPersonId,
onClose,
}: {
authorization: ComponentProps["authorization"];
company: CompanyDTO;
- csrfToken: string;
authorizations: ComponentProps["authorizations"];
initialPersonId: ComponentProps["initialPersonId"];
onClose: () => void;
@@ -39,7 +37,6 @@ export function TeleworkAuthorizationEditorDialog({
authorization={authorization}
authorizations={authorizations}
company={company}
- csrfToken={csrfToken}
initialPersonId={initialPersonId}
onSaved={() => onClose()}
/>
diff --git a/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-form.tsx b/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-form.tsx
index 329cb5f..e1af063 100644
--- a/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-form.tsx
+++ b/modules/companies/src/web/telework-authorizations/shared/ui/telework-authorization-form.tsx
@@ -16,7 +16,7 @@ import type { TeleworkAuthorizationFormProps } from "../types";
import { TeleworkFeedback } from "./telework-feedback";
export function TeleworkAuthorizationForm(props: TeleworkAuthorizationFormProps) {
- const { company, csrfToken, authorization } = props;
+ const { company, authorization } = props;
const { quick, setQuick, form, values, fixed, mutation, reserved, submit, personCreated } =
useTeleworkAuthorizationFormController(props);
const { t } = useTranslation("companies");
@@ -110,7 +110,6 @@ export function TeleworkAuthorizationForm(props: TeleworkAuthorizationFormProps)
{quick && (
{
if (!open) {
setQuick(false);
diff --git a/modules/companies/src/web/tickets/create/types/ticket-quick-editor-props.ts b/modules/companies/src/web/tickets/create/types/ticket-quick-editor-props.ts
index 83fd285..035c07a 100644
--- a/modules/companies/src/web/tickets/create/types/ticket-quick-editor-props.ts
+++ b/modules/companies/src/web/tickets/create/types/ticket-quick-editor-props.ts
@@ -3,6 +3,5 @@ import type { TicketTargetInput } from "../../../../common/tickets";
export type TicketQuickEditorProps = {
companyId: string;
kind: TicketTargetInput["kind"];
- csrfToken: string;
onSaved: (id: string) => void;
};
diff --git a/modules/companies/src/web/tickets/create/ui/intervention-ticket-create-dialog.tsx b/modules/companies/src/web/tickets/create/ui/intervention-ticket-create-dialog.tsx
index d942f55..cbb3acf 100644
--- a/modules/companies/src/web/tickets/create/ui/intervention-ticket-create-dialog.tsx
+++ b/modules/companies/src/web/tickets/create/ui/intervention-ticket-create-dialog.tsx
@@ -7,7 +7,6 @@ import { TicketForm } from "../../shared";
export function InterventionTicketCreateDialog({
open,
companyId,
- csrfToken,
tickets,
companies,
technicians,
@@ -16,7 +15,6 @@ export function InterventionTicketCreateDialog({
}: {
open: boolean;
companyId: string;
- csrfToken: string;
tickets: ComponentProps["data"]["tickets"];
companies: ComponentProps["data"]["companies"];
technicians: ComponentProps["data"]["technicians"];
@@ -36,7 +34,6 @@ export function InterventionTicketCreateDialog({
>
{open && (
- {kind === "person" && (
-
- )}
- {kind === "resource" && (
-
- )}
+ {kind === "person" && }
+ {kind === "resource" && }
{kind === "asset" && catalog.data && (
)}
{kind === "workstation" && (
-
+
)}
{
nested.onSaved(id);
setNested(undefined);
@@ -76,7 +65,6 @@ export function TicketQuickEditor(props: TicketQuickEditorProps) {
{nested?.kind === "site" && (
{
nested.onSaved(id);
setNested(undefined);
diff --git a/modules/companies/src/web/tickets/create/ui/ticket-quick-forms.tsx b/modules/companies/src/web/tickets/create/ui/ticket-quick-forms.tsx
index ad705b0..8f77655 100644
--- a/modules/companies/src/web/tickets/create/ui/ticket-quick-forms.tsx
+++ b/modules/companies/src/web/tickets/create/ui/ticket-quick-forms.tsx
@@ -7,14 +7,12 @@ import { PersonForm } from "../../../people";
export function TicketQuickForms({
kind,
companyId,
- csrfToken,
onClose,
onCompany,
onPerson,
}: {
kind: "company" | "person" | undefined;
companyId: string;
- csrfToken: string;
onClose: () => void;
onCompany: (id: string) => void;
onPerson: (id: string) => void;
@@ -33,12 +31,8 @@ export function TicketQuickForms({
open={Boolean(kind)}
title={t(kind === "company" ? "newCompany" : "newPerson")}
>
- {kind === "company" && (
-
- )}
- {kind === "person" && (
-
- )}
+ {kind === "company" && }
+ {kind === "person" && }
);
}
diff --git a/modules/companies/src/web/tickets/create/ui/ticket-target-create-dialog.tsx b/modules/companies/src/web/tickets/create/ui/ticket-target-create-dialog.tsx
index 83dcada..a2ea106 100644
--- a/modules/companies/src/web/tickets/create/ui/ticket-target-create-dialog.tsx
+++ b/modules/companies/src/web/tickets/create/ui/ticket-target-create-dialog.tsx
@@ -7,13 +7,11 @@ import { TicketQuickEditor } from "./ticket-quick-editor";
export function TicketTargetCreateDialog({
quick,
companyId,
- csrfToken,
onSaved,
onOpenChange,
}: {
quick: ComponentProps["kind"] | undefined;
companyId: string;
- csrfToken: string;
onSaved: (id: string) => void;
onOpenChange: (open: boolean) => void;
}) {
@@ -28,14 +26,7 @@ export function TicketTargetCreateDialog({
title={t("tickets.newTarget")}
wide
>
- {quick && (
-
- )}
+ {quick && }
);
}
diff --git a/modules/companies/src/web/tickets/list/types/tickets-page-props.ts b/modules/companies/src/web/tickets/list/types/tickets-page-props.ts
index 3e0dc8e..cf885d6 100644
--- a/modules/companies/src/web/tickets/list/types/tickets-page-props.ts
+++ b/modules/companies/src/web/tickets/list/types/tickets-page-props.ts
@@ -8,7 +8,6 @@ export type TicketFilters = {
export type TicketsPageProps = {
companyId?: string | undefined;
- csrfToken: string;
initialId?: string | undefined;
initialCreate?: boolean | undefined;
initialPendingOnly?: boolean | undefined;
diff --git a/modules/companies/src/web/tickets/list/ui/tickets-page.tsx b/modules/companies/src/web/tickets/list/ui/tickets-page.tsx
index 79afc01..97fe489 100644
--- a/modules/companies/src/web/tickets/list/ui/tickets-page.tsx
+++ b/modules/companies/src/web/tickets/list/ui/tickets-page.tsx
@@ -19,7 +19,7 @@ import { useTicketsPageController } from "../controllers";
import type { TicketsPageProps } from "../types";
export function TicketsPage(props: TicketsPageProps) {
- const { companyId, csrfToken } = props;
+ const { companyId } = props;
const {
query,
filters,
@@ -256,14 +256,12 @@ export function TicketsPage(props: TicketsPageProps) {
/>
setInterventionTicketId(undefined)}
/>
diff --git a/modules/companies/src/web/tickets/shared/api/ticket-api.ts b/modules/companies/src/web/tickets/shared/api/ticket-api.ts
index 3b48d1e..20f9cdf 100644
--- a/modules/companies/src/web/tickets/shared/api/ticket-api.ts
+++ b/modules/companies/src/web/tickets/shared/api/ticket-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { SaveTicketInput } from "../../../../common/tickets";
@@ -18,11 +19,11 @@ export class TicketApiError extends Error {
}
}
-async function request(path: string, input?: SaveTicketInput, token?: string) {
- const response = await fetch(`/api/tickets${path}`, {
+async function request(path: string, input?: SaveTicketInput) {
+ const response = await csrfFetch(`/api/tickets${path}`, {
method: input ? "POST" : "GET",
credentials: "same-origin",
- headers: input ? { "content-type": "application/json", "x-csrf-token": token ?? "" } : {},
+ headers: input ? { "content-type": "application/json" } : {},
...(input ? { body: JSON.stringify(input) } : {}),
});
const data: unknown = await response.json();
@@ -43,9 +44,9 @@ export const ticketApi = {
async lookups(companyId: string) {
return TicketLookupsSchema.parse(await request(`/${companyId}/lookups`));
},
- async save(companyId: string, input: SaveTicketInput, token: string, id?: string) {
+ async save(companyId: string, input: SaveTicketInput, id?: string) {
return TicketResponseSchema.parse(
- await request(`/${companyId}${id ? `/${id}/update` : ""}`, input, token)
+ await request(`/${companyId}${id ? `/${id}/update` : ""}`, input)
);
},
};
diff --git a/modules/companies/src/web/tickets/shared/controllers/use-ticket-form-controller.ts b/modules/companies/src/web/tickets/shared/controllers/use-ticket-form-controller.ts
index 4ee3673..eedc9ad 100644
--- a/modules/companies/src/web/tickets/shared/controllers/use-ticket-form-controller.ts
+++ b/modules/companies/src/web/tickets/shared/controllers/use-ticket-form-controller.ts
@@ -9,7 +9,7 @@ import { TicketInputSchema } from "../../../../common/tickets";
import { ticketApi, ticketKeys } from "../api";
import type { TicketFormProps } from "../types";
-export function useTicketFormController({ scope, ticket, csrfToken, onSaved }: TicketFormProps) {
+export function useTicketFormController({ scope, ticket, onSaved }: TicketFormProps) {
const client = useQueryClient();
const [companyId, setCompanyId] = useState(ticket?.companyId ?? scope ?? "");
const [requestKey] = useState(() => UniqueID.generateNewID().toPrimitive());
@@ -38,7 +38,6 @@ export function useTicketFormController({ scope, ticket, csrfToken, onSaved }: T
ticketApi.save(
companyId,
{ values: input, requestKey, expectedRevisionId: ticket?.history.at(-1)?.id ?? null },
- csrfToken,
ticket?.id
),
onSuccess: async (response) => {
diff --git a/modules/companies/src/web/tickets/shared/tickets.test.tsx b/modules/companies/src/web/tickets/shared/tickets.test.tsx
index d1259d4..d68c248 100644
--- a/modules/companies/src/web/tickets/shared/tickets.test.tsx
+++ b/modules/companies/src/web/tickets/shared/tickets.test.tsx
@@ -99,9 +99,7 @@ test("tickets: filtros globales por compañía, estado, prioridad, responsable y
assert.equal(filterTickets([item], { ...empty, assignee: "unassigned" }).length, 1);
});
test("tickets: alta modal, compañía fija y ayuda inferior", async () => {
- const html = await render(
- undefined} scope={companyId} />
- );
+ const html = await render( undefined} scope={companyId} />);
assert.ok(html.includes("Compañía test"));
assert.ok(html.includes("Nueva persona"));
@@ -115,12 +113,12 @@ test("tickets: vistas global y por compañía sin formularios junto al listado,
["es", "Todos los tickets"],
["en", "All tickets"],
]) {
- const html = await render( , language);
+ const html = await render( , language);
assert.ok(html.includes(expected ?? ""));
assert.equal(html.includes(" );
+ const scoped = await render( );
assert.equal(scoped.includes("tickets-company-filter"), false);
});
diff --git a/modules/companies/src/web/tickets/shared/types/ticket-form-props.ts b/modules/companies/src/web/tickets/shared/types/ticket-form-props.ts
index 510af26..0d6a17e 100644
--- a/modules/companies/src/web/tickets/shared/types/ticket-form-props.ts
+++ b/modules/companies/src/web/tickets/shared/types/ticket-form-props.ts
@@ -4,6 +4,5 @@ export type TicketFormProps = {
scope?: string;
ticket?: TicketDTO;
data: TicketListDTO;
- csrfToken: string;
onSaved: (id: string) => void;
};
diff --git a/modules/companies/src/web/tickets/shared/ui/ticket-editor-dialog.tsx b/modules/companies/src/web/tickets/shared/ui/ticket-editor-dialog.tsx
index c0b703f..1ada42c 100644
--- a/modules/companies/src/web/tickets/shared/ui/ticket-editor-dialog.tsx
+++ b/modules/companies/src/web/tickets/shared/ui/ticket-editor-dialog.tsx
@@ -8,14 +8,12 @@ export function TicketEditorDialog({
open,
edit,
companyId,
- csrfToken,
data,
onOpenChange,
}: {
open: boolean;
edit: ComponentProps["ticket"];
companyId: string | undefined;
- csrfToken: string;
data: ComponentProps["data"] | undefined;
onOpenChange: (open: boolean) => void;
}) {
@@ -35,7 +33,6 @@ export function TicketEditorDialog({
key={edit?.id ?? "new"}
{...(companyId ? { scope: companyId } : {})}
{...(edit ? { ticket: edit } : {})}
- csrfToken={csrfToken}
data={data}
onSaved={() => onOpenChange(false)}
/>
diff --git a/modules/companies/src/web/tickets/shared/ui/ticket-form.tsx b/modules/companies/src/web/tickets/shared/ui/ticket-form.tsx
index ba48697..ff95239 100644
--- a/modules/companies/src/web/tickets/shared/ui/ticket-form.tsx
+++ b/modules/companies/src/web/tickets/shared/ui/ticket-form.tsx
@@ -19,7 +19,7 @@ import { TicketHelp } from "./ticket-help";
import { TicketTargets } from "./ticket-targets";
export function TicketForm(props: TicketFormProps) {
- const { scope, ticket, data, csrfToken } = props;
+ const { scope, ticket, data } = props;
const {
client,
companyId,
@@ -130,7 +130,6 @@ export function TicketForm(props: TicketFormProps) {
{lookups.data && (
setQuick(undefined)}
onCompany={(id) => {
diff --git a/modules/companies/src/web/tickets/shared/ui/ticket-targets.tsx b/modules/companies/src/web/tickets/shared/ui/ticket-targets.tsx
index a0dedf4..c4891b1 100644
--- a/modules/companies/src/web/tickets/shared/ui/ticket-targets.tsx
+++ b/modules/companies/src/web/tickets/shared/ui/ticket-targets.tsx
@@ -12,14 +12,12 @@ import { ticketTargetOptions } from "../helpers";
export function TicketTargets({
companyId,
- csrfToken,
values,
lookups,
onChange,
lookupKey,
}: {
companyId: string;
- csrfToken: string;
values: TicketTargetInput[];
lookups: TicketLookupsDTO;
onChange: (values: TicketTargetInput[]) => void;
@@ -116,7 +114,6 @@ export function TicketTargets({
{
if (!open) {
setQuick(undefined);
diff --git a/modules/companies/src/web/work-environments/detail/ui/environment-content.tsx b/modules/companies/src/web/work-environments/detail/ui/environment-content.tsx
index 7793ccf..094b794 100644
--- a/modules/companies/src/web/work-environments/detail/ui/environment-content.tsx
+++ b/modules/companies/src/web/work-environments/detail/ui/environment-content.tsx
@@ -23,7 +23,6 @@ export function EnvironmentContent({
profile,
profiles,
sources,
- csrfToken,
onManage,
onProfile,
}: {
@@ -33,7 +32,6 @@ export function EnvironmentContent({
authorizations: readonly TeleworkAuthorizationDTO[];
profiles: readonly WorkProfileDTO[];
sources: EnvironmentSources;
- csrfToken: string;
onManage: (kind: ProfileConfigurationKind | "telework" | "remote") => void;
onProfile: (id: string) => void;
}) {
@@ -190,7 +188,6 @@ export function EnvironmentContent({
diff --git a/modules/companies/src/web/work-environments/detail/ui/profile-configurations.tsx b/modules/companies/src/web/work-environments/detail/ui/profile-configurations.tsx
index c308fee..bb35f27 100644
--- a/modules/companies/src/web/work-environments/detail/ui/profile-configurations.tsx
+++ b/modules/companies/src/web/work-environments/detail/ui/profile-configurations.tsx
@@ -16,20 +16,18 @@ import { WorkEnvironmentPage } from "./work-environment-page";
export function ProfileConfigurations({
personId,
company,
- csrfToken,
selection,
onBack,
onSelection,
}: {
company: CompanyDTO;
- csrfToken: string;
personId: string | undefined;
selection: ProfileSelection;
onSelection: (selection: ProfileSelection) => void;
onBack: () => void;
}) {
const { t } = useTranslation("companies");
- const props = { company, csrfToken, initialProfileId: selection.profileId };
+ const props = { company, initialProfileId: selection.profileId };
return (
@@ -44,7 +42,6 @@ export function ProfileConfigurations({
{selection.kind === "environment" && (
onSelection({ kind, profileId: selection.profileId, fromEnvironment: true })
}
@@ -53,14 +50,10 @@ export function ProfileConfigurations({
/>
)}
{selection.kind === "remote" && (
-
+
)}
{selection.kind === "telework" && (
-
+
)}
{selection.kind === "folders" && }
{selection.kind === "mail" && }
diff --git a/modules/companies/src/web/work-environments/detail/ui/work-environment-page.tsx b/modules/companies/src/web/work-environments/detail/ui/work-environment-page.tsx
index 685576f..b6cb84e 100644
--- a/modules/companies/src/web/work-environments/detail/ui/work-environment-page.tsx
+++ b/modules/companies/src/web/work-environments/detail/ui/work-environment-page.tsx
@@ -10,13 +10,11 @@ import { EnvironmentContent } from "./environment-content";
export function WorkEnvironmentPage({
company,
profileId,
- csrfToken,
onManage,
onProfile,
}: {
company: CompanyDTO;
profileId: string;
- csrfToken: string;
onManage: (kind: ProfileConfigurationKind | "telework" | "remote") => void;
onProfile: (id: string) => void;
}) {
@@ -54,7 +52,6 @@ export function WorkEnvironmentPage({
authorizations={query.data.authorizations}
company={company}
connections={query.data.connections}
- csrfToken={csrfToken}
key={profile.id}
onManage={onManage}
onProfile={onProfile}
diff --git a/modules/companies/src/web/work-environments/shared/work-environment.test.tsx b/modules/companies/src/web/work-environments/shared/work-environment.test.tsx
index ef4543c..16c9528 100644
--- a/modules/companies/src/web/work-environments/shared/work-environment.test.tsx
+++ b/modules/companies/src/web/work-environments/shared/work-environment.test.tsx
@@ -401,7 +401,6 @@ async function render(
undefined}
onProfile={() => undefined}
profileId={profile.id}
diff --git a/modules/companies/src/web/work-profiles/list/types/work-profiles-page-props.ts b/modules/companies/src/web/work-profiles/list/types/work-profiles-page-props.ts
index f8a632a..65da7cc 100644
--- a/modules/companies/src/web/work-profiles/list/types/work-profiles-page-props.ts
+++ b/modules/companies/src/web/work-profiles/list/types/work-profiles-page-props.ts
@@ -2,7 +2,6 @@ import type { CompanyDTO } from "../../../../common";
export type WorkProfilesPageProps = {
company: CompanyDTO;
- csrfToken: string;
initialId?: string | undefined;
initialConfiguration?:
| "folders"
diff --git a/modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx b/modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx
index 9232460..b5a9299 100644
--- a/modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx
+++ b/modules/companies/src/web/work-profiles/list/ui/work-profiles-page.tsx
@@ -16,7 +16,7 @@ import { useWorkProfilesPageController } from "../controllers";
import type { WorkProfilesPageProps } from "../types";
export function WorkProfilesPage(props: WorkProfilesPageProps) {
- const { company, csrfToken } = props;
+ const { company } = props;
const {
configuration,
setConfiguration,
@@ -50,7 +50,6 @@ export function WorkProfilesPage(props: WorkProfilesPageProps) {
return (
item.id === configuration.profileId)?.values.personId}
@@ -213,7 +212,6 @@ export function WorkProfilesPage(props: WorkProfilesPageProps) {
{editor && (
setEditor(undefined)}
profile={edited}
/>
diff --git a/modules/companies/src/web/work-profiles/shared/api/work-profile-api.ts b/modules/companies/src/web/work-profiles/shared/api/work-profile-api.ts
index bd844ad..8f14da2 100644
--- a/modules/companies/src/web/work-profiles/shared/api/work-profile-api.ts
+++ b/modules/companies/src/web/work-profiles/shared/api/work-profile-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { WorkProfileInput } from "../../../../common/work-profiles";
@@ -14,11 +15,11 @@ export class WorkProfileApiError extends Error {
}
}
-async function request(companyId: string, values?: WorkProfileInput, token?: string, id?: string) {
- const response = await fetch(`/api/work-profiles/${companyId}${id ? `/${id}/update` : ""}`, {
+async function request(companyId: string, values?: WorkProfileInput, id?: string) {
+ const response = await csrfFetch(`/api/work-profiles/${companyId}${id ? `/${id}/update` : ""}`, {
method: values ? "POST" : "GET",
credentials: "same-origin",
- headers: values ? { "content-type": "application/json", "x-csrf-token": token ?? "" } : {},
+ headers: values ? { "content-type": "application/json" } : {},
...(values ? { body: JSON.stringify({ values }) } : {}),
});
const json: unknown = await response.json();
@@ -36,7 +37,7 @@ export const profileApi = {
async get(companyId: string) {
return WorkProfilesResponseSchema.parse(await request(companyId));
},
- async save(companyId: string, values: WorkProfileInput, token: string, id?: string) {
- return WorkProfileResponseSchema.parse(await request(companyId, values, token, id));
+ async save(companyId: string, values: WorkProfileInput, id?: string) {
+ return WorkProfileResponseSchema.parse(await request(companyId, values, id));
},
};
diff --git a/modules/companies/src/web/work-profiles/shared/controllers/use-work-profile-form-controller.ts b/modules/companies/src/web/work-profiles/shared/controllers/use-work-profile-form-controller.ts
index ccfa72a..2da3f3d 100644
--- a/modules/companies/src/web/work-profiles/shared/controllers/use-work-profile-form-controller.ts
+++ b/modules/companies/src/web/work-profiles/shared/controllers/use-work-profile-form-controller.ts
@@ -13,12 +13,7 @@ import type { ConfigurationQuickKind } from "../../../shared/types";
import { profileApi, profileKeys } from "../api";
import type { WorkProfileFormProps } from "../types";
-export function useWorkProfileFormController({
- company,
- csrfToken,
- profile,
- onSaved,
-}: WorkProfileFormProps) {
+export function useWorkProfileFormController({ company, profile, onSaved }: WorkProfileFormProps) {
const client = useQueryClient();
const mounted = useRef(true);
@@ -67,8 +62,7 @@ export function useWorkProfileFormController({
);
});
const mutation = useMutation({
- mutationFn: (input: WorkProfileInput) =>
- profileApi.save(company.id, input, csrfToken, profile?.id),
+ mutationFn: (input: WorkProfileInput) => profileApi.save(company.id, input, profile?.id),
onSuccess: async (result) => {
await client.invalidateQueries({ queryKey: profileKeys.company(company.id) });
if (mounted.current) {
diff --git a/modules/companies/src/web/work-profiles/shared/profile.test.tsx b/modules/companies/src/web/work-profiles/shared/profile.test.tsx
index 2c54efd..eba6935 100644
--- a/modules/companies/src/web/work-profiles/shared/profile.test.tsx
+++ b/modules/companies/src/web/work-profiles/shared/profile.test.tsx
@@ -57,7 +57,7 @@ async function render(language: string, node: ReactNode) {
test("perfiles: listado es/en, alta en cabecera y ausencia de formulario junto al listado", async () => {
for (const language of ["es", "en"]) {
- const html = await render(language, );
+ const html = await render(language, );
assert.equal(html.includes(" {
- const html = await render(
- "es",
- undefined} />
- );
+ const html = await render("es", undefined} />);
for (const label of ["Nueva persona", "Nueva cuenta", "Nuevo dispositivo"]) {
assert.ok(html.includes(`aria-label="${label}"`));
diff --git a/modules/companies/src/web/work-profiles/shared/types/work-profile-form-props.ts b/modules/companies/src/web/work-profiles/shared/types/work-profile-form-props.ts
index e301b01..02e5bf6 100644
--- a/modules/companies/src/web/work-profiles/shared/types/work-profile-form-props.ts
+++ b/modules/companies/src/web/work-profiles/shared/types/work-profile-form-props.ts
@@ -3,7 +3,6 @@ import type { WorkProfileDTO } from "../../../../common/work-profiles";
export type WorkProfileFormProps = {
company: CompanyDTO;
- csrfToken: string;
profile?: WorkProfileDTO | undefined;
onSaved: (id: string) => void;
allowQuickCreate?: boolean;
diff --git a/modules/companies/src/web/work-profiles/shared/ui/work-profile-editor-dialog.tsx b/modules/companies/src/web/work-profiles/shared/ui/work-profile-editor-dialog.tsx
index 7f6602f..a45bffd 100644
--- a/modules/companies/src/web/work-profiles/shared/ui/work-profile-editor-dialog.tsx
+++ b/modules/companies/src/web/work-profiles/shared/ui/work-profile-editor-dialog.tsx
@@ -9,12 +9,10 @@ import { WorkProfileForm } from "./work-profile-form";
export function WorkProfileEditorDialog({
profile,
company,
- csrfToken,
onClose,
}: {
profile: ComponentProps["profile"];
company: CompanyDTO;
- csrfToken: string;
onClose: () => void;
}) {
const { t } = useTranslation("companies");
@@ -32,12 +30,7 @@ export function WorkProfileEditorDialog({
title={t(profile ? "profiles.edit" : "profiles.new")}
wide
>
- onClose()}
- profile={profile}
- />
+ onClose()} profile={profile} />
);
}
diff --git a/modules/companies/src/web/work-profiles/shared/ui/work-profile-form.tsx b/modules/companies/src/web/work-profiles/shared/ui/work-profile-form.tsx
index dbd47f1..3ba8349 100644
--- a/modules/companies/src/web/work-profiles/shared/ui/work-profile-form.tsx
+++ b/modules/companies/src/web/work-profiles/shared/ui/work-profile-form.tsx
@@ -16,7 +16,7 @@ import type { WorkProfileFormProps } from "../types";
import { ProfileFeedback } from "./profile-feedback";
export function WorkProfileForm(props: WorkProfileFormProps) {
- const { company, csrfToken, profile, allowQuickCreate = true } = props;
+ const { company, profile, allowQuickCreate = true } = props;
const {
quick,
setQuick,
@@ -132,7 +132,6 @@ export function WorkProfileForm(props: WorkProfileFormProps) {
{quick && (
setQuick(undefined)}
diff --git a/modules/companies/src/web/workspace/catalogs/ui/global-catalog-content.tsx b/modules/companies/src/web/workspace/catalogs/ui/global-catalog-content.tsx
index 18751a1..4d13c47 100644
--- a/modules/companies/src/web/workspace/catalogs/ui/global-catalog-content.tsx
+++ b/modules/companies/src/web/workspace/catalogs/ui/global-catalog-content.tsx
@@ -6,25 +6,19 @@ import { InterventionTemplatesPage } from "../../../intervention-templates";
import { ProcessTemplatesPage } from "../../../process-templates";
import type { GlobalCatalog } from "../../shared/types";
-export function GlobalCatalogContent({
- catalog,
- csrfToken,
-}: {
- catalog: GlobalCatalog;
- csrfToken: string;
-}) {
+export function GlobalCatalogContent({ catalog }: { catalog: GlobalCatalog }) {
switch (catalog) {
case "process-templates":
- return ;
+ return ;
case "intervention-templates":
- return ;
+ return ;
case "access":
- return ;
+ return ;
case "assets":
- return ;
+ return ;
case "brands":
- return ;
+ return ;
case "resources":
- return ;
+ return ;
}
}
diff --git a/modules/companies/src/web/workspace/view/types/companies-workspace-props.ts b/modules/companies/src/web/workspace/view/types/companies-workspace-props.ts
index 976176f..232614a 100644
--- a/modules/companies/src/web/workspace/view/types/companies-workspace-props.ts
+++ b/modules/companies/src/web/workspace/view/types/companies-workspace-props.ts
@@ -1,7 +1,6 @@
import type { ReactNode } from "react";
export type CompaniesWorkspaceProps = {
- csrfToken: string;
accountNavigation: ReactNode;
userName: string;
languageSwitcher: ReactNode;
diff --git a/modules/companies/src/web/workspace/view/ui/companies-workspace.tsx b/modules/companies/src/web/workspace/view/ui/companies-workspace.tsx
index 8837656..eee0b8b 100644
--- a/modules/companies/src/web/workspace/view/ui/companies-workspace.tsx
+++ b/modules/companies/src/web/workspace/view/ui/companies-workspace.tsx
@@ -11,7 +11,7 @@ import { WorkspaceHeader } from "./workspace-header";
import { WorkspaceSidebar } from "./workspace-sidebar";
export function CompaniesWorkspace(props: CompaniesWorkspaceProps) {
- const { csrfToken, accountNavigation, userName, languageSwitcher } = props;
+ const { accountNavigation, userName, languageSwitcher } = props;
const {
query,
setLocation,
@@ -71,7 +71,6 @@ export function CompaniesWorkspace(props: CompaniesWorkspaceProps) {
)}
{current.area === "company" ? (
void;
onSelectCompany: (id: string) => void;
}) {
@@ -32,7 +30,6 @@ export function WorkspaceContent({
case "interventions":
return (
);
case "catalogs":
- return catalog ? (
-
- ) : (
-
- );
+ return catalog ? : ;
case "company":
return null;
case "home":
- return ;
+ return ;
case "not-found":
case "invalid-route":
return ;
diff --git a/modules/core/package.json b/modules/core/package.json
index 4df1b66..5985d71 100644
--- a/modules/core/package.json
+++ b/modules/core/package.json
@@ -10,7 +10,7 @@
},
"scripts": {
"typecheck": "tsc -p tsconfig.json",
- "test": "node --import tsx --test src/common/dto/response/get-health.response.dto.test.ts src/web/navigation/shared/browser-navigation.test.ts"
+ "test": "node --import tsx --test src/common/dto/response/get-health.response.dto.test.ts src/web/navigation/shared/browser-navigation.test.ts src/web/http/shared/api/csrf-fetch.test.ts"
},
"dependencies": {
"zod": "4.3.6",
diff --git a/modules/core/src/web/http/shared/api/csrf-fetch.test.ts b/modules/core/src/web/http/shared/api/csrf-fetch.test.ts
new file mode 100644
index 0000000..6c7fbf3
--- /dev/null
+++ b/modules/core/src/web/http/shared/api/csrf-fetch.test.ts
@@ -0,0 +1,109 @@
+import assert from "node:assert/strict";
+import { test } from "node:test";
+
+import { QueryClient } from "@tanstack/react-query";
+
+import { configureCsrfTokenReader, csrfFetch } from "./csrf-fetch";
+
+const FIRST_TOKEN = "a".repeat(64);
+const NEXT_TOKEN = "b".repeat(64);
+
+test("las escrituras leen la sesión actual de Query y siguen su rotación y eliminación", async (context) => {
+ const client = new QueryClient();
+ const key = ["identity", "session"];
+ const tokens: (string | null)[] = [];
+
+ context.after(
+ configureCsrfTokenReader(() => client.getQueryData<{ csrfToken: string }>(key)?.csrfToken)
+ );
+ context.mock.method(globalThis, "fetch", async (_path: string, options: RequestInit) => {
+ tokens.push(new Headers(options.headers).get("x-csrf-token"));
+
+ return new Response(null, { status: 204 });
+ });
+ client.setQueryData(key, { csrfToken: FIRST_TOKEN });
+ await csrfFetch("/api/users", { method: "POST" });
+ client.setQueryData(key, { csrfToken: NEXT_TOKEN });
+ await csrfFetch("/api/users", { method: "DELETE" });
+ client.removeQueries({ queryKey: key });
+ assert.throws(() => csrfFetch("/api/users", { method: "POST" }), /CSRF_SESSION_UNAVAILABLE/);
+ assert.deepEqual(tokens, [FIRST_TOKEN, NEXT_TOKEN]);
+ client.clear();
+});
+
+test("GET, HEAD y OPTIONS funcionan sin sesión y no envían tokens suministrados por el llamador", async (context) => {
+ context.after(configureCsrfTokenReader(() => undefined));
+ context.mock.method(globalThis, "fetch", async (path: string, options: RequestInit) => {
+ assert.equal(path, "/api/auth/session");
+ assert.equal(options.credentials, "same-origin");
+ assert.equal(new Headers(options.headers).has("x-csrf-token"), false);
+
+ return new Response(null, { status: 204 });
+ });
+ await csrfFetch("/api/auth/session");
+ for (const method of ["GET", "HEAD", "OPTIONS"]) {
+ await csrfFetch("/api/auth/session", { method, headers: { "x-csrf-token": "obsolete" } });
+ }
+});
+
+test("mantiene cuerpos JSON, binarios, headers, cancelación y respuestas de error sin reintentar", async (context) => {
+ context.after(configureCsrfTokenReader(() => FIRST_TOKEN));
+ const bodies = [
+ JSON.stringify({ name: "Ana" }),
+ new File(["photo"], "photo.webp", { type: "image/webp" }),
+ ];
+ const controller = new AbortController();
+ const response = Response.json({ code: "FORBIDDEN" }, { status: 403 });
+ const headers = new Headers({
+ "content-type": "application/octet-stream",
+ "x-csrf-token": "obsolete",
+ });
+ let calls = 0;
+
+ context.mock.method(globalThis, "fetch", async (_path: string, options: RequestInit) => {
+ assert.equal(options.body, bodies[calls]);
+ assert.equal(options.signal, controller.signal);
+ assert.equal(options.credentials, "same-origin");
+ assert.equal(new Headers(options.headers).get("x-csrf-token"), FIRST_TOKEN);
+ assert.equal(new Headers(options.headers).get("content-type"), "application/octet-stream");
+ calls += 1;
+
+ return response;
+ });
+ for (const body of bodies) {
+ assert.equal(
+ await csrfFetch("/api/companies/photo", {
+ method: "POST",
+ body,
+ headers,
+ signal: controller.signal,
+ }),
+ response
+ );
+ }
+ assert.equal(calls, 2);
+ assert.equal(headers.get("x-csrf-token"), "obsolete");
+});
+
+test("rechaza tokens ausentes o inválidos y destinos externos antes de enviar una petición", (context) => {
+ const mock = context.mock.method(globalThis, "fetch", async () => new Response());
+
+ for (const token of [undefined, "short", "g".repeat(64)]) {
+ const reset = configureCsrfTokenReader(() => token);
+
+ try {
+ assert.throws(() => csrfFetch("/api/users", { method: "POST" }), /CSRF_SESSION_UNAVAILABLE/);
+ } finally {
+ reset();
+ }
+ }
+ context.after(configureCsrfTokenReader(() => FIRST_TOKEN));
+ for (const path of [
+ "https://outside.test/api/users",
+ "//outside.test/api/users",
+ "/api\\outside.test",
+ ]) {
+ assert.throws(() => csrfFetch(path, { method: "POST" }), /INVALID_API_PATH/);
+ }
+ assert.equal(mock.mock.callCount(), 0);
+});
diff --git a/modules/core/src/web/http/shared/api/csrf-fetch.ts b/modules/core/src/web/http/shared/api/csrf-fetch.ts
new file mode 100644
index 0000000..ce1d17f
--- /dev/null
+++ b/modules/core/src/web/http/shared/api/csrf-fetch.ts
@@ -0,0 +1,35 @@
+type CsrfTokenReader = () => string | undefined;
+
+let readCsrfToken: CsrfTokenReader = () => undefined;
+
+/** La composición web aporta la sesión actual; no se duplica su token ni se usa storage. */
+export function configureCsrfTokenReader(reader: CsrfTokenReader) {
+ const previous = readCsrfToken;
+
+ readCsrfToken = reader;
+
+ return () => {
+ readCsrfToken = previous;
+ };
+}
+
+/** Añade CSRF únicamente a escrituras contra la API local, manteniendo body y errores. */
+export function csrfFetch(path: string, options: RequestInit = {}): Promise {
+ if (!path.startsWith("/api/") || path.includes("\\")) {
+ throw new Error("INVALID_API_PATH");
+ }
+ const headers = new Headers(options.headers);
+ const method = (options.method ?? "GET").toUpperCase();
+
+ headers.delete("x-csrf-token");
+ if (!["GET", "HEAD", "OPTIONS"].includes(method)) {
+ const token = readCsrfToken();
+
+ if (!(token && /^[a-f0-9]{64}$/.test(token))) {
+ throw new Error("CSRF_SESSION_UNAVAILABLE");
+ }
+ headers.set("x-csrf-token", token);
+ }
+
+ return fetch(path, { ...options, credentials: "same-origin", headers });
+}
diff --git a/modules/core/src/web/index.ts b/modules/core/src/web/index.ts
index 8a01fce..e83e42b 100644
--- a/modules/core/src/web/index.ts
+++ b/modules/core/src/web/index.ts
@@ -1,7 +1,7 @@
export { default as coreEnglish } from "../common/locales/en.json";
-
export { default as coreSpanish } from "../common/locales/es.json";
+export { configureCsrfTokenReader, csrfFetch } from "./http/shared/api/csrf-fetch";
export {
BrowserLink,
EntityNotFound,
@@ -16,5 +16,4 @@ export {
useCreateNavigation,
useEntityNavigation,
} from "./navigation";
-
export { HomePage } from "./workspace";
diff --git a/modules/identity/src/web/passwords/change/api/change-password.api.ts b/modules/identity/src/web/passwords/change/api/change-password.api.ts
index a2b2de0..e1a638d 100644
--- a/modules/identity/src/web/passwords/change/api/change-password.api.ts
+++ b/modules/identity/src/web/passwords/change/api/change-password.api.ts
@@ -1,5 +1,5 @@
import { UserResponseSchema } from "../../../../common";
import { identityRequest } from "../../../shared/api/identity-request";
-export const changePassword = (body: unknown, token: string) =>
- identityRequest("/auth/change-password", UserResponseSchema, body, token);
+export const changePassword = (body: unknown) =>
+ identityRequest("/auth/change-password", UserResponseSchema, body);
diff --git a/modules/identity/src/web/passwords/change/ui/account-password-dialog.tsx b/modules/identity/src/web/passwords/change/ui/account-password-dialog.tsx
index 741ef49..207603b 100644
--- a/modules/identity/src/web/passwords/change/ui/account-password-dialog.tsx
+++ b/modules/identity/src/web/passwords/change/ui/account-password-dialog.tsx
@@ -3,15 +3,7 @@ import { useTranslation } from "react-i18next";
import { PasswordForm } from "../../shared";
-export function AccountPasswordDialog({
- open,
- csrfToken,
- onClose,
-}: {
- open: boolean;
- csrfToken: string;
- onClose: () => void;
-}) {
+export function AccountPasswordDialog({ open, onClose }: { open: boolean; onClose: () => void }) {
const { t } = useTranslation("identity");
return (
@@ -26,7 +18,7 @@ export function AccountPasswordDialog({
open={open}
title={t("changePassword")}
>
-
+
);
}
diff --git a/modules/identity/src/web/passwords/reset/api/reset-user-password.api.ts b/modules/identity/src/web/passwords/reset/api/reset-user-password.api.ts
index d7cdbdf..142d6d9 100644
--- a/modules/identity/src/web/passwords/reset/api/reset-user-password.api.ts
+++ b/modules/identity/src/web/passwords/reset/api/reset-user-password.api.ts
@@ -1,5 +1,5 @@
import { UserResponseSchema } from "../../../../common";
import { identityRequest } from "../../../shared/api/identity-request";
-export const resetUserPassword = (id: string, body: unknown, token: string) =>
- identityRequest(`/users/${id}/reset-password`, UserResponseSchema, body, token);
+export const resetUserPassword = (id: string, body: unknown) =>
+ identityRequest(`/users/${id}/reset-password`, UserResponseSchema, body);
diff --git a/modules/identity/src/web/passwords/shared/controllers/use-password-form-controller.ts b/modules/identity/src/web/passwords/shared/controllers/use-password-form-controller.ts
index fad865c..f703f9f 100644
--- a/modules/identity/src/web/passwords/shared/controllers/use-password-form-controller.ts
+++ b/modules/identity/src/web/passwords/shared/controllers/use-password-form-controller.ts
@@ -10,7 +10,7 @@ import { changePassword } from "../../change/api";
import { resetUserPassword } from "../../reset/api";
import type { PasswordFormProps } from "../types";
-export function usePasswordFormController({ target, csrfToken, onSaved }: PasswordFormProps) {
+export function usePasswordFormController({ target, onSaved }: PasswordFormProps) {
const client = useQueryClient();
const form = useForm({
resolver: zodResolver(
@@ -25,10 +25,9 @@ export function usePasswordFormController({ target, csrfToken, onSaved }: Passwo
target
? resetUserPassword(
target.id,
- ResetPasswordRequestSchema.parse({ password: values.password }),
- csrfToken
+ ResetPasswordRequestSchema.parse({ password: values.password })
)
- : changePassword(values, csrfToken),
+ : changePassword(values),
onSuccess: async () => {
form.reset();
await client.invalidateQueries({ queryKey: identityKeys.session });
diff --git a/modules/identity/src/web/passwords/shared/types/password-form-props.ts b/modules/identity/src/web/passwords/shared/types/password-form-props.ts
index 94f81b3..139f478 100644
--- a/modules/identity/src/web/passwords/shared/types/password-form-props.ts
+++ b/modules/identity/src/web/passwords/shared/types/password-form-props.ts
@@ -2,7 +2,6 @@ import type { UserDTO } from "../../../../common";
export type PasswordFormProps = {
target?: UserDTO;
- csrfToken: string;
onSaved?: () => void;
showTitle?: boolean;
};
diff --git a/modules/identity/src/web/sessions/shared/api/authenticate.api.ts b/modules/identity/src/web/sessions/shared/api/authenticate.api.ts
index 5022aa2..6a7e14b 100644
--- a/modules/identity/src/web/sessions/shared/api/authenticate.api.ts
+++ b/modules/identity/src/web/sessions/shared/api/authenticate.api.ts
@@ -1,5 +1,5 @@
import { UserResponseSchema } from "../../../../common";
import { identityRequest } from "../../../shared/api/identity-request";
-export const authenticate = (setup: boolean, body: unknown, token: string) =>
- identityRequest(setup ? "/auth/bootstrap" : "/auth/login", UserResponseSchema, body, token);
+export const authenticate = (setup: boolean, body: unknown) =>
+ identityRequest(setup ? "/auth/bootstrap" : "/auth/login", UserResponseSchema, body);
diff --git a/modules/identity/src/web/sessions/shared/api/logout.api.ts b/modules/identity/src/web/sessions/shared/api/logout.api.ts
index 873a0c3..83762d5 100644
--- a/modules/identity/src/web/sessions/shared/api/logout.api.ts
+++ b/modules/identity/src/web/sessions/shared/api/logout.api.ts
@@ -1,5 +1,4 @@
import { ActionResponseSchema } from "../../../../common";
import { identityRequest } from "../../../shared/api/identity-request";
-export const logout = (token: string) =>
- identityRequest("/auth/logout", ActionResponseSchema, {}, token);
+export const logout = () => identityRequest("/auth/logout", ActionResponseSchema, {});
diff --git a/modules/identity/src/web/sessions/shared/controllers/use-credential-form-controller.ts b/modules/identity/src/web/sessions/shared/controllers/use-credential-form-controller.ts
index da2f510..e0fc628 100644
--- a/modules/identity/src/web/sessions/shared/controllers/use-credential-form-controller.ts
+++ b/modules/identity/src/web/sessions/shared/controllers/use-credential-form-controller.ts
@@ -8,7 +8,7 @@ import { identityKeys } from "../../../shared/queries";
import { authenticate } from "../api";
import type { CredentialFormProps } from "../types";
-export function useCredentialFormController({ setup, csrfToken }: CredentialFormProps) {
+export function useCredentialFormController({ setup }: CredentialFormProps) {
const client = useQueryClient();
const form = useForm({
resolver: zodResolver(
@@ -25,8 +25,7 @@ export function useCredentialFormController({ setup, csrfToken }: CredentialForm
setup,
setup
? BootstrapAdminRequestSchema.parse(values)
- : LoginRequestSchema.parse({ email: values.email, password: values.password }),
- csrfToken
+ : LoginRequestSchema.parse({ email: values.email, password: values.password })
),
onSuccess: async () => {
client.removeQueries({
diff --git a/modules/identity/src/web/sessions/shared/types/credential-form-props.ts b/modules/identity/src/web/sessions/shared/types/credential-form-props.ts
index 9803f28..ab7413b 100644
--- a/modules/identity/src/web/sessions/shared/types/credential-form-props.ts
+++ b/modules/identity/src/web/sessions/shared/types/credential-form-props.ts
@@ -1,4 +1,3 @@
export type CredentialFormProps = {
setup: boolean;
- csrfToken: string;
};
diff --git a/modules/identity/src/web/shared/api/identity-api.test.ts b/modules/identity/src/web/shared/api/identity-api.test.ts
index 8cec768..85ce029 100644
--- a/modules/identity/src/web/shared/api/identity-api.test.ts
+++ b/modules/identity/src/web/shared/api/identity-api.test.ts
@@ -1,13 +1,15 @@
import assert from "node:assert/strict";
import { test } from "node:test";
+import { configureCsrfTokenReader } from "@metis/core/client";
+
import { getSession, logout } from "../../sessions/shared/api";
import { identityApi } from "./identity-api";
import { IdentityApiError } from "./identity-api-error";
const USER_ID = "e0420eb9-2aab-4368-96a0-2ce83dd23eb4";
-const CSRF_TOKEN = "a".repeat(32);
+const CSRF_TOKEN = "a".repeat(64);
const USER = {
id: USER_ID,
name: "Ana",
@@ -17,6 +19,7 @@ const USER = {
};
test("la sesión valida la respuesta y conserva el contrato público utilizado por la aplicación", async (context) => {
+ context.after(configureCsrfTokenReader(() => CSRF_TOKEN));
context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => {
assert.equal(url, "/api/auth/session");
assert.equal(options.method, "GET");
@@ -34,6 +37,7 @@ test("la sesión valida la respuesta y conserva el contrato público utilizado p
});
test("login, configuración inicial, usuarios y contraseñas conservan rutas, body y CSRF", async (context) => {
+ context.after(configureCsrfTokenReader(() => CSRF_TOKEN));
const calls: { url: unknown; options: RequestInit }[] = [];
context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => {
@@ -43,12 +47,12 @@ test("login, configuración inicial, usuarios y contraseñas conservan rutas, bo
});
const body = { password: "example-password" };
- await identityApi.authenticate(false, body, CSRF_TOKEN);
- await identityApi.authenticate(true, body, CSRF_TOKEN);
- await identityApi.create(body, CSRF_TOKEN);
- await identityApi.update(USER_ID, body, CSRF_TOKEN);
- await identityApi.resetPassword(USER_ID, body, CSRF_TOKEN);
- await identityApi.changePassword(body, CSRF_TOKEN);
+ await identityApi.authenticate(false, body);
+ await identityApi.authenticate(true, body);
+ await identityApi.create(body);
+ await identityApi.update(USER_ID, body);
+ await identityApi.resetPassword(USER_ID, body);
+ await identityApi.changePassword(body);
assert.deepEqual(
calls.map((call) => call.url),
[
@@ -68,6 +72,7 @@ test("login, configuración inicial, usuarios y contraseñas conservan rutas, bo
});
test("cerrar sesión espera la respuesta de la operación sin perder el token", async (context) => {
+ context.after(configureCsrfTokenReader(() => CSRF_TOKEN));
context.mock.method(globalThis, "fetch", async (url: unknown, options: RequestInit) => {
assert.equal(url, "/api/auth/logout");
assert.equal(options.body, "{}");
@@ -75,10 +80,11 @@ test("cerrar sesión espera la respuesta de la operación sin perder el token",
return Response.json({ success: true });
});
- assert.deepEqual(await logout(CSRF_TOKEN), { success: true });
+ assert.deepEqual(await logout(), { success: true });
});
test("los errores HTTP no filtran detalles internos y los datos de sesión inválidos se rechazan", async (context) => {
+ context.after(configureCsrfTokenReader(() => CSRF_TOKEN));
const responses = [
Response.json({ code: "FORBIDDEN", requestId: USER_ID }, { status: 403 }),
Response.json({ sql: "private" }, { status: 500 }),
diff --git a/modules/identity/src/web/shared/api/identity-request.ts b/modules/identity/src/web/shared/api/identity-request.ts
index 6384d5d..712d3ee 100644
--- a/modules/identity/src/web/shared/api/identity-request.ts
+++ b/modules/identity/src/web/shared/api/identity-request.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import type { z } from "zod/v4";
import { IdentityErrorResponseSchema } from "../../../common";
@@ -7,16 +8,12 @@ import { IdentityApiError } from "./identity-api-error";
export async function identityRequest(
path: string,
schema: z.ZodType,
- body?: unknown,
- csrfToken?: string
+ body?: unknown
): Promise {
- const response = await fetch(`/api${path}`, {
+ const response = await csrfFetch(`/api${path}`, {
method: body === undefined ? "GET" : "POST",
credentials: "same-origin",
- headers:
- body === undefined
- ? {}
- : { "content-type": "application/json", "x-csrf-token": csrfToken ?? "" },
+ headers: body === undefined ? {} : { "content-type": "application/json" },
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
const json: unknown = await response.json();
diff --git a/modules/identity/src/web/users/create/api/create-user.api.ts b/modules/identity/src/web/users/create/api/create-user.api.ts
index a99c803..a70e6ba 100644
--- a/modules/identity/src/web/users/create/api/create-user.api.ts
+++ b/modules/identity/src/web/users/create/api/create-user.api.ts
@@ -1,5 +1,4 @@
import { UserResponseSchema } from "../../../../common";
import { identityRequest } from "../../../shared/api/identity-request";
-export const createUser = (body: unknown, token: string) =>
- identityRequest("/users", UserResponseSchema, body, token);
+export const createUser = (body: unknown) => identityRequest("/users", UserResponseSchema, body);
diff --git a/modules/identity/src/web/users/list/types/index.ts b/modules/identity/src/web/users/list/types/index.ts
deleted file mode 100644
index 880d3f0..0000000
--- a/modules/identity/src/web/users/list/types/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export type { UserManagementProps } from "./user-management-props";
diff --git a/modules/identity/src/web/users/list/types/user-management-props.ts b/modules/identity/src/web/users/list/types/user-management-props.ts
deleted file mode 100644
index 113dd75..0000000
--- a/modules/identity/src/web/users/list/types/user-management-props.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export type UserManagementProps = {
- csrfToken: string;
-};
diff --git a/modules/identity/src/web/users/list/ui/user-management-dialog.tsx b/modules/identity/src/web/users/list/ui/user-management-dialog.tsx
index 992631c..898b5a7 100644
--- a/modules/identity/src/web/users/list/ui/user-management-dialog.tsx
+++ b/modules/identity/src/web/users/list/ui/user-management-dialog.tsx
@@ -5,11 +5,9 @@ import { UserManagement } from "./user-management";
export function UserManagementDialog({
open,
- csrfToken,
onOpenChange,
}: {
open: boolean;
- csrfToken: string;
onOpenChange: (open: boolean) => void;
}) {
const { t } = useTranslation("identity");
@@ -22,7 +20,7 @@ export function UserManagementDialog({
title={t("users")}
wide
>
-
+
);
}
diff --git a/modules/identity/src/web/users/list/ui/user-management.tsx b/modules/identity/src/web/users/list/ui/user-management.tsx
index 9827101..01cb1a7 100644
--- a/modules/identity/src/web/users/list/ui/user-management.tsx
+++ b/modules/identity/src/web/users/list/ui/user-management.tsx
@@ -11,10 +11,8 @@ import { useTranslation } from "react-i18next";
import { FormFeedback } from "../../../shared";
import { UserEditorDialog } from "../../shared";
import { useUserManagementController } from "../controllers";
-import type { UserManagementProps } from "../types";
-export function UserManagement(props: UserManagementProps) {
- const { csrfToken } = props;
+export function UserManagement() {
const { users, createOpen, setCreateOpen, selection, setSelection, selected } =
useUserManagementController();
const { t, i18n } = useTranslation("identity");
@@ -105,15 +103,9 @@ export function UserManagement(props: UserManagementProps) {
title={t("users")}
/>
)}
- setCreateOpen(false)}
- open={createOpen}
- />
+ setCreateOpen(false)} open={createOpen} />
{selected && selection && (
setSelection(undefined)}
open
diff --git a/modules/identity/src/web/users/shared/controllers/use-user-form-controller.ts b/modules/identity/src/web/users/shared/controllers/use-user-form-controller.ts
index f46697c..3ca0d77 100644
--- a/modules/identity/src/web/users/shared/controllers/use-user-form-controller.ts
+++ b/modules/identity/src/web/users/shared/controllers/use-user-form-controller.ts
@@ -10,7 +10,7 @@ import { updateUser } from "../../update/api";
import { UserFormSchema } from "../schemas";
import type { UserFormProps, UserFormValues } from "../types";
-export function useUserFormController({ user, csrfToken, onSaved }: UserFormProps) {
+export function useUserFormController({ user, onSaved }: UserFormProps) {
const client = useQueryClient();
const form = useForm({
resolver: zodResolver(user ? UserFormSchema.extend({ password: z.string() }) : UserFormSchema),
@@ -30,16 +30,14 @@ export function useUserFormController({ user, csrfToken, onSaved }: UserFormProp
name: values.name,
email: values.email,
active: values.active,
- }),
- csrfToken
+ })
)
: createUser(
CreateUserRequestSchema.parse({
name: values.name,
email: values.email,
password: values.password,
- }),
- csrfToken
+ })
),
onSuccess: async () => {
if (!user) {
diff --git a/modules/identity/src/web/users/shared/types/user-form-props.ts b/modules/identity/src/web/users/shared/types/user-form-props.ts
index f55f417..1f16c21 100644
--- a/modules/identity/src/web/users/shared/types/user-form-props.ts
+++ b/modules/identity/src/web/users/shared/types/user-form-props.ts
@@ -7,7 +7,6 @@ export type UserFormValues = z.infer;
export type UserFormProps = {
user?: UserDTO;
- csrfToken: string;
onSaved?: () => void;
showTitle?: boolean;
};
diff --git a/modules/identity/src/web/users/shared/ui/user-editor-dialog.tsx b/modules/identity/src/web/users/shared/ui/user-editor-dialog.tsx
index 4e76267..1d00336 100644
--- a/modules/identity/src/web/users/shared/ui/user-editor-dialog.tsx
+++ b/modules/identity/src/web/users/shared/ui/user-editor-dialog.tsx
@@ -9,7 +9,6 @@ import { UserForm } from "./user-form";
export function UserEditorDialog(
props: {
open: boolean;
- csrfToken: string;
onClose: () => void;
} & ({ mode: "create" } | { mode: "edit" | "password"; user: UserDTO })
) {
@@ -36,7 +35,6 @@ export function UserEditorDialog(
>
{props.mode === "password" ? (
) : (
- identityRequest(`/users/${id}/update`, UserResponseSchema, body, token);
+export const updateUser = (id: string, body: unknown) =>
+ identityRequest(`/users/${id}/update`, UserResponseSchema, body);
diff --git a/modules/identity/src/web/workspace/view/controllers/use-authenticated-workspace-controller.ts b/modules/identity/src/web/workspace/view/controllers/use-authenticated-workspace-controller.ts
index ec96f13..8a39de2 100644
--- a/modules/identity/src/web/workspace/view/controllers/use-authenticated-workspace-controller.ts
+++ b/modules/identity/src/web/workspace/view/controllers/use-authenticated-workspace-controller.ts
@@ -3,9 +3,8 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
import { logout as logoutSession } from "../../../sessions/shared/api";
import { identityKeys } from "../../../shared/queries";
-import type { AuthenticatedWorkspaceProps } from "../types";
-export function useAuthenticatedWorkspaceController({ snapshot }: AuthenticatedWorkspaceProps) {
+export function useAuthenticatedWorkspaceController() {
const client = useQueryClient();
const location = useBrowserLocation();
const pathname = location.split("?")[0];
@@ -25,7 +24,7 @@ export function useAuthenticatedWorkspaceController({ snapshot }: AuthenticatedW
};
const logout = useMutation({
- mutationFn: () => logoutSession(snapshot.csrfToken),
+ mutationFn: () => logoutSession(),
onSuccess: async () => {
client.removeQueries({
predicate: (query) => query.queryKey[0] !== "identity" || query.queryKey[1] !== "session",
diff --git a/modules/identity/src/web/workspace/view/ui/authenticated-workspace.tsx b/modules/identity/src/web/workspace/view/ui/authenticated-workspace.tsx
index 6ce2140..4ac4a2e 100644
--- a/modules/identity/src/web/workspace/view/ui/authenticated-workspace.tsx
+++ b/modules/identity/src/web/workspace/view/ui/authenticated-workspace.tsx
@@ -16,7 +16,7 @@ function isHomePage(page: string, isInitialAdmin: boolean) {
export function AuthenticatedWorkspace(props: AuthenticatedWorkspaceProps) {
const { snapshot, children, pages, renderWorkspace } = props;
- const { page, setPage, logout } = useAuthenticatedWorkspaceController(props);
+ const { page, setPage, logout } = useAuthenticatedWorkspaceController();
const { t } = useTranslation("identity");
if (!snapshot.user) {
@@ -82,11 +82,11 @@ export function AuthenticatedWorkspace(props: AuthenticatedWorkspaceProps) {
) : (
{page === "users" ? (
-
+
) : page === "password" ? (
-
+
) : (
diff --git a/modules/identity/src/web/workspace/view/ui/custom-workspace.tsx b/modules/identity/src/web/workspace/view/ui/custom-workspace.tsx
index 90d9877..f8fec41 100644
--- a/modules/identity/src/web/workspace/view/ui/custom-workspace.tsx
+++ b/modules/identity/src/web/workspace/view/ui/custom-workspace.tsx
@@ -72,7 +72,6 @@ export function CustomWorkspace({
)}
{
if (!open) {
setPage("home");
@@ -80,11 +79,7 @@ export function CustomWorkspace({
}}
open={page === "users" && snapshot.user.isInitialAdmin}
/>
- setPage("home")}
- open={page === "password"}
- />
+ setPage("home")} open={page === "password"} />
>
);
}
diff --git a/modules/identity/src/web/workspace/view/ui/identity-workspace.tsx b/modules/identity/src/web/workspace/view/ui/identity-workspace.tsx
index bfaf1b3..ad95c19 100644
--- a/modules/identity/src/web/workspace/view/ui/identity-workspace.tsx
+++ b/modules/identity/src/web/workspace/view/ui/identity-workspace.tsx
@@ -60,7 +60,6 @@ export function IdentityWorkspace(props: IdentityWorkspaceProps) {
diff --git a/modules/resources/src/web/catalog-fields/create/ui/catalog-field-create-dialog.tsx b/modules/resources/src/web/catalog-fields/create/ui/catalog-field-create-dialog.tsx
index 68f6a09..d9c1662 100644
--- a/modules/resources/src/web/catalog-fields/create/ui/catalog-field-create-dialog.tsx
+++ b/modules/resources/src/web/catalog-fields/create/ui/catalog-field-create-dialog.tsx
@@ -5,12 +5,10 @@ import { CatalogFieldForm } from "../../shared";
export function CatalogFieldCreateDialog({
scope,
- csrfToken,
onSaved,
onOpenChange,
}: {
scope: string;
- csrfToken: string;
onSaved: (id: string) => void;
onOpenChange: (open: boolean) => void;
}) {
@@ -25,7 +23,7 @@ export function CatalogFieldCreateDialog({
title={t("newField")}
>
{t("quickNotice")}
-
+
);
}
diff --git a/modules/resources/src/web/catalog-fields/shared/controllers/use-catalog-form-controller.ts b/modules/resources/src/web/catalog-fields/shared/controllers/use-catalog-form-controller.ts
index f832fc9..2fa51de 100644
--- a/modules/resources/src/web/catalog-fields/shared/controllers/use-catalog-form-controller.ts
+++ b/modules/resources/src/web/catalog-fields/shared/controllers/use-catalog-form-controller.ts
@@ -5,12 +5,7 @@ import { useCatalogSave } from "../../../catalog/shared/controllers";
import { FieldFormSchema } from "../schemas";
import type { CatalogFieldFormProps, FieldFormValues } from "../types";
-export function useCatalogFieldFormController({
- scope,
- csrfToken,
- item,
- onSaved,
-}: CatalogFieldFormProps) {
+export function useCatalogFieldFormController({ scope, item, onSaved }: CatalogFieldFormProps) {
const current = item?.values.kind === "field" ? item.values : undefined;
const form = useForm({
resolver: zodResolver(FieldFormSchema),
@@ -23,7 +18,7 @@ export function useCatalogFieldFormController({
choicesText: current?.choices.join("\n") ?? "",
},
});
- const mutation = useCatalogSave(scope, csrfToken, onSaved, item?.id);
+ const mutation = useCatalogSave(scope, onSaved, item?.id);
const type = form.watch("type");
const submit = form.handleSubmit(({ choicesText, ...values }) =>
mutation.mutate({
diff --git a/modules/resources/src/web/catalog-fields/shared/types/catalog-form-props.ts b/modules/resources/src/web/catalog-fields/shared/types/catalog-form-props.ts
index 840378b..06149b8 100644
--- a/modules/resources/src/web/catalog-fields/shared/types/catalog-form-props.ts
+++ b/modules/resources/src/web/catalog-fields/shared/types/catalog-form-props.ts
@@ -8,7 +8,6 @@ export type FieldFormValues = z.infer;
export type CatalogFieldFormProps = {
scope: string;
- csrfToken: string;
item?: CatalogItemDTO | undefined;
onSaved: CatalogSaved;
};
diff --git a/modules/resources/src/web/catalog-templates/create/ui/catalog-template-create-dialog.tsx b/modules/resources/src/web/catalog-templates/create/ui/catalog-template-create-dialog.tsx
index 6098616..be827d0 100644
--- a/modules/resources/src/web/catalog-templates/create/ui/catalog-template-create-dialog.tsx
+++ b/modules/resources/src/web/catalog-templates/create/ui/catalog-template-create-dialog.tsx
@@ -6,13 +6,11 @@ import { CatalogTemplateForm } from "../../shared";
export function CatalogTemplateCreateDialog({
scope,
- csrfToken,
items,
onSaved,
onOpenChange,
}: {
scope: string;
- csrfToken: string;
items: ComponentProps["items"];
onSaved: (id: string) => void;
onOpenChange: (open: boolean) => void;
@@ -29,13 +27,7 @@ export function CatalogTemplateCreateDialog({
wide
>
{t("relatedNotice")}
-
+
);
}
diff --git a/modules/resources/src/web/catalog-templates/shared/controllers/use-catalog-template-form-controller.ts b/modules/resources/src/web/catalog-templates/shared/controllers/use-catalog-template-form-controller.ts
index d75ef17..d82da53 100644
--- a/modules/resources/src/web/catalog-templates/shared/controllers/use-catalog-template-form-controller.ts
+++ b/modules/resources/src/web/catalog-templates/shared/controllers/use-catalog-template-form-controller.ts
@@ -12,7 +12,6 @@ import type { CatalogTemplateFormProps, TemplateFormValues } from "../types";
export function useCatalogTemplateFormController({
scope,
- csrfToken,
item,
copy,
items,
@@ -38,7 +37,7 @@ export function useCatalogTemplateFormController({
sections: layout.sections,
},
});
- const mutation = useCatalogSave(scope, csrfToken, onSaved, item?.id);
+ const mutation = useCatalogSave(scope, onSaved, item?.id);
const selected = form.watch("fields");
const fields = items.filter((entry) => entry.values.kind === "field");
diff --git a/modules/resources/src/web/catalog-templates/shared/types/catalog-template-form-props.ts b/modules/resources/src/web/catalog-templates/shared/types/catalog-template-form-props.ts
index f009f9e..afd7e40 100644
--- a/modules/resources/src/web/catalog-templates/shared/types/catalog-template-form-props.ts
+++ b/modules/resources/src/web/catalog-templates/shared/types/catalog-template-form-props.ts
@@ -8,7 +8,6 @@ export type TemplateFormValues = z.infer;
export type CatalogTemplateFormProps = {
scope: string;
- csrfToken: string;
item?: CatalogItemDTO | undefined;
copy?: CatalogItemDTO | undefined;
items: readonly CatalogItemDTO[];
diff --git a/modules/resources/src/web/catalog-templates/shared/ui/catalog-template-form.tsx b/modules/resources/src/web/catalog-templates/shared/ui/catalog-template-form.tsx
index 25e39e2..7703f8a 100644
--- a/modules/resources/src/web/catalog-templates/shared/ui/catalog-template-form.tsx
+++ b/modules/resources/src/web/catalog-templates/shared/ui/catalog-template-form.tsx
@@ -17,7 +17,7 @@ import { useCatalogTemplateFormController } from "../controllers";
import type { CatalogTemplateFormProps } from "../types";
export function CatalogTemplateForm(props: CatalogTemplateFormProps) {
- const { scope, csrfToken, item, allowQuickCreate = true } = props;
+ const { scope, item, allowQuickCreate = true } = props;
const { creatingField, setCreatingField, form, mutation, selected, fields, add, submit } =
useCatalogTemplateFormController(props);
const { t } = useTranslation("resources");
@@ -139,7 +139,6 @@ export function CatalogTemplateForm(props: CatalogTemplateFormProps) {
{creatingField && (
{
if (!open) {
setCreatingField(false);
diff --git a/modules/resources/src/web/catalog/list/controllers/use-catalog-page-controller.ts b/modules/resources/src/web/catalog/list/controllers/use-catalog-page-controller.ts
index f2da745..c820b0c 100644
--- a/modules/resources/src/web/catalog/list/controllers/use-catalog-page-controller.ts
+++ b/modules/resources/src/web/catalog/list/controllers/use-catalog-page-controller.ts
@@ -7,7 +7,7 @@ import type { CatalogEditor } from "../../shared";
import { catalogApi, catalogKeys } from "../../shared/api";
import type { ResourceCatalogPageProps } from "../types";
-export function useResourceCatalogPageController({ scope, csrfToken }: ResourceCatalogPageProps) {
+export function useResourceCatalogPageController({ scope }: ResourceCatalogPageProps) {
const client = useQueryClient();
const { searchParams, setSearchParams } = useBrowserSearchParams();
const requestedTab = searchParams.get("tab");
@@ -41,7 +41,7 @@ export function useResourceCatalogPageController({ scope, csrfToken }: ResourceC
});
const mutation = useMutation({
mutationFn: ({ item, active }: { item: CatalogItemDTO; active: boolean | null }) =>
- catalogApi.status(scope, item.id, active, csrfToken),
+ catalogApi.status(scope, item.id, active),
onSuccess: async (response) => {
await client.invalidateQueries({ queryKey: ["resource-catalog"] });
client.setQueryData(catalogKeys.scope(scope), response);
diff --git a/modules/resources/src/web/catalog/list/types/catalog-page-props.ts b/modules/resources/src/web/catalog/list/types/catalog-page-props.ts
index 64cffd2..307d7df 100644
--- a/modules/resources/src/web/catalog/list/types/catalog-page-props.ts
+++ b/modules/resources/src/web/catalog/list/types/catalog-page-props.ts
@@ -1,4 +1,3 @@
export type ResourceCatalogPageProps = {
scope: string;
- csrfToken: string;
};
diff --git a/modules/resources/src/web/catalog/list/ui/catalog-page.tsx b/modules/resources/src/web/catalog/list/ui/catalog-page.tsx
index ec37132..5fa19de 100644
--- a/modules/resources/src/web/catalog/list/ui/catalog-page.tsx
+++ b/modules/resources/src/web/catalog/list/ui/catalog-page.tsx
@@ -10,7 +10,7 @@ import type { ResourceCatalogPageProps } from "../types";
import { CatalogCell } from "./catalog-cell";
export function ResourceCatalogPage(props: ResourceCatalogPageProps) {
- const { scope, csrfToken } = props;
+ const { scope } = props;
const {
tab,
setTab,
@@ -177,7 +177,6 @@ export function ResourceCatalogPage(props: ResourceCatalogPageProps) {
setViewId(undefined)} />
{editor && (
setEditor(undefined)}
diff --git a/modules/resources/src/web/catalog/shared/api/catalog-api.ts b/modules/resources/src/web/catalog/shared/api/catalog-api.ts
index 2186fb4..aa90885 100644
--- a/modules/resources/src/web/catalog/shared/api/catalog-api.ts
+++ b/modules/resources/src/web/catalog/shared/api/catalog-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { ResourceDefinitionSpec } from "../../../../common";
@@ -11,14 +12,11 @@ export class CatalogApiError extends Error {
}
}
-async function request(path: string, body?: unknown, csrfToken?: string) {
- const response = await fetch(`/api/resource-catalog/${path}`, {
+async function request(path: string, body?: unknown) {
+ const response = await csrfFetch(`/api/resource-catalog/${path}`, {
method: body === undefined ? "GET" : "POST",
credentials: "same-origin",
- headers:
- body === undefined
- ? {}
- : { "content-type": "application/json", "x-csrf-token": csrfToken ?? "" },
+ headers: body === undefined ? {} : { "content-type": "application/json" },
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
const json: unknown = await response.json();
@@ -36,14 +34,12 @@ export const catalogApi = {
async get(scope: string) {
return CatalogResponseSchema.parse(await request(scope));
},
- async save(scope: string, values: ResourceDefinitionSpec, csrfToken: string, id?: string) {
+ async save(scope: string, values: ResourceDefinitionSpec, id?: string) {
return SaveDefinitionResponseSchema.parse(
- await request(`${scope}${id ? `/${id}/update` : ""}`, { values }, csrfToken)
+ await request(`${scope}${id ? `/${id}/update` : ""}`, { values })
);
},
- async status(scope: string, id: string, active: boolean | null, csrfToken: string) {
- return CatalogResponseSchema.parse(
- await request(`${scope}/${id}/status`, { active }, csrfToken)
- );
+ async status(scope: string, id: string, active: boolean | null) {
+ return CatalogResponseSchema.parse(await request(`${scope}/${id}/status`, { active }));
},
};
diff --git a/modules/resources/src/web/catalog/shared/catalog.test.tsx b/modules/resources/src/web/catalog/shared/catalog.test.tsx
index d008a9c..6a2b27c 100644
--- a/modules/resources/src/web/catalog/shared/catalog.test.tsx
+++ b/modules/resources/src/web/catalog/shared/catalog.test.tsx
@@ -48,7 +48,7 @@ test("el catálogo muestra plantillas de serie y acción de alta sin formularios
["en", "New template", "Actions"],
]) {
assert.ok(language && create && actions);
- const html = await render(language, );
+ const html = await render(language, );
assert.ok(html.includes("Buzón de correo"));
assert.ok(html.includes(create));
@@ -58,17 +58,14 @@ test("el catálogo muestra plantillas de serie y acción de alta sin formularios
}
});
test("los formularios tienen ayuda inferior y selector de campo con alta integrada", async () => {
- const field = await render(
- "es",
- undefined} scope="global" />
- );
+ const field = await render("es", undefined} scope="global" />);
assert.ok(field.indexOf('name="description"') < field.indexOf(" undefined} scope="global" />
+ undefined} scope="global" />
);
assert.ok(template.includes('aria-label="Nuevo campo"'));
diff --git a/modules/resources/src/web/catalog/shared/controllers/use-catalog-save.ts b/modules/resources/src/web/catalog/shared/controllers/use-catalog-save.ts
index 9c6a669..1c12029 100644
--- a/modules/resources/src/web/catalog/shared/controllers/use-catalog-save.ts
+++ b/modules/resources/src/web/catalog/shared/controllers/use-catalog-save.ts
@@ -6,12 +6,7 @@ import { catalogApi, catalogKeys } from "../api";
export type CatalogSaved = (id: string, data: SaveDefinitionResponseDTO) => void;
-export function useCatalogSave(
- scope: string,
- csrfToken: string,
- onSaved: CatalogSaved,
- id?: string
-) {
+export function useCatalogSave(scope: string, onSaved: CatalogSaved, id?: string) {
const client = useQueryClient();
const mounted = useRef(true);
@@ -24,7 +19,7 @@ export function useCatalogSave(
}, []);
return useMutation({
- mutationFn: (values: ResourceDefinitionSpec) => catalogApi.save(scope, values, csrfToken, id),
+ mutationFn: (values: ResourceDefinitionSpec) => catalogApi.save(scope, values, id),
onSuccess: async (response) => {
await client.invalidateQueries({ queryKey: ["resource-catalog"] });
client.setQueryData(catalogKeys.scope(scope), { items: response.items });
diff --git a/modules/resources/src/web/catalog/shared/ui/catalog-editor-dialog.tsx b/modules/resources/src/web/catalog/shared/ui/catalog-editor-dialog.tsx
index 3541569..97f386a 100644
--- a/modules/resources/src/web/catalog/shared/ui/catalog-editor-dialog.tsx
+++ b/modules/resources/src/web/catalog/shared/ui/catalog-editor-dialog.tsx
@@ -23,13 +23,11 @@ export function CatalogEditorDialog({
editor,
items,
scope,
- csrfToken,
onClose,
}: {
editor: CatalogEditor;
items: readonly CatalogItemDTO[];
scope: string;
- csrfToken: string;
onClose: () => void;
}) {
const { t } = useTranslation("resources");
@@ -48,16 +46,10 @@ export function CatalogEditorDialog({
wide={editor.kind === "template"}
>
{editor.kind === "field" ? (
- onClose()}
- scope={scope}
- />
+ onClose()} scope={scope} />
) : (
onClose()}
diff --git a/modules/resources/src/web/resources/list/types/resources-page-props.ts b/modules/resources/src/web/resources/list/types/resources-page-props.ts
index 4f648f5..f94f775 100644
--- a/modules/resources/src/web/resources/list/types/resources-page-props.ts
+++ b/modules/resources/src/web/resources/list/types/resources-page-props.ts
@@ -4,7 +4,6 @@ import type { ResourceDTO } from "../../../../common";
export type ResourcesPageProps = {
companyId: string;
- csrfToken: string;
relatedContent?: (resource: ResourceDTO) => ReactNode;
initialId?: string | undefined;
initialCreate?: boolean | undefined;
diff --git a/modules/resources/src/web/resources/list/ui/resources-page.tsx b/modules/resources/src/web/resources/list/ui/resources-page.tsx
index 19299ce..5cf8a1c 100644
--- a/modules/resources/src/web/resources/list/ui/resources-page.tsx
+++ b/modules/resources/src/web/resources/list/ui/resources-page.tsx
@@ -16,7 +16,7 @@ import { useResourcesPageController } from "../controllers";
import type { ResourcesPageProps } from "../types";
export function ResourcesPage(props: ResourcesPageProps) {
- const { companyId, csrfToken, relatedContent } = props;
+ const { companyId, relatedContent } = props;
const {
search,
setSearch,
@@ -129,7 +129,6 @@ export function ResourcesPage(props: ResourcesPageProps) {
{editor && catalog.data && (
setEditor(undefined)}
onSaved={(id) => {
diff --git a/modules/resources/src/web/resources/shared/api/inventory-api.ts b/modules/resources/src/web/resources/shared/api/inventory-api.ts
index e63d5f1..8b5509e 100644
--- a/modules/resources/src/web/resources/shared/api/inventory-api.ts
+++ b/modules/resources/src/web/resources/shared/api/inventory-api.ts
@@ -1,3 +1,4 @@
+import { csrfFetch } from "@metis/core/client";
import { z } from "zod/v4";
import type { ResourceInput } from "../../../../common/inventory";
@@ -11,14 +12,11 @@ export class InventoryApiError extends Error {
}
}
-async function request(path: string, body?: unknown, csrfToken?: string) {
- const response = await fetch(`/api/resources/${path}`, {
+async function request(path: string, body?: unknown) {
+ const response = await csrfFetch(`/api/resources/${path}`, {
method: body === undefined ? "GET" : "POST",
credentials: "same-origin",
- headers:
- body === undefined
- ? {}
- : { "content-type": "application/json", "x-csrf-token": csrfToken ?? "" },
+ headers: body === undefined ? {} : { "content-type": "application/json" },
...(body === undefined ? {} : { body: JSON.stringify(body) }),
});
const data: unknown = await response.json();
@@ -36,9 +34,9 @@ export const inventoryApi = {
async get(companyId: string) {
return InventoryResponseSchema.parse(await request(companyId));
},
- async save(companyId: string, values: ResourceInput, token: string, id?: string) {
+ async save(companyId: string, values: ResourceInput, id?: string) {
return ResourceResponseSchema.parse(
- await request(`${companyId}${id ? `/${id}/update` : ""}`, { values }, token)
+ await request(`${companyId}${id ? `/${id}/update` : ""}`, { values })
);
},
};
diff --git a/modules/resources/src/web/resources/shared/controllers/use-resource-form-controller.ts b/modules/resources/src/web/resources/shared/controllers/use-resource-form-controller.ts
index 4b5e140..3115321 100644
--- a/modules/resources/src/web/resources/shared/controllers/use-resource-form-controller.ts
+++ b/modules/resources/src/web/resources/shared/controllers/use-resource-form-controller.ts
@@ -12,7 +12,6 @@ import type { ResourceFormProps } from "../types";
export function useResourceFormController({
companyId,
- csrfToken,
resource,
items,
onSaved,
@@ -66,8 +65,7 @@ export function useResourceFormController({
);
const helpPrefix = isSoftwareLicense ? "license" : "resource";
const mutation = useMutation({
- mutationFn: (input: ResourceInput) =>
- inventoryApi.save(companyId, input, csrfToken, resource?.id),
+ mutationFn: (input: ResourceInput) => inventoryApi.save(companyId, input, resource?.id),
onSuccess: async (response) => {
await Promise.all(
[
diff --git a/modules/resources/src/web/resources/shared/resources.test.tsx b/modules/resources/src/web/resources/shared/resources.test.tsx
index 7bf1f0e..c10b7c5 100644
--- a/modules/resources/src/web/resources/shared/resources.test.tsx
+++ b/modules/resources/src/web/resources/shared/resources.test.tsx
@@ -52,7 +52,7 @@ test("recursos: listado con alta modal y sin formulario visible, en español e i
["en", "New resource"],
]) {
assert.ok(language && label);
- const html = await render(language, );
+ const html = await render(language, );
assert.ok(html.includes(label));
assert.equal(html.includes(" {
const html = await render(
"es",
- undefined} />
+ undefined} />
);
assert.ok(html.includes('aria-label="Nueva plantilla"'));
@@ -74,7 +74,6 @@ test("recurso: ayuda inferior, plantilla con alta rápida y sin asignaciones de
undefined}
/>
@@ -125,7 +124,6 @@ test("licencia: formulario reutilizable con campos opcionales y ayuda antes de g
language,
undefined}
resource={resource}
diff --git a/modules/resources/src/web/resources/shared/types/resource-editor-props.ts b/modules/resources/src/web/resources/shared/types/resource-editor-props.ts
index 046b421..d0ebb54 100644
--- a/modules/resources/src/web/resources/shared/types/resource-editor-props.ts
+++ b/modules/resources/src/web/resources/shared/types/resource-editor-props.ts
@@ -1,6 +1,5 @@
export type ResourceEditorProps = {
companyId: string;
- csrfToken: string;
resourceId?: string | undefined;
initialKind?: "mailbox" | "access" | "application" | "certificate" | undefined;
initialAddress?: string;
diff --git a/modules/resources/src/web/resources/shared/types/resource-form-props.ts b/modules/resources/src/web/resources/shared/types/resource-form-props.ts
index 78c8bf9..f064cea 100644
--- a/modules/resources/src/web/resources/shared/types/resource-form-props.ts
+++ b/modules/resources/src/web/resources/shared/types/resource-form-props.ts
@@ -3,7 +3,6 @@ import type { ResourceDTO, ResourceInput } from "../../../../common/inventory";
export type ResourceFormProps = {
companyId: string;
- csrfToken: string;
resource?: ResourceDTO | undefined;
items: readonly CatalogItemDTO[];
onSaved: (id: string) => void;
diff --git a/modules/resources/src/web/resources/shared/ui/resource-editor-dialog.tsx b/modules/resources/src/web/resources/shared/ui/resource-editor-dialog.tsx
index 4378fee..1c670e1 100644
--- a/modules/resources/src/web/resources/shared/ui/resource-editor-dialog.tsx
+++ b/modules/resources/src/web/resources/shared/ui/resource-editor-dialog.tsx
@@ -7,14 +7,12 @@ import { ResourceForm } from "./resource-form";
export function ResourceEditorDialog({
resource,
companyId,
- csrfToken,
items,
onClose,
onSaved,
}: {
resource: ComponentProps["resource"];
companyId: string;
- csrfToken: string;
items: ComponentProps["items"];
onClose: () => void;
onSaved: (id: string) => void;
@@ -34,13 +32,7 @@ export function ResourceEditorDialog({
title={t(resource ? "editResource" : "newResource")}
wide
>
-
+
);
}
diff --git a/modules/resources/src/web/resources/shared/ui/resource-editor.tsx b/modules/resources/src/web/resources/shared/ui/resource-editor.tsx
index ebc2266..d977032 100644
--- a/modules/resources/src/web/resources/shared/ui/resource-editor.tsx
+++ b/modules/resources/src/web/resources/shared/ui/resource-editor.tsx
@@ -9,7 +9,6 @@ import { ResourceForm } from "./resource-form";
export function ResourceEditor(props: ResourceEditorProps) {
const {
companyId,
- csrfToken,
resourceId,
initialKind,
initialAddress = "",
@@ -46,7 +45,6 @@ export function ResourceEditor(props: ResourceEditorProps) {
{creatingTemplate && (
{
if (!open) {