@ews-admin/global-design-system 1.1.21 → 1.1.22
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 +75 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.css +1 -1
- package/dist/index.esm.js +148 -24
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +148 -22
- package/dist/index.js.map +1 -1
- package/dist/utils/index.d.ts +19 -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 +5 -0
- package/src/utils/index.ts +31 -0
package/dist/index.js
CHANGED
|
@@ -86,6 +86,36 @@ function isValidPhoneNumber(value) {
|
|
|
86
86
|
const phoneRegex = /^(\+\d{1,17}|\d{1,17})$/;
|
|
87
87
|
return phoneRegex.test(trimmedValue);
|
|
88
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Blood type enum matching backend BloodTypeEnum values
|
|
91
|
+
*/
|
|
92
|
+
exports.BloodType = void 0;
|
|
93
|
+
(function (BloodType) {
|
|
94
|
+
BloodType["A_POSITIVE"] = "A+";
|
|
95
|
+
BloodType["A_NEGATIVE"] = "A-";
|
|
96
|
+
BloodType["B_POSITIVE"] = "B+";
|
|
97
|
+
BloodType["B_NEGATIVE"] = "B-";
|
|
98
|
+
BloodType["AB_POSITIVE"] = "AB+";
|
|
99
|
+
BloodType["AB_NEGATIVE"] = "AB-";
|
|
100
|
+
BloodType["O_POSITIVE"] = "O+";
|
|
101
|
+
BloodType["O_NEGATIVE"] = "O-";
|
|
102
|
+
BloodType["UNKNOWN"] = "UNKNOWN";
|
|
103
|
+
})(exports.BloodType || (exports.BloodType = {}));
|
|
104
|
+
/**
|
|
105
|
+
* Ordered list of all blood type values.
|
|
106
|
+
* Use this to build select/dropdown options.
|
|
107
|
+
*/
|
|
108
|
+
const BLOOD_TYPES = [
|
|
109
|
+
exports.BloodType.A_POSITIVE,
|
|
110
|
+
exports.BloodType.A_NEGATIVE,
|
|
111
|
+
exports.BloodType.B_POSITIVE,
|
|
112
|
+
exports.BloodType.B_NEGATIVE,
|
|
113
|
+
exports.BloodType.AB_POSITIVE,
|
|
114
|
+
exports.BloodType.AB_NEGATIVE,
|
|
115
|
+
exports.BloodType.O_POSITIVE,
|
|
116
|
+
exports.BloodType.O_NEGATIVE,
|
|
117
|
+
exports.BloodType.UNKNOWN,
|
|
118
|
+
];
|
|
89
119
|
|
|
90
120
|
const Button = React.forwardRef(({ className, variant = "ews-primary", size = "md", loading = false, fullWidth = false, leftIcon, rightIcon, children, disabled, ...props }, ref) => {
|
|
91
121
|
const baseStyles = "inline-flex items-center justify-center font-medium rounded-md transition-colors focus:outline-none disabled:opacity-50 disabled:pointer-events-none";
|
|
@@ -229,11 +259,11 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
229
259
|
*/
|
|
230
260
|
|
|
231
261
|
|
|
232
|
-
const __iconNode$
|
|
262
|
+
const __iconNode$e = [
|
|
233
263
|
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
234
264
|
["path", { d: "m12 5 7 7-7 7", key: "xquz4c" }]
|
|
235
265
|
];
|
|
236
|
-
const ArrowRight = createLucideIcon("arrow-right", __iconNode$
|
|
266
|
+
const ArrowRight = createLucideIcon("arrow-right", __iconNode$e);
|
|
237
267
|
|
|
238
268
|
/**
|
|
239
269
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -243,8 +273,8 @@ const ArrowRight = createLucideIcon("arrow-right", __iconNode$c);
|
|
|
243
273
|
*/
|
|
244
274
|
|
|
245
275
|
|
|
246
|
-
const __iconNode$
|
|
247
|
-
const Check = createLucideIcon("check", __iconNode$
|
|
276
|
+
const __iconNode$d = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
277
|
+
const Check = createLucideIcon("check", __iconNode$d);
|
|
248
278
|
|
|
249
279
|
/**
|
|
250
280
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -254,8 +284,8 @@ const Check = createLucideIcon("check", __iconNode$b);
|
|
|
254
284
|
*/
|
|
255
285
|
|
|
256
286
|
|
|
257
|
-
const __iconNode$
|
|
258
|
-
const ChevronDown = createLucideIcon("chevron-down", __iconNode$
|
|
287
|
+
const __iconNode$c = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
288
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$c);
|
|
259
289
|
|
|
260
290
|
/**
|
|
261
291
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -265,12 +295,12 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$a);
|
|
|
265
295
|
*/
|
|
266
296
|
|
|
267
297
|
|
|
268
|
-
const __iconNode$
|
|
298
|
+
const __iconNode$b = [
|
|
269
299
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
270
300
|
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
271
301
|
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
272
302
|
];
|
|
273
|
-
const CircleAlert = createLucideIcon("circle-alert", __iconNode$
|
|
303
|
+
const CircleAlert = createLucideIcon("circle-alert", __iconNode$b);
|
|
274
304
|
|
|
275
305
|
/**
|
|
276
306
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -280,11 +310,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$9);
|
|
|
280
310
|
*/
|
|
281
311
|
|
|
282
312
|
|
|
283
|
-
const __iconNode$
|
|
313
|
+
const __iconNode$a = [
|
|
284
314
|
["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
|
|
285
315
|
["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
|
|
286
316
|
];
|
|
287
|
-
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$
|
|
317
|
+
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$a);
|
|
288
318
|
|
|
289
319
|
/**
|
|
290
320
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -294,7 +324,7 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$8);
|
|
|
294
324
|
*/
|
|
295
325
|
|
|
296
326
|
|
|
297
|
-
const __iconNode$
|
|
327
|
+
const __iconNode$9 = [
|
|
298
328
|
[
|
|
299
329
|
"path",
|
|
300
330
|
{
|
|
@@ -312,7 +342,7 @@ const __iconNode$7 = [
|
|
|
312
342
|
],
|
|
313
343
|
["path", { d: "m2 2 20 20", key: "1ooewy" }]
|
|
314
344
|
];
|
|
315
|
-
const EyeOff = createLucideIcon("eye-off", __iconNode$
|
|
345
|
+
const EyeOff = createLucideIcon("eye-off", __iconNode$9);
|
|
316
346
|
|
|
317
347
|
/**
|
|
318
348
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -322,7 +352,7 @@ const EyeOff = createLucideIcon("eye-off", __iconNode$7);
|
|
|
322
352
|
*/
|
|
323
353
|
|
|
324
354
|
|
|
325
|
-
const __iconNode$
|
|
355
|
+
const __iconNode$8 = [
|
|
326
356
|
[
|
|
327
357
|
"path",
|
|
328
358
|
{
|
|
@@ -332,7 +362,7 @@ const __iconNode$6 = [
|
|
|
332
362
|
],
|
|
333
363
|
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
334
364
|
];
|
|
335
|
-
const Eye = createLucideIcon("eye", __iconNode$
|
|
365
|
+
const Eye = createLucideIcon("eye", __iconNode$8);
|
|
336
366
|
|
|
337
367
|
/**
|
|
338
368
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -342,7 +372,7 @@ const Eye = createLucideIcon("eye", __iconNode$6);
|
|
|
342
372
|
*/
|
|
343
373
|
|
|
344
374
|
|
|
345
|
-
const __iconNode$
|
|
375
|
+
const __iconNode$7 = [
|
|
346
376
|
[
|
|
347
377
|
"path",
|
|
348
378
|
{
|
|
@@ -351,7 +381,7 @@ const __iconNode$5 = [
|
|
|
351
381
|
}
|
|
352
382
|
]
|
|
353
383
|
];
|
|
354
|
-
const Heart = createLucideIcon("heart", __iconNode$
|
|
384
|
+
const Heart = createLucideIcon("heart", __iconNode$7);
|
|
355
385
|
|
|
356
386
|
/**
|
|
357
387
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -361,11 +391,31 @@ const Heart = createLucideIcon("heart", __iconNode$5);
|
|
|
361
391
|
*/
|
|
362
392
|
|
|
363
393
|
|
|
364
|
-
const __iconNode$
|
|
394
|
+
const __iconNode$6 = [
|
|
395
|
+
[
|
|
396
|
+
"path",
|
|
397
|
+
{
|
|
398
|
+
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",
|
|
399
|
+
key: "1a8usu"
|
|
400
|
+
}
|
|
401
|
+
],
|
|
402
|
+
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
403
|
+
];
|
|
404
|
+
const Pencil = createLucideIcon("pencil", __iconNode$6);
|
|
405
|
+
|
|
406
|
+
/**
|
|
407
|
+
* @license lucide-react v0.544.0 - ISC
|
|
408
|
+
*
|
|
409
|
+
* This source code is licensed under the ISC license.
|
|
410
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
411
|
+
*/
|
|
412
|
+
|
|
413
|
+
|
|
414
|
+
const __iconNode$5 = [
|
|
365
415
|
["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
|
|
366
416
|
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
|
|
367
417
|
];
|
|
368
|
-
const Search = createLucideIcon("search", __iconNode$
|
|
418
|
+
const Search = createLucideIcon("search", __iconNode$5);
|
|
369
419
|
|
|
370
420
|
/**
|
|
371
421
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -375,14 +425,29 @@ const Search = createLucideIcon("search", __iconNode$4);
|
|
|
375
425
|
*/
|
|
376
426
|
|
|
377
427
|
|
|
378
|
-
const __iconNode$
|
|
428
|
+
const __iconNode$4 = [
|
|
379
429
|
["path", { d: "M11 2v2", key: "1539x4" }],
|
|
380
430
|
["path", { d: "M5 2v2", key: "1yf1q8" }],
|
|
381
431
|
["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" }],
|
|
382
432
|
["path", { d: "M8 15a6 6 0 0 0 12 0v-3", key: "x18d4x" }],
|
|
383
433
|
["circle", { cx: "20", cy: "10", r: "2", key: "ts1r5v" }]
|
|
384
434
|
];
|
|
385
|
-
const Stethoscope = createLucideIcon("stethoscope", __iconNode$
|
|
435
|
+
const Stethoscope = createLucideIcon("stethoscope", __iconNode$4);
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* @license lucide-react v0.544.0 - ISC
|
|
439
|
+
*
|
|
440
|
+
* This source code is licensed under the ISC license.
|
|
441
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
442
|
+
*/
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
const __iconNode$3 = [
|
|
446
|
+
["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", key: "miytrc" }],
|
|
447
|
+
["path", { d: "M3 6h18", key: "d0wm0j" }],
|
|
448
|
+
["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2", key: "e791ji" }]
|
|
449
|
+
];
|
|
450
|
+
const Trash = createLucideIcon("trash", __iconNode$3);
|
|
386
451
|
|
|
387
452
|
/**
|
|
388
453
|
* @license lucide-react v0.544.0 - ISC
|
|
@@ -457,7 +522,7 @@ const UserIcon = ({ size = 24, color = "currentColor", className = "", ...props
|
|
|
457
522
|
return jsxRuntime.jsx(User, { size: size, color: color, className: className, ...props });
|
|
458
523
|
};
|
|
459
524
|
|
|
460
|
-
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) => {
|
|
525
|
+
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) => {
|
|
461
526
|
const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
|
|
462
527
|
const hasError = Boolean(error);
|
|
463
528
|
const actualVariant = hasError ? "error" : variant;
|
|
@@ -516,7 +581,7 @@ const Input = React.forwardRef(({ className, variant = "default", size = "md", l
|
|
|
516
581
|
countryCodeSelect.onChange(item.code);
|
|
517
582
|
setIsDropdownOpen(false);
|
|
518
583
|
}, 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: [jsxRuntime.jsx("span", { className: "font-medium", children: item.code }), item.country && (jsxRuntime.jsx("span", { className: cn("ml-2 text-xs", isSelected ? "text-white/80" : "text-ews-gray-500"), children: item.country }))] }, item.code));
|
|
519
|
-
}) }))] }) })), leftIcon && !countryCodeSelect && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none", children: jsxRuntime.jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: leftIcon }) })), jsxRuntime.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 && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 right-0 items-center pr-3 pointer-events-none", children: jsxRuntime.jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: rightIcon }) })), shouldShowPasswordToggle && (jsxRuntime.jsx("button", { type: "button", className: "flex absolute inset-y-0 right-0 items-center pr-3", onClick: () => setShowPassword(!showPassword), tabIndex: -1, children: jsxRuntime.jsx("span", { className: cn("transition-colors text-ews-gray-400 hover:text-ews-gray-600", iconSizes[size]), children: showPassword ? jsxRuntime.jsx(EyeOff, { size: 16 }) : jsxRuntime.jsx(Eye, { size: 16 }) }) }))] }), (error || helperText) && (jsxRuntime.jsx("p", { className: cn("text-sm", error ? "text-ews-error" : "text-ews-gray-500"), children: error || helperText }))] }));
|
|
584
|
+
}) }))] }) })), leftIcon && !countryCodeSelect && !leftAddon && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 left-0 items-center pl-3 pointer-events-none", children: jsxRuntime.jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: leftIcon }) })), leftAddon && !countryCodeSelect && !leftIcon && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 left-0 items-center pointer-events-none overflow-hidden rounded-l-md", children: jsxRuntime.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 }) })), jsxRuntime.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 && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 right-0 items-center pr-3 pointer-events-none", children: jsxRuntime.jsx("span", { className: "text-sm font-medium text-ews-gray-500", children: rightAddon }) })), rightIcon && !shouldShowPasswordToggle && (jsxRuntime.jsx("div", { className: "flex absolute inset-y-0 right-0 items-center pr-3 pointer-events-none", children: jsxRuntime.jsx("span", { className: cn("text-ews-gray-400", iconSizes[size]), children: rightIcon }) })), shouldShowPasswordToggle && (jsxRuntime.jsx("button", { type: "button", className: "flex absolute inset-y-0 right-0 items-center pr-3", onClick: () => setShowPassword(!showPassword), tabIndex: -1, children: jsxRuntime.jsx("span", { className: cn("transition-colors text-ews-gray-400 hover:text-ews-gray-600", iconSizes[size]), children: showPassword ? jsxRuntime.jsx(EyeOff, { size: 16 }) : jsxRuntime.jsx(Eye, { size: 16 }) }) }))] }), (error || helperText) && (jsxRuntime.jsx("p", { className: cn("text-sm", error ? "text-ews-error" : "text-ews-gray-500"), children: error || helperText }))] }));
|
|
520
585
|
});
|
|
521
586
|
Input.displayName = "Input";
|
|
522
587
|
|
|
@@ -1712,6 +1777,65 @@ const Modal = ({ isOpen, onClose, title, children, variant = "info", size = "md"
|
|
|
1712
1777
|
return (jsxRuntime.jsxs("div", { className: "flex fixed inset-0 z-50 justify-center items-center", children: [jsxRuntime.jsx("div", { className: "absolute inset-0 backdrop-blur-sm bg-black/50", onClick: handleOverlayClick }), jsxRuntime.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: [jsxRuntime.jsxs("div", { className: cn("flex items-center justify-between p-6 border-b", variantStyles.borderColor), children: [jsxRuntime.jsxs("div", { className: "flex items-center space-x-3", children: [jsxRuntime.jsx("div", { className: cn("p-2 rounded-full", variantStyles.iconBg), children: variantStyles.icon }), jsxRuntime.jsx("h2", { id: "modal-title", className: cn("text-lg font-semibold", variantStyles.titleColor), children: title })] }), jsxRuntime.jsx("button", { onClick: onClose, className: "p-1 text-gray-400 transition-colors hover:text-gray-600", "aria-label": "Close modal", children: jsxRuntime.jsx(X, { className: "w-5 h-5" }) })] }), jsxRuntime.jsx("div", { className: cn("p-6", contentClassName), children: jsxRuntime.jsx("div", { className: "leading-relaxed text-gray-700", children: error && variant === "error" ? (jsxRuntime.jsxs("div", { className: "space-y-3", children: [jsxRuntime.jsx("p", { children: error.message }), error.fields && error.fields.length > 0 && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("p", { className: "font-semibold text-gray-900", children: "Erreurs de champ:" }), jsxRuntime.jsx("ul", { className: "mt-2 space-y-1", children: error.fields.map((field, index) => (jsxRuntime.jsxs("li", { className: "text-ews-error", children: ["\u2022 ", field.path, ": ", field.message] }, index))) })] }))] })) : (children) }) }), (primaryAction || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex justify-end items-center p-6 pt-0 space-x-3", children: [secondaryAction && (jsxRuntime.jsx(Button, { variant: "outline", onClick: onSecondaryAction || onClose, disabled: isLoading, children: secondaryAction })), primaryAction && (jsxRuntime.jsx(Button, { variant: variant === "error" ? "error" : "ews-primary", onClick: onPrimaryAction, loading: isLoading, children: primaryAction }))] }))] })] }));
|
|
1713
1778
|
};
|
|
1714
1779
|
|
|
1780
|
+
const SIZE_CLASSES = {
|
|
1781
|
+
sm: "h-10 w-10",
|
|
1782
|
+
md: "h-16 w-16",
|
|
1783
|
+
lg: "h-32 w-32",
|
|
1784
|
+
};
|
|
1785
|
+
const INDICATOR_CLASSES = {
|
|
1786
|
+
sm: "h-2 w-2",
|
|
1787
|
+
md: "h-4 w-4",
|
|
1788
|
+
lg: "h-8 w-8",
|
|
1789
|
+
};
|
|
1790
|
+
function UploadProgressBar({ progress, isLoading, }) {
|
|
1791
|
+
const [visible, setVisible] = React.useState(false);
|
|
1792
|
+
React.useEffect(() => {
|
|
1793
|
+
if (isLoading) {
|
|
1794
|
+
setVisible(true);
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
// isLoading just turned false
|
|
1798
|
+
if (progress >= 100) {
|
|
1799
|
+
setVisible(true);
|
|
1800
|
+
const t = setTimeout(() => setVisible(false), 1000);
|
|
1801
|
+
return () => clearTimeout(t);
|
|
1802
|
+
}
|
|
1803
|
+
// Legacy path (no isLoading prop): driven purely by progress
|
|
1804
|
+
if (progress > 0 && progress < 100) {
|
|
1805
|
+
setVisible(true);
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1808
|
+
setVisible(false);
|
|
1809
|
+
}, [progress, isLoading]);
|
|
1810
|
+
if (!visible)
|
|
1811
|
+
return null;
|
|
1812
|
+
const indeterminate = isLoading && progress === 0;
|
|
1813
|
+
return (jsxRuntime.jsx("div", { className: "mt-2 h-1.5 w-32 rounded-full bg-gray-200", children: jsxRuntime.jsx("div", { className: cn("h-full rounded-full bg-ews-primary transition-all duration-300", indeterminate && "animate-pulse"), style: { width: indeterminate ? "35%" : `${progress}%` } }) }));
|
|
1814
|
+
}
|
|
1815
|
+
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, }) => {
|
|
1816
|
+
const fileInputRef = React.useRef(null);
|
|
1817
|
+
const [isHovered, setIsHovered] = React.useState(false);
|
|
1818
|
+
const [showConfirm, setShowConfirm] = React.useState(false);
|
|
1819
|
+
const handleEditClick = () => fileInputRef.current?.click();
|
|
1820
|
+
const handleFileChange = (e) => {
|
|
1821
|
+
const file = e.target.files?.[0];
|
|
1822
|
+
if (!file)
|
|
1823
|
+
return;
|
|
1824
|
+
if (file.size > maxFileSizeMB * 1024 * 1024) {
|
|
1825
|
+
onFileSizeExceeded?.();
|
|
1826
|
+
e.target.value = "";
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
onFileSelect(file);
|
|
1830
|
+
e.target.value = ""; // allow re-selecting the same file
|
|
1831
|
+
};
|
|
1832
|
+
const handleConfirmDelete = () => {
|
|
1833
|
+
setShowConfirm(false);
|
|
1834
|
+
onDeleteConfirm();
|
|
1835
|
+
};
|
|
1836
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("div", { className: "inline-flex flex-col items-center", children: [jsxRuntime.jsxs("div", { className: "relative", onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), children: [jsxRuntime.jsx("img", { src: imageUrl, alt: altText, className: cn("rounded-full border-4 border-white object-cover", SIZE_CLASSES[size]) }), jsxRuntime.jsx("div", { className: cn("absolute bottom-0 right-0 rounded-full border-4 border-white bg-green-400", INDICATOR_CLASSES[size]) }), jsxRuntime.jsx("input", { type: "file", ref: fileInputRef, accept: accept, className: "hidden", onChange: handleFileChange }), isHovered && !readOnly && !isLoading && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.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: jsxRuntime.jsx(Pencil, { className: "h-4 w-4 text-white" }) }), showDeleteButton && (jsxRuntime.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: jsxRuntime.jsx(Trash, { className: "h-4 w-4 text-white" }) }))] }))] }), jsxRuntime.jsx(UploadProgressBar, { progress: uploadProgress, isLoading: isLoading })] }), jsxRuntime.jsx(Modal, { isOpen: showConfirm, onClose: () => setShowConfirm(false), title: deleteConfirmTitle, variant: "error", size: "sm", primaryAction: deleteConfirmLabel, secondaryAction: cancelLabel, onPrimaryAction: handleConfirmDelete, onSecondaryAction: () => setShowConfirm(false), children: jsxRuntime.jsx("p", { children: deleteConfirmMessage }) })] }));
|
|
1837
|
+
};
|
|
1838
|
+
|
|
1715
1839
|
const DropdownMultiSelect = ({ options, name, control, placeholder = "Select options", searchPlaceholder = "Search...", onChange, value: controlledValue, defaultValue, onValidate, disabled = false, error, label, className, }) => {
|
|
1716
1840
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
1717
1841
|
const [searchTerm, setSearchTerm] = React.useState("");
|
|
@@ -1999,6 +2123,7 @@ const SpecialtySearchAutocomplete = ({ selectedSpecialties = [], onSpecialtiesCh
|
|
|
1999
2123
|
};
|
|
2000
2124
|
|
|
2001
2125
|
exports.ArrowRight = ArrowRight;
|
|
2126
|
+
exports.BLOOD_TYPES = BLOOD_TYPES;
|
|
2002
2127
|
exports.Button = Button;
|
|
2003
2128
|
exports.Check = Check;
|
|
2004
2129
|
exports.DoctorIcon = DoctorIcon;
|
|
@@ -2009,6 +2134,7 @@ exports.Logo = Logo;
|
|
|
2009
2134
|
exports.Modal = Modal;
|
|
2010
2135
|
exports.MultiSearchAutocomplete = MultiSearchAutocomplete;
|
|
2011
2136
|
exports.PatientIcon = PatientIcon;
|
|
2137
|
+
exports.ProfileImageUpload = ProfileImageUpload;
|
|
2012
2138
|
exports.Search = Search;
|
|
2013
2139
|
exports.SearchAutocomplete = SearchAutocomplete;
|
|
2014
2140
|
exports.Select = Select;
|