ptechcore_ui 1.0.25 → 1.0.29

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.cjs CHANGED
@@ -40,6 +40,7 @@ __export(index_exports, {
40
40
  CHOICES: () => Choices_default,
41
41
  CountrySelector: () => CountrySelector,
42
42
  DateInput: () => DateInput,
43
+ EntityFileManager: () => EntityFileManager,
43
44
  FDrawer: () => FDrawer,
44
45
  FetchApi: () => FetchApi,
45
46
  FileInput: () => FileInput,
@@ -59,6 +60,7 @@ __export(index_exports, {
59
60
  SelectCostCenter: () => SelectCostCenter,
60
61
  SelectDepartment: () => SelectDepartment,
61
62
  SelectInput: () => SelectInput,
63
+ SelectUnit: () => SelectUnit,
62
64
  SelectUser: () => SelectUser,
63
65
  SelectVendor: () => SelectVendor,
64
66
  SessionProvider: () => SessionProvider,
@@ -68,12 +70,15 @@ __export(index_exports, {
68
70
  ThemeProvider: () => ThemeContext_default,
69
71
  ToastContainer: () => Toast_default,
70
72
  ToastProvider: () => ToastProvider,
73
+ UnitServices: () => UnitServices,
71
74
  UserServices: () => UserServices,
75
+ fileManagerApi: () => fileManagerApi,
72
76
  formatDate: () => formatDate,
73
77
  formatFileSize: () => formatFileSize,
74
78
  getFileIcon: () => getFileIcon,
75
79
  useAlert: () => useAlert,
76
80
  useFileManager: () => useFileManager,
81
+ useFileManagerApi: () => useFileManagerApi,
77
82
  useSession: () => useSession,
78
83
  useToast: () => useToast
79
84
  });
@@ -92,9 +97,9 @@ var PrimaryButton = ({
92
97
  {
93
98
  type: "submit",
94
99
  disabled: loading || props.disabled,
95
- className: `px-4 py-2 text-sm rounded-lg hover:bg-opacity-80 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex justify-center items-center ${classname} ${variant === "full" ? "bg-[#6A8A82] text-white" : variant === "outline" ? "border border-[#6A8A82] text-[#6A8A82] bg-transparent" : "bg-transparent text-[#6A8A82]"}`,
100
+ className: `px-4 py-2 text-sm rounded-lg hover:opacity-80 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex justify-center items-center ${classname} ${variant === "full" ? "bg-[var(--color-primary)] text-[var(--color-text-inverse)]" : variant === "outline" ? "border border-[var(--color-primary)] text-[var(--color-primary)] bg-transparent" : "bg-transparent text-[var(--color-primary)]"}`,
96
101
  ...props,
97
- children: loading ? "Connexion en cours..." : children
102
+ children: loading ? "Chargement..." : children
98
103
  }
99
104
  );
100
105
  var SecondaryButton = ({
@@ -107,9 +112,9 @@ var SecondaryButton = ({
107
112
  {
108
113
  type: "button",
109
114
  disabled: loading || props.disabled,
110
- className: `px-4 py-2 rounded-lg hover:bg-opacity-80 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center ${variant === "full" ? "bg-[#B87333] text-white" : variant === "outline" ? "border border-[#B87333] text-[#B87333] bg-transparent" : "bg-transparent text-[#B87333]"}`,
115
+ className: `px-4 py-2 text-sm rounded-lg hover:opacity-80 transition-colors disabled:opacity-50 disabled:cursor-not-allowed flex items-center ${variant === "full" ? "bg-[var(--color-secondary)] text-[var(--color-text-inverse)]" : variant === "outline" ? "border border-[var(--color-secondary)] text-[var(--color-secondary)] bg-transparent" : "bg-transparent text-[var(--color-secondary)]"}`,
111
116
  ...props,
112
- children: loading ? "Connexion en cours..." : children
117
+ children: loading ? "Chargement..." : children
113
118
  }
114
119
  );
115
120
  var Buttons_default = PrimaryButton;
@@ -117,7 +122,7 @@ var Buttons_default = PrimaryButton;
117
122
  // src/components/common/Modals.tsx
118
123
  var import_react_dom = require("react-dom");
119
124
  var import_jsx_runtime2 = require("react/jsx-runtime");
120
- var Modal = ({ title, description, width = "max-w-md", open, onClose, children }) => {
125
+ var Modal = ({ title, description, width = "max-w-md", minContentHeight, open, onClose, children }) => {
121
126
  if (!open) return null;
122
127
  const modalContent = /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-[9999]", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `bg-[var(--color-surface)] rounded-lg p-6 mx-4 w-full ${width}`, children: [
123
128
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex justify-between items-start mb-6", children: [
@@ -135,7 +140,14 @@ var Modal = ({ title, description, width = "max-w-md", open, onClose, children }
135
140
  }
136
141
  )
137
142
  ] }),
138
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "w-full max-h-[80vh] overflow-y-auto", children })
143
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
144
+ "div",
145
+ {
146
+ className: "w-full max-h-[80vh] overflow-y-auto",
147
+ style: minContentHeight ? { minHeight: minContentHeight } : void 0,
148
+ children
149
+ }
150
+ )
139
151
  ] }) });
140
152
  return (0, import_react_dom.createPortal)(modalContent, document.body);
141
153
  };
@@ -157,10 +169,10 @@ var InputField = ({
157
169
  onBlur
158
170
  }) => {
159
171
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col gap-1 w-full", children: [
160
- label && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { htmlFor: name, className: "block text-gray-700 text-sm font-medium mb-2", children: [
172
+ label && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { htmlFor: name, className: "block text-[var(--color-text-secondary)] text-sm font-medium mb-2", children: [
161
173
  label,
162
174
  " ",
163
- required && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-red-500", children: "*" })
175
+ required && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[var(--color-error)]", children: "*" })
164
176
  ] }),
165
177
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
166
178
  "input",
@@ -174,13 +186,15 @@ var InputField = ({
174
186
  disabled,
175
187
  onChange,
176
188
  onBlur,
177
- className: `w-full px-3 py-2 border border-[#D9D9D9] focus:ring-2 focus:ring-[#6A8A82]/20
178
- ${error ? "border-red-500" : "border-gray-300"}
179
- ${disabled ? "bg-gray-100 cursor-not-allowed" : ""}
189
+ className: `w-full px-3 py-2 border rounded-lg text-sm
190
+ bg-[var(--color-surface)] text-[var(--color-text-primary)]
191
+ focus:ring-2 focus:ring-[var(--color-primary)]/20 focus:border-[var(--color-primary)] focus:outline-none
192
+ ${error ? "border-[var(--color-error)]" : "border-[var(--color-border)]"}
193
+ ${disabled ? "bg-[var(--color-background)] cursor-not-allowed opacity-60" : ""}
180
194
  `
181
195
  }
182
196
  ),
183
- error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-red-500", children: error })
197
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-[var(--color-error)]", children: error })
184
198
  ] });
185
199
  };
186
200
  var TextInput = (props) => {
@@ -210,11 +224,11 @@ var SelectInput = ({
210
224
  "label",
211
225
  {
212
226
  htmlFor: name,
213
- className: "block text-gray-700 text-sm font-medium mb-2",
227
+ className: "block text-[var(--color-text-secondary)] text-sm font-medium mb-2",
214
228
  children: [
215
229
  label,
216
230
  " ",
217
- required && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-red-500", children: "*" })
231
+ required && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "text-[var(--color-error)]", children: "*" })
218
232
  ]
219
233
  }
220
234
  ),
@@ -229,9 +243,10 @@ var SelectInput = ({
229
243
  onChange,
230
244
  onBlur,
231
245
  className: `w-full px-4 py-2 border rounded-lg text-sm
232
- focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
233
- ${error ? "border-red-500" : "border-gray-300"}
234
- ${disabled ? "bg-gray-100 cursor-not-allowed" : ""}
246
+ bg-[var(--color-surface)] text-[var(--color-text-primary)]
247
+ focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]/20 focus:border-[var(--color-primary)]
248
+ ${error ? "border-[var(--color-error)]" : "border-[var(--color-border)]"}
249
+ ${disabled ? "bg-[var(--color-background)] cursor-not-allowed opacity-60" : ""}
235
250
  `,
236
251
  children: [
237
252
  defaultValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: typeof defaultValue === "string" ? defaultValue : "S\xE9lectionnez une option" }),
@@ -239,7 +254,7 @@ var SelectInput = ({
239
254
  ]
240
255
  }
241
256
  ),
242
- error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-red-500", children: error })
257
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "text-xs text-[var(--color-error)]", children: error })
243
258
  ] });
244
259
  };
245
260
  var addressIpformMedia = "http://localhost:8000/media/";
@@ -765,7 +780,7 @@ var import_react2 = require("react");
765
780
 
766
781
  // src/services/api.ts
767
782
  var chooseEnv = localStorage.getItem("env") ?? "prod";
768
- var ADDRESS_IP = chooseEnv === "prod" ? "backend-core.rewise.praedium-tech.com" : "localhost:8000";
783
+ var ADDRESS_IP = chooseEnv === "prod" ? "core.backend-rewise.praedium-tech.com" : "localhost:8000";
769
784
  var ADDRESS_IP_URL = chooseEnv === "prod" ? `https://${ADDRESS_IP}/` : `http://${ADDRESS_IP}/`;
770
785
  var API_URL = `${ADDRESS_IP_URL}api`;
771
786
  var FetchApi = class {
@@ -968,6 +983,21 @@ var SessionProvider = ({ children }) => {
968
983
  localStorage.removeItem("token");
969
984
  setToken(null);
970
985
  };
986
+ const refreshSession = async () => {
987
+ if (!token) return;
988
+ try {
989
+ const res = await AuthServices.getUserInformations(token);
990
+ const result = res;
991
+ if (result.success === true) {
992
+ setLoggedUser(result.data.user);
993
+ setActiveBusinessEntity(
994
+ result.data.user.centers_access.find((item) => parseInt(String(item.id)) === parseInt(saved_center_id)) || result.data.user.centers_access[0] || null
995
+ );
996
+ }
997
+ } catch (error) {
998
+ console.error("Failed to refresh session:", error);
999
+ }
1000
+ };
971
1001
  (0, import_react2.useEffect)(() => {
972
1002
  if (token) {
973
1003
  AuthServices.getUserInformations(token).then((res) => {
@@ -995,10 +1025,12 @@ var SessionProvider = ({ children }) => {
995
1025
  activeBusinessEntity,
996
1026
  setActiveBusinessEntity,
997
1027
  token,
1028
+ setToken,
998
1029
  login,
999
1030
  logout,
1000
1031
  showAuthModal,
1001
1032
  setShowAuthModal,
1033
+ refreshSession,
1002
1034
  vendors,
1003
1035
  setVendors,
1004
1036
  loadingVendors,
@@ -1027,9 +1059,8 @@ var UserServices = {
1027
1059
  deleteUser: (id, token) => FetchApi.delete(`${USERS_API_URL}${id}/`, token),
1028
1060
  // Obtenir les utilisateurs d'une entité
1029
1061
  getEntityUsers: (entityId, token) => FetchApi.get(`${API_URL}/core/entities/${entityId}/users/`, token),
1030
- // Obtenir les utilisateurs d'une entité
1031
- getuserEntitiesAccess: (id, token) => FetchApi.get(`${API_URL}/core/entities/`, token),
1032
- // !!! ce n'est pas la bonne url
1062
+ // Obtenir les entités auxquelles un utilisateur a accès
1063
+ getuserEntitiesAccess: (id, token) => FetchApi.get(`${API_URL}/core/users/${id}/entities/`, token),
1033
1064
  // Ajouter un utilisateur à une entité
1034
1065
  addUserToEntity: (entityId, userId, token) => FetchApi.post(`${API_URL}/core/entities/${entityId}/users/`, { user_id: userId }, token),
1035
1066
  // === Nouvelles méthodes pour le profil utilisateur ===
@@ -1074,16 +1105,17 @@ var ToastProvider = ({ children }) => {
1074
1105
  const addToast = (0, import_react3.useCallback)((toast) => {
1075
1106
  const id = generateId();
1076
1107
  const defaultDuration = toast.type === "error" ? 7e3 : 3e3;
1108
+ const duration = toast.duration ?? defaultDuration;
1077
1109
  const newToast = {
1110
+ ...toast,
1078
1111
  id,
1079
- duration: toast.duration ?? defaultDuration,
1080
- ...toast
1112
+ duration
1081
1113
  };
1082
1114
  setToasts((prev) => [...prev, newToast]);
1083
- if (newToast.duration && newToast.duration > 0) {
1115
+ if (duration > 0) {
1084
1116
  setTimeout(() => {
1085
- removeToast(id);
1086
- }, newToast.duration);
1117
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1118
+ }, duration);
1087
1119
  }
1088
1120
  }, []);
1089
1121
  const removeToast = (0, import_react3.useCallback)((id) => {
@@ -1896,7 +1928,7 @@ var RewiseLayout = ({ children, module_name = "Rewise", module_description = "De
1896
1928
  "organizations": "organizations",
1897
1929
  "entities": "entities"
1898
1930
  };
1899
- setSelectedModule(routeMapping[moduleId] || "dashboard");
1931
+ setSelectedModule(routeMapping[moduleId] || moduleId);
1900
1932
  }
1901
1933
  }, [location]);
1902
1934
  const handleThemeChange = (type) => {
@@ -3470,6 +3502,16 @@ var Pages = ({
3470
3502
  };
3471
3503
  var Pages_default = Pages;
3472
3504
 
3505
+ // src/services/UnitServices.ts
3506
+ var URI = `${API_URL}/crm/units/`;
3507
+ var UnitServices = {
3508
+ create: (data) => FetchApi.post(`${URI}`, data),
3509
+ get: (id) => FetchApi.get(`${URI}${id}/`),
3510
+ list: (params) => FetchApi.get(`${URI}?${new URLSearchParams(params).toString()}`),
3511
+ update: (id, data) => FetchApi.put(`${URI}${id}/`, data),
3512
+ delete: (id) => FetchApi.delete(`${URI}${id}/`)
3513
+ };
3514
+
3473
3515
  // src/components/common/FDrawer.tsx
3474
3516
  var import_react8 = __toESM(require("react"), 1);
3475
3517
  var import_react_router_dom4 = require("react-router-dom");
@@ -5351,7 +5393,7 @@ var ApprovalWorkflow = ({
5351
5393
  if (CustomBtn) {
5352
5394
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
5353
5395
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CustomBtn, { onClick: open_modal }),
5354
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Modals_default, { open: isOpen, onClose: close_modal, title, children: formulaire() })
5396
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Modals_default, { open: isOpen, onClose: close_modal, title, width: "max-w-lg", children: formulaire() })
5355
5397
  ] });
5356
5398
  }
5357
5399
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
@@ -5549,7 +5591,7 @@ var AddStageButton = ({
5549
5591
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5550
5592
  Modals_default,
5551
5593
  {
5552
- width: "",
5594
+ width: "max-w-lg",
5553
5595
  title: "Ajouter une personne",
5554
5596
  description: "S\xE9lectionnez un utilisateur interne ou ajoutez un validateur externe",
5555
5597
  open: showModal,
@@ -5868,7 +5910,7 @@ var MinimalVendorForm = ({
5868
5910
  Modals_default,
5869
5911
  {
5870
5912
  title: "Ajouter un fournisseur",
5871
- width: "w-[100%]",
5913
+ width: "max-w-2xl",
5872
5914
  description: ``,
5873
5915
  open: isOpen,
5874
5916
  onClose,
@@ -5923,17 +5965,17 @@ var MinimalVendorForm = ({
5923
5965
  };
5924
5966
 
5925
5967
  // src/services/DepartmentServices.ts
5926
- var URI = `${API_URL}/core/departments/`;
5968
+ var URI2 = `${API_URL}/core/departments/`;
5927
5969
  var DepartmentServices = {
5928
- create: (data) => FetchApi.post(`${URI}`, data),
5929
- get: (id) => FetchApi.get(`${URI}${id}/`),
5930
- list: (params) => FetchApi.get(`${URI}?${new URLSearchParams(params).toString()}`),
5931
- update: (id, data) => FetchApi.put(`${URI}${id}/`, data),
5932
- delete: (id) => FetchApi.delete(`${URI}${id}/`)
5970
+ create: (data) => FetchApi.post(`${URI2}`, data),
5971
+ get: (id) => FetchApi.get(`${URI2}${id}/`),
5972
+ list: (params) => FetchApi.get(`${URI2}?${new URLSearchParams(params).toString()}`),
5973
+ update: (id, data) => FetchApi.put(`${URI2}${id}/`, data),
5974
+ delete: (id) => FetchApi.delete(`${URI2}${id}/`)
5933
5975
  };
5934
5976
 
5935
5977
  // src/services/ProfitCostsServices.ts
5936
- var URI2 = `${API_URL}/accounting/profit-or-cost-center/`;
5978
+ var URI3 = `${API_URL}/accounting/profit-or-cost-center/`;
5937
5979
  var COST_URI = `${API_URL}/accounting/cost-center/`;
5938
5980
  var CostServices = {
5939
5981
  create: (data) => FetchApi.post(`${COST_URI}`, data),
@@ -6240,6 +6282,80 @@ var SelectCostCenter = ({
6240
6282
  loading && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm text-gray-500 mt-2", children: "Chargement des centres de co\xFBt..." })
6241
6283
  ] });
6242
6284
  };
6285
+ var SelectUnit = ({
6286
+ value,
6287
+ onSelect
6288
+ }) => {
6289
+ const { token, activeBusinessEntity } = useSession();
6290
+ const [units, setUnits] = (0, import_react13.useState)(() => {
6291
+ const cacheKey = `units_cache_${activeBusinessEntity?.id || "default"}`;
6292
+ const cached = sessionStorage.getItem(cacheKey);
6293
+ return cached ? JSON.parse(cached) : [];
6294
+ });
6295
+ const [loading, setLoading] = (0, import_react13.useState)(false);
6296
+ (0, import_react13.useEffect)(() => {
6297
+ const cacheKey = `units_cache_${activeBusinessEntity?.id || "default"}`;
6298
+ const cached = sessionStorage.getItem(cacheKey);
6299
+ if (!cached) {
6300
+ loadUnits();
6301
+ } else {
6302
+ setUnits(JSON.parse(cached));
6303
+ }
6304
+ }, [activeBusinessEntity?.id]);
6305
+ const loadUnits = async () => {
6306
+ if (!token) return;
6307
+ try {
6308
+ setLoading(true);
6309
+ const result = await UnitServices.list({ business_entity_id: activeBusinessEntity?.id });
6310
+ if (result.success) {
6311
+ setUnits(result.data);
6312
+ const cacheKey = `units_cache_${activeBusinessEntity?.id || "default"}`;
6313
+ sessionStorage.setItem(cacheKey, JSON.stringify(result.data));
6314
+ }
6315
+ } catch (error) {
6316
+ console.error(error);
6317
+ } finally {
6318
+ setLoading(false);
6319
+ }
6320
+ };
6321
+ const handleRefresh = () => {
6322
+ const cacheKey = `units_cache_${activeBusinessEntity?.id || "default"}`;
6323
+ sessionStorage.removeItem(cacheKey);
6324
+ loadUnits();
6325
+ };
6326
+ const getUnitOptions = () => {
6327
+ return units.map((unit) => ({
6328
+ value: unit.id,
6329
+ label: `${unit.code ? `[${unit.code}] ` : ""}${unit.name || "Sans nom"}`,
6330
+ object: unit,
6331
+ content: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex items-center space-x-3", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex-1", children: [
6332
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "font-medium text-gray-900", children: unit.name || "Sans nom" }),
6333
+ unit.code && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "text-sm text-gray-500", children: [
6334
+ "Code: ",
6335
+ unit.code
6336
+ ] }),
6337
+ unit.location && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "text-xs text-gray-400", children: unit.location })
6338
+ ] }) })
6339
+ }));
6340
+ };
6341
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { children: [
6342
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "flex justify-between ", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "S\xE9lectionner une unit\xE9" }) }),
6343
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
6344
+ SearchableSelect,
6345
+ {
6346
+ value,
6347
+ options: getUnitOptions(),
6348
+ placeholder: "S\xE9lectionner une unit\xE9 ...",
6349
+ searchPlaceholder: "Rechercher...",
6350
+ onSelect,
6351
+ disabled: loading,
6352
+ refresh: handleRefresh
6353
+ },
6354
+ "unit" + value
6355
+ ),
6356
+ loading && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm text-gray-500 mt-2", children: "Chargement des unit\xE9s..." })
6357
+ ] });
6358
+ };
6243
6359
 
6244
6360
  // src/components/common/Choices.tsx
6245
6361
  var import_jsx_runtime19 = require("react/jsx-runtime");
@@ -7762,6 +7878,495 @@ var FileManagerContent = ({ className }) => {
7762
7878
  var FileManager = (props) => {
7763
7879
  return /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FileManagerProvider, { ...props, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(FileManagerContent, { className: props.className }) });
7764
7880
  };
7881
+
7882
+ // src/components/common/FileManager/components/EntityFileManager.tsx
7883
+ var import_react22 = __toESM(require("react"), 1);
7884
+ var import_lucide_react17 = require("lucide-react");
7885
+
7886
+ // src/components/common/FileManager/hooks/useFileManagerApi.ts
7887
+ var import_react21 = require("react");
7888
+
7889
+ // src/components/common/FileManager/services/fileManagerApi.ts
7890
+ var API_BASE = "/api/files_manager";
7891
+ var ENTITY_MODEL_MAP = {
7892
+ CLIENT: "accounting.Client",
7893
+ VENDOR: "accounting.Vendor",
7894
+ RFQ: "procurement.RFQ",
7895
+ DEPT: "core.Departments",
7896
+ PROJECT: "core.Project"
7897
+ };
7898
+ async function apiRequest(endpoint, options = {}) {
7899
+ const url = `${API_BASE}${endpoint}`;
7900
+ const headers = {
7901
+ ...options.headers
7902
+ };
7903
+ if (!(options.body instanceof FormData)) {
7904
+ headers["Content-Type"] = "application/json";
7905
+ }
7906
+ const csrfToken = getCsrfToken();
7907
+ if (csrfToken) {
7908
+ headers["X-CSRFToken"] = csrfToken;
7909
+ }
7910
+ const response = await fetch(url, {
7911
+ ...options,
7912
+ headers,
7913
+ credentials: "include"
7914
+ // Inclure les cookies pour l'auth
7915
+ });
7916
+ if (!response.ok) {
7917
+ let errorMessage = `Erreur HTTP ${response.status}`;
7918
+ try {
7919
+ const errorData = await response.json();
7920
+ errorMessage = errorData.detail || errorData.message || errorMessage;
7921
+ } catch {
7922
+ }
7923
+ throw new Error(errorMessage);
7924
+ }
7925
+ if (response.status === 204) {
7926
+ return {};
7927
+ }
7928
+ return response.json();
7929
+ }
7930
+ function getCsrfToken() {
7931
+ const name = "csrftoken";
7932
+ const cookies = document.cookie.split(";");
7933
+ for (const cookie of cookies) {
7934
+ const trimmed = cookie.trim();
7935
+ if (trimmed.startsWith(`${name}=`)) {
7936
+ return trimmed.substring(name.length + 1);
7937
+ }
7938
+ }
7939
+ return null;
7940
+ }
7941
+ function buildQueryString(params) {
7942
+ const searchParams = new URLSearchParams();
7943
+ for (const [key, value] of Object.entries(params)) {
7944
+ if (value !== void 0 && value !== null) {
7945
+ searchParams.append(key, String(value));
7946
+ }
7947
+ }
7948
+ const queryString = searchParams.toString();
7949
+ return queryString ? `?${queryString}` : "";
7950
+ }
7951
+ async function getEntityFolders(entityType, entityId, folderType) {
7952
+ const model = ENTITY_MODEL_MAP[entityType];
7953
+ if (!model) {
7954
+ throw new Error(`Type d'entit\xE9 non support\xE9: ${entityType}`);
7955
+ }
7956
+ const params = buildQueryString({
7957
+ model,
7958
+ id: entityId,
7959
+ type: folderType
7960
+ });
7961
+ return apiRequest(`/folders/for_entity/${params}`);
7962
+ }
7963
+ async function getFolderTree(folderCode) {
7964
+ return apiRequest(`/folders/${folderCode}/tree/`);
7965
+ }
7966
+ async function getFolder(folderCode) {
7967
+ return apiRequest(`/folders/${folderCode}/`);
7968
+ }
7969
+ async function createFolder(name, parentCode, businessEntityId) {
7970
+ return apiRequest("/folders/", {
7971
+ method: "POST",
7972
+ body: JSON.stringify({
7973
+ name,
7974
+ parent: parentCode,
7975
+ business_entity: businessEntityId,
7976
+ folder_type: "MISC",
7977
+ // Type par défaut pour les dossiers créés manuellement
7978
+ is_system_folder: false
7979
+ })
7980
+ });
7981
+ }
7982
+ async function renameFolder(folderCode, newName) {
7983
+ return apiRequest(`/folders/${folderCode}/`, {
7984
+ method: "PATCH",
7985
+ body: JSON.stringify({ name: newName })
7986
+ });
7987
+ }
7988
+ async function deleteFolder(folderCode) {
7989
+ await apiRequest(`/folders/${folderCode}/`, {
7990
+ method: "DELETE"
7991
+ });
7992
+ }
7993
+ async function getFolderFiles(folderId) {
7994
+ const params = buildQueryString({ folder: folderId });
7995
+ return apiRequest(`/files/${params}`);
7996
+ }
7997
+ async function uploadFile(file, folderCode, options = {}) {
7998
+ const formData = new FormData();
7999
+ formData.append("file", file);
8000
+ formData.append("folder_id", folderCode);
8001
+ if (options.name) {
8002
+ formData.append("name", options.name);
8003
+ }
8004
+ if (options.description) {
8005
+ formData.append("description", options.description);
8006
+ }
8007
+ if (options.tags && options.tags.length > 0) {
8008
+ formData.append("tags", JSON.stringify(options.tags));
8009
+ }
8010
+ return apiRequest("/files/", {
8011
+ method: "POST",
8012
+ body: formData
8013
+ });
8014
+ }
8015
+ async function uploadFiles(files, folderCode) {
8016
+ const results = [];
8017
+ for (const file of files) {
8018
+ const uploaded = await uploadFile(file, folderCode);
8019
+ results.push(uploaded);
8020
+ }
8021
+ return results;
8022
+ }
8023
+ async function renameFile(fileCode, newName) {
8024
+ return apiRequest(`/files/${fileCode}/`, {
8025
+ method: "PATCH",
8026
+ body: JSON.stringify({ name: newName })
8027
+ });
8028
+ }
8029
+ async function deleteFile(fileCode) {
8030
+ await apiRequest(`/files/${fileCode}/`, {
8031
+ method: "DELETE"
8032
+ });
8033
+ }
8034
+ function getDownloadUrl(fileCode) {
8035
+ return `${API_BASE}/files/${fileCode}/download/`;
8036
+ }
8037
+ function getFileUrl(fileUrl) {
8038
+ if (fileUrl.startsWith("http://") || fileUrl.startsWith("https://")) {
8039
+ return fileUrl;
8040
+ }
8041
+ return fileUrl.startsWith("/") ? fileUrl : `/${fileUrl}`;
8042
+ }
8043
+ var fileManagerApi = {
8044
+ // Dossiers
8045
+ getEntityFolders,
8046
+ getFolderTree,
8047
+ getFolder,
8048
+ createFolder,
8049
+ renameFolder,
8050
+ deleteFolder,
8051
+ // Fichiers
8052
+ getFolderFiles,
8053
+ uploadFile,
8054
+ uploadFiles,
8055
+ renameFile,
8056
+ deleteFile,
8057
+ // URLs
8058
+ getDownloadUrl,
8059
+ getFileUrl,
8060
+ // Helpers exposés
8061
+ ENTITY_MODEL_MAP
8062
+ };
8063
+
8064
+ // src/components/common/FileManager/hooks/useFileManagerApi.ts
8065
+ function transformFile(backendFile, parentPath, parentId) {
8066
+ return {
8067
+ id: backendFile.code,
8068
+ name: backendFile.name,
8069
+ type: "file",
8070
+ mimeType: backendFile.mime_type,
8071
+ size: backendFile.size,
8072
+ path: `${parentPath}/${backendFile.name}`,
8073
+ parentId,
8074
+ url: fileManagerApi.getFileUrl(backendFile.file_url),
8075
+ createdAt: backendFile.created_at,
8076
+ updatedAt: backendFile.updated_at,
8077
+ metadata: {
8078
+ extension: backendFile.extension,
8079
+ folderId: backendFile.folder
8080
+ }
8081
+ };
8082
+ }
8083
+ function transformFolder(backendFolder, parentPath = "", parentId = null) {
8084
+ const currentPath = parentPath ? `${parentPath}/${backendFolder.name}` : `/${backendFolder.name}`;
8085
+ const childFolders = (backendFolder.children || []).map(
8086
+ (child) => transformFolder(child, currentPath, backendFolder.code)
8087
+ );
8088
+ const childFiles = (backendFolder.files || []).map(
8089
+ (file) => transformFile(file, currentPath, backendFolder.code)
8090
+ );
8091
+ return {
8092
+ id: backendFolder.code,
8093
+ name: backendFolder.name,
8094
+ type: "folder",
8095
+ path: currentPath,
8096
+ parentId,
8097
+ children: [...childFolders, ...childFiles],
8098
+ metadata: {
8099
+ folderType: backendFolder.folder_type,
8100
+ folderTypeDisplay: backendFolder.folder_type_display,
8101
+ categoryType: backendFolder.category_type,
8102
+ isSystemFolder: backendFolder.is_system_folder,
8103
+ fileCount: backendFolder.file_count,
8104
+ totalSize: backendFolder.total_size
8105
+ }
8106
+ };
8107
+ }
8108
+ function extractRootChildren(entityFolder) {
8109
+ return entityFolder.children || [];
8110
+ }
8111
+ function useFileManagerApi(entityType, entityId, businessEntityId) {
8112
+ const [data, setData] = (0, import_react21.useState)([]);
8113
+ const [loading, setLoading] = (0, import_react21.useState)(true);
8114
+ const [error, setError] = (0, import_react21.useState)(null);
8115
+ const [rootFolderCode, setRootFolderCode] = (0, import_react21.useState)(null);
8116
+ const loadEntityFolders = (0, import_react21.useCallback)(async () => {
8117
+ setLoading(true);
8118
+ setError(null);
8119
+ try {
8120
+ const folders = await fileManagerApi.getEntityFolders(entityType, entityId);
8121
+ if (!folders || folders.length === 0) {
8122
+ setData([]);
8123
+ setRootFolderCode(null);
8124
+ setLoading(false);
8125
+ return;
8126
+ }
8127
+ const entityFolder = folders.find((f) => f.folder_type === "ENTITY");
8128
+ if (!entityFolder) {
8129
+ console.warn("Dossier ENTITY non trouv\xE9, utilisation du premier dossier");
8130
+ const firstFolder = folders[0];
8131
+ setRootFolderCode(firstFolder.code);
8132
+ const tree = await fileManagerApi.getFolderTree(firstFolder.code);
8133
+ const transformed = transformFolder(tree);
8134
+ setData(extractRootChildren(transformed));
8135
+ } else {
8136
+ setRootFolderCode(entityFolder.code);
8137
+ const tree = await fileManagerApi.getFolderTree(entityFolder.code);
8138
+ const transformed = transformFolder(tree);
8139
+ setData(extractRootChildren(transformed));
8140
+ }
8141
+ } catch (err) {
8142
+ console.error("Erreur lors du chargement des dossiers:", err);
8143
+ setError(err instanceof Error ? err : new Error(String(err)));
8144
+ setData([]);
8145
+ } finally {
8146
+ setLoading(false);
8147
+ }
8148
+ }, [entityType, entityId]);
8149
+ const refresh = (0, import_react21.useCallback)(async () => {
8150
+ await loadEntityFolders();
8151
+ }, [loadEntityFolders]);
8152
+ (0, import_react21.useEffect)(() => {
8153
+ loadEntityFolders();
8154
+ }, [loadEntityFolders]);
8155
+ const handleCreateFolder = (0, import_react21.useCallback)(
8156
+ async (name, parentId) => {
8157
+ try {
8158
+ const created = await fileManagerApi.createFolder(
8159
+ name,
8160
+ parentId,
8161
+ businessEntityId
8162
+ );
8163
+ await refresh();
8164
+ return transformFolder(created, "", parentId);
8165
+ } catch (err) {
8166
+ console.error("Erreur lors de la cr\xE9ation du dossier:", err);
8167
+ setError(err instanceof Error ? err : new Error(String(err)));
8168
+ throw err;
8169
+ }
8170
+ },
8171
+ [businessEntityId, refresh]
8172
+ );
8173
+ const handleUploadFiles = (0, import_react21.useCallback)(
8174
+ async (files, parentId) => {
8175
+ try {
8176
+ const uploaded = await fileManagerApi.uploadFiles(files, parentId);
8177
+ await refresh();
8178
+ return uploaded.map((file) => transformFile(file, "", parentId));
8179
+ } catch (err) {
8180
+ console.error("Erreur lors de l'upload:", err);
8181
+ setError(err instanceof Error ? err : new Error(String(err)));
8182
+ throw err;
8183
+ }
8184
+ },
8185
+ [refresh]
8186
+ );
8187
+ const handleRename = (0, import_react21.useCallback)(
8188
+ async (item, newName) => {
8189
+ try {
8190
+ if (item.type === "folder") {
8191
+ await fileManagerApi.renameFolder(item.id, newName);
8192
+ } else {
8193
+ await fileManagerApi.renameFile(item.id, newName);
8194
+ }
8195
+ await refresh();
8196
+ } catch (err) {
8197
+ console.error("Erreur lors du renommage:", err);
8198
+ setError(err instanceof Error ? err : new Error(String(err)));
8199
+ throw err;
8200
+ }
8201
+ },
8202
+ [refresh]
8203
+ );
8204
+ const handleDelete = (0, import_react21.useCallback)(
8205
+ async (item) => {
8206
+ try {
8207
+ if (item.metadata?.isSystemFolder) {
8208
+ throw new Error("Les dossiers syst\xE8me ne peuvent pas \xEAtre supprim\xE9s");
8209
+ }
8210
+ if (item.type === "folder") {
8211
+ await fileManagerApi.deleteFolder(item.id);
8212
+ } else {
8213
+ await fileManagerApi.deleteFile(item.id);
8214
+ }
8215
+ await refresh();
8216
+ } catch (err) {
8217
+ console.error("Erreur lors de la suppression:", err);
8218
+ setError(err instanceof Error ? err : new Error(String(err)));
8219
+ throw err;
8220
+ }
8221
+ },
8222
+ [refresh]
8223
+ );
8224
+ const handleDownload = (0, import_react21.useCallback)((item) => {
8225
+ if (item.type === "file") {
8226
+ const url = item.url || fileManagerApi.getDownloadUrl(item.id);
8227
+ window.open(url, "_blank");
8228
+ }
8229
+ }, []);
8230
+ return {
8231
+ data,
8232
+ loading,
8233
+ error,
8234
+ rootFolderCode,
8235
+ refresh,
8236
+ handlers: {
8237
+ onCreateFolder: handleCreateFolder,
8238
+ onUploadFiles: handleUploadFiles,
8239
+ onRename: handleRename,
8240
+ onDelete: handleDelete,
8241
+ onDownload: handleDownload
8242
+ }
8243
+ };
8244
+ }
8245
+
8246
+ // src/components/common/FileManager/components/EntityFileManager.tsx
8247
+ var import_jsx_runtime29 = require("react/jsx-runtime");
8248
+ function getRootName(entityType) {
8249
+ const names = {
8250
+ CLIENT: "Documents Client",
8251
+ VENDOR: "Documents Fournisseur",
8252
+ RFQ: "Documents RFQ",
8253
+ DEPT: "Documents D\xE9partement",
8254
+ PROJECT: "Documents Projet"
8255
+ };
8256
+ return names[entityType] || "Documents";
8257
+ }
8258
+ var LoadingState = ({ height = "400px" }) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
8259
+ "div",
8260
+ {
8261
+ className: "flex flex-col items-center justify-center bg-gray-50 dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800",
8262
+ style: { height },
8263
+ children: [
8264
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react17.Loader2, { className: "w-10 h-10 text-blue-500 animate-spin mb-4" }),
8265
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-gray-600 dark:text-gray-400 text-sm", children: "Chargement des documents..." })
8266
+ ]
8267
+ }
8268
+ );
8269
+ var ErrorState = ({ error, onRetry, height = "400px" }) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
8270
+ "div",
8271
+ {
8272
+ className: "flex flex-col items-center justify-center bg-red-50 dark:bg-red-900/20 rounded-xl border border-red-200 dark:border-red-800",
8273
+ style: { height },
8274
+ children: [
8275
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react17.AlertCircle, { className: "w-10 h-10 text-red-500 mb-4" }),
8276
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-red-600 dark:text-red-400 text-sm font-medium mb-2", children: "Erreur lors du chargement" }),
8277
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-red-500 dark:text-red-400 text-xs mb-4 max-w-md text-center px-4", children: error.message }),
8278
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
8279
+ "button",
8280
+ {
8281
+ onClick: onRetry,
8282
+ className: "flex items-center gap-2 px-4 py-2 bg-red-100 dark:bg-red-900/40 text-red-700 dark:text-red-300 rounded-lg hover:bg-red-200 dark:hover:bg-red-900/60 transition-colors text-sm",
8283
+ children: [
8284
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react17.RefreshCw, { className: "w-4 h-4" }),
8285
+ "R\xE9essayer"
8286
+ ]
8287
+ }
8288
+ )
8289
+ ]
8290
+ }
8291
+ );
8292
+ var EmptyState = ({ height = "400px" }) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
8293
+ "div",
8294
+ {
8295
+ className: "flex flex-col items-center justify-center bg-gray-50 dark:bg-gray-900 rounded-xl border border-gray-200 dark:border-gray-800",
8296
+ style: { height },
8297
+ children: [
8298
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_lucide_react17.FolderX, { className: "w-10 h-10 text-gray-400 mb-4" }),
8299
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-gray-600 dark:text-gray-400 text-sm font-medium mb-1", children: "Aucun document trouv\xE9" }),
8300
+ /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("p", { className: "text-gray-500 dark:text-gray-500 text-xs", children: "La structure de dossiers n'a pas encore \xE9t\xE9 cr\xE9\xE9e pour cette entit\xE9." })
8301
+ ]
8302
+ }
8303
+ );
8304
+ var EntityFileManager = ({
8305
+ entityType,
8306
+ entityId,
8307
+ businessEntityId,
8308
+ className,
8309
+ height = "600px",
8310
+ // Permissions (défaut: tout autorisé)
8311
+ allowUpload = true,
8312
+ allowCreateFolder = true,
8313
+ allowRename = true,
8314
+ allowDelete = true,
8315
+ allowDownload = true,
8316
+ // Callbacks
8317
+ onFileSelect,
8318
+ onFileOpen,
8319
+ onUploadSuccess,
8320
+ onError
8321
+ }) => {
8322
+ const { data, loading, error, refresh, handlers } = useFileManagerApi(
8323
+ entityType,
8324
+ entityId,
8325
+ businessEntityId
8326
+ );
8327
+ import_react22.default.useEffect(() => {
8328
+ if (error && onError) {
8329
+ onError(error);
8330
+ }
8331
+ }, [error, onError]);
8332
+ if (loading) {
8333
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(LoadingState, { height });
8334
+ }
8335
+ if (error) {
8336
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(ErrorState, { error, onRetry: refresh, height });
8337
+ }
8338
+ if (!data || data.length === 0) {
8339
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(EmptyState, { height });
8340
+ }
8341
+ const handleUploadFiles = async (files, parentId) => {
8342
+ const result = await handlers.onUploadFiles(files, parentId);
8343
+ if (result && onUploadSuccess) {
8344
+ onUploadSuccess(result);
8345
+ }
8346
+ return result;
8347
+ };
8348
+ return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("div", { className: cn("relative", className), style: { height }, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
8349
+ FileManager,
8350
+ {
8351
+ data,
8352
+ rootName: getRootName(entityType),
8353
+ onCreateFolder: handlers.onCreateFolder,
8354
+ onUploadFiles: handleUploadFiles,
8355
+ onRename: handlers.onRename,
8356
+ onDelete: handlers.onDelete,
8357
+ onDownload: handlers.onDownload,
8358
+ onSelect: onFileSelect,
8359
+ onOpen: onFileOpen,
8360
+ allowUpload,
8361
+ allowCreateFolder,
8362
+ allowRename,
8363
+ allowDelete,
8364
+ allowDownload,
8365
+ allowMultiSelect: true,
8366
+ className: "h-full"
8367
+ }
8368
+ ) });
8369
+ };
7765
8370
  // Annotate the CommonJS export names for ESM import in node:
7766
8371
  0 && (module.exports = {
7767
8372
  Alert,
@@ -7775,6 +8380,7 @@ var FileManager = (props) => {
7775
8380
  CHOICES,
7776
8381
  CountrySelector,
7777
8382
  DateInput,
8383
+ EntityFileManager,
7778
8384
  FDrawer,
7779
8385
  FetchApi,
7780
8386
  FileInput,
@@ -7794,6 +8400,7 @@ var FileManager = (props) => {
7794
8400
  SelectCostCenter,
7795
8401
  SelectDepartment,
7796
8402
  SelectInput,
8403
+ SelectUnit,
7797
8404
  SelectUser,
7798
8405
  SelectVendor,
7799
8406
  SessionProvider,
@@ -7803,12 +8410,15 @@ var FileManager = (props) => {
7803
8410
  ThemeProvider,
7804
8411
  ToastContainer,
7805
8412
  ToastProvider,
8413
+ UnitServices,
7806
8414
  UserServices,
8415
+ fileManagerApi,
7807
8416
  formatDate,
7808
8417
  formatFileSize,
7809
8418
  getFileIcon,
7810
8419
  useAlert,
7811
8420
  useFileManager,
8421
+ useFileManagerApi,
7812
8422
  useSession,
7813
8423
  useToast
7814
8424
  });