ptechcore_ui 1.0.27 → 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
@@ -60,6 +60,7 @@ __export(index_exports, {
60
60
  SelectCostCenter: () => SelectCostCenter,
61
61
  SelectDepartment: () => SelectDepartment,
62
62
  SelectInput: () => SelectInput,
63
+ SelectUnit: () => SelectUnit,
63
64
  SelectUser: () => SelectUser,
64
65
  SelectVendor: () => SelectVendor,
65
66
  SessionProvider: () => SessionProvider,
@@ -69,6 +70,7 @@ __export(index_exports, {
69
70
  ThemeProvider: () => ThemeContext_default,
70
71
  ToastContainer: () => Toast_default,
71
72
  ToastProvider: () => ToastProvider,
73
+ UnitServices: () => UnitServices,
72
74
  UserServices: () => UserServices,
73
75
  fileManagerApi: () => fileManagerApi,
74
76
  formatDate: () => formatDate,
@@ -95,9 +97,9 @@ var PrimaryButton = ({
95
97
  {
96
98
  type: "submit",
97
99
  disabled: loading || props.disabled,
98
- 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)]"}`,
99
101
  ...props,
100
- children: loading ? "Connexion en cours..." : children
102
+ children: loading ? "Chargement..." : children
101
103
  }
102
104
  );
103
105
  var SecondaryButton = ({
@@ -110,9 +112,9 @@ var SecondaryButton = ({
110
112
  {
111
113
  type: "button",
112
114
  disabled: loading || props.disabled,
113
- 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)]"}`,
114
116
  ...props,
115
- children: loading ? "Connexion en cours..." : children
117
+ children: loading ? "Chargement..." : children
116
118
  }
117
119
  );
118
120
  var Buttons_default = PrimaryButton;
@@ -120,7 +122,7 @@ var Buttons_default = PrimaryButton;
120
122
  // src/components/common/Modals.tsx
121
123
  var import_react_dom = require("react-dom");
122
124
  var import_jsx_runtime2 = require("react/jsx-runtime");
123
- var Modal = ({ title, description, width = "max-w-md", open, onClose, children }) => {
125
+ var Modal = ({ title, description, width = "max-w-md", minContentHeight, open, onClose, children }) => {
124
126
  if (!open) return null;
125
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: [
126
128
  /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "flex justify-between items-start mb-6", children: [
@@ -138,7 +140,14 @@ var Modal = ({ title, description, width = "max-w-md", open, onClose, children }
138
140
  }
139
141
  )
140
142
  ] }),
141
- /* @__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
+ )
142
151
  ] }) });
143
152
  return (0, import_react_dom.createPortal)(modalContent, document.body);
144
153
  };
@@ -160,10 +169,10 @@ var InputField = ({
160
169
  onBlur
161
170
  }) => {
162
171
  return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex flex-col gap-1 w-full", children: [
163
- 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: [
164
173
  label,
165
174
  " ",
166
- 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: "*" })
167
176
  ] }),
168
177
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
169
178
  "input",
@@ -177,13 +186,15 @@ var InputField = ({
177
186
  disabled,
178
187
  onChange,
179
188
  onBlur,
180
- className: `w-full px-3 py-2 border border-[#D9D9D9] focus:ring-2 focus:ring-[#6A8A82]/20
181
- ${error ? "border-red-500" : "border-gray-300"}
182
- ${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" : ""}
183
194
  `
184
195
  }
185
196
  ),
186
- 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 })
187
198
  ] });
188
199
  };
189
200
  var TextInput = (props) => {
@@ -213,11 +224,11 @@ var SelectInput = ({
213
224
  "label",
214
225
  {
215
226
  htmlFor: name,
216
- 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",
217
228
  children: [
218
229
  label,
219
230
  " ",
220
- 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: "*" })
221
232
  ]
222
233
  }
223
234
  ),
@@ -232,9 +243,10 @@ var SelectInput = ({
232
243
  onChange,
233
244
  onBlur,
234
245
  className: `w-full px-4 py-2 border rounded-lg text-sm
235
- focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
236
- ${error ? "border-red-500" : "border-gray-300"}
237
- ${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" : ""}
238
250
  `,
239
251
  children: [
240
252
  defaultValue !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "", children: typeof defaultValue === "string" ? defaultValue : "S\xE9lectionnez une option" }),
@@ -242,7 +254,7 @@ var SelectInput = ({
242
254
  ]
243
255
  }
244
256
  ),
245
- 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 })
246
258
  ] });
247
259
  };
248
260
  var addressIpformMedia = "http://localhost:8000/media/";
@@ -971,6 +983,21 @@ var SessionProvider = ({ children }) => {
971
983
  localStorage.removeItem("token");
972
984
  setToken(null);
973
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
+ };
974
1001
  (0, import_react2.useEffect)(() => {
975
1002
  if (token) {
976
1003
  AuthServices.getUserInformations(token).then((res) => {
@@ -1003,6 +1030,7 @@ var SessionProvider = ({ children }) => {
1003
1030
  logout,
1004
1031
  showAuthModal,
1005
1032
  setShowAuthModal,
1033
+ refreshSession,
1006
1034
  vendors,
1007
1035
  setVendors,
1008
1036
  loadingVendors,
@@ -1077,16 +1105,17 @@ var ToastProvider = ({ children }) => {
1077
1105
  const addToast = (0, import_react3.useCallback)((toast) => {
1078
1106
  const id = generateId();
1079
1107
  const defaultDuration = toast.type === "error" ? 7e3 : 3e3;
1108
+ const duration = toast.duration ?? defaultDuration;
1080
1109
  const newToast = {
1110
+ ...toast,
1081
1111
  id,
1082
- duration: toast.duration ?? defaultDuration,
1083
- ...toast
1112
+ duration
1084
1113
  };
1085
1114
  setToasts((prev) => [...prev, newToast]);
1086
- if (newToast.duration && newToast.duration > 0) {
1115
+ if (duration > 0) {
1087
1116
  setTimeout(() => {
1088
- removeToast(id);
1089
- }, newToast.duration);
1117
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1118
+ }, duration);
1090
1119
  }
1091
1120
  }, []);
1092
1121
  const removeToast = (0, import_react3.useCallback)((id) => {
@@ -3473,6 +3502,16 @@ var Pages = ({
3473
3502
  };
3474
3503
  var Pages_default = Pages;
3475
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
+
3476
3515
  // src/components/common/FDrawer.tsx
3477
3516
  var import_react8 = __toESM(require("react"), 1);
3478
3517
  var import_react_router_dom4 = require("react-router-dom");
@@ -5354,7 +5393,7 @@ var ApprovalWorkflow = ({
5354
5393
  if (CustomBtn) {
5355
5394
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
5356
5395
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(CustomBtn, { onClick: open_modal }),
5357
- /* @__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() })
5358
5397
  ] });
5359
5398
  }
5360
5399
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_jsx_runtime14.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
@@ -5552,7 +5591,7 @@ var AddStageButton = ({
5552
5591
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
5553
5592
  Modals_default,
5554
5593
  {
5555
- width: "",
5594
+ width: "max-w-lg",
5556
5595
  title: "Ajouter une personne",
5557
5596
  description: "S\xE9lectionnez un utilisateur interne ou ajoutez un validateur externe",
5558
5597
  open: showModal,
@@ -5871,7 +5910,7 @@ var MinimalVendorForm = ({
5871
5910
  Modals_default,
5872
5911
  {
5873
5912
  title: "Ajouter un fournisseur",
5874
- width: "w-[100%]",
5913
+ width: "max-w-2xl",
5875
5914
  description: ``,
5876
5915
  open: isOpen,
5877
5916
  onClose,
@@ -5926,17 +5965,17 @@ var MinimalVendorForm = ({
5926
5965
  };
5927
5966
 
5928
5967
  // src/services/DepartmentServices.ts
5929
- var URI = `${API_URL}/core/departments/`;
5968
+ var URI2 = `${API_URL}/core/departments/`;
5930
5969
  var DepartmentServices = {
5931
- create: (data) => FetchApi.post(`${URI}`, data),
5932
- get: (id) => FetchApi.get(`${URI}${id}/`),
5933
- list: (params) => FetchApi.get(`${URI}?${new URLSearchParams(params).toString()}`),
5934
- update: (id, data) => FetchApi.put(`${URI}${id}/`, data),
5935
- 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}/`)
5936
5975
  };
5937
5976
 
5938
5977
  // src/services/ProfitCostsServices.ts
5939
- var URI2 = `${API_URL}/accounting/profit-or-cost-center/`;
5978
+ var URI3 = `${API_URL}/accounting/profit-or-cost-center/`;
5940
5979
  var COST_URI = `${API_URL}/accounting/cost-center/`;
5941
5980
  var CostServices = {
5942
5981
  create: (data) => FetchApi.post(`${COST_URI}`, data),
@@ -6243,6 +6282,80 @@ var SelectCostCenter = ({
6243
6282
  loading && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "text-sm text-gray-500 mt-2", children: "Chargement des centres de co\xFBt..." })
6244
6283
  ] });
6245
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
+ };
6246
6359
 
6247
6360
  // src/components/common/Choices.tsx
6248
6361
  var import_jsx_runtime19 = require("react/jsx-runtime");
@@ -8287,6 +8400,7 @@ var EntityFileManager = ({
8287
8400
  SelectCostCenter,
8288
8401
  SelectDepartment,
8289
8402
  SelectInput,
8403
+ SelectUnit,
8290
8404
  SelectUser,
8291
8405
  SelectVendor,
8292
8406
  SessionProvider,
@@ -8296,6 +8410,7 @@ var EntityFileManager = ({
8296
8410
  ThemeProvider,
8297
8411
  ToastContainer,
8298
8412
  ToastProvider,
8413
+ UnitServices,
8299
8414
  UserServices,
8300
8415
  fileManagerApi,
8301
8416
  formatDate,
package/dist/index.d.cts CHANGED
@@ -15,6 +15,7 @@ interface ModalProps {
15
15
  title: string;
16
16
  description?: string;
17
17
  width?: string;
18
+ minContentHeight?: string;
18
19
  open: boolean;
19
20
  onClose: () => void;
20
21
  children: React$1.ReactNode;
@@ -88,6 +89,12 @@ declare const RewiseLayout: React$1.FC<PrivateLayoutProps>;
88
89
 
89
90
  declare const ToastContainer: React$1.FC;
90
91
 
92
+ interface TrackableModel {
93
+ id?: number | null;
94
+ created_at?: string;
95
+ updated_at?: string;
96
+ }
97
+
91
98
  interface Module$1 {
92
99
  id: number;
93
100
  code: string;
@@ -257,6 +264,7 @@ interface SessionContextType {
257
264
  logout: () => void;
258
265
  showAuthModal: boolean;
259
266
  setShowAuthModal: (data: boolean) => void;
267
+ refreshSession: () => Promise<void>;
260
268
  vendors: Vendor[];
261
269
  setVendors: (vendors: Vendor[]) => void;
262
270
  loadingVendors: boolean;
@@ -557,6 +565,46 @@ declare const ApprovalServices: {
557
565
  }>;
558
566
  };
559
567
 
568
+ type UnitOccupancyStatus = 'occupiable' | 'non_occupiable' | 'in_negociated' | 'indeterminate';
569
+ type UnitStatus = 'long rental' | 'short rental' | 'other' | 'draft' | 'active';
570
+ type UnitDestination = 'Nl' | 'L';
571
+ type UnitArchived = 'archived' | 'not_archived';
572
+ interface Unit extends TrackableModel {
573
+ name?: string | null;
574
+ code?: string | null;
575
+ location?: string | null;
576
+ object_name?: string | null;
577
+ unit_description?: string | null;
578
+ unit_comment?: string | null;
579
+ area_gla?: number | null;
580
+ area_gfa?: number | null;
581
+ area_gfa_mezz?: number | null;
582
+ area_m_2?: number | null;
583
+ area_m_2_mezz?: number | null;
584
+ height?: number | null;
585
+ width?: number | null;
586
+ length?: number | null;
587
+ unit_destination?: UnitDestination;
588
+ no_leasable_occupancy_status?: string;
589
+ area_category?: string | null;
590
+ detail_cat?: string | null;
591
+ zoning?: number | null;
592
+ drawing?: string | null;
593
+ archived?: UnitArchived;
594
+ unit_start_date?: string | null;
595
+ unit_end_date?: string | null;
596
+ occupancy_status?: UnitOccupancyStatus;
597
+ status?: UnitStatus;
598
+ }
599
+
600
+ declare const UnitServices: {
601
+ create: (data: Partial<Unit>) => Promise<unknown>;
602
+ get: (id: number) => Promise<unknown>;
603
+ list: (params?: any) => Promise<unknown>;
604
+ update: (id: number, data: Partial<Unit>) => Promise<unknown>;
605
+ delete: (id: number) => Promise<unknown>;
606
+ };
607
+
560
608
  type ImportField = {
561
609
  value: string;
562
610
  label: string;
@@ -679,6 +727,7 @@ declare const SelectVendor: React.FC<SelectProps$1>;
679
727
  declare const SelectUser: React.FC<SelectProps$1>;
680
728
  declare const SelectDepartment: React.FC<SelectProps$1>;
681
729
  declare const SelectCostCenter: React.FC<SelectProps$1>;
730
+ declare const SelectUnit: React.FC<SelectProps$1>;
682
731
 
683
732
  interface SelectProps {
684
733
  value?: any;
@@ -1286,4 +1335,4 @@ declare const getFileIcon: (mimeType?: string, isFolder?: boolean, isOpen?: bool
1286
1335
  declare const formatFileSize: (bytes?: number) => string;
1287
1336
  declare const formatDate: (date?: Date | string) => string;
1288
1337
 
1289
- export { Alert, AlertProvider, ApprovalAnswerModal, ApprovalAnswerPage, ApprovalPreviewAnswer, ApprovalServices, ApprovalWorkflow, AuthServices, type BackendFile, type BackendFolder, CHOICES, type ConfirmOptions, CountrySelector, DateInput, EntityFileManager, type EntityFileManagerProps, type EntityType, FDrawer, FetchApi, FileInput, type FileItem, FileManager, type FileManagerProps, FileManagerProvider, type FileManagerTexts, ForeignCurrencySelector, InputField, InvoiceTypeSelector, LegalFormSelector, type MenuItem, Modal, NumberInput, Pages, PaymentMethodSelector, PrimaryButton, RewiseLayout, SecondaryButton, SelectCostCenter, SelectDepartment, SelectInput, SelectUser, SelectVendor, SessionProvider, TaxSelector, TemplateFNESelector, TextInput, ThemeProvider, ToastContainer, ToastProvider, type UseFileManagerApiReturn, type User, UserServices, type ViewMode, fileManagerApi, formatDate, formatFileSize, getFileIcon, useAlert, useFileManager, useFileManagerApi, useSession, useToast };
1338
+ export { Alert, AlertProvider, ApprovalAnswerModal, ApprovalAnswerPage, ApprovalPreviewAnswer, ApprovalServices, ApprovalWorkflow, AuthServices, type BackendFile, type BackendFolder, CHOICES, type ConfirmOptions, CountrySelector, DateInput, EntityFileManager, type EntityFileManagerProps, type EntityType, FDrawer, FetchApi, FileInput, type FileItem, FileManager, type FileManagerProps, FileManagerProvider, type FileManagerTexts, ForeignCurrencySelector, InputField, InvoiceTypeSelector, LegalFormSelector, type MenuItem, Modal, NumberInput, Pages, PaymentMethodSelector, PrimaryButton, RewiseLayout, SecondaryButton, SelectCostCenter, SelectDepartment, SelectInput, SelectUnit, SelectUser, SelectVendor, SessionProvider, TaxSelector, TemplateFNESelector, TextInput, ThemeProvider, ToastContainer, ToastProvider, type Unit, UnitServices, type UseFileManagerApiReturn, type User, UserServices, type ViewMode, fileManagerApi, formatDate, formatFileSize, getFileIcon, useAlert, useFileManager, useFileManagerApi, useSession, useToast };
package/dist/index.d.ts CHANGED
@@ -15,6 +15,7 @@ interface ModalProps {
15
15
  title: string;
16
16
  description?: string;
17
17
  width?: string;
18
+ minContentHeight?: string;
18
19
  open: boolean;
19
20
  onClose: () => void;
20
21
  children: React$1.ReactNode;
@@ -88,6 +89,12 @@ declare const RewiseLayout: React$1.FC<PrivateLayoutProps>;
88
89
 
89
90
  declare const ToastContainer: React$1.FC;
90
91
 
92
+ interface TrackableModel {
93
+ id?: number | null;
94
+ created_at?: string;
95
+ updated_at?: string;
96
+ }
97
+
91
98
  interface Module$1 {
92
99
  id: number;
93
100
  code: string;
@@ -257,6 +264,7 @@ interface SessionContextType {
257
264
  logout: () => void;
258
265
  showAuthModal: boolean;
259
266
  setShowAuthModal: (data: boolean) => void;
267
+ refreshSession: () => Promise<void>;
260
268
  vendors: Vendor[];
261
269
  setVendors: (vendors: Vendor[]) => void;
262
270
  loadingVendors: boolean;
@@ -557,6 +565,46 @@ declare const ApprovalServices: {
557
565
  }>;
558
566
  };
559
567
 
568
+ type UnitOccupancyStatus = 'occupiable' | 'non_occupiable' | 'in_negociated' | 'indeterminate';
569
+ type UnitStatus = 'long rental' | 'short rental' | 'other' | 'draft' | 'active';
570
+ type UnitDestination = 'Nl' | 'L';
571
+ type UnitArchived = 'archived' | 'not_archived';
572
+ interface Unit extends TrackableModel {
573
+ name?: string | null;
574
+ code?: string | null;
575
+ location?: string | null;
576
+ object_name?: string | null;
577
+ unit_description?: string | null;
578
+ unit_comment?: string | null;
579
+ area_gla?: number | null;
580
+ area_gfa?: number | null;
581
+ area_gfa_mezz?: number | null;
582
+ area_m_2?: number | null;
583
+ area_m_2_mezz?: number | null;
584
+ height?: number | null;
585
+ width?: number | null;
586
+ length?: number | null;
587
+ unit_destination?: UnitDestination;
588
+ no_leasable_occupancy_status?: string;
589
+ area_category?: string | null;
590
+ detail_cat?: string | null;
591
+ zoning?: number | null;
592
+ drawing?: string | null;
593
+ archived?: UnitArchived;
594
+ unit_start_date?: string | null;
595
+ unit_end_date?: string | null;
596
+ occupancy_status?: UnitOccupancyStatus;
597
+ status?: UnitStatus;
598
+ }
599
+
600
+ declare const UnitServices: {
601
+ create: (data: Partial<Unit>) => Promise<unknown>;
602
+ get: (id: number) => Promise<unknown>;
603
+ list: (params?: any) => Promise<unknown>;
604
+ update: (id: number, data: Partial<Unit>) => Promise<unknown>;
605
+ delete: (id: number) => Promise<unknown>;
606
+ };
607
+
560
608
  type ImportField = {
561
609
  value: string;
562
610
  label: string;
@@ -679,6 +727,7 @@ declare const SelectVendor: React.FC<SelectProps$1>;
679
727
  declare const SelectUser: React.FC<SelectProps$1>;
680
728
  declare const SelectDepartment: React.FC<SelectProps$1>;
681
729
  declare const SelectCostCenter: React.FC<SelectProps$1>;
730
+ declare const SelectUnit: React.FC<SelectProps$1>;
682
731
 
683
732
  interface SelectProps {
684
733
  value?: any;
@@ -1286,4 +1335,4 @@ declare const getFileIcon: (mimeType?: string, isFolder?: boolean, isOpen?: bool
1286
1335
  declare const formatFileSize: (bytes?: number) => string;
1287
1336
  declare const formatDate: (date?: Date | string) => string;
1288
1337
 
1289
- export { Alert, AlertProvider, ApprovalAnswerModal, ApprovalAnswerPage, ApprovalPreviewAnswer, ApprovalServices, ApprovalWorkflow, AuthServices, type BackendFile, type BackendFolder, CHOICES, type ConfirmOptions, CountrySelector, DateInput, EntityFileManager, type EntityFileManagerProps, type EntityType, FDrawer, FetchApi, FileInput, type FileItem, FileManager, type FileManagerProps, FileManagerProvider, type FileManagerTexts, ForeignCurrencySelector, InputField, InvoiceTypeSelector, LegalFormSelector, type MenuItem, Modal, NumberInput, Pages, PaymentMethodSelector, PrimaryButton, RewiseLayout, SecondaryButton, SelectCostCenter, SelectDepartment, SelectInput, SelectUser, SelectVendor, SessionProvider, TaxSelector, TemplateFNESelector, TextInput, ThemeProvider, ToastContainer, ToastProvider, type UseFileManagerApiReturn, type User, UserServices, type ViewMode, fileManagerApi, formatDate, formatFileSize, getFileIcon, useAlert, useFileManager, useFileManagerApi, useSession, useToast };
1338
+ export { Alert, AlertProvider, ApprovalAnswerModal, ApprovalAnswerPage, ApprovalPreviewAnswer, ApprovalServices, ApprovalWorkflow, AuthServices, type BackendFile, type BackendFolder, CHOICES, type ConfirmOptions, CountrySelector, DateInput, EntityFileManager, type EntityFileManagerProps, type EntityType, FDrawer, FetchApi, FileInput, type FileItem, FileManager, type FileManagerProps, FileManagerProvider, type FileManagerTexts, ForeignCurrencySelector, InputField, InvoiceTypeSelector, LegalFormSelector, type MenuItem, Modal, NumberInput, Pages, PaymentMethodSelector, PrimaryButton, RewiseLayout, SecondaryButton, SelectCostCenter, SelectDepartment, SelectInput, SelectUnit, SelectUser, SelectVendor, SessionProvider, TaxSelector, TemplateFNESelector, TextInput, ThemeProvider, ToastContainer, ToastProvider, type Unit, UnitServices, type UseFileManagerApiReturn, type User, UserServices, type ViewMode, fileManagerApi, formatDate, formatFileSize, getFileIcon, useAlert, useFileManager, useFileManagerApi, useSession, useToast };
package/dist/index.js CHANGED
@@ -11,9 +11,9 @@ var PrimaryButton = ({
11
11
  {
12
12
  type: "submit",
13
13
  disabled: loading || props.disabled,
14
- 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]"}`,
14
+ 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)]"}`,
15
15
  ...props,
16
- children: loading ? "Connexion en cours..." : children
16
+ children: loading ? "Chargement..." : children
17
17
  }
18
18
  );
19
19
  var SecondaryButton = ({
@@ -26,9 +26,9 @@ var SecondaryButton = ({
26
26
  {
27
27
  type: "button",
28
28
  disabled: loading || props.disabled,
29
- 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]"}`,
29
+ 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)]"}`,
30
30
  ...props,
31
- children: loading ? "Connexion en cours..." : children
31
+ children: loading ? "Chargement..." : children
32
32
  }
33
33
  );
34
34
  var Buttons_default = PrimaryButton;
@@ -36,7 +36,7 @@ var Buttons_default = PrimaryButton;
36
36
  // src/components/common/Modals.tsx
37
37
  import { createPortal } from "react-dom";
38
38
  import { jsx as jsx2, jsxs } from "react/jsx-runtime";
39
- var Modal = ({ title, description, width = "max-w-md", open, onClose, children }) => {
39
+ var Modal = ({ title, description, width = "max-w-md", minContentHeight, open, onClose, children }) => {
40
40
  if (!open) return null;
41
41
  const modalContent = /* @__PURE__ */ jsx2("div", { className: "fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-[9999]", children: /* @__PURE__ */ jsxs("div", { className: `bg-[var(--color-surface)] rounded-lg p-6 mx-4 w-full ${width}`, children: [
42
42
  /* @__PURE__ */ jsxs("div", { className: "flex justify-between items-start mb-6", children: [
@@ -54,7 +54,14 @@ var Modal = ({ title, description, width = "max-w-md", open, onClose, children }
54
54
  }
55
55
  )
56
56
  ] }),
57
- /* @__PURE__ */ jsx2("div", { className: "w-full max-h-[80vh] overflow-y-auto", children })
57
+ /* @__PURE__ */ jsx2(
58
+ "div",
59
+ {
60
+ className: "w-full max-h-[80vh] overflow-y-auto",
61
+ style: minContentHeight ? { minHeight: minContentHeight } : void 0,
62
+ children
63
+ }
64
+ )
58
65
  ] }) });
59
66
  return createPortal(modalContent, document.body);
60
67
  };
@@ -76,10 +83,10 @@ var InputField = ({
76
83
  onBlur
77
84
  }) => {
78
85
  return /* @__PURE__ */ jsxs2("div", { className: "flex flex-col gap-1 w-full", children: [
79
- label && /* @__PURE__ */ jsxs2("label", { htmlFor: name, className: "block text-gray-700 text-sm font-medium mb-2", children: [
86
+ label && /* @__PURE__ */ jsxs2("label", { htmlFor: name, className: "block text-[var(--color-text-secondary)] text-sm font-medium mb-2", children: [
80
87
  label,
81
88
  " ",
82
- required && /* @__PURE__ */ jsx3("span", { className: "text-red-500", children: "*" })
89
+ required && /* @__PURE__ */ jsx3("span", { className: "text-[var(--color-error)]", children: "*" })
83
90
  ] }),
84
91
  /* @__PURE__ */ jsx3(
85
92
  "input",
@@ -93,13 +100,15 @@ var InputField = ({
93
100
  disabled,
94
101
  onChange,
95
102
  onBlur,
96
- className: `w-full px-3 py-2 border border-[#D9D9D9] focus:ring-2 focus:ring-[#6A8A82]/20
97
- ${error ? "border-red-500" : "border-gray-300"}
98
- ${disabled ? "bg-gray-100 cursor-not-allowed" : ""}
103
+ className: `w-full px-3 py-2 border rounded-lg text-sm
104
+ bg-[var(--color-surface)] text-[var(--color-text-primary)]
105
+ focus:ring-2 focus:ring-[var(--color-primary)]/20 focus:border-[var(--color-primary)] focus:outline-none
106
+ ${error ? "border-[var(--color-error)]" : "border-[var(--color-border)]"}
107
+ ${disabled ? "bg-[var(--color-background)] cursor-not-allowed opacity-60" : ""}
99
108
  `
100
109
  }
101
110
  ),
102
- error && /* @__PURE__ */ jsx3("p", { className: "text-xs text-red-500", children: error })
111
+ error && /* @__PURE__ */ jsx3("p", { className: "text-xs text-[var(--color-error)]", children: error })
103
112
  ] });
104
113
  };
105
114
  var TextInput = (props) => {
@@ -129,11 +138,11 @@ var SelectInput = ({
129
138
  "label",
130
139
  {
131
140
  htmlFor: name,
132
- className: "block text-gray-700 text-sm font-medium mb-2",
141
+ className: "block text-[var(--color-text-secondary)] text-sm font-medium mb-2",
133
142
  children: [
134
143
  label,
135
144
  " ",
136
- required && /* @__PURE__ */ jsx3("span", { className: "text-red-500", children: "*" })
145
+ required && /* @__PURE__ */ jsx3("span", { className: "text-[var(--color-error)]", children: "*" })
137
146
  ]
138
147
  }
139
148
  ),
@@ -148,9 +157,10 @@ var SelectInput = ({
148
157
  onChange,
149
158
  onBlur,
150
159
  className: `w-full px-4 py-2 border rounded-lg text-sm
151
- focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent
152
- ${error ? "border-red-500" : "border-gray-300"}
153
- ${disabled ? "bg-gray-100 cursor-not-allowed" : ""}
160
+ bg-[var(--color-surface)] text-[var(--color-text-primary)]
161
+ focus:outline-none focus:ring-2 focus:ring-[var(--color-primary)]/20 focus:border-[var(--color-primary)]
162
+ ${error ? "border-[var(--color-error)]" : "border-[var(--color-border)]"}
163
+ ${disabled ? "bg-[var(--color-background)] cursor-not-allowed opacity-60" : ""}
154
164
  `,
155
165
  children: [
156
166
  defaultValue !== void 0 && /* @__PURE__ */ jsx3("option", { value: "", children: typeof defaultValue === "string" ? defaultValue : "S\xE9lectionnez une option" }),
@@ -158,7 +168,7 @@ var SelectInput = ({
158
168
  ]
159
169
  }
160
170
  ),
161
- error && /* @__PURE__ */ jsx3("p", { className: "text-xs text-red-500", children: error })
171
+ error && /* @__PURE__ */ jsx3("p", { className: "text-xs text-[var(--color-error)]", children: error })
162
172
  ] });
163
173
  };
164
174
  var addressIpformMedia = "http://localhost:8000/media/";
@@ -915,6 +925,21 @@ var SessionProvider = ({ children }) => {
915
925
  localStorage.removeItem("token");
916
926
  setToken(null);
917
927
  };
928
+ const refreshSession = async () => {
929
+ if (!token) return;
930
+ try {
931
+ const res = await AuthServices.getUserInformations(token);
932
+ const result = res;
933
+ if (result.success === true) {
934
+ setLoggedUser(result.data.user);
935
+ setActiveBusinessEntity(
936
+ result.data.user.centers_access.find((item) => parseInt(String(item.id)) === parseInt(saved_center_id)) || result.data.user.centers_access[0] || null
937
+ );
938
+ }
939
+ } catch (error) {
940
+ console.error("Failed to refresh session:", error);
941
+ }
942
+ };
918
943
  useEffect2(() => {
919
944
  if (token) {
920
945
  AuthServices.getUserInformations(token).then((res) => {
@@ -947,6 +972,7 @@ var SessionProvider = ({ children }) => {
947
972
  logout,
948
973
  showAuthModal,
949
974
  setShowAuthModal,
975
+ refreshSession,
950
976
  vendors,
951
977
  setVendors,
952
978
  loadingVendors,
@@ -1021,16 +1047,17 @@ var ToastProvider = ({ children }) => {
1021
1047
  const addToast = useCallback((toast) => {
1022
1048
  const id = generateId();
1023
1049
  const defaultDuration = toast.type === "error" ? 7e3 : 3e3;
1050
+ const duration = toast.duration ?? defaultDuration;
1024
1051
  const newToast = {
1052
+ ...toast,
1025
1053
  id,
1026
- duration: toast.duration ?? defaultDuration,
1027
- ...toast
1054
+ duration
1028
1055
  };
1029
1056
  setToasts((prev) => [...prev, newToast]);
1030
- if (newToast.duration && newToast.duration > 0) {
1057
+ if (duration > 0) {
1031
1058
  setTimeout(() => {
1032
- removeToast(id);
1033
- }, newToast.duration);
1059
+ setToasts((prev) => prev.filter((t) => t.id !== id));
1060
+ }, duration);
1034
1061
  }
1035
1062
  }, []);
1036
1063
  const removeToast = useCallback((id) => {
@@ -3417,6 +3444,16 @@ var Pages = ({
3417
3444
  };
3418
3445
  var Pages_default = Pages;
3419
3446
 
3447
+ // src/services/UnitServices.ts
3448
+ var URI = `${API_URL}/crm/units/`;
3449
+ var UnitServices = {
3450
+ create: (data) => FetchApi.post(`${URI}`, data),
3451
+ get: (id) => FetchApi.get(`${URI}${id}/`),
3452
+ list: (params) => FetchApi.get(`${URI}?${new URLSearchParams(params).toString()}`),
3453
+ update: (id, data) => FetchApi.put(`${URI}${id}/`, data),
3454
+ delete: (id) => FetchApi.delete(`${URI}${id}/`)
3455
+ };
3456
+
3420
3457
  // src/components/common/FDrawer.tsx
3421
3458
  import React7, { useEffect as useEffect6, useState as useState8, useRef } from "react";
3422
3459
  import { useLocation as useLocation2, useNavigate as useNavigate2, useSearchParams as useSearchParams2, Link as Link2 } from "react-router-dom";
@@ -5298,7 +5335,7 @@ var ApprovalWorkflow = ({
5298
5335
  if (CustomBtn) {
5299
5336
  return /* @__PURE__ */ jsxs11(Fragment6, { children: [
5300
5337
  /* @__PURE__ */ jsx14(CustomBtn, { onClick: open_modal }),
5301
- /* @__PURE__ */ jsx14(Modals_default, { open: isOpen, onClose: close_modal, title, children: formulaire() })
5338
+ /* @__PURE__ */ jsx14(Modals_default, { open: isOpen, onClose: close_modal, title, width: "max-w-lg", children: formulaire() })
5302
5339
  ] });
5303
5340
  }
5304
5341
  return /* @__PURE__ */ jsx14(Fragment6, { children: /* @__PURE__ */ jsx14(
@@ -5496,7 +5533,7 @@ var AddStageButton = ({
5496
5533
  /* @__PURE__ */ jsx14(
5497
5534
  Modals_default,
5498
5535
  {
5499
- width: "",
5536
+ width: "max-w-lg",
5500
5537
  title: "Ajouter une personne",
5501
5538
  description: "S\xE9lectionnez un utilisateur interne ou ajoutez un validateur externe",
5502
5539
  open: showModal,
@@ -5815,7 +5852,7 @@ var MinimalVendorForm = ({
5815
5852
  Modals_default,
5816
5853
  {
5817
5854
  title: "Ajouter un fournisseur",
5818
- width: "w-[100%]",
5855
+ width: "max-w-2xl",
5819
5856
  description: ``,
5820
5857
  open: isOpen,
5821
5858
  onClose,
@@ -5870,17 +5907,17 @@ var MinimalVendorForm = ({
5870
5907
  };
5871
5908
 
5872
5909
  // src/services/DepartmentServices.ts
5873
- var URI = `${API_URL}/core/departments/`;
5910
+ var URI2 = `${API_URL}/core/departments/`;
5874
5911
  var DepartmentServices = {
5875
- create: (data) => FetchApi.post(`${URI}`, data),
5876
- get: (id) => FetchApi.get(`${URI}${id}/`),
5877
- list: (params) => FetchApi.get(`${URI}?${new URLSearchParams(params).toString()}`),
5878
- update: (id, data) => FetchApi.put(`${URI}${id}/`, data),
5879
- delete: (id) => FetchApi.delete(`${URI}${id}/`)
5912
+ create: (data) => FetchApi.post(`${URI2}`, data),
5913
+ get: (id) => FetchApi.get(`${URI2}${id}/`),
5914
+ list: (params) => FetchApi.get(`${URI2}?${new URLSearchParams(params).toString()}`),
5915
+ update: (id, data) => FetchApi.put(`${URI2}${id}/`, data),
5916
+ delete: (id) => FetchApi.delete(`${URI2}${id}/`)
5880
5917
  };
5881
5918
 
5882
5919
  // src/services/ProfitCostsServices.ts
5883
- var URI2 = `${API_URL}/accounting/profit-or-cost-center/`;
5920
+ var URI3 = `${API_URL}/accounting/profit-or-cost-center/`;
5884
5921
  var COST_URI = `${API_URL}/accounting/cost-center/`;
5885
5922
  var CostServices = {
5886
5923
  create: (data) => FetchApi.post(`${COST_URI}`, data),
@@ -6187,6 +6224,80 @@ var SelectCostCenter = ({
6187
6224
  loading && /* @__PURE__ */ jsx18("p", { className: "text-sm text-gray-500 mt-2", children: "Chargement des centres de co\xFBt..." })
6188
6225
  ] });
6189
6226
  };
6227
+ var SelectUnit = ({
6228
+ value,
6229
+ onSelect
6230
+ }) => {
6231
+ const { token, activeBusinessEntity } = useSession();
6232
+ const [units, setUnits] = useState13(() => {
6233
+ const cacheKey = `units_cache_${activeBusinessEntity?.id || "default"}`;
6234
+ const cached = sessionStorage.getItem(cacheKey);
6235
+ return cached ? JSON.parse(cached) : [];
6236
+ });
6237
+ const [loading, setLoading] = useState13(false);
6238
+ useEffect10(() => {
6239
+ const cacheKey = `units_cache_${activeBusinessEntity?.id || "default"}`;
6240
+ const cached = sessionStorage.getItem(cacheKey);
6241
+ if (!cached) {
6242
+ loadUnits();
6243
+ } else {
6244
+ setUnits(JSON.parse(cached));
6245
+ }
6246
+ }, [activeBusinessEntity?.id]);
6247
+ const loadUnits = async () => {
6248
+ if (!token) return;
6249
+ try {
6250
+ setLoading(true);
6251
+ const result = await UnitServices.list({ business_entity_id: activeBusinessEntity?.id });
6252
+ if (result.success) {
6253
+ setUnits(result.data);
6254
+ const cacheKey = `units_cache_${activeBusinessEntity?.id || "default"}`;
6255
+ sessionStorage.setItem(cacheKey, JSON.stringify(result.data));
6256
+ }
6257
+ } catch (error) {
6258
+ console.error(error);
6259
+ } finally {
6260
+ setLoading(false);
6261
+ }
6262
+ };
6263
+ const handleRefresh = () => {
6264
+ const cacheKey = `units_cache_${activeBusinessEntity?.id || "default"}`;
6265
+ sessionStorage.removeItem(cacheKey);
6266
+ loadUnits();
6267
+ };
6268
+ const getUnitOptions = () => {
6269
+ return units.map((unit) => ({
6270
+ value: unit.id,
6271
+ label: `${unit.code ? `[${unit.code}] ` : ""}${unit.name || "Sans nom"}`,
6272
+ object: unit,
6273
+ content: /* @__PURE__ */ jsx18("div", { className: "flex items-center space-x-3", children: /* @__PURE__ */ jsxs15("div", { className: "flex-1", children: [
6274
+ /* @__PURE__ */ jsx18("div", { className: "font-medium text-gray-900", children: unit.name || "Sans nom" }),
6275
+ unit.code && /* @__PURE__ */ jsxs15("div", { className: "text-sm text-gray-500", children: [
6276
+ "Code: ",
6277
+ unit.code
6278
+ ] }),
6279
+ unit.location && /* @__PURE__ */ jsx18("div", { className: "text-xs text-gray-400", children: unit.location })
6280
+ ] }) })
6281
+ }));
6282
+ };
6283
+ return /* @__PURE__ */ jsxs15("div", { children: [
6284
+ /* @__PURE__ */ jsx18("div", { className: "flex justify-between ", children: /* @__PURE__ */ jsx18("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: "S\xE9lectionner une unit\xE9" }) }),
6285
+ /* @__PURE__ */ jsx18(
6286
+ SearchableSelect,
6287
+ {
6288
+ value,
6289
+ options: getUnitOptions(),
6290
+ placeholder: "S\xE9lectionner une unit\xE9 ...",
6291
+ searchPlaceholder: "Rechercher...",
6292
+ onSelect,
6293
+ disabled: loading,
6294
+ refresh: handleRefresh
6295
+ },
6296
+ "unit" + value
6297
+ ),
6298
+ loading && /* @__PURE__ */ jsx18("p", { className: "text-sm text-gray-500 mt-2", children: "Chargement des unit\xE9s..." })
6299
+ ] });
6300
+ };
6190
6301
 
6191
6302
  // src/components/common/Choices.tsx
6192
6303
  import { jsx as jsx19 } from "react/jsx-runtime";
@@ -8242,6 +8353,7 @@ export {
8242
8353
  SelectCostCenter,
8243
8354
  SelectDepartment,
8244
8355
  SelectInput,
8356
+ SelectUnit,
8245
8357
  SelectUser,
8246
8358
  SelectVendor,
8247
8359
  SessionProvider,
@@ -8251,6 +8363,7 @@ export {
8251
8363
  ThemeContext_default as ThemeProvider,
8252
8364
  Toast_default as ToastContainer,
8253
8365
  ToastProvider,
8366
+ UnitServices,
8254
8367
  UserServices,
8255
8368
  fileManagerApi,
8256
8369
  formatDate,
package/package.json CHANGED
@@ -1,57 +1,57 @@
1
- {
2
- "name": "ptechcore_ui",
3
- "version": "1.0.27",
4
- "type": "module",
5
- "main": "./dist/index.cjs",
6
- "module": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "types": "./dist/index.d.ts",
11
- "import": "./dist/index.js",
12
- "require": "./dist/index.cjs"
13
- }
14
- },
15
- "files": [
16
- "dist"
17
- ],
18
- "scripts": {
19
- "dev": "vite",
20
- "build": "tsup src/index.ts --format cjs,esm --dts",
21
- "build:app": "vite build",
22
- "build:lib": "tsup src/index.ts --format cjs,esm --dts",
23
- "lint": "eslint .",
24
- "preview": "vite preview"
25
- },
26
- "dependencies": {
27
- "clsx": "^2.1.1",
28
- "date-fns": "^2.30.0",
29
- "leaflet": "^1.9.4",
30
- "lucide-react": "^0.344.0",
31
- "react": "^18.3.1",
32
- "react-dom": "^18.3.1",
33
- "react-hook-form": "^7.48.2",
34
- "react-leaflet": "^4.2.1",
35
- "react-router-dom": "^6.26.0",
36
- "tailwind-merge": "^3.3.1",
37
- "tailwindcss-animate": "^1.0.7"
38
- },
39
- "devDependencies": {
40
- "@eslint/js": "^9.9.1",
41
- "@types/leaflet": "^1.9.8",
42
- "@types/react": "^18.3.5",
43
- "@types/react-dom": "^18.3.0",
44
- "@vitejs/plugin-react": "^4.3.1",
45
- "autoprefixer": "^10.4.18",
46
- "eslint": "^9.9.1",
47
- "eslint-plugin-react-hooks": "^5.1.0-rc.0",
48
- "eslint-plugin-react-refresh": "^0.4.11",
49
- "globals": "^15.9.0",
50
- "postcss": "^8.4.35",
51
- "tailwindcss": "^3.4.1",
52
- "tsup": "^8.5.0",
53
- "typescript": "^5.5.3",
54
- "typescript-eslint": "^8.3.0",
55
- "vite": "^5.4.2"
56
- }
57
- }
1
+ {
2
+ "name": "ptechcore_ui",
3
+ "version": "1.0.29",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "dev": "vite",
20
+ "build": "tsup src/index.ts --format cjs,esm --dts",
21
+ "build:app": "vite build",
22
+ "build:lib": "tsup src/index.ts --format cjs,esm --dts",
23
+ "lint": "eslint .",
24
+ "preview": "vite preview"
25
+ },
26
+ "dependencies": {
27
+ "clsx": "^2.1.1",
28
+ "date-fns": "^2.30.0",
29
+ "leaflet": "^1.9.4",
30
+ "lucide-react": "^0.344.0",
31
+ "react": "^18.3.1",
32
+ "react-dom": "^18.3.1",
33
+ "react-hook-form": "^7.48.2",
34
+ "react-leaflet": "^4.2.1",
35
+ "react-router-dom": "^6.26.0",
36
+ "tailwind-merge": "^3.3.1",
37
+ "tailwindcss-animate": "^1.0.7"
38
+ },
39
+ "devDependencies": {
40
+ "@eslint/js": "^9.9.1",
41
+ "@types/leaflet": "^1.9.8",
42
+ "@types/react": "^18.3.5",
43
+ "@types/react-dom": "^18.3.0",
44
+ "@vitejs/plugin-react": "^4.3.1",
45
+ "autoprefixer": "^10.4.18",
46
+ "eslint": "^9.9.1",
47
+ "eslint-plugin-react-hooks": "^5.1.0-rc.0",
48
+ "eslint-plugin-react-refresh": "^0.4.11",
49
+ "globals": "^15.9.0",
50
+ "postcss": "^8.4.35",
51
+ "tailwindcss": "^3.4.1",
52
+ "tsup": "^8.5.0",
53
+ "typescript": "^5.5.3",
54
+ "typescript-eslint": "^8.3.0",
55
+ "vite": "^5.4.2"
56
+ }
57
+ }