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
@@ -0,0 +1,254 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import React from "react";
3
+ import { useTheme } from "../react/hooks/useTheme";
4
+ import { getButtonStyles } from "./theme-styles";
5
+ export const PatientSelectionStep = ({ verifiedPatients, selectedPatient, onSelectPatient, onProceedAsNewPatient, onBack, isFirstStep = false, }) => {
6
+ const theme = useTheme();
7
+ const BUTTON_STYLES = getButtonStyles(theme);
8
+ const styles = getPatientSelectionStyles(theme);
9
+ const [tempSelection, setTempSelection] = React.useState(null);
10
+ const handlePatientSelect = (patient) => {
11
+ setTempSelection({ type: "existing", patient });
12
+ };
13
+ const handleNewPatientSelect = () => {
14
+ setTempSelection({ type: "new" });
15
+ };
16
+ const handleNext = () => {
17
+ if (tempSelection) {
18
+ if (tempSelection.type === "existing" && tempSelection.patient) {
19
+ onSelectPatient(tempSelection.patient);
20
+ }
21
+ else if (tempSelection.type === "new") {
22
+ onProceedAsNewPatient();
23
+ }
24
+ }
25
+ };
26
+ return (_jsxs("div", { style: styles.container, children: [_jsxs("div", { style: styles.header, children: [_jsx("h3", { style: styles.title, children: "Select Patient" }), verifiedPatients.length > 0 ? (_jsxs("p", { style: styles.subtitle, children: ["We found ", verifiedPatients.length, " registered patient", verifiedPatients.length > 1 ? "s" : "", " with this number"] })) : (_jsx("p", { style: styles.subtitle, children: "No registered patients found with this number" }))] }), _jsxs("div", { style: styles.content, children: [verifiedPatients.length > 0 && (_jsxs(_Fragment, { children: [_jsx("div", { style: styles.patientList, children: verifiedPatients.map((patient) => (_jsx(PatientCard, { patient: patient, isSelected: tempSelection?.type === "existing" &&
27
+ tempSelection?.patient?.id === patient.id, onSelect: () => handlePatientSelect(patient), theme: theme }, patient.id))) }), _jsx("div", { style: styles.divider, children: _jsx("span", { style: styles.dividerText, children: "OR" }) })] })), _jsxs("button", { style: {
28
+ ...styles.newPatientButton,
29
+ ...(tempSelection?.type === "new"
30
+ ? styles.newPatientButtonSelected
31
+ : {}),
32
+ }, onClick: handleNewPatientSelect, children: [_jsx("div", { style: styles.newPatientIcon, children: "+" }), _jsxs("div", { style: styles.newPatientContent, children: [_jsx("div", { style: styles.newPatientTitle, children: "Register as New Patient" }), _jsx("div", { style: styles.newPatientSubtitle, children: "Fill out the form to create a new patient profile" })] })] })] }), _jsxs("div", { style: {
33
+ ...styles.footer,
34
+ justifyContent: "flex-end",
35
+ }, children: [!isFirstStep && (_jsx("button", { style: BUTTON_STYLES.secondary, onClick: onBack, children: "Back" })), _jsx("button", { style: {
36
+ ...BUTTON_STYLES.primary,
37
+ opacity: tempSelection ? 1 : 0.6,
38
+ }, onClick: handleNext, disabled: !tempSelection, children: "Next" })] })] }));
39
+ };
40
+ const PatientCard = ({ patient, isSelected, onSelect, theme }) => {
41
+ const styles = getPatientCardStyles(theme, isSelected);
42
+ const formatDate = (dateStr) => {
43
+ const date = new Date(dateStr);
44
+ return date.toLocaleDateString("en-US", {
45
+ year: "numeric",
46
+ month: "short",
47
+ day: "numeric",
48
+ });
49
+ };
50
+ return (_jsxs("button", { style: styles.card, onClick: onSelect, type: "button", children: [_jsx("div", { style: styles.radioContainer, children: _jsx("div", { style: styles.radio, children: isSelected && _jsx("div", { style: styles.radioInner }) }) }), _jsxs("div", { style: styles.content, children: [_jsxs("div", { style: styles.header, children: [_jsxs("div", { style: styles.name, children: [patient.firstName, " ", patient.lastName] }), _jsxs("div", { style: styles.mrn, children: ["MRN: ", patient.mrn] })] }), _jsxs("div", { style: styles.details, children: [_jsxs("div", { style: styles.detailRow, children: [_jsx("span", { style: styles.detailLabel, children: "Email:" }), _jsx("span", { style: styles.detailValue, children: patient.email })] }), _jsxs("div", { style: styles.detailRow, children: [_jsx("span", { style: styles.detailLabel, children: "Phone:" }), _jsxs("span", { style: styles.detailValue, children: [patient.countryCode, " ", patient.phoneNumber] })] }), _jsxs("div", { style: styles.detailRow, children: [_jsx("span", { style: styles.detailLabel, children: "DOB:" }), _jsx("span", { style: styles.detailValue, children: formatDate(patient.dob) })] }), _jsxs("div", { style: styles.detailRow, children: [_jsx("span", { style: styles.detailLabel, children: "Gender:" }), _jsx("span", { style: styles.detailValue, children: patient.gender })] }), _jsxs("div", { style: styles.detailRow, children: [_jsx("span", { style: styles.detailLabel, children: "Blood Group:" }), _jsx("span", { style: styles.detailValue, children: patient.bloodGroup })] }), patient.address && (_jsxs("div", { style: styles.detailRow, children: [_jsx("span", { style: styles.detailLabel, children: "Address:" }), _jsxs("span", { style: styles.detailValue, children: [patient.address.city, ", ", patient.address.state] })] }))] })] })] }));
51
+ };
52
+ const getPatientSelectionStyles = (theme) => ({
53
+ container: {
54
+ display: "flex",
55
+ flexDirection: "column",
56
+ height: "100%",
57
+ gap: "20px",
58
+ },
59
+ header: {
60
+ textAlign: "center",
61
+ marginBottom: "4px",
62
+ },
63
+ title: {
64
+ fontSize: "24px",
65
+ fontWeight: "600",
66
+ color: theme.colors.text,
67
+ marginBottom: "8px",
68
+ },
69
+ subtitle: {
70
+ fontSize: "14px",
71
+ color: theme.colors.textSecondary,
72
+ margin: 0,
73
+ },
74
+ content: {
75
+ flex: 1,
76
+ overflowY: "auto",
77
+ display: "flex",
78
+ flexDirection: "column",
79
+ gap: "20px",
80
+ },
81
+ patientList: {
82
+ display: "flex",
83
+ flexDirection: "column",
84
+ gap: "12px",
85
+ },
86
+ divider: {
87
+ display: "flex",
88
+ alignItems: "center",
89
+ textAlign: "center",
90
+ margin: "16px 0",
91
+ position: "relative",
92
+ "&::before": {
93
+ content: '""',
94
+ flex: 1,
95
+ borderBottom: `1px solid ${theme.colors.border}`,
96
+ },
97
+ "&::after": {
98
+ content: '""',
99
+ flex: 1,
100
+ borderBottom: `1px solid ${theme.colors.border}`,
101
+ },
102
+ },
103
+ dividerText: {
104
+ padding: "0 16px",
105
+ color: theme.colors.textSecondary,
106
+ fontSize: "14px",
107
+ fontWeight: "500",
108
+ backgroundColor: theme.colors.background,
109
+ },
110
+ newPatientButton: {
111
+ display: "flex",
112
+ alignItems: "center",
113
+ justifyContent: "center",
114
+ gap: "16px",
115
+ padding: "14px",
116
+ border: `2px dashed ${theme.colors.border}`,
117
+ borderRadius: theme.radii.md,
118
+ background: theme.colors.background,
119
+ cursor: "pointer",
120
+ transition: "all 0.2s ease",
121
+ textAlign: "center",
122
+ "&:hover": {
123
+ borderColor: theme.colors.primary,
124
+ background: `${theme.colors.primary}10`,
125
+ },
126
+ },
127
+ newPatientIcon: {
128
+ width: "48px",
129
+ height: "48px",
130
+ borderRadius: "50%",
131
+ background: theme.colors.primary,
132
+ color: "white",
133
+ display: "flex",
134
+ alignItems: "center",
135
+ justifyContent: "center",
136
+ fontSize: "24px",
137
+ fontWeight: "400",
138
+ flexShrink: 0,
139
+ lineHeight: "1",
140
+ },
141
+ newPatientContent: {
142
+ display: "flex",
143
+ flexDirection: "column",
144
+ alignItems: "center",
145
+ justifyContent: "center",
146
+ textAlign: "center",
147
+ },
148
+ newPatientTitle: {
149
+ fontSize: "16px",
150
+ fontWeight: "600",
151
+ color: theme.colors.text,
152
+ marginBottom: "4px",
153
+ textAlign: "center",
154
+ },
155
+ newPatientSubtitle: {
156
+ fontSize: "14px",
157
+ color: theme.colors.textSecondary,
158
+ textAlign: "center",
159
+ },
160
+ newPatientButtonSelected: {
161
+ borderColor: theme.colors.primary,
162
+ background: `${theme.colors.primary}08`,
163
+ },
164
+ footer: {
165
+ display: "flex",
166
+ justifyContent: "space-between",
167
+ gap: "12px",
168
+ paddingTop: "16px",
169
+ borderTop: `1px solid ${theme.colors.border}`,
170
+ },
171
+ nextBtnDisabled: {
172
+ backgroundColor: theme.colors.textSecondary || "#9ca3af",
173
+ cursor: "not-allowed",
174
+ opacity: 0.6,
175
+ color: "white",
176
+ },
177
+ });
178
+ const getPatientCardStyles = (theme, isSelected) => ({
179
+ card: {
180
+ display: "flex",
181
+ gap: "16px",
182
+ padding: "16px",
183
+ border: `2px solid ${isSelected ? theme.colors.primary : theme.colors.border}`,
184
+ borderRadius: theme.radii.md,
185
+ background: isSelected
186
+ ? `${theme.colors.primary}08`
187
+ : theme.colors.background,
188
+ cursor: "pointer",
189
+ transition: "all 0.2s ease",
190
+ "&:hover": {
191
+ borderColor: theme.colors.primary,
192
+ background: `${theme.colors.primary}05`,
193
+ },
194
+ },
195
+ radioContainer: {
196
+ paddingTop: "2px",
197
+ },
198
+ radio: {
199
+ width: "20px",
200
+ height: "20px",
201
+ borderRadius: "50%",
202
+ border: `2px solid ${isSelected ? theme.colors.primary : theme.colors.border}`,
203
+ display: "flex",
204
+ alignItems: "center",
205
+ justifyContent: "center",
206
+ transition: "all 0.2s ease",
207
+ },
208
+ radioInner: {
209
+ width: "10px",
210
+ height: "10px",
211
+ borderRadius: "50%",
212
+ background: theme.colors.primary,
213
+ },
214
+ content: {
215
+ flex: 1,
216
+ },
217
+ header: {
218
+ display: "flex",
219
+ justifyContent: "space-between",
220
+ alignItems: "center",
221
+ marginBottom: "12px",
222
+ },
223
+ name: {
224
+ fontSize: "18px",
225
+ fontWeight: "600",
226
+ color: theme.colors.text,
227
+ },
228
+ mrn: {
229
+ fontSize: "13px",
230
+ color: theme.colors.textSecondary,
231
+ fontWeight: "500",
232
+ padding: "4px 8px",
233
+ background: theme.colors.border,
234
+ borderRadius: theme.radii.sm,
235
+ },
236
+ details: {
237
+ display: "flex",
238
+ flexDirection: "column",
239
+ gap: "6px",
240
+ },
241
+ detailRow: {
242
+ display: "flex",
243
+ fontSize: "14px",
244
+ gap: "8px",
245
+ },
246
+ detailLabel: {
247
+ color: theme.colors.textSecondary,
248
+ fontWeight: "500",
249
+ minWidth: "100px",
250
+ },
251
+ detailValue: {
252
+ color: theme.colors.text,
253
+ },
254
+ });
@@ -21,7 +21,7 @@ export const PhoneVerificationStep = ({ state, dispatch, onSendOtp, onVerifyOtp,
21
21
  }, children: "Change Number" }), _jsx("button", { style: {
22
22
  ...BUTTON_STYLES.primary,
23
23
  opacity: state.otpCode.length === 6 ? 1 : 0.6,
24
- }, disabled: state.otpCode.length !== 6 || state.otpVerifying, onClick: onVerifyOtp, children: state.otpVerifying ? "Verifying..." : "Verify OTP" })] })) : (_jsxs(_Fragment, { children: [_jsx("button", { style: BUTTON_STYLES.secondary, onClick: onBack, children: "Back" }), _jsx("button", { style: BUTTON_STYLES.primary, onClick: onContinue, children: "Continue to Details" })] })) })] }));
24
+ }, disabled: state.otpCode.length !== 6 || state.otpVerifying, onClick: onVerifyOtp, children: state.otpVerifying ? "Verifying..." : "Verify OTP" })] })) : (_jsxs(_Fragment, { children: [_jsx("button", { style: BUTTON_STYLES.secondary, onClick: onBack, children: "Back" }), _jsx("button", { style: BUTTON_STYLES.primary, onClick: onContinue, children: "Continue" })] })) })] }));
25
25
  };
26
26
  const PhoneInputSection = ({ countryCode, patientPhone, onCountryCodeChange, onPhoneChange }) => {
27
27
  const theme = useTheme();
@@ -5,5 +5,5 @@ export const SuccessStep = ({ onReset }) => {
5
5
  const theme = useTheme();
6
6
  const SUCCESS_STYLES = getSuccessStyles(theme);
7
7
  const BUTTON_STYLES = getButtonStyles(theme);
8
- return (_jsxs("div", { style: SUCCESS_STYLES.container, children: [_jsx("div", { style: SUCCESS_STYLES.iconContainer, children: _jsx("div", { style: { fontSize: "48px", color: theme.colors.success }, children: "\u2713" }) }), _jsxs("div", { style: SUCCESS_STYLES.detailsContainer, children: [_jsx("h3", { style: SUCCESS_STYLES.detailsTitle, children: "Inquiry Submitted Successfully" }), _jsx("p", { style: SUCCESS_STYLES.confirmationNote, children: "Thank you for your inquiry. We will get back to you soon." })] }), _jsx("div", { style: { ...SUCCESS_STYLES.actionContainer, textAlign: "center" }, children: _jsx("button", { onClick: onReset, style: BUTTON_STYLES.primary, children: "Submit Another Inquiry" }) })] }));
8
+ return (_jsxs("div", { style: SUCCESS_STYLES.container, children: [_jsx("div", { style: SUCCESS_STYLES.iconContainer, children: _jsx("svg", { width: "32", height: "32", viewBox: "0 0 24 24", fill: "none", stroke: theme.colors.success, strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) }) }), _jsxs("div", { style: SUCCESS_STYLES.detailsContainer, children: [_jsx("h3", { style: SUCCESS_STYLES.detailsTitle, children: "Inquiry Submitted Successfully" }), _jsx("p", { style: SUCCESS_STYLES.confirmationNote, children: "Thank you for your inquiry. We will get back to you soon." })] }), _jsx("div", { style: SUCCESS_STYLES.actionContainer, children: _jsx("button", { onClick: onReset, style: BUTTON_STYLES.primary, children: "Submit Another Inquiry" }) })] }));
9
9
  };
@@ -0,0 +1,5 @@
1
+ import React from "react";
2
+ export interface AppointmentCalenderProps {
3
+ onError?: (err: Error) => void;
4
+ }
5
+ export declare const AppointmentCalender: React.FC<AppointmentCalenderProps>;
@@ -0,0 +1,247 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { AppointmentDateTimeModal } from "../AppointmentDateTimeModal";
3
+ import { DoctorSelectModal } from "../DoctorSelectModal";
4
+ import { PhoneVerificationStep } from "../PhoneVerificationStep";
5
+ import { PatientSelectionStep } from "../PatientSelectionStep";
6
+ import { PatientDetailsStep } from "../PatientDetailsStep";
7
+ import AppointmentConfirmationStep from "../AppointmentConfirmationStep";
8
+ import { BookingOptionStep } from "../BookingOptionStep";
9
+ import { AppointmentSummaryStep } from "../AppointmentSummaryStep";
10
+ import { useTheme } from "../../react/hooks/useTheme";
11
+ import { useBreakpoint } from "../../core/theme/responsive";
12
+ import MedosLogo from "../Icons/MedosLogo";
13
+ import { useAppointmentState, useAppointmentFlow, useInitializeAddresses, } from "./hooks";
14
+ import { formatDateToISO } from "../utils";
15
+ export const AppointmentCalender = ({ onError, }) => {
16
+ const { state, dispatch, setStep, resetForm } = useAppointmentState();
17
+ const { goBack, handleDateChange, sendOtp, verifyOtp, submitAppointment } = useAppointmentFlow(state, dispatch, onError);
18
+ useInitializeAddresses(dispatch, onError);
19
+ const handlePhoneVerificationContinue = () => {
20
+ if (state.otpVerified) {
21
+ const activePack = state.userSessionPacks?.find((pack) => pack.remainingSessions > 0);
22
+ const hasAvailablePackages = (state.availablePackages || []).length > 0;
23
+ if (!activePack && !hasAvailablePackages) {
24
+ dispatch({
25
+ type: "SET_BOOKING_OPTION_TYPE",
26
+ payload: "new-appointment",
27
+ });
28
+ dispatch({ type: "SET_BOOKING_TYPE", payload: "ONE_TIME_APPOINTMENT" });
29
+ setStep(2);
30
+ }
31
+ else {
32
+ setStep(1);
33
+ }
34
+ }
35
+ };
36
+ const handleBookingOptionSelect = (optionType, sessionPack, newPackage) => {
37
+ dispatch({ type: "SET_BOOKING_OPTION_TYPE", payload: optionType });
38
+ if (optionType === "session-pack" && sessionPack) {
39
+ dispatch({ type: "SET_SELECTED_SESSION_PACK", payload: sessionPack });
40
+ dispatch({ type: "SET_BOOKING_TYPE", payload: "USE_ACTIVE_PACKAGE" });
41
+ setStep(2);
42
+ }
43
+ else if (optionType === "explore-packages") {
44
+ dispatch({ type: "SET_BOOKING_TYPE", payload: "PACKAGE_PURCHASE" });
45
+ dispatch({ type: "SET_SHOW_PACKAGE_EXPLORER", payload: true });
46
+ }
47
+ else if (optionType === "new-appointment") {
48
+ dispatch({ type: "SET_BOOKING_TYPE", payload: "ONE_TIME_APPOINTMENT" });
49
+ setStep(2);
50
+ }
51
+ };
52
+ const handlePackageSelect = (pkg) => {
53
+ dispatch({ type: "SET_SELECTED_NEW_PACKAGE", payload: pkg });
54
+ dispatch({ type: "SET_BOOKING_TYPE", payload: "PACKAGE_PURCHASE" });
55
+ dispatch({ type: "SET_SHOW_PACKAGE_EXPLORER", payload: false });
56
+ setStep(2);
57
+ };
58
+ const handleDoctorSelect = (addrId, docId) => {
59
+ dispatch({ type: "SET_SELECTED_ADDRESS", payload: addrId });
60
+ dispatch({ type: "SET_SELECTED_DOCTOR", payload: docId });
61
+ setStep(3);
62
+ };
63
+ const handleDateTimeModalContinue = (mode, date, slot, charge) => {
64
+ dispatch({ type: "SET_CONSULTATION_MODE", payload: mode });
65
+ dispatch({ type: "SET_SELECTED_DATE", payload: date });
66
+ dispatch({ type: "SET_SELECTED_SLOT", payload: slot });
67
+ dispatch({ type: "SET_CONSULTATION_CHARGE", payload: charge });
68
+ setStep(4);
69
+ };
70
+ const handleSelectExistingPatient = (patient) => {
71
+ dispatch({ type: "SET_SELECTED_PATIENT", payload: patient });
72
+ dispatch({ type: "SET_USE_EXISTING_PATIENT", payload: true });
73
+ dispatch({
74
+ type: "SET_PATIENT_NAME",
75
+ payload: `${patient.firstName} ${patient.lastName}`,
76
+ });
77
+ dispatch({ type: "SET_PATIENT_EMAIL", payload: patient.email });
78
+ dispatch({ type: "SET_PATIENT_AGE", payload: patient.age.toString() });
79
+ dispatch({ type: "SET_PATIENT_GENDER", payload: patient.gender });
80
+ dispatch({ type: "SET_BLOOD_GROUP", payload: patient.bloodGroup });
81
+ if (patient.address) {
82
+ dispatch({
83
+ type: "SET_PATIENT_ADDRESS",
84
+ payload: patient.address.addressLine1,
85
+ });
86
+ dispatch({ type: "SET_PATIENT_CITY", payload: patient.address.city });
87
+ dispatch({ type: "SET_PATIENT_STATE", payload: patient.address.state });
88
+ dispatch({
89
+ type: "SET_PATIENT_COUNTRY",
90
+ payload: patient.address.country,
91
+ });
92
+ dispatch({
93
+ type: "SET_PATIENT_ZIPCODE",
94
+ payload: patient.address.zipcode,
95
+ });
96
+ dispatch({
97
+ type: "SET_PATIENT_LANDMARK",
98
+ payload: patient.address.landmark || "",
99
+ });
100
+ }
101
+ setStep(6);
102
+ };
103
+ const handleProceedAsNewPatient = () => {
104
+ dispatch({ type: "SET_SELECTED_PATIENT", payload: null });
105
+ dispatch({ type: "SET_USE_EXISTING_PATIENT", payload: false });
106
+ dispatch({ type: "SET_PATIENT_NAME", payload: "" });
107
+ dispatch({ type: "SET_PATIENT_EMAIL", payload: "" });
108
+ dispatch({ type: "SET_PATIENT_AGE", payload: "" });
109
+ dispatch({ type: "SET_PATIENT_GENDER", payload: "" });
110
+ dispatch({ type: "SET_BLOOD_GROUP", payload: "" });
111
+ dispatch({ type: "SET_PATIENT_ADDRESS", payload: "" });
112
+ dispatch({ type: "SET_PATIENT_CITY", payload: "" });
113
+ dispatch({ type: "SET_PATIENT_STATE", payload: "" });
114
+ dispatch({ type: "SET_PATIENT_COUNTRY", payload: "" });
115
+ dispatch({ type: "SET_PATIENT_ZIPCODE", payload: "" });
116
+ dispatch({ type: "SET_PATIENT_LANDMARK", payload: "" });
117
+ setStep(5);
118
+ };
119
+ const handlePatientDetailsSubmit = async () => {
120
+ setStep(6);
121
+ };
122
+ const handleSummaryConfirm = async () => {
123
+ await submitAppointment();
124
+ };
125
+ const handleGoBack = () => {
126
+ if (state.showPackageExplorer) {
127
+ dispatch({ type: "SET_SHOW_PACKAGE_EXPLORER", payload: false });
128
+ return;
129
+ }
130
+ const currentStep = state.step;
131
+ if (currentStep > 0) {
132
+ if (currentStep === 6 && state.useExistingPatient) {
133
+ dispatch({ type: "SET_SELECTED_PATIENT", payload: null });
134
+ dispatch({ type: "SET_USE_EXISTING_PATIENT", payload: false });
135
+ setStep(4);
136
+ return;
137
+ }
138
+ if (currentStep === 2) {
139
+ dispatch({ type: "SET_BOOKING_OPTION_TYPE", payload: null });
140
+ dispatch({ type: "SET_SELECTED_SESSION_PACK", payload: null });
141
+ dispatch({ type: "SET_SELECTED_NEW_PACKAGE", payload: null });
142
+ const activePack = state.userSessionPacks?.find((pack) => pack.remainingSessions > 0);
143
+ const hasAvailablePackages = (state.availablePackages || []).length > 0;
144
+ if (!activePack && !hasAvailablePackages) {
145
+ setStep(0);
146
+ }
147
+ else {
148
+ setStep(1);
149
+ }
150
+ }
151
+ else {
152
+ setStep(currentStep - 1);
153
+ }
154
+ }
155
+ };
156
+ const theme = useTheme();
157
+ const breakpoint = useBreakpoint(theme);
158
+ const styles = getStyles(theme, breakpoint);
159
+ return (_jsx("div", { style: styles.container, children: _jsxs("div", { style: styles.card, children: [_jsx("div", { style: styles.header, children: _jsx("h2", { style: styles.title, children: "Book Appointment" }) }), _jsx("hr", {}), _jsxs("div", { style: styles.content, children: [state.loading && _jsx("div", { style: { marginBottom: 12 }, children: "Loading..." }), state.error && _jsx("div", { style: styles.errorMessage, children: state.error }), state.step === 0 && (_jsx(PhoneVerificationStep, { state: state, dispatch: dispatch, onSendOtp: sendOtp, onVerifyOtp: verifyOtp, onBack: () => { }, onContinue: handlePhoneVerificationContinue })), state.step === 1 && (_jsx(BookingOptionStep, { userSessionPacks: state.userSessionPacks || [], availablePackages: state.availablePackages || [], showPackageExplorer: state.showPackageExplorer || false, selectedSessionPack: state.selectedSessionPack, selectedNewPackage: state.selectedNewPackage, onSelectOption: handleBookingOptionSelect, onSelectPackage: handlePackageSelect, onBack: handleGoBack })), state.step === 2 && (_jsx(DoctorSelectModal, { addresses: state.addresses, addressDoctorsMap: state.addressDoctorsMap, selectedAddressId: state.selectedAddress, selectedDoctorId: state.selectedDoctor, onCancel: handleGoBack, onContinue: handleDoctorSelect })), state.step === 3 && (_jsx(AppointmentDateTimeModal, { onlineFee: 500, offlineFee: 300, slots: state.slots, selectedDate: state.selectedDate, selectedSlot: state.selectedSlot, consultationMode: state.consultationMode, onCancel: handleGoBack, onDateChange: handleDateChange, onContinue: handleDateTimeModalContinue, initialStep: "consultation" })), state.step === 4 && (_jsx(PatientSelectionStep, { verifiedPatients: state.verifiedPatients, selectedPatient: state.selectedPatient, onSelectPatient: handleSelectExistingPatient, onProceedAsNewPatient: handleProceedAsNewPatient, onBack: handleGoBack })), state.step === 5 && (_jsx(PatientDetailsStep, { state: state, dispatch: dispatch, onBack: handleGoBack, onSubmit: handlePatientDetailsSubmit })), state.step === 6 && (_jsx(AppointmentSummaryStep, { state: state, selectedDoctor: state.selectedAddress && state.selectedDoctor
160
+ ? state.addressDoctorsMap[state.selectedAddress]?.find((doc) => doc.id === state.selectedDoctor) || null
161
+ : null, selectedAddress: state.selectedAddress
162
+ ? state.addresses.find((addr) => addr.id === state.selectedAddress) || null
163
+ : null, onBack: handleGoBack, onConfirm: handleSummaryConfirm })), state.step === 7 && (_jsx(AppointmentConfirmationStep, { appointment: {
164
+ patientName: state.patientName,
165
+ visitationType: state.consultationMode === "ONLINE"
166
+ ? "Online Consultation"
167
+ : "In-Person Visit",
168
+ appointmentDate: formatDateToISO(state.selectedDate),
169
+ fromTime: state.selectedSlot?.start
170
+ ? new Date(state.selectedSlot.start)
171
+ .toTimeString()
172
+ .slice(0, 5)
173
+ : "",
174
+ toTime: state.selectedSlot?.end
175
+ ? new Date(state.selectedSlot.end).toTimeString().slice(0, 5)
176
+ : "",
177
+ location: state.addresses.find((addr) => addr.id === state.selectedAddress)?.label || "Clinic",
178
+ mode: state.consultationMode,
179
+ paymentMode: "Cash",
180
+ }, patient: {
181
+ patientName: state.patientName,
182
+ }, selectedDoctor: state.selectedAddress && state.selectedDoctor
183
+ ? state.addressDoctorsMap[state.selectedAddress]?.find((doc) => doc.id === state.selectedDoctor) || null
184
+ : null, selectedAddress: state.selectedAddress
185
+ ? state.addresses.find((addr) => addr.id === state.selectedAddress) || null
186
+ : null, onClose: resetForm, onGoBackToSlots: () => setStep(3) })), _jsxs("div", { style: styles.branding, children: [_jsx("span", { style: styles.poweredBy, children: "Powered by" }), _jsx("a", { href: "https://medos.one", target: "_blank", rel: "noopener noreferrer", children: _jsx(MedosLogo, { style: { height: 50, width: "auto" } }) })] })] })] }) }));
187
+ };
188
+ const getStyles = (theme, breakpoint) => {
189
+ const isMobile = breakpoint === "mobile";
190
+ const isTablet = breakpoint === "tablet";
191
+ return {
192
+ container: {
193
+ display: "flex",
194
+ justifyContent: "center",
195
+ padding: isMobile ? 12 : 20,
196
+ fontFamily: theme.typography.fontFamily,
197
+ background: theme.colors.background,
198
+ },
199
+ card: {
200
+ width: "100%",
201
+ maxWidth: isMobile || isTablet ? "100%" : 840,
202
+ background: theme.colors.surface,
203
+ borderRadius: isMobile ? theme.radii.md : theme.radii.lg,
204
+ boxShadow: isMobile ? theme.shadows.md : theme.shadows.lg,
205
+ overflow: "hidden",
206
+ boxSizing: "border-box",
207
+ },
208
+ header: {
209
+ padding: isMobile ? "16px 16px" : "20px 24px",
210
+ },
211
+ title: {
212
+ margin: 0,
213
+ fontSize: isMobile
214
+ ? theme.typography.fontSizeLg
215
+ : theme.typography.fontSizeXl,
216
+ fontWeight: theme.typography.fontWeightSemibold,
217
+ },
218
+ content: {
219
+ padding: isMobile ? 16 : 24,
220
+ },
221
+ errorMessage: {
222
+ marginBottom: 12,
223
+ color: theme.colors.error,
224
+ fontWeight: 600,
225
+ padding: isMobile ? "10px" : "12px",
226
+ background: theme.colors.errorBackground,
227
+ borderRadius: theme.radii.md,
228
+ border: `1px solid ${theme.colors.errorBorder}`,
229
+ fontSize: theme.typography.fontSizeSm,
230
+ },
231
+ branding: {
232
+ display: "flex",
233
+ alignItems: "center",
234
+ justifyContent: "center",
235
+ gap: 8,
236
+ marginTop: isMobile ? 16 : 24,
237
+ paddingTop: isMobile ? 12 : 16,
238
+ borderTop: `1px solid ${theme.colors.border}`,
239
+ opacity: 0.8,
240
+ },
241
+ poweredBy: {
242
+ fontSize: 12,
243
+ color: theme.colors.textSecondary,
244
+ fontWeight: 500,
245
+ },
246
+ };
247
+ };
@@ -0,0 +1,3 @@
1
+ export { useAppointmentState } from "./useAppointmentState";
2
+ export { useAppointmentFlow } from "./useAppointmentFlow";
3
+ export { useInitializeAddresses } from "./useInitializeAddresses";
@@ -0,0 +1,3 @@
1
+ export { useAppointmentState } from "./useAppointmentState";
2
+ export { useAppointmentFlow } from "./useAppointmentFlow";
3
+ export { useInitializeAddresses } from "./useInitializeAddresses";
@@ -0,0 +1,8 @@
1
+ import { AppointmentState } from "../types";
2
+ export declare const useAppointmentFlow: (state: AppointmentState, dispatch: React.Dispatch<any>, onError?: (error: Error) => void) => {
3
+ goBack: () => void;
4
+ handleDateChange: (date: Date) => Promise<(() => void) | undefined>;
5
+ sendOtp: () => Promise<void>;
6
+ verifyOtp: () => Promise<void>;
7
+ submitAppointment: () => Promise<void>;
8
+ };