medos-sdk 1.1.9 → 1.1.11

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.
Files changed (118) hide show
  1. package/dist/client/MedosClient.d.ts +1 -0
  2. package/dist/client/MedosClient.js +7 -0
  3. package/dist/components/AppointmentCalender.js +22 -8
  4. package/dist/components/AppointmentConfirmationStep.d.ts +4 -0
  5. package/dist/components/AppointmentConfirmationStep.js +50 -52
  6. package/dist/components/AppointmentDateTimeModal.d.ts +4 -0
  7. package/dist/components/AppointmentDateTimeModal.js +216 -165
  8. package/dist/components/AppointmentSummaryStep.d.ts +12 -0
  9. package/dist/components/AppointmentSummaryStep.js +168 -0
  10. package/dist/components/BookingOptionStep.d.ts +14 -0
  11. package/dist/components/BookingOptionStep.js +346 -0
  12. package/dist/components/ContactInformationStep.js +13 -6
  13. package/dist/components/ContactPreferenceStep.js +16 -6
  14. package/dist/components/DoctorSelectModal.d.ts +5 -0
  15. package/dist/components/DoctorSelectModal.js +169 -74
  16. package/dist/components/EnquiryForm.js +84 -72
  17. package/dist/components/Icons/CloseIcon.d.ts +9 -0
  18. package/dist/components/Icons/CloseIcon.js +5 -0
  19. package/dist/components/InquiryDetailsStep.js +11 -6
  20. package/dist/components/PatientDetailsStep.js +17 -12
  21. package/dist/components/PatientSelectionStep.d.ts +12 -0
  22. package/dist/components/PatientSelectionStep.js +254 -0
  23. package/dist/components/PhoneVerificationStep.js +1 -1
  24. package/dist/components/SuccessStep.js +1 -1
  25. package/dist/components/appointment-booking/AppointmentCalender.d.ts +5 -0
  26. package/dist/components/appointment-booking/AppointmentCalender.js +247 -0
  27. package/dist/components/appointment-booking/hooks/index.d.ts +3 -0
  28. package/dist/components/appointment-booking/hooks/index.js +3 -0
  29. package/dist/components/appointment-booking/hooks/useAppointmentFlow.d.ts +8 -0
  30. package/dist/components/appointment-booking/hooks/useAppointmentFlow.js +318 -0
  31. package/dist/components/appointment-booking/hooks/useAppointmentState.d.ts +9 -0
  32. package/dist/components/appointment-booking/hooks/useAppointmentState.js +125 -0
  33. package/dist/components/appointment-booking/hooks/useInitializeAddresses.d.ts +1 -0
  34. package/dist/components/appointment-booking/hooks/useInitializeAddresses.js +55 -0
  35. package/dist/components/appointment-booking/index.d.ts +5 -0
  36. package/dist/components/appointment-booking/index.js +3 -0
  37. package/dist/components/appointment-booking/types.d.ts +291 -0
  38. package/dist/components/appointment-booking/types.js +49 -0
  39. package/dist/components/appointment-modal-styles.d.ts +259 -0
  40. package/dist/components/appointment-modal-styles.js +395 -0
  41. package/dist/components/constant.d.ts +2 -0
  42. package/dist/components/constant.js +15 -0
  43. package/dist/components/custom-calendar.js +20 -11
  44. package/dist/components/styles.js +93 -52
  45. package/dist/components/theme-styles.d.ts +5 -4
  46. package/dist/components/theme-styles.js +221 -125
  47. package/dist/components/types.d.ts +12 -139
  48. package/dist/components/types.js +15 -32
  49. package/dist/components/uiComponents/SelectDropdown.d.ts +1 -1
  50. package/dist/components/uiComponents/SelectDropdown.js +24 -24
  51. package/dist/components/utils.d.ts +3 -0
  52. package/dist/components/utils.js +59 -0
  53. package/dist/components/validation.d.ts +2 -0
  54. package/dist/components/validation.js +41 -0
  55. package/dist/core/theme/index.d.ts +1 -0
  56. package/dist/core/theme/index.js +1 -0
  57. package/dist/core/theme/responsive.d.ts +15 -0
  58. package/dist/core/theme/responsive.js +113 -0
  59. package/dist/core/theme/themes.js +16 -4
  60. package/dist/core/theme/types.d.ts +8 -0
  61. package/dist/enquiry-form/validation.js +1 -1
  62. package/dist/index.d.ts +3 -1
  63. package/dist/index.js +2 -1
  64. package/dist/react/ThemeProvider.d.ts +2 -1
  65. package/dist/react/ThemeProvider.js +49 -10
  66. package/dist/react/index.d.ts +2 -1
  67. package/dist/react/index.js +1 -1
  68. package/dist/services/AppointmentService.d.ts +80 -2
  69. package/dist/services/AppointmentService.js +114 -5
  70. package/dist/services/WorkspaceService.d.ts +58 -3
  71. package/dist/services/WorkspaceService.js +10 -1
  72. package/dist/vanilla/AppointmentCalendarWidget.d.ts +9 -7
  73. package/dist/vanilla/AppointmentCalendarWidget.js +834 -384
  74. package/dist/vanilla/EnquiryFormWidget.d.ts +1 -0
  75. package/dist/vanilla/EnquiryFormWidget.js +25 -43
  76. package/dist/vanilla/client/MedosClient.d.ts +1 -0
  77. package/dist/vanilla/components/AppointmentConfirmationStep.d.ts +4 -0
  78. package/dist/vanilla/components/AppointmentDateTimeModal.d.ts +4 -0
  79. package/dist/vanilla/components/AppointmentSummaryStep.d.ts +12 -0
  80. package/dist/vanilla/components/BookingOptionStep.d.ts +14 -0
  81. package/dist/vanilla/components/DoctorSelectModal.d.ts +5 -0
  82. package/dist/vanilla/components/Icons/CloseIcon.d.ts +9 -0
  83. package/dist/vanilla/components/PatientSelectionStep.d.ts +12 -0
  84. package/dist/vanilla/components/VanillaCalendar.js +33 -18
  85. package/dist/vanilla/components/VanillaIcons.d.ts +5 -0
  86. package/dist/vanilla/components/VanillaIcons.js +92 -0
  87. package/dist/vanilla/components/VanillaSelect.d.ts +3 -0
  88. package/dist/vanilla/components/VanillaSelect.js +93 -5
  89. package/dist/vanilla/components/appointment-booking/AppointmentCalender.d.ts +5 -0
  90. package/dist/vanilla/components/appointment-booking/hooks/index.d.ts +3 -0
  91. package/dist/vanilla/components/appointment-booking/hooks/useAppointmentFlow.d.ts +8 -0
  92. package/dist/vanilla/components/appointment-booking/hooks/useAppointmentState.d.ts +9 -0
  93. package/dist/vanilla/components/appointment-booking/hooks/useInitializeAddresses.d.ts +1 -0
  94. package/dist/vanilla/components/appointment-booking/index.d.ts +5 -0
  95. package/dist/vanilla/components/appointment-booking/types.d.ts +291 -0
  96. package/dist/vanilla/components/appointment-modal-styles.d.ts +259 -0
  97. package/dist/vanilla/components/constant.d.ts +2 -0
  98. package/dist/vanilla/components/theme-styles.d.ts +5 -4
  99. package/dist/vanilla/components/types.d.ts +12 -139
  100. package/dist/vanilla/components/uiComponents/SelectDropdown.d.ts +1 -1
  101. package/dist/vanilla/components/utils.d.ts +3 -0
  102. package/dist/vanilla/components/validation.d.ts +2 -0
  103. package/dist/vanilla/core/theme/index.d.ts +1 -0
  104. package/dist/vanilla/core/theme/responsive.d.ts +15 -0
  105. package/dist/vanilla/core/theme/types.d.ts +8 -0
  106. package/dist/vanilla/enquiry-widget.js +374 -53
  107. package/dist/vanilla/index.d.ts +3 -1
  108. package/dist/vanilla/react/ThemeProvider.d.ts +2 -1
  109. package/dist/vanilla/react/index.d.ts +2 -1
  110. package/dist/vanilla/services/AppointmentService.d.ts +80 -2
  111. package/dist/vanilla/services/WorkspaceService.d.ts +58 -3
  112. package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +9 -7
  113. package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +1 -0
  114. package/dist/vanilla/vanilla/components/VanillaIcons.d.ts +5 -0
  115. package/dist/vanilla/vanilla/components/VanillaSelect.d.ts +3 -0
  116. package/dist/vanilla/widget.css +833 -207
  117. package/dist/vanilla/widget.js +6463 -5687
  118. package/package.json +1 -1
@@ -1,20 +1,19 @@
1
- import { Doctor, Slot, AddressItem } from "../services/AppointmentService";
2
- export type AppointmentCalenderProps = {
3
- onError?: (err: Error) => void;
4
- };
1
+ export type { AppointmentState, AppointmentAction, Patient, SessionPack, AvailablePackage, BookingOptionType, } from "./appointment-booking/types";
2
+ export { INITIAL_STATE } from "./appointment-booking/types";
5
3
  export type PhoneVerificationStepProps = {
6
- state: AppointmentState;
7
- dispatch: React.Dispatch<AppointmentAction>;
4
+ state: any;
5
+ dispatch: React.Dispatch<any>;
8
6
  onSendOtp: () => Promise<void>;
9
7
  onVerifyOtp: () => Promise<void>;
10
8
  onBack: () => void;
11
9
  onContinue: () => void;
12
10
  };
13
11
  export type PatientDetailsStepProps = {
14
- state: AppointmentState;
15
- dispatch: React.Dispatch<AppointmentAction>;
12
+ state: any;
13
+ dispatch: React.Dispatch<any>;
16
14
  onBack: () => void;
17
15
  onSubmit: () => Promise<void>;
16
+ isFirstStep?: boolean;
18
17
  };
19
18
  export type SuccessStepProps = {
20
19
  onReset: () => void;
@@ -33,138 +32,12 @@ export type OtpInputSectionProps = {
33
32
  onOtpChange: (code: string) => void;
34
33
  };
35
34
  export type PatientInfoSectionProps = {
36
- state: AppointmentState;
37
- dispatch: React.Dispatch<AppointmentAction>;
35
+ state: any;
36
+ dispatch: React.Dispatch<any>;
38
37
  };
39
38
  export type AddressInfoSectionProps = {
40
- state: AppointmentState;
41
- dispatch: React.Dispatch<AppointmentAction>;
42
- };
43
- export interface AppointmentState {
44
- step: number;
45
- loading: boolean;
46
- error: string | null;
47
- workspaceId: number | null;
48
- addresses: AddressItem[];
49
- addressDoctorsMap: Record<number, Doctor[]>;
50
- selectedAddress: number | null;
51
- selectedDoctor: number | null;
52
- selectedDate: Date;
53
- slots: Slot[];
54
- selectedSlot: Slot | null;
55
- consultationMode: "ONLINE" | "OFFLINE";
56
- consultationCharge: string;
57
- patientName: string;
58
- patientAge: string;
59
- patientEmail: string;
60
- patientGender: string;
61
- bloodGroup: string;
62
- patientAddress: string;
63
- patientCity: string;
64
- patientState: string;
65
- patientCountry: string;
66
- patientZipcode: string;
67
- patientLandmark: string;
68
- countryCode: string;
69
- patientPhone: string;
70
- otpCode: string;
71
- otpSent: boolean;
72
- otpVerified: boolean;
73
- otpSending: boolean;
74
- otpVerifying: boolean;
75
- }
76
- export type AppointmentAction = {
77
- type: "SET_STEP";
78
- payload: number;
79
- } | {
80
- type: "SET_LOADING";
81
- payload: boolean;
82
- } | {
83
- type: "SET_ERROR";
84
- payload: string | null;
85
- } | {
86
- type: "SET_WORKSPACE";
87
- payload: {
88
- id: number;
89
- addresses: AddressItem[];
90
- };
91
- } | {
92
- type: "SET_SELECTED_ADDRESS";
93
- payload: number | null;
94
- } | {
95
- type: "SET_SELECTED_DOCTOR";
96
- payload: number | null;
97
- } | {
98
- type: "SET_SELECTED_DATE";
99
- payload: Date;
100
- } | {
101
- type: "SET_SLOTS";
102
- payload: Slot[];
103
- } | {
104
- type: "SET_SELECTED_SLOT";
105
- payload: Slot | null;
106
- } | {
107
- type: "SET_CONSULTATION_MODE";
108
- payload: "ONLINE" | "OFFLINE";
109
- } | {
110
- type: "SET_CONSULTATION_CHARGE";
111
- payload: string;
112
- } | {
113
- type: "SET_PATIENT_NAME";
114
- payload: string;
115
- } | {
116
- type: "SET_PATIENT_AGE";
117
- payload: string;
118
- } | {
119
- type: "SET_PATIENT_EMAIL";
120
- payload: string;
121
- } | {
122
- type: "SET_PATIENT_GENDER";
123
- payload: string;
124
- } | {
125
- type: "SET_BLOOD_GROUP";
126
- payload: string;
127
- } | {
128
- type: "SET_PATIENT_ADDRESS";
129
- payload: string;
130
- } | {
131
- type: "SET_PATIENT_CITY";
132
- payload: string;
133
- } | {
134
- type: "SET_PATIENT_STATE";
135
- payload: string;
136
- } | {
137
- type: "SET_PATIENT_COUNTRY";
138
- payload: string;
139
- } | {
140
- type: "SET_PATIENT_ZIPCODE";
141
- payload: string;
142
- } | {
143
- type: "SET_PATIENT_LANDMARK";
144
- payload: string;
145
- } | {
146
- type: "SET_COUNTRY_CODE";
147
- payload: string;
148
- } | {
149
- type: "SET_PATIENT_PHONE";
150
- payload: string;
151
- } | {
152
- type: "SET_OTP_CODE";
153
- payload: string;
154
- } | {
155
- type: "SET_OTP_SENT";
156
- payload: boolean;
157
- } | {
158
- type: "SET_OTP_VERIFIED";
159
- payload: boolean;
160
- } | {
161
- type: "SET_OTP_SENDING";
162
- payload: boolean;
163
- } | {
164
- type: "SET_OTP_VERIFYING";
165
- payload: boolean;
166
- } | {
167
- type: "RESET_FORM";
39
+ state: any;
40
+ dispatch: React.Dispatch<any>;
168
41
  };
169
42
  export declare const COUNTRY_CODES: {
170
43
  code: string;
@@ -178,4 +51,4 @@ export declare const BLOOD_GROUP_OPTIONS: {
178
51
  value: string;
179
52
  label: string;
180
53
  }[];
181
- export declare const INITIAL_STATE: AppointmentState;
54
+ export declare const mapBloodGroupToApi: (uiBloodGroup: string) => string;
@@ -1,3 +1,4 @@
1
+ export { INITIAL_STATE } from "./appointment-booking/types";
1
2
  export const COUNTRY_CODES = [
2
3
  { code: "+91", label: "🇮🇳 +91" },
3
4
  { code: "+1", label: "🇺🇸 +1" },
@@ -19,37 +20,19 @@ export const BLOOD_GROUP_OPTIONS = [
19
20
  { value: "AB-", label: "AB-" },
20
21
  { value: "O+", label: "O+" },
21
22
  { value: "O-", label: "O-" },
23
+ { value: "UNKNOWN", label: "Unknown" },
22
24
  ];
23
- export const INITIAL_STATE = {
24
- step: 0,
25
- loading: false,
26
- error: null,
27
- workspaceId: null,
28
- addresses: [],
29
- addressDoctorsMap: {},
30
- selectedAddress: null,
31
- selectedDoctor: null,
32
- selectedDate: new Date(),
33
- slots: [],
34
- selectedSlot: null,
35
- consultationMode: "OFFLINE",
36
- consultationCharge: "",
37
- patientName: "",
38
- patientAge: "",
39
- patientEmail: "",
40
- patientGender: "",
41
- bloodGroup: "",
42
- patientAddress: "",
43
- patientCity: "",
44
- patientState: "",
45
- patientCountry: "",
46
- patientZipcode: "",
47
- patientLandmark: "",
48
- countryCode: "+91",
49
- patientPhone: "",
50
- otpCode: "",
51
- otpSent: false,
52
- otpVerified: false,
53
- otpSending: false,
54
- otpVerifying: false,
25
+ export const mapBloodGroupToApi = (uiBloodGroup) => {
26
+ const bloodGroupMap = {
27
+ "A+": "A_POSITIVE",
28
+ "A-": "A_NEGATIVE",
29
+ "B+": "B_POSITIVE",
30
+ "B-": "B_NEGATIVE",
31
+ "AB+": "AB_POSITIVE",
32
+ "AB-": "AB_NEGATIVE",
33
+ "O+": "O_POSITIVE",
34
+ "O-": "O_NEGATIVE",
35
+ UNKNOWN: "UNKNOWN",
36
+ };
37
+ return bloodGroupMap[uiBloodGroup] || "UNKNOWN";
55
38
  };
@@ -1,4 +1,4 @@
1
- import * as React from 'react';
1
+ import * as React from "react";
2
2
  interface SelectProps {
3
3
  children: React.ReactNode;
4
4
  value?: string;
@@ -1,14 +1,14 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { ChevronDownIcon } from '../Icons/ChevronDownIcon';
4
- import { Check } from '../Icons/Check';
2
+ import * as React from "react";
3
+ import { ChevronDownIcon } from "../Icons/ChevronDownIcon";
4
+ import { Check } from "../Icons/Check";
5
5
  const cn = (...classes) => {
6
- return classes.filter(Boolean).join(' ');
6
+ return classes.filter(Boolean).join(" ");
7
7
  };
8
- if (typeof document !== 'undefined') {
9
- const styleId = 'custom-select-styles';
8
+ if (typeof document !== "undefined") {
9
+ const styleId = "custom-select-styles";
10
10
  if (!document.getElementById(styleId)) {
11
- const styleElement = document.createElement('style');
11
+ const styleElement = document.createElement("style");
12
12
  styleElement.id = styleId;
13
13
  styleElement.innerHTML = `
14
14
  /* Container */
@@ -226,14 +226,14 @@ const SelectContext = React.createContext(undefined);
226
226
  const useSelectContext = () => {
227
227
  const context = React.useContext(SelectContext);
228
228
  if (!context) {
229
- throw new Error('Select components must be used within a Select');
229
+ throw new Error("Select components must be used within a Select");
230
230
  }
231
231
  return context;
232
232
  };
233
- const Select = ({ children, value, onValueChange, defaultValue, disabled = false }) => {
233
+ const Select = ({ children, value, onValueChange, defaultValue, disabled = false, }) => {
234
234
  const [isOpen, setIsOpen] = React.useState(false);
235
- const [selectedValue, setSelectedValue] = React.useState(value || defaultValue || '');
236
- const [selectedLabel, setSelectedLabel] = React.useState('');
235
+ const [selectedValue, setSelectedValue] = React.useState(value || defaultValue || "");
236
+ const [selectedLabel, setSelectedLabel] = React.useState("");
237
237
  const triggerRef = React.useRef(null);
238
238
  const contentRef = React.useRef(null);
239
239
  React.useEffect(() => {
@@ -251,8 +251,8 @@ const Select = ({ children, value, onValueChange, defaultValue, disabled = false
251
251
  }
252
252
  };
253
253
  if (isOpen) {
254
- document.addEventListener('mousedown', handleClickOutside);
255
- return () => document.removeEventListener('mousedown', handleClickOutside);
254
+ document.addEventListener("mousedown", handleClickOutside);
255
+ return () => document.removeEventListener("mousedown", handleClickOutside);
256
256
  }
257
257
  }, [isOpen]);
258
258
  const handleSelect = (value, label) => {
@@ -276,27 +276,27 @@ const Select = ({ children, value, onValueChange, defaultValue, disabled = false
276
276
  };
277
277
  const SelectTrigger = React.forwardRef(({ children, className, error = false, ...props }, ref) => {
278
278
  const { isOpen, setIsOpen, triggerRef, disabled } = useSelectContext();
279
- return (_jsxs("button", { ref: triggerRef, type: "button", className: cn('select-trigger', error && 'select-trigger-error', className), onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "listbox", ...props, children: [children, _jsx(ChevronDownIcon, { className: cn('select-icon', error && 'select-icon-error') })] }));
279
+ return (_jsxs("button", { ref: triggerRef, type: "button", className: cn("select-trigger", error && "select-trigger-error", className), onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, "aria-expanded": isOpen, "aria-haspopup": "listbox", ...props, children: [children, _jsx(ChevronDownIcon, { className: cn("select-icon", error && "select-icon-error") })] }));
280
280
  });
281
- SelectTrigger.displayName = 'SelectTrigger';
282
- const SelectValue = ({ placeholder = 'Select...' }) => {
281
+ SelectTrigger.displayName = "SelectTrigger";
282
+ const SelectValue = ({ placeholder = "Select...", }) => {
283
283
  const { selectedLabel, selectedValue } = useSelectContext();
284
- return (_jsx("span", { className: cn('select-value', !selectedValue && 'select-placeholder'), children: selectedLabel || placeholder }));
284
+ return (_jsx("span", { className: cn("select-value", !selectedValue && "select-placeholder"), children: selectedLabel || placeholder }));
285
285
  };
286
286
  const SelectContent = React.forwardRef(({ children, className, ...props }, ref) => {
287
287
  const { isOpen, contentRef } = useSelectContext();
288
288
  if (!isOpen)
289
289
  return null;
290
- return (_jsx("div", { ref: contentRef, className: cn('select-content', className), role: "listbox", ...props, children: _jsx("div", { className: "select-viewport", children: children }) }));
290
+ return (_jsx("div", { ref: contentRef, className: cn("select-content", className), role: "listbox", ...props, children: _jsx("div", { className: "select-viewport", children: children }) }));
291
291
  });
292
- SelectContent.displayName = 'SelectContent';
292
+ SelectContent.displayName = "SelectContent";
293
293
  const SelectItem = React.forwardRef(({ children, value, className, disabled = false, ...props }, ref) => {
294
294
  const { selectedValue, handleSelect } = useSelectContext();
295
295
  const isSelected = selectedValue === value;
296
- return (_jsxs("div", { ref: ref, className: cn('select-item', isSelected && 'select-item-selected', disabled && 'select-item-disabled', className), onClick: () => !disabled && handleSelect(value, children), role: "option", "aria-selected": isSelected, "data-disabled": disabled, ...props, children: [isSelected && (_jsx("span", { className: "select-item-indicator", children: _jsx(Check, {}) })), _jsx("span", { className: "select-item-text", children: children })] }));
296
+ return (_jsxs("div", { ref: ref, className: cn("select-item", isSelected && "select-item-selected", disabled && "select-item-disabled", className), onClick: () => !disabled && handleSelect(value, children), role: "option", "aria-selected": isSelected, "data-disabled": disabled, ...props, children: [isSelected && (_jsx("span", { className: "select-item-indicator", children: _jsx(Check, {}) })), _jsx("span", { className: "select-item-text", children: children })] }));
297
297
  });
298
- SelectItem.displayName = 'SelectItem';
299
- const SelectGroup = ({ children, className }) => (_jsx("div", { className: cn('select-group', className), children: children }));
300
- const SelectLabel = ({ children, className }) => (_jsx("div", { className: cn('select-label', className), children: children }));
301
- const SelectSeparator = ({ className }) => (_jsx("div", { className: cn('select-separator', className) }));
298
+ SelectItem.displayName = "SelectItem";
299
+ const SelectGroup = ({ children, className }) => (_jsx("div", { className: cn("select-group", className), children: children }));
300
+ const SelectLabel = ({ children, className }) => (_jsx("div", { className: cn("select-label", className), children: children }));
301
+ const SelectSeparator = ({ className }) => (_jsx("div", { className: cn("select-separator", className) }));
302
302
  export { Select, SelectGroup, SelectValue, SelectTrigger, SelectContent, SelectLabel, SelectItem, SelectSeparator, };
@@ -1,4 +1,7 @@
1
1
  export declare const formatDateToISO: (date: Date) => string;
2
+ export declare const formatDate: (date: Date | string | null) => string;
3
+ export declare const formatTime: (timeStr: string | number) => string;
4
+ export declare const calculateDuration: (startTime?: string | number, endTime?: string | number, defaultDuration?: number) => number;
2
5
  export declare const parsePatientName: (fullName: string) => {
3
6
  firstName: string;
4
7
  lastName: string;
@@ -4,6 +4,65 @@ export const formatDateToISO = (date) => {
4
4
  const day = String(date.getDate()).padStart(2, "0");
5
5
  return `${year}-${month}-${day}`;
6
6
  };
7
+ export const formatDate = (date) => {
8
+ if (!date)
9
+ return "Not selected";
10
+ try {
11
+ const dateObj = typeof date === "string" ? new Date(date) : date;
12
+ return dateObj.toLocaleDateString("en-US", {
13
+ weekday: "long",
14
+ year: "numeric",
15
+ month: "long",
16
+ day: "numeric",
17
+ });
18
+ }
19
+ catch {
20
+ return String(date);
21
+ }
22
+ };
23
+ export const formatTime = (timeStr) => {
24
+ try {
25
+ if (typeof timeStr === "number" || !Number.isNaN(Number(timeStr))) {
26
+ const time = new Date(Number(timeStr));
27
+ return time.toLocaleTimeString("en-US", {
28
+ hour: "numeric",
29
+ minute: "2-digit",
30
+ hour12: true,
31
+ });
32
+ }
33
+ if (timeStr.includes(":") && timeStr.length <= 5) {
34
+ const time = new Date(`2000-01-01T${timeStr}`);
35
+ return time.toLocaleTimeString("en-US", {
36
+ hour: "numeric",
37
+ minute: "2-digit",
38
+ hour12: true,
39
+ });
40
+ }
41
+ const time = new Date(timeStr);
42
+ return time.toLocaleTimeString("en-US", {
43
+ hour: "numeric",
44
+ minute: "2-digit",
45
+ hour12: true,
46
+ });
47
+ }
48
+ catch {
49
+ return String(timeStr);
50
+ }
51
+ };
52
+ export const calculateDuration = (startTime, endTime, defaultDuration = 60) => {
53
+ if (!startTime || !endTime)
54
+ return defaultDuration;
55
+ try {
56
+ const start = new Date(startTime);
57
+ const end = new Date(endTime);
58
+ const diffMs = end.getTime() - start.getTime();
59
+ const diffMinutes = Math.round(diffMs / (1000 * 60));
60
+ return diffMinutes > 0 ? diffMinutes : defaultDuration;
61
+ }
62
+ catch {
63
+ return defaultDuration;
64
+ }
65
+ };
7
66
  export const parsePatientName = (fullName) => {
8
67
  const nameParts = fullName.trim().split(/\s+/);
9
68
  const firstName = nameParts[0] || "Patient";
@@ -1,2 +1,4 @@
1
1
  export declare const validatePhoneNumber: (phone: string) => boolean;
2
2
  export declare const validateCountryCode: (code: string) => boolean;
3
+ export declare const validateBloodGroup: (bloodGroup: string) => boolean;
4
+ export declare const validateDateOfBirth: (dob: string) => boolean;
@@ -5,3 +5,44 @@ export const validatePhoneNumber = (phone) => {
5
5
  export const validateCountryCode = (code) => {
6
6
  return /^\+[1-9]\d{0,3}$/.test(code);
7
7
  };
8
+ export const validateBloodGroup = (bloodGroup) => {
9
+ const validBloodGroups = [
10
+ "A+",
11
+ "A-",
12
+ "B+",
13
+ "B-",
14
+ "AB+",
15
+ "AB-",
16
+ "O+",
17
+ "O-",
18
+ "UNKNOWN",
19
+ ];
20
+ return validBloodGroups.includes(bloodGroup);
21
+ };
22
+ export const validateDateOfBirth = (dob) => {
23
+ if (!dob)
24
+ return false;
25
+ const dateRegex = /^\d{4}-\d{2}-\d{2}$/;
26
+ if (!dateRegex.test(dob))
27
+ return false;
28
+ const [yearStr, monthStr, dayStr] = dob.split("-");
29
+ const year = parseInt(yearStr, 10);
30
+ const month = parseInt(monthStr, 10);
31
+ const day = parseInt(dayStr, 10);
32
+ if (month < 1 || month > 12 || day < 1 || day > 31)
33
+ return false;
34
+ const date = new Date(year, month - 1, day);
35
+ if (date.getFullYear() !== year ||
36
+ date.getMonth() !== month - 1 ||
37
+ date.getDate() !== day) {
38
+ return false;
39
+ }
40
+ const today = new Date();
41
+ today.setHours(0, 0, 0, 0);
42
+ date.setHours(0, 0, 0, 0);
43
+ if (date > today)
44
+ return false;
45
+ if (year < 1900)
46
+ return false;
47
+ return true;
48
+ };
@@ -1,3 +1,4 @@
1
1
  export * from "./types";
2
2
  export * from "./themes";
3
3
  export * from "./utils";
4
+ export * from "./responsive";
@@ -1,3 +1,4 @@
1
1
  export * from "./types";
2
2
  export * from "./themes";
3
3
  export * from "./utils";
4
+ export * from "./responsive";
@@ -0,0 +1,15 @@
1
+ import { MedosTheme } from "./types";
2
+ export type Breakpoint = "mobile" | "tablet" | "desktop" | "wide";
3
+ export declare function useMediaQuery(query: string): boolean;
4
+ export declare function useBreakpoint(theme: MedosTheme): Breakpoint;
5
+ export declare function useIsMobile(theme: MedosTheme): boolean;
6
+ export declare function useIsTablet(theme: MedosTheme): boolean;
7
+ export declare function useIsDesktop(theme: MedosTheme): boolean;
8
+ export declare function useResponsiveValue<T>(theme: MedosTheme, values: Partial<Record<Breakpoint, T>>): T | undefined;
9
+ export declare function responsiveStyles(styles: Partial<Record<Breakpoint | "base", React.CSSProperties>>, currentBreakpoint: Breakpoint): React.CSSProperties;
10
+ export declare function getResponsiveMaxWidth(theme: MedosTheme, breakpoint: Breakpoint, customMaxWidths?: Partial<Record<Breakpoint, string>>): string;
11
+ export declare function getResponsivePadding(theme: MedosTheme, breakpoint: Breakpoint): string;
12
+ export declare function getResponsiveFontSize(theme: MedosTheme, breakpoint: Breakpoint, size?: keyof MedosTheme["typography"]): string;
13
+ export declare function isTouchDevice(): boolean;
14
+ export declare const MIN_TOUCH_TARGET_SIZE = "44px";
15
+ export declare function getResponsiveInputHeight(breakpoint: Breakpoint): string;
@@ -0,0 +1,113 @@
1
+ import { useState, useEffect } from "react";
2
+ export function useMediaQuery(query) {
3
+ const [matches, setMatches] = useState(false);
4
+ useEffect(() => {
5
+ const mediaQuery = window.matchMedia(query);
6
+ setMatches(mediaQuery.matches);
7
+ const handler = (event) => {
8
+ setMatches(event.matches);
9
+ };
10
+ if (mediaQuery.addEventListener) {
11
+ mediaQuery.addEventListener("change", handler);
12
+ return () => mediaQuery.removeEventListener("change", handler);
13
+ }
14
+ else {
15
+ mediaQuery.addListener(handler);
16
+ return () => mediaQuery.removeListener(handler);
17
+ }
18
+ }, [query]);
19
+ return matches;
20
+ }
21
+ export function useBreakpoint(theme) {
22
+ const isWide = useMediaQuery(`(min-width: ${theme.breakpoints.wide})`);
23
+ const isDesktop = useMediaQuery(`(min-width: ${theme.breakpoints.desktop})`);
24
+ const isTablet = useMediaQuery(`(min-width: ${theme.breakpoints.tablet})`);
25
+ if (isWide)
26
+ return "wide";
27
+ if (isDesktop)
28
+ return "desktop";
29
+ if (isTablet)
30
+ return "tablet";
31
+ return "mobile";
32
+ }
33
+ export function useIsMobile(theme) {
34
+ return useMediaQuery(`(max-width: ${parseInt(theme.breakpoints.tablet) - 1}px)`);
35
+ }
36
+ export function useIsTablet(theme) {
37
+ const minWidth = theme.breakpoints.tablet;
38
+ const maxWidth = `${parseInt(theme.breakpoints.desktop) - 1}px`;
39
+ return useMediaQuery(`(min-width: ${minWidth}) and (max-width: ${maxWidth})`);
40
+ }
41
+ export function useIsDesktop(theme) {
42
+ return useMediaQuery(`(min-width: ${theme.breakpoints.desktop})`);
43
+ }
44
+ export function useResponsiveValue(theme, values) {
45
+ const breakpoint = useBreakpoint(theme);
46
+ if (values[breakpoint] !== undefined) {
47
+ return values[breakpoint];
48
+ }
49
+ if (breakpoint === "wide" && values.desktop !== undefined) {
50
+ return values.desktop;
51
+ }
52
+ if ((breakpoint === "desktop" || breakpoint === "wide") &&
53
+ values.tablet !== undefined) {
54
+ return values.tablet;
55
+ }
56
+ if (values.mobile !== undefined) {
57
+ return values.mobile;
58
+ }
59
+ return undefined;
60
+ }
61
+ export function responsiveStyles(styles, currentBreakpoint) {
62
+ const baseStyles = styles.base || {};
63
+ const breakpointStyles = styles[currentBreakpoint] || {};
64
+ return {
65
+ ...baseStyles,
66
+ ...breakpointStyles,
67
+ };
68
+ }
69
+ export function getResponsiveMaxWidth(theme, breakpoint, customMaxWidths) {
70
+ if (customMaxWidths?.[breakpoint]) {
71
+ return customMaxWidths[breakpoint];
72
+ }
73
+ const defaults = {
74
+ mobile: "100%",
75
+ tablet: "100%",
76
+ desktop: "840px",
77
+ wide: "1200px",
78
+ };
79
+ return defaults[breakpoint];
80
+ }
81
+ export function getResponsivePadding(theme, breakpoint) {
82
+ const paddingMap = {
83
+ mobile: "md",
84
+ tablet: "lg",
85
+ desktop: "xl",
86
+ wide: "2xl",
87
+ };
88
+ return theme.spacing[paddingMap[breakpoint]];
89
+ }
90
+ export function getResponsiveFontSize(theme, breakpoint, size = "fontSizeMd") {
91
+ if (breakpoint === "mobile" && size.startsWith("fontSize")) {
92
+ const sizeMap = {
93
+ fontSize3xl: "fontSize2xl",
94
+ fontSize2xl: "fontSizeXl",
95
+ fontSizeXl: "fontSizeLg",
96
+ fontSizeLg: "fontSizeMd",
97
+ };
98
+ const adjustedSize = sizeMap[size] || size;
99
+ return theme.typography[adjustedSize];
100
+ }
101
+ return theme.typography[size];
102
+ }
103
+ export function isTouchDevice() {
104
+ return ("ontouchstart" in window ||
105
+ navigator.maxTouchPoints > 0 ||
106
+ navigator.msMaxTouchPoints > 0);
107
+ }
108
+ export const MIN_TOUCH_TARGET_SIZE = "44px";
109
+ export function getResponsiveInputHeight(breakpoint) {
110
+ return breakpoint === "mobile" && isTouchDevice()
111
+ ? MIN_TOUCH_TARGET_SIZE
112
+ : "40px";
113
+ }
@@ -18,11 +18,11 @@ export const defaultTheme = {
18
18
  borderFocus: "#27903F",
19
19
  text: "#111827",
20
20
  textSecondary: "#374151",
21
- textTertiary: "#6b7280",
21
+ textTertiary: "#4E8F50",
22
22
  textDisabled: "#9ca3af",
23
23
  textOnPrimary: "#fff",
24
24
  textOnSecondary: "#fff",
25
- success: "#10b981",
25
+ success: "#4E8F50",
26
26
  successBackground: "#ecfdf5",
27
27
  successBorder: "#6ee7b7",
28
28
  error: "#ef4444",
@@ -84,6 +84,12 @@ export const defaultTheme = {
84
84
  normal: "200ms cubic-bezier(0.4, 0, 0.2, 1)",
85
85
  slow: "300ms cubic-bezier(0.4, 0, 0.2, 1)",
86
86
  },
87
+ breakpoints: {
88
+ mobile: "320px",
89
+ tablet: "768px",
90
+ desktop: "1024px",
91
+ wide: "1280px",
92
+ },
87
93
  };
88
94
  export const modernTheme = {
89
95
  name: "modern",
@@ -95,7 +101,7 @@ export const modernTheme = {
95
101
  secondaryHover: "#ff5722",
96
102
  accent: "#3b82f6",
97
103
  accentHover: "#2563eb",
98
- background: "#ffffff",
104
+ background: "#fff",
99
105
  backgroundSecondary: "#f8fafc",
100
106
  backgroundTertiary: "#f1f5f9",
101
107
  surface: "#ffffff",
@@ -109,7 +115,7 @@ export const modernTheme = {
109
115
  textDisabled: "#cbd5e1",
110
116
  textOnPrimary: "#ffffff",
111
117
  textOnSecondary: "#ffffff",
112
- success: "#10b981",
118
+ success: "#4E8F50",
113
119
  successBackground: "#ecfdf5",
114
120
  successBorder: "#6ee7b7",
115
121
  error: "#ef4444",
@@ -171,6 +177,12 @@ export const modernTheme = {
171
177
  normal: "200ms cubic-bezier(0.4, 0, 0.2, 1)",
172
178
  slow: "300ms cubic-bezier(0.4, 0, 0.2, 1)",
173
179
  },
180
+ breakpoints: {
181
+ mobile: "320px",
182
+ tablet: "768px",
183
+ desktop: "1024px",
184
+ wide: "1280px",
185
+ },
174
186
  };
175
187
  export const themes = {
176
188
  default: defaultTheme,