@ews-admin/global-design-system 1.1.21 → 1.1.23
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/components/Input/Input.d.ts +8 -0
- package/dist/components/Input/Input.d.ts.map +1 -1
- package/dist/components/ProfileImageUpload/ProfileImageUpload.d.ts +47 -0
- package/dist/components/ProfileImageUpload/ProfileImageUpload.d.ts.map +1 -0
- package/dist/components/ProfileImageUpload/index.d.ts +3 -0
- package/dist/components/ProfileImageUpload/index.d.ts.map +1 -0
- package/dist/index.css +1 -1
- package/dist/index.d.ts +107 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +202 -24
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +203 -22
- package/dist/index.js.map +1 -1
- package/dist/utils/env-config.d.ts +32 -0
- package/dist/utils/env-config.d.ts.map +1 -0
- package/dist/utils/index.d.ts +21 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/Input/Input.tsx +28 -2
- package/src/components/ProfileImageUpload/ProfileImageUpload.tsx +231 -0
- package/src/components/ProfileImageUpload/index.ts +2 -0
- package/src/index.ts +7 -0
- package/src/utils/env-config.ts +82 -0
- package/src/utils/index.ts +38 -0
package/dist/index.esm.js
CHANGED
|
@@ -1,8 +1,62 @@
|
|
|
1
|
-
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
1
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
2
|
import React, { forwardRef, createElement, useState, useRef, useEffect, useId, useCallback, createContext, useContext } from 'react';
|
|
3
3
|
|
|
4
4
|
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
|
|
5
5
|
|
|
6
|
+
const LOCAL_PORTS = {
|
|
7
|
+
bff: 8082,
|
|
8
|
+
loginBff: 8080,
|
|
9
|
+
app: 3000,
|
|
10
|
+
login: 3001,
|
|
11
|
+
dashboard: 3002,
|
|
12
|
+
admin: 3008,
|
|
13
|
+
};
|
|
14
|
+
function buildUrls(environment) {
|
|
15
|
+
if (environment === "local") {
|
|
16
|
+
const base = "http://local";
|
|
17
|
+
const domain = "medecine360local.com";
|
|
18
|
+
return {
|
|
19
|
+
bffUrl: `${base}.api.${domain}:${LOCAL_PORTS.bff}/bff/api/v1`,
|
|
20
|
+
loginBffUrl: `${base}.api.${domain}:${LOCAL_PORTS.loginBff}/login-bff/api/v1`,
|
|
21
|
+
appUrl: `${base}.app.${domain}:${LOCAL_PORTS.app}`,
|
|
22
|
+
loginUrl: `${base}.login.${domain}:${LOCAL_PORTS.login}`,
|
|
23
|
+
dashboardUrl: `${base}.dashboard.${domain}:${LOCAL_PORTS.dashboard}`,
|
|
24
|
+
adminUrl: `${base}.admin.${domain}:${LOCAL_PORTS.admin}`,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const prefix = environment === "prod" ? "" : `${environment}.`;
|
|
28
|
+
const domain = "medecine360.com";
|
|
29
|
+
return {
|
|
30
|
+
bffUrl: `https://${prefix}api.${domain}/bff/api/v1`,
|
|
31
|
+
loginBffUrl: `https://${prefix}api.${domain}/login-bff/api/v1`,
|
|
32
|
+
appUrl: `https://${prefix}app.${domain}`,
|
|
33
|
+
loginUrl: `https://${prefix}login.${domain}`,
|
|
34
|
+
dashboardUrl: `https://${prefix}dashboard.${domain}`,
|
|
35
|
+
adminUrl: `https://${prefix}admin.${domain}`,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Creates an environment configuration with all derived URLs.
|
|
40
|
+
*
|
|
41
|
+
* For deployed environments (dev, qa, prod), only the environment name is needed
|
|
42
|
+
* — all URLs follow a predictable convention.
|
|
43
|
+
*
|
|
44
|
+
* For local development, sensible defaults are provided but can be overridden
|
|
45
|
+
* (e.g. to point BFF URL at a mock server).
|
|
46
|
+
*
|
|
47
|
+
* @param env - The environment name (VITE_ENV value)
|
|
48
|
+
* @param overrides - Optional URL overrides (e.g. for local mock servers)
|
|
49
|
+
*/
|
|
50
|
+
function createEnvConfig(env, overrides) {
|
|
51
|
+
const environment = (env || "local");
|
|
52
|
+
const derived = buildUrls(environment);
|
|
53
|
+
return {
|
|
54
|
+
env: environment,
|
|
55
|
+
...derived,
|
|
56
|
+
...overrides,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
6
60
|
/**
|
|
7
61
|
* Default currency for price formatting
|
|
8
62
|
*/
|
|
@@ -84,6 +138,36 @@ function isValidPhoneNumber(value) {
|
|
|
84
138
|
const phoneRegex = /^(\+\d{1,17}|\d{1,17})$/;
|
|
85
139
|
return phoneRegex.test(trimmedValue);
|
|
86
140
|
}
|
|
141
|
+
/**
|
|
142
|
+
* Blood type enum matching backend BloodTypeEnum values
|
|
143
|
+
*/
|
|
144
|
+
var BloodType;
|
|
145
|
+
(function (BloodType) {
|
|
146
|
+
BloodType["A_POSITIVE"] = "A+";
|
|
147
|
+
BloodType["A_NEGATIVE"] = "A-";
|
|
148
|
+
BloodType["B_POSITIVE"] = "B+";
|
|
149
|
+
BloodType["B_NEGATIVE"] = "B-";
|
|
150
|
+
BloodType["AB_POSITIVE"] = "AB+";
|
|
151
|
+
BloodType["AB_NEGATIVE"] = "AB-";
|
|
152
|
+
BloodType["O_POSITIVE"] = "O+";
|
|
153
|
+
BloodType["O_NEGATIVE"] = "O-";
|
|
154
|
+
BloodType["UNKNOWN"] = "UNKNOWN";
|
|
155
|
+
})(BloodType || (BloodType = {}));
|
|
156
|
+
/**
|
|
157
|
+
* Ordered list of all blood type values.
|
|
158
|
+
* Use this to build select/dropdown options.
|
|
159
|
+
*/
|
|
160
|
+
const BLOOD_TYPES = [
|
|
161
|
+
BloodType.A_POSITIVE,
|
|
162
|
+
BloodType.A_NEGATIVE,
|
|
163
|
+
BloodType.B_POSITIVE,
|
|
164
|
+
BloodType.B_NEGATIVE,
|
|
165
|
+
BloodType.AB_POSITIVE,
|
|
166
|
+
BloodType.AB_NEGATIVE,
|
|
167
|
+
BloodType.O_POSITIVE,
|
|
168
|
+
BloodType.O_NEGATIVE,
|
|
169
|
+
BloodType.UNKNOWN,
|
|
170
|
+
];
|
|
87
171
|
|
|
88
172
|
const Button = React.forwardRef(({ className, variant = "ews-primary", size = "md", loading = false, fullWidth = false, leftIcon, rightIcon, children, disabled, ...props }, ref) => {
|
|
89
173
|
const baseStyles = "inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none disabled:opacity-50 disabled:pointer-events-none";
|
|
@@ -227,11 +311,11 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
227
311
|
*/
|
|
228
312
|
|
|
229
313
|
|
|
230
|
-
const __iconNode$
|
|
314
|
+
const __iconNode$e = [
|
|
231
315
|
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
232
316
|
["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
|
|
233
317
|
];
|
|
234
|
-
const ArrowRight = createLucideIcon("arrow-right", __iconNode$
|
|
318
|
+
const ArrowRight = createLucideIcon("arrow-right", __iconNode$e);
|
|
235
319
|
|
|
236
320
|
/**
|
|
237
321
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -241,8 +325,8 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$c);
|
|
|
241
325
|
*/
|
|
242
326
|
|
|
243
327
|
|
|
244
|
-
const __iconNode$
|
|
245
|
-
const Check = createLucideIcon("check", __iconNode$
|
|
328
|
+
const __iconNode$d = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
329
|
+
const Check = createLucideIcon("check", __iconNode$d);
|
|
246
330
|
|
|
247
331
|
/**
|
|
248
332
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -252,8 +336,8 @@ const Check = createLucideIcon("check", __iconNode$b);
|
|
|
252
336
|
*/
|
|
253
337
|
|
|
254
338
|
|
|
255
|
-
const __iconNode$
|
|
256
|
-
const ChevronDown = createLucideIcon("chevron-down", __iconNode$
|
|
339
|
+
const __iconNode$c = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
340
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$c);
|
|
257
341
|
|
|
258
342
|
/**
|
|
259
343
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -263,12 +347,12 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$a);
|
|
|
263
347
|
*/
|
|
264
348
|
|
|
265
349
|
|
|
266
|
-
const __iconNode$
|
|
350
|
+
const __iconNode$b = [
|
|
267
351
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
268
352
|
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
269
353
|
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
270
354
|
];
|
|
271
|
-
const CircleAlert = createLucideIcon("circle-alert", __iconNode$
|
|
355
|
+
const CircleAlert = createLucideIcon("circle-alert", __iconNode$b);
|
|
272
356
|
|
|
273
357
|
/**
|
|
274
358
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -278,11 +362,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$9);
|
|
|
278
362
|
*/
|
|
279
363
|
|
|
280
364
|
|
|
281
|
-
const __iconNode$
|
|
365
|
+
const __iconNode$a = [
|
|
282
366
|
["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
|
|
283
367
|
["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
|
|
284
368
|
];
|
|
285
|
-
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$
|
|
369
|
+
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$a);
|
|
286
370
|
|
|
287
371
|
/**
|
|
288
372
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -292,7 +376,7 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$8);
|
|
|
292
376
|
*/
|
|
293
377
|
|
|
294
378
|
|
|
295
|
-
const __iconNode$
|
|
379
|
+
const __iconNode$9 = [
|
|
296
380
|
[
|
|
297
381
|
"path",
|
|
298
382
|
{
|
|
@@ -310,7 +394,7 @@ const __iconNode$7 = [
|
|
|
310
394
|
],
|
|
311
395
|
["path", { d: "m2 2 20 20", key: "1ooewy" }]
|
|
312
396
|
];
|
|
313
|
-
const EyeOff = createLucideIcon("eye-off", __iconNode$
|
|
397
|
+
const EyeOff = createLucideIcon("eye-off", __iconNode$9);
|
|
314
398
|
|
|
315
399
|
/**
|
|
316
400
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -320,7 +404,7 @@ const EyeOff = createLucideIcon("eye-off", __iconNode$7);
|
|
|
320
404
|
*/
|
|
321
405
|
|
|
322
406
|
|
|
323
|
-
const __iconNode$
|
|
407
|
+
const __iconNode$8 = [
|
|
324
408
|
[
|
|
325
409
|
"path",
|
|
326
410
|
{
|
|
@@ -330,7 +414,7 @@ const __iconNode$6 = [
|
|
|
330
414
|
],
|
|
331
415
|
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
332
416
|
];
|
|
333
|
-
const Eye = createLucideIcon("eye", __iconNode$
|
|
417
|
+
const Eye = createLucideIcon("eye", __iconNode$8);
|
|
334
418
|
|
|
335
419
|
/**
|
|
336
420
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -340,7 +424,7 @@ const Eye = createLucideIcon("eye", __iconNode$6);
|
|
|
340
424
|
*/
|
|
341
425
|
|
|
342
426
|
|
|
343
|
-
const __iconNode$
|
|
427
|
+
const __iconNode$7 = [
|
|
344
428
|
[
|
|
345
429
|
"path",
|
|
346
430
|
{
|
|
@@ -349,7 +433,7 @@ const __iconNode$5 = [
|
|
|
349
433
|
}
|
|
350
434
|
]
|
|
351
435
|
];
|
|
352
|
-
const Heart = createLucideIcon("heart", __iconNode$
|
|
436
|
+
const Heart = createLucideIcon("heart", __iconNode$7);
|
|
353
437
|
|
|
354
438
|
/**
|
|
355
439
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -359,11 +443,31 @@ const Heart = createLucideIcon("heart", __iconNode$5);
|
|
|
359
443
|
*/
|
|
360
444
|
|
|
361
445
|
|
|
362
|
-
const __iconNode$
|
|
446
|
+
const __iconNode$6 = [
|
|
447
|
+
[
|
|
448
|
+
"path",
|
|
449
|
+
{
|
|
450
|
+
d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
|
|
451
|
+
key: "1a8usu"
|
|
452
|
+
}
|
|
453
|
+
],
|
|
454
|
+
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
455
|
+
];
|
|
456
|
+
const Pencil = createLucideIcon("pencil", __iconNode$6);
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* @license lucide-react v0.544.0 - ISC
|
|
460
|
+
*
|
|
461
|
+
* This source code is licensed under the ISC license.
|
|
462
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
463
|
+
*/
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
const __iconNode$5 = [
|
|
363
467
|
["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
|
|
364
468
|
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
|
|
365
469
|
];
|
|
366
|
-
const Search = createLucideIcon("search", __iconNode$
|
|
470
|
+
const Search = createLucideIcon("search", __iconNode$5);
|
|
367
471
|
|
|
368
472
|
/**
|
|
369
473
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -373,14 +477,29 @@ const Search = createLucideIcon("search", __iconNode$4);
|
|
|
373
477
|
*/
|
|
374
478
|
|
|
375
479
|
|
|
376
|
-
const __iconNode$
|
|
480
|
+
const __iconNode$4 = [
|
|
377
481
|
["path", { d: "M11 2v2", key: "1539x4" }],
|
|
378
482
|
["path", { d: "M5 2v2", key: "1yf1q8" }],
|
|
379
483
|
["path", { d: "M5 3H4a2 2 0 0 0-2 2v4a6 6 0 0 0 12 0V5a2 2 0 0 0-2-2h-1", key: "rb5t3r" }],
|
|
380
484
|
["path", { d: "M8 15a6 6 0 0 0 12 0v-3", key: "x18d4x" }],
|
|
381
485
|
["circle", { cx: "20", cy: "10", r: "2", key: "ts1r5v" }]
|
|
382
486
|
];
|
|
383
|
-
const Stethoscope = createLucideIcon("stethoscope", __iconNode$
|
|
487
|
+
const Stethoscope = createLucideIcon("stethoscope", __iconNode$4);
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* @license lucide-react v0.544.0 - ISC
|
|
491
|
+
*
|
|
492
|
+
* This source code is licensed under the ISC license.
|
|
493
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
494
|
+
*/
|
|
495
|
+
|
|
496
|
+
|
|
497
|
+
const __iconNode$3 = [
|
|
498
|
+
["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", key: "miytrc" }],
|
|
499
|
+
["path", { d: "M3 6h18", key: "d0wm0j" }],
|
|
500
|
+
["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2", key: "e791ji" }]
|
|
501
|
+
];
|
|
502
|
+
const Trash = createLucideIcon("trash", __iconNode$3);
|
|
384
503
|
|
|
385
504
|
/**
|
|
386
505
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -455,7 +574,7 @@ const UserIcon = ({ size = 24, color = "currentColor", className = "", ...props
|
|
|
455
574
|
return jsx(User, { size: size, color: color, className: className, ...props });
|
|
456
575
|
};
|
|
457
576
|
|
|
458
|
-
const Input = React.forwardRef(({ className, variant = "default", size = "md", label, helperText, error, leftIcon, rightIcon, fullWidth = false, showPasswordToggle = false, required = false, countryCodeSelect, id, type = "text", ...props }, ref) => {
|
|
577
|
+
const Input = React.forwardRef(({ className, variant = "default", size = "md", label, helperText, error, leftIcon, rightIcon, fullWidth = false, showPasswordToggle = false, required = false, countryCodeSelect, leftAddon, rightAddon, id, type = "text", ...props }, ref) => {
|
|
459
578
|
const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
|
|
460
579
|
const hasError = Boolean(error);
|
|
461
580
|
const actualVariant = hasError ? "error" : variant;
|
|
@@ -514,7 +633,7 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
|
|
|
514
633
|
countryCodeSelect.onChange(item.code);
|
|
515
634
|
setIsDropdownOpen(false);
|
|
516
635
|
}, className: cn("px-3 py-2 text-sm cursor-pointer transition-colors", isSelected && "bg-ews-primary text-white", !isSelected && "hover:bg-ews-gray-50"), children: [jsx("span", { className: "font-medium", children: item.code }), item.country && (jsx("span", { className: cn("ml-2 text-xs", isSelected ? "text-white/80" : "text-ews-gray-500"), children: item.country }))] }, item.code));
|
|
517
|
-
}) }))] }) })), leftIcon && !countryCodeSelect && (jsx("div", { className: "flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none", children: jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: leftIcon }) })), jsx("input", { id: inputId, type: actualType, className: cn(baseStyles, variants[actualVariant], sizes[size], countryCodeSelect && "pl-24", leftIcon && !countryCodeSelect && "pl-10", (rightIcon || shouldShowPasswordToggle) && "pr-10", className), ref: ref, ...props }), rightIcon && !shouldShowPasswordToggle && (jsx("div", { className: "flex absolute inset-y-0 right-0 items-center pr-3 pointer-events-none", children: jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: rightIcon }) })), shouldShowPasswordToggle && (jsx("button", { type: "button", className: "flex absolute inset-y-0 right-0 items-center pr-3", onClick: () => setShowPassword(!showPassword), tabIndex: -1, children: jsx("span", { className: cn("transition-colors text-ews-gray-400 hover:text-ews-gray-600", iconSizes[size]), children: showPassword ? jsx(EyeOff, { size: 16 }) : jsx(Eye, { size: 16 }) }) }))] }), (error || helperText) && (jsx("p", { className: cn("text-sm", error ? "text-ews-error" : "text-ews-gray-500"), children: error || helperText }))] }));
|
|
636
|
+
}) }))] }) })), leftIcon && !countryCodeSelect && !leftAddon && (jsx("div", { className: "flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none", children: jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: leftIcon }) })), leftAddon && !countryCodeSelect && !leftIcon && (jsx("div", { className: "flex absolute inset-y-0 left-0 items-center pointer-events-none overflow-hidden rounded-l-md", children: jsx("span", { className: "flex items-center h-full px-3 text-sm font-medium whitespace-nowrap bg-ews-gray-50 border-r border-ews-gray-300 text-ews-gray-600", children: leftAddon }) })), jsx("input", { id: inputId, type: actualType, className: cn(baseStyles, variants[actualVariant], sizes[size], countryCodeSelect && "pl-24", leftIcon && !countryCodeSelect && !leftAddon && "pl-10", leftAddon && !countryCodeSelect && !leftIcon && "pl-16", (rightIcon || shouldShowPasswordToggle) && "pr-10", rightAddon && !rightIcon && !shouldShowPasswordToggle && "pr-16", className), ref: ref, ...props }), rightAddon && !rightIcon && !shouldShowPasswordToggle && (jsx("div", { className: "flex absolute inset-y-0 right-0 items-center pr-3 pointer-events-none", children: jsx("span", { className: "text-sm font-medium text-ews-gray-500", children: rightAddon }) })), rightIcon && !shouldShowPasswordToggle && (jsx("div", { className: "flex absolute inset-y-0 right-0 items-center pr-3 pointer-events-none", children: jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: rightIcon }) })), shouldShowPasswordToggle && (jsx("button", { type: "button", className: "flex absolute inset-y-0 right-0 items-center pr-3", onClick: () => setShowPassword(!showPassword), tabIndex: -1, children: jsx("span", { className: cn("transition-colors text-ews-gray-400 hover:text-ews-gray-600", iconSizes[size]), children: showPassword ? jsx(EyeOff, { size: 16 }) : jsx(Eye, { size: 16 }) }) }))] }), (error || helperText) && (jsx("p", { className: cn("text-sm", error ? "text-ews-error" : "text-ews-gray-500"), children: error || helperText }))] }));
|
|
518
637
|
});
|
|
519
638
|
Input.displayName = "Input";
|
|
520
639
|
|
|
@@ -1710,6 +1829,65 @@ const Modal = ({ isOpen, onClose, title, children, variant = "info", size = "md"
|
|
|
1710
1829
|
return (jsxs("div", { className: "flex fixed inset-0 z-50 justify-center items-center", children: [jsx("div", { className: "absolute inset-0 backdrop-blur-sm bg-black/50", onClick: handleOverlayClick }), jsxs("div", { className: cn("relative w-full bg-white rounded-lg shadow-xl transition-all transform", "duration-200 animate-in fade-in-0 zoom-in-95", getSizeClasses(), "mx-4", className), role: "dialog", "aria-modal": "true", "aria-labelledby": "modal-title", children: [jsxs("div", { className: cn("flex items-center justify-between p-6 border-b", variantStyles.borderColor), children: [jsxs("div", { className: "flex items-center space-x-3", children: [jsx("div", { className: cn("p-2 rounded-full", variantStyles.iconBg), children: variantStyles.icon }), jsx("h2", { id: "modal-title", className: cn("text-lg font-semibold", variantStyles.titleColor), children: title })] }), jsx("button", { onClick: onClose, className: "p-1 text-gray-400 transition-colors hover:text-gray-600", "aria-label": "Close modal", children: jsx(X, { className: "w-5 h-5" }) })] }), jsx("div", { className: cn("p-6", contentClassName), children: jsx("div", { className: "leading-relaxed text-gray-700", children: error && variant === "error" ? (jsxs("div", { className: "space-y-3", children: [jsx("p", { children: error.message }), error.fields && error.fields.length > 0 && (jsxs("div", { children: [jsx("p", { className: "font-semibold text-gray-900", children: "Erreurs de champ:" }), jsx("ul", { className: "mt-2 space-y-1", children: error.fields.map((field, index) => (jsxs("li", { className: "text-ews-error", children: ["\u2022 ", field.path, ": ", field.message] }, index))) })] }))] })) : (children) }) }), (primaryAction || secondaryAction) && (jsxs("div", { className: "flex justify-end items-center p-6 pt-0 space-x-3", children: [secondaryAction && (jsx(Button, { variant: "outline", onClick: onSecondaryAction || onClose, disabled: isLoading, children: secondaryAction })), primaryAction && (jsx(Button, { variant: variant === "error" ? "error" : "ews-primary", onClick: onPrimaryAction, loading: isLoading, children: primaryAction }))] }))] })] }));
|
|
1711
1830
|
};
|
|
1712
1831
|
|
|
1832
|
+
const SIZE_CLASSES = {
|
|
1833
|
+
sm: "h-10 w-10",
|
|
1834
|
+
md: "h-16 w-16",
|
|
1835
|
+
lg: "h-32 w-32",
|
|
1836
|
+
};
|
|
1837
|
+
const INDICATOR_CLASSES = {
|
|
1838
|
+
sm: "h-2 w-2",
|
|
1839
|
+
md: "h-4 w-4",
|
|
1840
|
+
lg: "h-8 w-8",
|
|
1841
|
+
};
|
|
1842
|
+
function UploadProgressBar({ progress, isLoading, }) {
|
|
1843
|
+
const [visible, setVisible] = useState(false);
|
|
1844
|
+
useEffect(() => {
|
|
1845
|
+
if (isLoading) {
|
|
1846
|
+
setVisible(true);
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
// isLoading just turned false
|
|
1850
|
+
if (progress >= 100) {
|
|
1851
|
+
setVisible(true);
|
|
1852
|
+
const t = setTimeout(() => setVisible(false), 1000);
|
|
1853
|
+
return () => clearTimeout(t);
|
|
1854
|
+
}
|
|
1855
|
+
// Legacy path (no isLoading prop): driven purely by progress
|
|
1856
|
+
if (progress > 0 && progress < 100) {
|
|
1857
|
+
setVisible(true);
|
|
1858
|
+
return;
|
|
1859
|
+
}
|
|
1860
|
+
setVisible(false);
|
|
1861
|
+
}, [progress, isLoading]);
|
|
1862
|
+
if (!visible)
|
|
1863
|
+
return null;
|
|
1864
|
+
const indeterminate = isLoading && progress === 0;
|
|
1865
|
+
return (jsx("div", { className: "mt-2 h-1.5 w-32 rounded-full bg-gray-200", children: jsx("div", { className: cn("h-full rounded-full bg-ews-primary transition-all duration-300", indeterminate && "animate-pulse"), style: { width: indeterminate ? "35%" : `${progress}%` } }) }));
|
|
1866
|
+
}
|
|
1867
|
+
const ProfileImageUpload = ({ imageUrl, altText, readOnly = false, size = "lg", uploadProgress = 0, isLoading = false, showDeleteButton = true, accept = "image/*", maxFileSizeMB = 3, onFileSelect, onFileSizeExceeded, onDeleteConfirm, deleteConfirmTitle, deleteConfirmMessage, deleteConfirmLabel, cancelLabel, }) => {
|
|
1868
|
+
const fileInputRef = useRef(null);
|
|
1869
|
+
const [isHovered, setIsHovered] = useState(false);
|
|
1870
|
+
const [showConfirm, setShowConfirm] = useState(false);
|
|
1871
|
+
const handleEditClick = () => fileInputRef.current?.click();
|
|
1872
|
+
const handleFileChange = (e) => {
|
|
1873
|
+
const file = e.target.files?.[0];
|
|
1874
|
+
if (!file)
|
|
1875
|
+
return;
|
|
1876
|
+
if (file.size > maxFileSizeMB * 1024 * 1024) {
|
|
1877
|
+
onFileSizeExceeded?.();
|
|
1878
|
+
e.target.value = "";
|
|
1879
|
+
return;
|
|
1880
|
+
}
|
|
1881
|
+
onFileSelect(file);
|
|
1882
|
+
e.target.value = ""; // allow re-selecting the same file
|
|
1883
|
+
};
|
|
1884
|
+
const handleConfirmDelete = () => {
|
|
1885
|
+
setShowConfirm(false);
|
|
1886
|
+
onDeleteConfirm();
|
|
1887
|
+
};
|
|
1888
|
+
return (jsxs(Fragment, { children: [jsxs("div", { className: "inline-flex flex-col items-center", children: [jsxs("div", { className: "relative", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsx("img", { src: imageUrl, alt: altText, className: cn("rounded-full border-4 border-white object-cover", SIZE_CLASSES[size]) }), jsx("div", { className: cn("absolute bottom-0 right-0 rounded-full border-4 border-white bg-green-400", INDICATOR_CLASSES[size]) }), jsx("input", { type: "file", ref: fileInputRef, accept: accept, className: "hidden", onChange: handleFileChange }), isHovered && !readOnly && !isLoading && (jsxs(Fragment, { children: [jsx("button", { type: "button", onClick: handleEditClick, className: "absolute left-0 top-0 flex h-8 w-8 cursor-pointer items-center justify-center rounded-full bg-ews-primary transition-colors hover:bg-ews-secondary", "aria-label": "Edit profile image", children: jsx(Pencil, { className: "h-4 w-4 text-white" }) }), showDeleteButton && (jsx("button", { type: "button", onClick: () => setShowConfirm(true), className: "absolute left-0 top-10 flex h-8 w-8 cursor-pointer items-center justify-center rounded-full bg-red-600 transition-colors hover:bg-red-700", "aria-label": "Delete profile image", children: jsx(Trash, { className: "h-4 w-4 text-white" }) }))] }))] }), jsx(UploadProgressBar, { progress: uploadProgress, isLoading: isLoading })] }), jsx(Modal, { isOpen: showConfirm, onClose: () => setShowConfirm(false), title: deleteConfirmTitle, variant: "error", size: "sm", primaryAction: deleteConfirmLabel, secondaryAction: cancelLabel, onPrimaryAction: handleConfirmDelete, onSecondaryAction: () => setShowConfirm(false), children: jsx("p", { children: deleteConfirmMessage }) })] }));
|
|
1889
|
+
};
|
|
1890
|
+
|
|
1713
1891
|
const DropdownMultiSelect = ({ options, name, control, placeholder = "Select options", searchPlaceholder = "Search...", onChange, value: controlledValue, defaultValue, onValidate, disabled = false, error, label, className, }) => {
|
|
1714
1892
|
const [isOpen, setIsOpen] = useState(false);
|
|
1715
1893
|
const [searchTerm, setSearchTerm] = useState("");
|
|
@@ -1996,5 +2174,5 @@ const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesCh
|
|
|
1996
2174
|
: `${selectedSpecialties.length} specialty${selectedSpecialties.length !== 1 ? "ies" : ""} selected` }), maxSelections && (jsxs("span", { className: "text-gray-400", children: [selectedSpecialties.length, "/", maxSelections] }))] }))] }));
|
|
1997
2175
|
};
|
|
1998
2176
|
|
|
1999
|
-
export { ArrowRight, Button, Check, DoctorIcon, DropdownMultiSelect, Icon, Input, Logo, Modal, MultiSearchAutocomplete, PatientIcon, Search, SearchAutocomplete, Select, SpecialtySearchAutocomplete, ThemeDebugger, ThemeProvider, ThemeToggle, UserIcon, cn, debounce, formatCurrency, formatDate, formatNumeric, generateId, isValidPhoneNumber, useDebounce, useDebouncedCallback, useSelectField, useTheme };
|
|
2177
|
+
export { ArrowRight, BLOOD_TYPES, BloodType, Button, Check, DoctorIcon, DropdownMultiSelect, Icon, Input, Logo, Modal, MultiSearchAutocomplete, PatientIcon, ProfileImageUpload, Search, SearchAutocomplete, Select, SpecialtySearchAutocomplete, ThemeDebugger, ThemeProvider, ThemeToggle, UserIcon, cn, createEnvConfig, debounce, formatCurrency, formatDate, formatNumeric, generateId, isValidPhoneNumber, useDebounce, useDebouncedCallback, useSelectField, useTheme };
|
|
2000
2178
|
//# sourceMappingURL=index.esm.js.map
|