Add helper function to secure handling of processId in the code
Some checks failed
Build and Push to Registry / build-and-push (push) Failing after 4m22s
Some checks failed
Build and Push to Registry / build-and-push (push) Failing after 4m22s
This commit is contained in:
parent
0a3be835a9
commit
56878c977c
@ -7,6 +7,7 @@ import DefaultDashboardWithList, { IPropsDashboardWithList } from "../DefaultDas
|
|||||||
import { DeedType } from "le-coffre-resources/dist/Notary";
|
import { DeedType } from "le-coffre-resources/dist/Notary";
|
||||||
|
|
||||||
import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService";
|
import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService";
|
||||||
|
import { idAsUrl } from "@Front/Utils/ProcessIdUtils";
|
||||||
|
|
||||||
type IProps = IPropsDashboardWithList;
|
type IProps = IPropsDashboardWithList;
|
||||||
|
|
||||||
@ -17,13 +18,13 @@ export default function DefaultDeedTypeDashboard(props: IProps) {
|
|||||||
const [deedTypes, setDeedTypes] = React.useState<DeedType[] | null>(null);
|
const [deedTypes, setDeedTypes] = React.useState<DeedType[] | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
DeedTypeService.getDeedTypes((processes: any[]) => {
|
DeedTypeService.getDeedTypes((processes: Record<string, any>) => {
|
||||||
if (processes.length > 0) {
|
const deedTypes = Object.entries(processes).map(([processId, processData]) => ({
|
||||||
let deedTypes = processes.map((process: any) => process.processData);
|
...processData,
|
||||||
|
processId: processId
|
||||||
// FilterBy archived_at = null or not defined
|
}));
|
||||||
deedTypes = deedTypes.filter((deedType: any) => !deedType.archived_at);
|
if (deedTypes.length > 0) {
|
||||||
|
deedTypes.filter((deedType: any) => !deedType.archived_at);
|
||||||
// OrderBy name asc
|
// OrderBy name asc
|
||||||
deedTypes.sort((a: any, b: any) => a.name.localeCompare(b.name));
|
deedTypes.sort((a: any, b: any) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
@ -35,7 +36,9 @@ export default function DefaultDeedTypeDashboard(props: IProps) {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const onSelectedBlock = (block: IBlock) => {
|
const onSelectedBlock = (block: IBlock) => {
|
||||||
router.push(Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.props.path.replace("[uid]", block.id));
|
// Remove ':0' suffix from processId for URL navigation
|
||||||
|
const urlId = idAsUrl(block.id as string);
|
||||||
|
router.push(Module.getInstance().get().modules.pages.DeedTypes.pages.DeedTypesInformations.props.path.replace("[uid]", urlId));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -44,11 +47,14 @@ export default function DefaultDeedTypeDashboard(props: IProps) {
|
|||||||
onSelectedBlock={onSelectedBlock}
|
onSelectedBlock={onSelectedBlock}
|
||||||
blocks={
|
blocks={
|
||||||
deedTypes
|
deedTypes
|
||||||
? deedTypes.map((deedTypes) => ({
|
? deedTypes.map((deedType: any) => {
|
||||||
id: deedTypes.uid!,
|
const urlId = idAsUrl(deedType.processId);
|
||||||
primaryText: deedTypes.name,
|
return {
|
||||||
isActive: deedTypes.uid === deedTypeUid,
|
id: deedType.processId, // Keep full processId for internal use
|
||||||
}))
|
primaryText: deedType.name,
|
||||||
|
isActive: urlId === deedTypeUid, // Compare without ':0' suffix
|
||||||
|
};
|
||||||
|
})
|
||||||
: []
|
: []
|
||||||
}
|
}
|
||||||
bottomButton={{
|
bottomButton={{
|
||||||
|
@ -19,6 +19,7 @@ import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
|||||||
import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService";
|
import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService";
|
||||||
import { DEFAULT_VALIDATOR_ID } from "@Front/Config/AppConstants";
|
import { DEFAULT_VALIDATOR_ID } from "@Front/Config/AppConstants";
|
||||||
import Auth from "@Front/Api/Auth/IdNot";
|
import Auth from "@Front/Api/Auth/IdNot";
|
||||||
|
import { idAsUrl } from "@Front/Utils/ProcessIdUtils";
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
export default function DeedTypesCreate(props: IProps) {
|
export default function DeedTypesCreate(props: IProps) {
|
||||||
@ -80,7 +81,7 @@ export default function DeedTypesCreate(props: IProps) {
|
|||||||
});
|
});
|
||||||
const deedTypeUid = processCreated.processId;
|
const deedTypeUid = processCreated.processId;
|
||||||
// Remove ':0' suffix from processId for URL navigation
|
// Remove ':0' suffix from processId for URL navigation
|
||||||
const urlId = deedTypeUid.replace(/:0$/, '');
|
const urlId = idAsUrl(deedTypeUid);
|
||||||
router.push(
|
router.push(
|
||||||
Module.getInstance()
|
Module.getInstance()
|
||||||
.get()
|
.get()
|
||||||
|
@ -17,6 +17,7 @@ import classes from "./classes.module.scss";
|
|||||||
import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService";
|
import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService";
|
||||||
import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
||||||
import MessageBus from "src/sdk/MessageBus";
|
import MessageBus from "src/sdk/MessageBus";
|
||||||
|
import { idAsProcessId } from "@Front/Utils/ProcessIdUtils";
|
||||||
|
|
||||||
export default function DeedTypesEdit() {
|
export default function DeedTypesEdit() {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -33,7 +34,7 @@ export default function DeedTypesEdit() {
|
|||||||
if (!deedTypeUid) return;
|
if (!deedTypeUid) return;
|
||||||
LoaderService.getInstance().show();
|
LoaderService.getInstance().show();
|
||||||
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
||||||
const processId = (deedTypeUid as string) + ':0';
|
const processId = idAsProcessId(deedTypeUid as string);
|
||||||
MessageBus.getInstance().getProcessData(processId).then((processData: any) => {
|
MessageBus.getInstance().getProcessData(processId).then((processData: any) => {
|
||||||
if (processData) {
|
if (processData) {
|
||||||
setDeedTypeSelected(processData);
|
setDeedTypeSelected(processData);
|
||||||
@ -66,7 +67,7 @@ export default function DeedTypesEdit() {
|
|||||||
try {
|
try {
|
||||||
LoaderService.getInstance().show();
|
LoaderService.getInstance().show();
|
||||||
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
||||||
const processId = (deedTypeUid as string) + ':0';
|
const processId = idAsProcessId(deedTypeUid as string);
|
||||||
|
|
||||||
const process = await MessageBus.getInstance().getProcessData(processId);
|
const process = await MessageBus.getInstance().getProcessData(processId);
|
||||||
if (process) {
|
if (process) {
|
||||||
|
@ -22,6 +22,7 @@ import DeedTypeService from "src/common/Api/LeCoffreApi/sdk/DeedTypeService";
|
|||||||
import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService";
|
import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService";
|
||||||
import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
||||||
import MessageBus from "src/sdk/MessageBus";
|
import MessageBus from "src/sdk/MessageBus";
|
||||||
|
import { idAsProcessId } from "@Front/Utils/ProcessIdUtils";
|
||||||
|
|
||||||
type IProps = {};
|
type IProps = {};
|
||||||
export default function DeedTypesInformations(props: IProps) {
|
export default function DeedTypesInformations(props: IProps) {
|
||||||
@ -51,12 +52,14 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
setIsSaveModalOpened(false);
|
setIsSaveModalOpened(false);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
const deleteDeedType = useCallback(async () => {
|
const deleteDeedType = async () => {
|
||||||
LoaderService.getInstance().show();
|
LoaderService.getInstance().show();
|
||||||
|
try {
|
||||||
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
||||||
const processId = (deedTypeUid as string) + ':0';
|
const processId = idAsProcessId(deedTypeUid as string);
|
||||||
MessageBus.getInstance().getProcessData(processId).then(async (process: any) => {
|
const process = await MessageBus.getInstance().getProcessData(processId);
|
||||||
if (process) {
|
|
||||||
|
if (process && process[processId]) {
|
||||||
// New data
|
// New data
|
||||||
const newData: any = {
|
const newData: any = {
|
||||||
isDeleted: 'true',
|
isDeleted: 'true',
|
||||||
@ -64,19 +67,22 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Merge process data with new data & update process
|
// Merge process data with new data & update process
|
||||||
process.processData.isDeleted = newData.isDeleted;
|
process[processId].isDeleted = newData.isDeleted;
|
||||||
process.processData.archived_at = newData.archived_at;
|
process[processId].archived_at = newData.archived_at;
|
||||||
await DeedTypeService.updateDeedType(process, newData);
|
await DeedTypeService.updateDeedType(processId, newData);
|
||||||
|
|
||||||
router.push(
|
router.push(
|
||||||
Module.getInstance()
|
Module.getInstance()
|
||||||
.get()
|
.get()
|
||||||
.modules.pages.DeedTypes.props.path
|
.modules.pages.DeedTypes.props.path
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error deleting deed type:', error);
|
||||||
|
} finally {
|
||||||
LoaderService.getInstance().hide();
|
LoaderService.getInstance().hide();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
}, [deedTypeUid, router]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function getDeedType() {
|
async function getDeedType() {
|
||||||
@ -84,7 +90,7 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
|
|
||||||
setSelectedDocuments([]);
|
setSelectedDocuments([]);
|
||||||
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
||||||
const processId = (deedTypeUid as string) + ':0';
|
const processId = idAsProcessId(deedTypeUid as string);
|
||||||
MessageBus.getInstance().getProcessData(processId).then((process: any) => {
|
MessageBus.getInstance().getProcessData(processId).then((process: any) => {
|
||||||
if (process) {
|
if (process) {
|
||||||
console.log('[DeedTypesInformations] process', process);
|
console.log('[DeedTypesInformations] process', process);
|
||||||
@ -131,7 +137,7 @@ export default function DeedTypesInformations(props: IProps) {
|
|||||||
const saveDocumentTypes = useCallback(async () => {
|
const saveDocumentTypes = useCallback(async () => {
|
||||||
LoaderService.getInstance().show();
|
LoaderService.getInstance().show();
|
||||||
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
// deedTypeUid comes from URL without ':0' suffix, add it back for API calls
|
||||||
const processId = (deedTypeUid as string) + ':0';
|
const processId = idAsProcessId(deedTypeUid as string);
|
||||||
console.log('[DeedTypesInformations] processId', processId);
|
console.log('[DeedTypesInformations] processId', processId);
|
||||||
const deedType = (await MessageBus.getInstance().getProcessData(processId))[processId];
|
const deedType = (await MessageBus.getInstance().getProcessData(processId))[processId];
|
||||||
if (deedType) {
|
if (deedType) {
|
||||||
|
@ -16,6 +16,7 @@ import classes from "./classes.module.scss";
|
|||||||
|
|
||||||
import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService";
|
import DocumentTypeService from "src/common/Api/LeCoffreApi/sdk/DocumentTypeService";
|
||||||
import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
import LoaderService from "src/common/Api/LeCoffreApi/sdk/Loader/LoaderService";
|
||||||
|
import { idAsUrl } from "@Front/Utils/ProcessIdUtils";
|
||||||
import UserStore from "@Front/Stores/UserStore";
|
import UserStore from "@Front/Stores/UserStore";
|
||||||
import { DEFAULT_VALIDATOR_ID } from "@Front/Config/AppConstants";
|
import { DEFAULT_VALIDATOR_ID } from "@Front/Config/AppConstants";
|
||||||
|
|
||||||
@ -68,7 +69,7 @@ export default function DocumentTypesCreate(props: IProps) {
|
|||||||
title: "Succès !",
|
title: "Succès !",
|
||||||
description: "Type de document créé avec succès"
|
description: "Type de document créé avec succès"
|
||||||
});
|
});
|
||||||
const documentTypeUid = processCreated.processId.split(':')[0];
|
const documentTypeUid = idAsUrl(processCreated.processId);
|
||||||
if (!documentTypeUid) {
|
if (!documentTypeUid) {
|
||||||
console.error("DocumentTypesCreate: documentTypeUid is undefined - processCreated.processId is missing");
|
console.error("DocumentTypesCreate: documentTypeUid is undefined - processCreated.processId is missing");
|
||||||
return;
|
return;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
import Button, { EButtonSize, EButtonstyletype, EButtonVariant } from "@Front/Components/DesignSystem/Button";
|
||||||
import EmptyAlert from "@Front/Components/DesignSystem/EmptyAlert";
|
import EmptyAlert from "@Front/Components/DesignSystem/EmptyAlert";
|
||||||
import Module from "@Front/Config/Module";
|
import Module from "@Front/Config/Module";
|
||||||
|
import { idAsUrl } from "@Front/Utils/ProcessIdUtils";
|
||||||
import { UserPlusIcon } from "@heroicons/react/24/outline";
|
import { UserPlusIcon } from "@heroicons/react/24/outline";
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import React, { useMemo } from "react";
|
import React, { useMemo } from "react";
|
||||||
@ -14,7 +15,7 @@ export default function AddClientSection(props: IProps) {
|
|||||||
|
|
||||||
const addClientPath = useMemo(() => {
|
const addClientPath = useMemo(() => {
|
||||||
if (!folderUid) return "";
|
if (!folderUid) return "";
|
||||||
return Module.getInstance().get().modules.pages.Folder.pages.AddClient.props.path.replace("[folderUid]", folderUid);
|
return Module.getInstance().get().modules.pages.Folder.pages.AddClient.props.path.replace("[folderUid]", idAsUrl(folderUid));
|
||||||
}, [folderUid]);
|
}, [folderUid]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -24,6 +24,8 @@ import DocumentService from "src/common/Api/LeCoffreApi/sdk/DocumentService";
|
|||||||
import FileService from "src/common/Api/LeCoffreApi/sdk/FileService";
|
import FileService from "src/common/Api/LeCoffreApi/sdk/FileService";
|
||||||
import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService";
|
import CustomerService from "src/common/Api/LeCoffreApi/sdk/CustomerService";
|
||||||
import { DEFAULT_VALIDATOR_ID } from "@Front/Config/AppConstants";
|
import { DEFAULT_VALIDATOR_ID } from "@Front/Config/AppConstants";
|
||||||
|
import { idAsProcessId } from "@Front/Utils/ProcessIdUtils";
|
||||||
|
import MessageBus from "src/sdk/MessageBus";
|
||||||
|
|
||||||
enum EClientSelection {
|
enum EClientSelection {
|
||||||
ALL_CLIENTS = "all_clients",
|
ALL_CLIENTS = "all_clients",
|
||||||
@ -70,7 +72,7 @@ export default function SendDocuments() {
|
|||||||
const customer: any = await new Promise<void>((resolve: (customer: any) => void) => {
|
const customer: any = await new Promise<void>((resolve: (customer: any) => void) => {
|
||||||
CustomerService.getCustomerByUid(selectedClient as string).then((process: any) => {
|
CustomerService.getCustomerByUid(selectedClient as string).then((process: any) => {
|
||||||
if (process) {
|
if (process) {
|
||||||
const customer: any = process.processData;
|
const customer: any = process;
|
||||||
resolve(customer);
|
resolve(customer);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -100,7 +102,7 @@ export default function SendDocuments() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
FileService.createFile(fileData, DEFAULT_VALIDATOR_ID).then((processCreated: any) => {
|
FileService.createFile(fileData, DEFAULT_VALIDATOR_ID).then((processCreated: any) => {
|
||||||
const fileUid: string = processCreated.processData.uid;
|
const fileUid: string = processCreated.uid;
|
||||||
|
|
||||||
const documentData: any = {
|
const documentData: any = {
|
||||||
folder: {
|
folder: {
|
||||||
@ -173,9 +175,9 @@ export default function SendDocuments() {
|
|||||||
|
|
||||||
const fetchFolder = useCallback(async () => {
|
const fetchFolder = useCallback(async () => {
|
||||||
LoaderService.getInstance().show();
|
LoaderService.getInstance().show();
|
||||||
FolderService.getFolderByUid(folderUid as string).then((process: any) => {
|
MessageBus.getInstance().getProcessData(idAsProcessId(folderUid as string)).then((process: any) => {
|
||||||
if (process) {
|
if (process) {
|
||||||
const folder: any = process.processData;
|
const folder: any = process;
|
||||||
setFolder(folder);
|
setFolder(folder);
|
||||||
LoaderService.getInstance().hide();
|
LoaderService.getInstance().hide();
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import { useEffect, useState } from "react";
|
|||||||
import classes from "./classes.module.scss";
|
import classes from "./classes.module.scss";
|
||||||
|
|
||||||
import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService";
|
import FolderService from "src/common/Api/LeCoffreApi/sdk/FolderService";
|
||||||
|
import { idAsUrl } from "@Front/Utils/ProcessIdUtils";
|
||||||
|
|
||||||
export default function Folder() {
|
export default function Folder() {
|
||||||
const [_isArchivedModalOpen, _setIsArchivedModalOpen] = useState(true);
|
const [_isArchivedModalOpen, _setIsArchivedModalOpen] = useState(true);
|
||||||
@ -39,7 +40,7 @@ export default function Folder() {
|
|||||||
folders = folders.sort((a: any, b: any) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
folders = folders.sort((a: any, b: any) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
|
||||||
|
|
||||||
if (folders.length > 0) {
|
if (folders.length > 0) {
|
||||||
const folderUid = folders[0]?.processId;
|
const folderUid = idAsUrl(folders[0]?.processId);
|
||||||
|
|
||||||
if (!folderUid) {
|
if (!folderUid) {
|
||||||
return;
|
return;
|
||||||
|
52
src/front/Utils/ProcessIdUtils.ts
Normal file
52
src/front/Utils/ProcessIdUtils.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
/**
|
||||||
|
* Utility functions to safely handle conversion between URL-friendly IDs and process IDs.
|
||||||
|
*
|
||||||
|
* Process IDs in the system use a ":0" suffix for API calls, but URLs use the clean ID without the suffix.
|
||||||
|
* These functions provide safe conversion between the two formats to avoid error-prone string manipulation.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a process ID to URL-friendly format by removing the ":0" suffix if present.
|
||||||
|
* Safe to call multiple times - won't remove ":0" from IDs that don't end with it.
|
||||||
|
*
|
||||||
|
* @param processId - The process ID that may or may not have ":0" suffix
|
||||||
|
* @returns The ID without ":0" suffix, suitable for use in URLs. Returns empty string for null/undefined.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* idAsUrl("abc123:0") // returns "abc123"
|
||||||
|
* idAsUrl("abc123") // returns "abc123" (no change)
|
||||||
|
* idAsUrl("abc:123:0") // returns "abc:123" (only removes trailing ":0")
|
||||||
|
* idAsUrl(null) // returns ""
|
||||||
|
* idAsUrl(undefined) // returns ""
|
||||||
|
*/
|
||||||
|
export function idAsUrl(processId: string | null | undefined): string {
|
||||||
|
if (!processId || typeof processId !== 'string') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only remove ":0" if it's at the very end of the string
|
||||||
|
return processId.replace(/:0$/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts a URL-friendly ID to process ID format by adding ":0" suffix if not already present.
|
||||||
|
* Safe to call multiple times - won't add ":0" if it's already there.
|
||||||
|
*
|
||||||
|
* @param urlId - The URL-friendly ID that may or may not have ":0" suffix
|
||||||
|
* @returns The ID with ":0" suffix, suitable for use in API calls. Returns ":0" for null/undefined.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* idAsProcessId("abc123") // returns "abc123:0"
|
||||||
|
* idAsProcessId("abc123:0") // returns "abc123:0" (no change)
|
||||||
|
* idAsProcessId("abc:123") // returns "abc:123:0"
|
||||||
|
* idAsProcessId(null) // returns ""
|
||||||
|
* idAsProcessId(undefined) // returns ""
|
||||||
|
*/
|
||||||
|
export function idAsProcessId(urlId: string | null | undefined): string {
|
||||||
|
if (!urlId || typeof urlId !== 'string') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only add ":0" if it's not already at the end
|
||||||
|
return urlId.endsWith(':0') ? urlId : `${urlId}:0`;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user