@ramses1er/cbk-toolkit 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +87 -39
- package/dist/index.js +69 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,57 +1,105 @@
|
|
|
1
|
-
import * as react from
|
|
2
|
-
import { ReactNode, ComponentType } from
|
|
1
|
+
import * as react from "react";
|
|
2
|
+
import { ReactNode, ComponentType } from "react";
|
|
3
3
|
|
|
4
|
-
type IconType =
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
type IconType =
|
|
5
|
+
| ReactNode
|
|
6
|
+
| ComponentType<{
|
|
7
|
+
size?: number;
|
|
8
|
+
}>;
|
|
7
9
|
interface NavItem {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
id: string;
|
|
11
|
+
label: string;
|
|
12
|
+
title?: string;
|
|
13
|
+
icon?: IconType;
|
|
14
|
+
href: string;
|
|
15
|
+
subItems?: NavItem[];
|
|
14
16
|
}
|
|
15
17
|
interface SideNavStaticConfig {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
brand?: {
|
|
19
|
+
logo?: ReactNode;
|
|
20
|
+
name?: string;
|
|
21
|
+
tagline?: string;
|
|
22
|
+
};
|
|
23
|
+
mainItems: NavItem[];
|
|
24
|
+
title?: string;
|
|
25
|
+
footer?: {
|
|
26
|
+
icon?: IconType;
|
|
27
|
+
label: string;
|
|
28
|
+
href: string;
|
|
29
|
+
}[];
|
|
30
|
+
toggleIcon?: ReactNode;
|
|
29
31
|
}
|
|
30
32
|
interface SideNavProps extends SideNavStaticConfig {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
children: ReactNode;
|
|
34
|
+
currentPath: string;
|
|
33
35
|
}
|
|
34
|
-
declare function SideNav({
|
|
36
|
+
declare function SideNav({
|
|
37
|
+
children,
|
|
38
|
+
title,
|
|
39
|
+
mainItems,
|
|
40
|
+
currentPath,
|
|
41
|
+
brand,
|
|
42
|
+
footer,
|
|
43
|
+
toggleIcon,
|
|
44
|
+
}: SideNavProps): react.JSX.Element;
|
|
35
45
|
|
|
36
|
-
declare function createSideNav(
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
declare function createSideNav(
|
|
47
|
+
config: SideNavStaticConfig,
|
|
48
|
+
): ({
|
|
49
|
+
children,
|
|
50
|
+
currentPath,
|
|
51
|
+
}: {
|
|
52
|
+
children: React.ReactNode;
|
|
53
|
+
currentPath: string;
|
|
39
54
|
}) => react.JSX.Element;
|
|
40
55
|
|
|
41
56
|
declare class ApiError extends Error {
|
|
57
|
+
status: number;
|
|
58
|
+
code?: string;
|
|
59
|
+
data?: unknown;
|
|
60
|
+
constructor(params: {
|
|
61
|
+
message: string;
|
|
42
62
|
status: number;
|
|
43
63
|
code?: string;
|
|
44
64
|
data?: unknown;
|
|
45
|
-
|
|
46
|
-
message: string;
|
|
47
|
-
status: number;
|
|
48
|
-
code?: string;
|
|
49
|
-
data?: unknown;
|
|
50
|
-
});
|
|
65
|
+
});
|
|
51
66
|
}
|
|
52
67
|
type FetcherOptions = RequestInit & {
|
|
53
|
-
|
|
68
|
+
skipJsonParsing?: boolean;
|
|
54
69
|
};
|
|
55
|
-
declare function fetcher<T = unknown>(
|
|
70
|
+
declare function fetcher<T = unknown>(
|
|
71
|
+
url: string,
|
|
72
|
+
options?: FetcherOptions,
|
|
73
|
+
): Promise<T>;
|
|
74
|
+
|
|
75
|
+
declare class HttpError extends Error {
|
|
76
|
+
status: number;
|
|
77
|
+
code?: string;
|
|
78
|
+
constructor(message: string, status?: number, code?: string);
|
|
79
|
+
}
|
|
56
80
|
|
|
57
|
-
|
|
81
|
+
/**
|
|
82
|
+
* Transforme n'importe quelle erreur en réponse JSON standardisée
|
|
83
|
+
* @param error L'erreur levée
|
|
84
|
+
* @param defaultStatus Statut HTTP par défaut si non défini
|
|
85
|
+
* @param showDetails Force l'affichage des détails (true) ou le mode sécurisé (false). Par défaut : automatique selon NODE_ENV
|
|
86
|
+
* @returns Response JSON
|
|
87
|
+
*/
|
|
88
|
+
declare function handleServerError(
|
|
89
|
+
error: unknown,
|
|
90
|
+
defaultStatus?: number,
|
|
91
|
+
showDetails?: boolean,
|
|
92
|
+
): Response;
|
|
93
|
+
|
|
94
|
+
export {
|
|
95
|
+
ApiError,
|
|
96
|
+
type FetcherOptions,
|
|
97
|
+
HttpError,
|
|
98
|
+
type NavItem,
|
|
99
|
+
SideNav,
|
|
100
|
+
type SideNavProps,
|
|
101
|
+
type SideNavStaticConfig,
|
|
102
|
+
createSideNav,
|
|
103
|
+
fetcher,
|
|
104
|
+
handleServerError,
|
|
105
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -167,10 +167,78 @@ async function fetcher(url, options = {}) {
|
|
|
167
167
|
}
|
|
168
168
|
return responseData;
|
|
169
169
|
}
|
|
170
|
+
|
|
171
|
+
// packages/lib/src/http-error.ts
|
|
172
|
+
var HttpError = class _HttpError extends Error {
|
|
173
|
+
status;
|
|
174
|
+
code;
|
|
175
|
+
constructor(message, status = 400, code) {
|
|
176
|
+
super(message);
|
|
177
|
+
this.name = "HttpError";
|
|
178
|
+
this.status = status;
|
|
179
|
+
this.code = code;
|
|
180
|
+
Object.setPrototypeOf(this, _HttpError.prototype);
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
// packages/lib/src/handle-server-error.ts
|
|
185
|
+
var GENERIC_MESSAGE = "Erreur serveur";
|
|
186
|
+
function shouldShowDetails(showDetails) {
|
|
187
|
+
return showDetails ?? process.env.NODE_ENV !== "production";
|
|
188
|
+
}
|
|
189
|
+
function sanitizedResponse(message, code, status, showDetails) {
|
|
190
|
+
return Response.json(
|
|
191
|
+
{
|
|
192
|
+
message: showDetails ? message : GENERIC_MESSAGE,
|
|
193
|
+
code: showDetails ? code : "INTERNAL_ERROR",
|
|
194
|
+
status
|
|
195
|
+
},
|
|
196
|
+
{ status }
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
function handleServerError(error, defaultStatus = 500, showDetails) {
|
|
200
|
+
const details = shouldShowDetails(showDetails);
|
|
201
|
+
console.error("Erreur captur\xE9e :", error);
|
|
202
|
+
if (error instanceof HttpError) {
|
|
203
|
+
const status = error.status ?? defaultStatus;
|
|
204
|
+
return Response.json(
|
|
205
|
+
{
|
|
206
|
+
message: error.message,
|
|
207
|
+
code: error.code ?? "INTERNAL_ERROR",
|
|
208
|
+
status
|
|
209
|
+
},
|
|
210
|
+
{ status }
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
if (error instanceof Error) {
|
|
214
|
+
return sanitizedResponse(
|
|
215
|
+
error.message,
|
|
216
|
+
"INTERNAL_ERROR",
|
|
217
|
+
defaultStatus,
|
|
218
|
+
details
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (typeof error === "object" && error !== null) {
|
|
222
|
+
return sanitizedResponse(
|
|
223
|
+
JSON.stringify(error),
|
|
224
|
+
"INTERNAL_ERROR",
|
|
225
|
+
defaultStatus,
|
|
226
|
+
details
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
return sanitizedResponse(
|
|
230
|
+
String(error),
|
|
231
|
+
"INTERNAL_ERROR",
|
|
232
|
+
defaultStatus,
|
|
233
|
+
details
|
|
234
|
+
);
|
|
235
|
+
}
|
|
170
236
|
export {
|
|
171
237
|
ApiError,
|
|
238
|
+
HttpError,
|
|
172
239
|
SideNav,
|
|
173
240
|
createSideNav,
|
|
174
|
-
fetcher
|
|
241
|
+
fetcher,
|
|
242
|
+
handleServerError
|
|
175
243
|
};
|
|
176
244
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../packages/ui/src/layouts/side-nav.tsx","../packages/ui/src/config/create-side-nav.tsx","../packages/utils/src/fetcher.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n ReactNode,\r\n useState,\r\n createElement,\r\n isValidElement,\r\n type ComponentType,\r\n} from \"react\";\r\n\r\ntype IconType = ReactNode | ComponentType<{ size?: number }>;\r\n\r\nexport interface NavItem {\r\n id: string;\r\n label: string;\r\n title?: string;\r\n icon?: IconType;\r\n href: string;\r\n subItems?: NavItem[];\r\n}\r\n\r\nexport interface SideNavStaticConfig {\r\n brand?: {\r\n logo?: ReactNode;\r\n name?: string;\r\n tagline?: string;\r\n };\r\n mainItems: NavItem[];\r\n title?: string;\r\n footer?: { icon?: IconType; label: string; href: string }[];\r\n toggleIcon?: ReactNode;\r\n}\r\n\r\nexport interface SideNavProps extends SideNavStaticConfig {\r\n children: ReactNode;\r\n currentPath: string;\r\n}\r\n\r\nfunction isActive(href: string, currentPath: string) {\r\n return currentPath === href || currentPath.startsWith(href + \"/\");\r\n}\r\n\r\nfunction isExactActive(href: string, currentPath: string) {\r\n return currentPath === href;\r\n}\r\n\r\nexport function SideNav({\r\n children,\r\n title,\r\n mainItems,\r\n currentPath,\r\n brand,\r\n footer,\r\n toggleIcon,\r\n}: SideNavProps) {\r\n const activeMain = mainItems.find((item) => isActive(item.href, currentPath));\r\n const headerTitle = title ?? activeMain?.title ?? activeMain?.label;\r\n const [expandedSection, setExpandedSection] = useState<string | null>(\r\n activeMain?.id ?? null,\r\n );\r\n\r\n const toggleSection = (id: string) => {\r\n setExpandedSection((prev) => (prev === id ? null : id));\r\n };\r\n\r\n return (\r\n <div className=\"flex min-h-screen\">\r\n <aside className=\"w-64 bg-white border-r border-gray-200 flex flex-col fixed h-full\">\r\n {brand && (\r\n <div className=\"p-[6.5px] border-b border-gray-100\">\r\n <div className=\"flex flex-row gap-2 items-center\">\r\n {brand.logo &&\r\n (typeof brand.logo === \"string\" ? (\r\n <img\r\n src={brand.logo}\r\n alt={brand.name ?? \"\"}\r\n className=\"w-12.5 h-12.5\"\r\n />\r\n ) : (\r\n brand.logo\r\n ))}\r\n {brand.name && (\r\n <p className=\"text-gray-500 text-base font-semibold\">\r\n {brand.name}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n <nav className=\"flex-1 p-4 overflow-y-auto\">\r\n <ul className=\"space-y-1\">\r\n {mainItems.map((item) => {\r\n const active = isActive(item.href, currentPath);\r\n const isExpanded = expandedSection === item.id;\r\n const hasSubItems = item.subItems && item.subItems.length > 0;\r\n\r\n return (\r\n <li key={item.id}>\r\n <div className=\"flex items-center gap-1\">\r\n <a\r\n href={item.href}\r\n className={`flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors flex-1 ${\r\n active\r\n ? \"bg-gray-200 text-black\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n >\r\n {item.icon &&\r\n (typeof item.icon === \"string\" ? (\r\n <span className=\"text-lg\">{item.icon}</span>\r\n ) : isValidElement(item.icon) ? (\r\n item.icon\r\n ) : (\r\n createElement(\r\n item.icon as ComponentType<{ size?: number }>,\r\n { size: 20 },\r\n )\r\n ))}\r\n {item.label}\r\n </a>\r\n {active && hasSubItems && (\r\n <button\r\n onClick={() => toggleSection(item.id)}\r\n className={`p-1.5 rounded-lg transition-colors ${\r\n active\r\n ? \"text-black hover:bg-gray-100\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n title={isExpanded ? \"Réduire\" : \"Développer\"}\r\n >\r\n {toggleIcon ? (\r\n <span\r\n className={`inline-block transition-transform duration-200 ${\r\n isExpanded ? \"rotate-0\" : \"-rotate-90\"\r\n }`}\r\n >\r\n {toggleIcon}\r\n </span>\r\n ) : (\r\n <span className=\"text-xs\">\r\n {isExpanded ? \"▼\" : \"▶\"}\r\n </span>\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {active && hasSubItems && (\r\n <div\r\n className={`grid transition-all duration-300 ease-in-out ${\r\n isExpanded ? \"grid-rows-[1fr]\" : \"grid-rows-[0fr]\"\r\n }`}\r\n >\r\n <div className=\"overflow-hidden\">\r\n <ul className=\"ml-4 mt-1 space-y-1 pl-2\">\r\n {item.subItems!.map((sub) => (\r\n <li key={sub.id}>\r\n <a\r\n href={sub.href}\r\n className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${\r\n isExactActive(sub.href, currentPath)\r\n ? \"bg-gray-200 text-black\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n >\r\n {sub.label}\r\n </a>\r\n </li>\r\n ))}\r\n </ul>\r\n </div>\r\n </div>\r\n )}\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n </nav>\r\n\r\n {footer && footer.length > 0 && (\r\n <div className=\"p-4 border-t border-gray-100 space-y-1\">\r\n {footer.map((item) => (\r\n <a\r\n key={item.label}\r\n href={item.href}\r\n className=\"flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-100 transition-colors\"\r\n >\r\n {typeof item.icon === \"string\" ? (\r\n <span className=\"text-lg\">{item.icon}</span>\r\n ) : isValidElement(item.icon) ? (\r\n item.icon\r\n ) : (\r\n createElement(item.icon as ComponentType<{ size?: number }>, {\r\n size: 20,\r\n })\r\n )}\r\n {item.label}\r\n </a>\r\n ))}\r\n </div>\r\n )}\r\n </aside>\r\n\r\n <div className=\"flex-1 ml-64\">\r\n {headerTitle && (\r\n <header className=\"h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6 fixed top-0 right-0 left-64 z-10\">\r\n <h1 className=\"text-base font-semibold text-gray-500\">\r\n {headerTitle}\r\n </h1>\r\n {brand?.tagline && (\r\n <span className=\"text-sm text-gray-500\">{brand.tagline}</span>\r\n )}\r\n </header>\r\n )}\r\n <main className={headerTitle ? \"p-6 pt-20\" : \"p-6\"}>{children}</main>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { SideNav, type SideNavStaticConfig } from \"../layouts/side-nav\";\n\nexport function createSideNav(config: SideNavStaticConfig) {\n return function ConfiguredSideNav({\n children,\n currentPath,\n }: {\n children: React.ReactNode;\n currentPath: string;\n }) {\n return (\n <SideNav {...config} currentPath={currentPath}>\n {children}\n </SideNav>\n );\n };\n}\n","export class ApiError extends Error {\r\n public status: number;\r\n public code?: string;\r\n public data?: unknown;\r\n\r\n constructor(params: {\r\n message: string;\r\n status: number;\r\n code?: string;\r\n data?: unknown;\r\n }) {\r\n super(params.message);\r\n this.status = params.status;\r\n this.code = params.code;\r\n this.data = params.data;\r\n }\r\n}\r\n\r\ntype BackendErrorShape = {\r\n code?: string;\r\n status?: number;\r\n message?: string;\r\n};\r\n\r\nexport type FetcherOptions = RequestInit & {\r\n skipJsonParsing?: boolean;\r\n};\r\n\r\nexport async function fetcher<T = unknown>(\r\n url: string,\r\n options: FetcherOptions = {},\r\n): Promise<T> {\r\n const { headers, skipJsonParsing = false, ...rest } = options;\r\n\r\n const response = await fetch(url, {\r\n credentials: \"include\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n ...rest,\r\n });\r\n\r\n let responseData: unknown = null;\r\n const contentType = response.headers.get(\"content-type\");\r\n\r\n if (!skipJsonParsing && contentType?.includes(\"application/json\")) {\r\n responseData = await response.json();\r\n }\r\n\r\n if (!response.ok) {\r\n const backendError = responseData as BackendErrorShape;\r\n\r\n throw new ApiError({\r\n message: backendError?.message || \"Une erreur est survenue\",\r\n status: backendError?.status || response.status,\r\n code: backendError?.code,\r\n data: responseData,\r\n });\r\n }\r\n\r\n return responseData as T;\r\n}\r\n"],"mappings":"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","names":["jsx"]}
|
|
1
|
+
{"version":3,"sources":["../packages/ui/src/layouts/side-nav.tsx","../packages/ui/src/config/create-side-nav.tsx","../packages/utils/src/fetcher.ts","../packages/lib/src/http-error.ts","../packages/lib/src/handle-server-error.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport {\r\n ReactNode,\r\n useState,\r\n createElement,\r\n isValidElement,\r\n type ComponentType,\r\n} from \"react\";\r\n\r\ntype IconType = ReactNode | ComponentType<{ size?: number }>;\r\n\r\nexport interface NavItem {\r\n id: string;\r\n label: string;\r\n title?: string;\r\n icon?: IconType;\r\n href: string;\r\n subItems?: NavItem[];\r\n}\r\n\r\nexport interface SideNavStaticConfig {\r\n brand?: {\r\n logo?: ReactNode;\r\n name?: string;\r\n tagline?: string;\r\n };\r\n mainItems: NavItem[];\r\n title?: string;\r\n footer?: { icon?: IconType; label: string; href: string }[];\r\n toggleIcon?: ReactNode;\r\n}\r\n\r\nexport interface SideNavProps extends SideNavStaticConfig {\r\n children: ReactNode;\r\n currentPath: string;\r\n}\r\n\r\nfunction isActive(href: string, currentPath: string) {\r\n return currentPath === href || currentPath.startsWith(href + \"/\");\r\n}\r\n\r\nfunction isExactActive(href: string, currentPath: string) {\r\n return currentPath === href;\r\n}\r\n\r\nexport function SideNav({\r\n children,\r\n title,\r\n mainItems,\r\n currentPath,\r\n brand,\r\n footer,\r\n toggleIcon,\r\n}: SideNavProps) {\r\n const activeMain = mainItems.find((item) => isActive(item.href, currentPath));\r\n const headerTitle = title ?? activeMain?.title ?? activeMain?.label;\r\n const [expandedSection, setExpandedSection] = useState<string | null>(\r\n activeMain?.id ?? null,\r\n );\r\n\r\n const toggleSection = (id: string) => {\r\n setExpandedSection((prev) => (prev === id ? null : id));\r\n };\r\n\r\n return (\r\n <div className=\"flex min-h-screen\">\r\n <aside className=\"w-64 bg-white border-r border-gray-200 flex flex-col fixed h-full\">\r\n {brand && (\r\n <div className=\"p-[6.5px] border-b border-gray-100\">\r\n <div className=\"flex flex-row gap-2 items-center\">\r\n {brand.logo &&\r\n (typeof brand.logo === \"string\" ? (\r\n <img\r\n src={brand.logo}\r\n alt={brand.name ?? \"\"}\r\n className=\"w-12.5 h-12.5\"\r\n />\r\n ) : (\r\n brand.logo\r\n ))}\r\n {brand.name && (\r\n <p className=\"text-gray-500 text-base font-semibold\">\r\n {brand.name}\r\n </p>\r\n )}\r\n </div>\r\n </div>\r\n )}\r\n\r\n <nav className=\"flex-1 p-4 overflow-y-auto\">\r\n <ul className=\"space-y-1\">\r\n {mainItems.map((item) => {\r\n const active = isActive(item.href, currentPath);\r\n const isExpanded = expandedSection === item.id;\r\n const hasSubItems = item.subItems && item.subItems.length > 0;\r\n\r\n return (\r\n <li key={item.id}>\r\n <div className=\"flex items-center gap-1\">\r\n <a\r\n href={item.href}\r\n className={`flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium transition-colors flex-1 ${\r\n active\r\n ? \"bg-gray-200 text-black\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n >\r\n {item.icon &&\r\n (typeof item.icon === \"string\" ? (\r\n <span className=\"text-lg\">{item.icon}</span>\r\n ) : isValidElement(item.icon) ? (\r\n item.icon\r\n ) : (\r\n createElement(\r\n item.icon as ComponentType<{ size?: number }>,\r\n { size: 20 },\r\n )\r\n ))}\r\n {item.label}\r\n </a>\r\n {active && hasSubItems && (\r\n <button\r\n onClick={() => toggleSection(item.id)}\r\n className={`p-1.5 rounded-lg transition-colors ${\r\n active\r\n ? \"text-black hover:bg-gray-100\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n title={isExpanded ? \"Réduire\" : \"Développer\"}\r\n >\r\n {toggleIcon ? (\r\n <span\r\n className={`inline-block transition-transform duration-200 ${\r\n isExpanded ? \"rotate-0\" : \"-rotate-90\"\r\n }`}\r\n >\r\n {toggleIcon}\r\n </span>\r\n ) : (\r\n <span className=\"text-xs\">\r\n {isExpanded ? \"▼\" : \"▶\"}\r\n </span>\r\n )}\r\n </button>\r\n )}\r\n </div>\r\n\r\n {active && hasSubItems && (\r\n <div\r\n className={`grid transition-all duration-300 ease-in-out ${\r\n isExpanded ? \"grid-rows-[1fr]\" : \"grid-rows-[0fr]\"\r\n }`}\r\n >\r\n <div className=\"overflow-hidden\">\r\n <ul className=\"ml-4 mt-1 space-y-1 pl-2\">\r\n {item.subItems!.map((sub) => (\r\n <li key={sub.id}>\r\n <a\r\n href={sub.href}\r\n className={`flex items-center gap-2 px-3 py-2 rounded-lg text-sm font-medium transition-colors ${\r\n isExactActive(sub.href, currentPath)\r\n ? \"bg-gray-200 text-black\"\r\n : \"text-gray-500 hover:bg-gray-100\"\r\n }`}\r\n >\r\n {sub.label}\r\n </a>\r\n </li>\r\n ))}\r\n </ul>\r\n </div>\r\n </div>\r\n )}\r\n </li>\r\n );\r\n })}\r\n </ul>\r\n </nav>\r\n\r\n {footer && footer.length > 0 && (\r\n <div className=\"p-4 border-t border-gray-100 space-y-1\">\r\n {footer.map((item) => (\r\n <a\r\n key={item.label}\r\n href={item.href}\r\n className=\"flex items-center gap-3 px-3 py-2.5 rounded-lg text-sm font-medium text-gray-700 hover:bg-gray-100 transition-colors\"\r\n >\r\n {typeof item.icon === \"string\" ? (\r\n <span className=\"text-lg\">{item.icon}</span>\r\n ) : isValidElement(item.icon) ? (\r\n item.icon\r\n ) : (\r\n createElement(item.icon as ComponentType<{ size?: number }>, {\r\n size: 20,\r\n })\r\n )}\r\n {item.label}\r\n </a>\r\n ))}\r\n </div>\r\n )}\r\n </aside>\r\n\r\n <div className=\"flex-1 ml-64\">\r\n {headerTitle && (\r\n <header className=\"h-16 bg-white border-b border-gray-200 flex items-center justify-between px-6 fixed top-0 right-0 left-64 z-10\">\r\n <h1 className=\"text-base font-semibold text-gray-500\">\r\n {headerTitle}\r\n </h1>\r\n {brand?.tagline && (\r\n <span className=\"text-sm text-gray-500\">{brand.tagline}</span>\r\n )}\r\n </header>\r\n )}\r\n <main className={headerTitle ? \"p-6 pt-20\" : \"p-6\"}>{children}</main>\r\n </div>\r\n </div>\r\n );\r\n}\r\n","import { SideNav, type SideNavStaticConfig } from \"../layouts/side-nav\";\n\nexport function createSideNav(config: SideNavStaticConfig) {\n return function ConfiguredSideNav({\n children,\n currentPath,\n }: {\n children: React.ReactNode;\n currentPath: string;\n }) {\n return (\n <SideNav {...config} currentPath={currentPath}>\n {children}\n </SideNav>\n );\n };\n}\n","export class ApiError extends Error {\r\n public status: number;\r\n public code?: string;\r\n public data?: unknown;\r\n\r\n constructor(params: {\r\n message: string;\r\n status: number;\r\n code?: string;\r\n data?: unknown;\r\n }) {\r\n super(params.message);\r\n this.status = params.status;\r\n this.code = params.code;\r\n this.data = params.data;\r\n }\r\n}\r\n\r\ntype BackendErrorShape = {\r\n code?: string;\r\n status?: number;\r\n message?: string;\r\n};\r\n\r\nexport type FetcherOptions = RequestInit & {\r\n skipJsonParsing?: boolean;\r\n};\r\n\r\nexport async function fetcher<T = unknown>(\r\n url: string,\r\n options: FetcherOptions = {},\r\n): Promise<T> {\r\n const { headers, skipJsonParsing = false, ...rest } = options;\r\n\r\n const response = await fetch(url, {\r\n credentials: \"include\",\r\n headers: {\r\n \"Content-Type\": \"application/json\",\r\n ...headers,\r\n },\r\n ...rest,\r\n });\r\n\r\n let responseData: unknown = null;\r\n const contentType = response.headers.get(\"content-type\");\r\n\r\n if (!skipJsonParsing && contentType?.includes(\"application/json\")) {\r\n responseData = await response.json();\r\n }\r\n\r\n if (!response.ok) {\r\n const backendError = responseData as BackendErrorShape;\r\n\r\n throw new ApiError({\r\n message: backendError?.message || \"Une erreur est survenue\",\r\n status: backendError?.status || response.status,\r\n code: backendError?.code,\r\n data: responseData,\r\n });\r\n }\r\n\r\n return responseData as T;\r\n}\r\n","export class HttpError extends Error {\r\n status: number;\r\n code?: string;\r\n\r\n constructor(message: string, status = 400, code?: string) {\r\n super(message);\r\n\r\n this.name = \"HttpError\";\r\n this.status = status;\r\n this.code = code;\r\n\r\n Object.setPrototypeOf(this, HttpError.prototype);\r\n }\r\n}\r\n","import { HttpError } from \"./http-error\";\r\n\r\nconst GENERIC_MESSAGE = \"Erreur serveur\";\r\n\r\nfunction shouldShowDetails(showDetails?: boolean): boolean {\r\n return showDetails ?? process.env.NODE_ENV !== \"production\";\r\n}\r\n\r\nfunction sanitizedResponse(\r\n message: string,\r\n code: string,\r\n status: number,\r\n showDetails?: boolean,\r\n) {\r\n return Response.json(\r\n {\r\n message: showDetails ? message : GENERIC_MESSAGE,\r\n code: showDetails ? code : \"INTERNAL_ERROR\",\r\n status,\r\n },\r\n { status },\r\n );\r\n}\r\n\r\n/**\r\n * Transforme n'importe quelle erreur en réponse JSON standardisée\r\n * @param error L'erreur levée\r\n * @param defaultStatus Statut HTTP par défaut si non défini\r\n * @param showDetails Force l'affichage des détails (true) ou le mode sécurisé (false). Par défaut : automatique selon NODE_ENV\r\n * @returns Response JSON\r\n */\r\nexport function handleServerError(\r\n error: unknown,\r\n defaultStatus = 500,\r\n showDetails?: boolean,\r\n) {\r\n const details = shouldShowDetails(showDetails);\r\n\r\n console.error(\"Erreur capturée :\", error);\r\n\r\n // Cas HttpError personnalisé — toujours visible (erreur intentionnelle)\r\n if (error instanceof HttpError) {\r\n const status = error.status ?? defaultStatus;\r\n return Response.json(\r\n {\r\n message: error.message,\r\n code: error.code ?? \"INTERNAL_ERROR\",\r\n status,\r\n },\r\n { status },\r\n );\r\n }\r\n\r\n // Cas classique : objet Error\r\n if (error instanceof Error) {\r\n return sanitizedResponse(\r\n error.message,\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n }\r\n\r\n // Cas objet brut ou autre type\r\n if (typeof error === \"object\" && error !== null) {\r\n return sanitizedResponse(\r\n JSON.stringify(error),\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n }\r\n\r\n // Cas fallback : string ou autre\r\n return sanitizedResponse(\r\n String(error),\r\n \"INTERNAL_ERROR\",\r\n defaultStatus,\r\n details,\r\n );\r\n}\r\n"],"mappings":"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","names":["jsx"]}
|