medos-sdk 1.0.2 → 1.0.3
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/client/MedosClient.d.ts +1 -1
- package/dist/client/MedosClient.js +1 -1
- package/dist/components/AppointmentCalender.d.ts +1 -4
- package/dist/components/AppointmentCalender.js +282 -530
- package/dist/components/AppointmentDateTimeModal.d.ts +14 -0
- package/dist/components/AppointmentDateTimeModal.js +206 -0
- package/dist/components/ConfigurableCard.d.ts +12 -0
- package/dist/components/ConfigurableCard.js +29 -0
- package/dist/components/DoctorSelectModal.d.ts +7 -0
- package/dist/components/DoctorSelectModal.js +80 -0
- package/dist/components/Icons/Check.d.ts +6 -0
- package/dist/components/Icons/Check.js +2 -0
- package/dist/components/Icons/ChevronDownIcon.d.ts +4 -0
- package/dist/components/Icons/ChevronDownIcon.js +2 -0
- package/dist/components/Icons/ChevronLeft.d.ts +3 -0
- package/dist/components/Icons/ChevronLeft.js +3 -0
- package/dist/components/Icons/ChevronRight.d.ts +3 -0
- package/dist/components/Icons/ChevronRight.js +3 -0
- package/dist/components/Icons/ConfirmationCheck.d.ts +1 -0
- package/dist/components/Icons/ConfirmationCheck.js +9 -0
- package/dist/components/Icons/ConsultationType.d.ts +1 -0
- package/dist/components/Icons/ConsultationType.js +2 -0
- package/dist/components/Icons/Date&TimeIcon.d.ts +1 -0
- package/dist/components/Icons/Date&TimeIcon.js +2 -0
- package/dist/components/Icons/MapIcon.d.ts +1 -0
- package/dist/components/Icons/MapIcon.js +2 -0
- package/dist/components/Icons/PaymentMethodIcon.d.ts +1 -0
- package/dist/components/Icons/PaymentMethodIcon.js +2 -0
- package/dist/components/Icons/UserIcon.d.ts +1 -0
- package/dist/components/Icons/UserIcon.js +2 -0
- package/dist/components/PatientDetailsStep.d.ts +3 -0
- package/dist/components/PatientDetailsStep.js +76 -0
- package/dist/components/PhoneVerificationStep.d.ts +3 -0
- package/dist/components/PhoneVerificationStep.js +39 -0
- package/dist/components/SuccessStep.d.ts +3 -0
- package/dist/components/SuccessStep.js +17 -0
- package/dist/components/custom-calendar.d.ts +5 -0
- package/dist/components/custom-calendar.js +153 -0
- package/dist/components/styles.d.ts +6 -0
- package/dist/components/styles.js +257 -0
- package/dist/components/types.d.ts +182 -0
- package/dist/components/types.js +55 -0
- package/dist/components/ui/select.d.ts +10 -0
- package/dist/components/ui/select.js +21 -0
- package/dist/components/uiComponents/SelectDropdown.d.ts +41 -0
- package/dist/components/uiComponents/SelectDropdown.js +302 -0
- package/dist/components/utils.d.ts +5 -0
- package/dist/components/utils.js +15 -0
- package/dist/components/validation.d.ts +2 -0
- package/dist/components/validation.js +7 -0
- package/dist/context/TemplateContext.d.ts +12 -0
- package/dist/context/TemplateContext.js +19 -0
- package/dist/lib/templateUtils.d.ts +3 -0
- package/dist/lib/templateUtils.js +28 -0
- package/dist/services/AppointmentService.d.ts +4 -5
- package/dist/services/AppointmentService.js +12 -10
- package/dist/templates/registry.d.ts +12 -0
- package/dist/templates/registry.js +58 -0
- package/dist/vanilla/AppointmentCalendarWidget.d.ts +2 -34
- package/dist/vanilla/AppointmentCalendarWidget.js +264 -273
- package/dist/vanilla/client/MedosClient.d.ts +1 -1
- package/dist/vanilla/components/AppointmentCalender.d.ts +1 -4
- package/dist/vanilla/components/AppointmentDateTimeModal.d.ts +14 -0
- package/dist/vanilla/components/ConfigurableCard.d.ts +12 -0
- package/dist/vanilla/components/DoctorSelectModal.d.ts +7 -0
- package/dist/vanilla/components/Icons/Check.d.ts +6 -0
- package/dist/vanilla/components/Icons/ChevronDownIcon.d.ts +4 -0
- package/dist/vanilla/components/Icons/ChevronLeft.d.ts +3 -0
- package/dist/vanilla/components/Icons/ChevronRight.d.ts +3 -0
- package/dist/vanilla/components/Icons/ConfirmationCheck.d.ts +1 -0
- package/dist/vanilla/components/Icons/ConsultationType.d.ts +1 -0
- package/dist/vanilla/components/Icons/Date&TimeIcon.d.ts +1 -0
- package/dist/vanilla/components/Icons/MapIcon.d.ts +1 -0
- package/dist/vanilla/components/Icons/PaymentMethodIcon.d.ts +1 -0
- package/dist/vanilla/components/Icons/UserIcon.d.ts +1 -0
- package/dist/vanilla/components/PatientDetailsStep.d.ts +3 -0
- package/dist/vanilla/components/PhoneVerificationStep.d.ts +3 -0
- package/dist/vanilla/components/SuccessStep.d.ts +3 -0
- package/dist/vanilla/components/custom-calendar.d.ts +5 -0
- package/dist/vanilla/components/styles.d.ts +6 -0
- package/dist/vanilla/components/types.d.ts +182 -0
- package/dist/vanilla/components/ui/select.d.ts +10 -0
- package/dist/vanilla/components/uiComponents/SelectDropdown.d.ts +41 -0
- package/dist/vanilla/components/utils.d.ts +5 -0
- package/dist/vanilla/components/validation.d.ts +2 -0
- package/dist/vanilla/context/TemplateContext.d.ts +12 -0
- package/dist/vanilla/lib/templateUtils.d.ts +3 -0
- package/dist/vanilla/services/AppointmentService.d.ts +4 -5
- package/dist/vanilla/templates/alternative.css +13 -0
- package/dist/vanilla/templates/default.css +13 -0
- package/dist/vanilla/templates/registry.d.ts +12 -0
- package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +2 -34
- package/dist/vanilla/widget.js +331 -283
- package/package.json +9 -4
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Slot } from "../services/AppointmentService";
|
|
3
|
+
export type AppointmentMode = "ONLINE" | "OFFLINE";
|
|
4
|
+
export type PaymentMode = "CASH" | "CARD" | "UPI";
|
|
5
|
+
type AppointmentModalProps = {
|
|
6
|
+
onlineFee?: number | null;
|
|
7
|
+
offlineFee?: number | null;
|
|
8
|
+
slots: Slot[];
|
|
9
|
+
onCancel: () => void;
|
|
10
|
+
onContinue: (mode: AppointmentMode, date: Date, slot: Slot, charge: string, paymentMode: PaymentMode) => void;
|
|
11
|
+
onDateChange?: (date: Date) => void;
|
|
12
|
+
};
|
|
13
|
+
export declare const AppointmentDateTimeModal: React.FC<AppointmentModalProps>;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState, useCallback, useMemo } from "react";
|
|
3
|
+
import { CustomCalendarWithDateSelector } from "./custom-calendar";
|
|
4
|
+
import { PaymentMethodIcon } from "./Icons/PaymentMethodIcon";
|
|
5
|
+
import { DateTimeIcon } from "./Icons/Date&TimeIcon";
|
|
6
|
+
import { ConsultationTypeIcon } from "./Icons/ConsultationType";
|
|
7
|
+
const MONTHS = [
|
|
8
|
+
"January",
|
|
9
|
+
"February",
|
|
10
|
+
"March",
|
|
11
|
+
"April",
|
|
12
|
+
"May",
|
|
13
|
+
"June",
|
|
14
|
+
"July",
|
|
15
|
+
"August",
|
|
16
|
+
"September",
|
|
17
|
+
"October",
|
|
18
|
+
"November",
|
|
19
|
+
"December",
|
|
20
|
+
];
|
|
21
|
+
const getOrdinalSuffix = (day) => {
|
|
22
|
+
if (day > 3 && day < 21)
|
|
23
|
+
return "th";
|
|
24
|
+
switch (day % 10) {
|
|
25
|
+
case 1:
|
|
26
|
+
return "st";
|
|
27
|
+
case 2:
|
|
28
|
+
return "nd";
|
|
29
|
+
case 3:
|
|
30
|
+
return "rd";
|
|
31
|
+
default:
|
|
32
|
+
return "th";
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const formatDate = (date) => {
|
|
36
|
+
const day = date.getDate();
|
|
37
|
+
const month = MONTHS[date.getMonth()];
|
|
38
|
+
const year = date.getFullYear();
|
|
39
|
+
return `${day}${getOrdinalSuffix(day)} ${month} ${year}`;
|
|
40
|
+
};
|
|
41
|
+
export const AppointmentDateTimeModal = ({ onlineFee, offlineFee, slots, onCancel, onContinue, onDateChange, }) => {
|
|
42
|
+
const [mode, setMode] = useState("OFFLINE");
|
|
43
|
+
const [consultationCharge, setConsultationCharge] = useState("");
|
|
44
|
+
const [paymentMode, setPaymentMode] = useState("CASH");
|
|
45
|
+
const [selectedDate, setSelectedDate] = useState(new Date());
|
|
46
|
+
const [selectedSlot, setSelectedSlot] = useState(null);
|
|
47
|
+
const handleDateSelect = useCallback((date) => {
|
|
48
|
+
setSelectedDate(date);
|
|
49
|
+
setSelectedSlot(null);
|
|
50
|
+
onDateChange?.(date);
|
|
51
|
+
}, [onDateChange]);
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
const charge = mode === "ONLINE" && onlineFee
|
|
54
|
+
? String(onlineFee)
|
|
55
|
+
: mode === "OFFLINE" && offlineFee
|
|
56
|
+
? String(offlineFee)
|
|
57
|
+
: "";
|
|
58
|
+
setConsultationCharge(charge);
|
|
59
|
+
}, [mode, onlineFee, offlineFee]);
|
|
60
|
+
const handleContinue = useCallback(() => {
|
|
61
|
+
if (!selectedSlot)
|
|
62
|
+
return;
|
|
63
|
+
onContinue(mode, selectedDate, selectedSlot, consultationCharge, paymentMode);
|
|
64
|
+
}, [
|
|
65
|
+
mode,
|
|
66
|
+
selectedDate,
|
|
67
|
+
selectedSlot,
|
|
68
|
+
consultationCharge,
|
|
69
|
+
paymentMode,
|
|
70
|
+
onContinue,
|
|
71
|
+
]);
|
|
72
|
+
const isSlotSelected = useCallback((slot) => selectedSlot?.start === slot.start && selectedSlot?.end === slot.end, [selectedSlot]);
|
|
73
|
+
const formattedDate = useMemo(() => formatDate(selectedDate), [selectedDate]);
|
|
74
|
+
const isFormValid = selectedDate && selectedSlot && consultationCharge;
|
|
75
|
+
return (_jsxs("div", { style: STYLES.modalWrapper, children: [_jsx(ConsultationTypeSection, { mode: mode, onlineFee: onlineFee, offlineFee: offlineFee, onModeChange: setMode }), _jsx(ChargesSection, { charge: consultationCharge }), _jsx(DateTimeSection, { selectedDate: selectedDate, formattedDate: formattedDate, slots: slots, selectedSlot: selectedSlot, onDateSelect: handleDateSelect, onSlotSelect: setSelectedSlot, isSlotSelected: isSlotSelected }), _jsx(FooterSection, { onCancel: onCancel, onContinue: handleContinue, isValid: !!isFormValid })] }));
|
|
76
|
+
};
|
|
77
|
+
const ConsultationTypeSection = ({ mode, onlineFee, offlineFee, onModeChange }) => (_jsxs("div", { style: STYLES.sectionCard, children: [_jsxs("div", { style: STYLES.sectionHeader, children: [_jsx(ConsultationTypeIcon, {}), _jsx("span", { style: STYLES.sectionTitle, children: "Consultation Type" })] }), _jsxs("div", { style: STYLES.sectionBody, children: [_jsx("p", { style: STYLES.label, children: "Consultation Mode" }), _jsx("div", { style: STYLES.modeContainer, children: ["ONLINE", "OFFLINE"].map((item) => {
|
|
78
|
+
const disabled = (item === "ONLINE" && (!onlineFee || onlineFee <= 0)) ||
|
|
79
|
+
(item === "OFFLINE" && (!offlineFee || offlineFee <= 0));
|
|
80
|
+
return (_jsxs("label", { style: { ...STYLES.radioLabel, opacity: disabled ? 0.5 : 1 }, children: [_jsx("input", { type: "radio", name: "mode", value: item, checked: mode === item, disabled: disabled, onChange: () => !disabled && onModeChange(item), style: STYLES.radioInput }), item === "ONLINE" ? "Online" : "Offline"] }, item));
|
|
81
|
+
}) })] })] }));
|
|
82
|
+
const ChargesSection = ({ charge }) => (_jsxs("div", { style: STYLES.sectionCard, children: [_jsxs("div", { style: STYLES.sectionHeader, children: [_jsx(PaymentMethodIcon, {}), _jsx("span", { style: STYLES.sectionTitle, children: "Charges & Mode of Payment" })] }), _jsx("div", { style: STYLES.sectionBody, children: _jsxs("span", { style: STYLES.rupee, children: ["\u20B9 ", charge] }) })] }));
|
|
83
|
+
const DateTimeSection = ({ selectedDate, formattedDate, slots, selectedSlot, onDateSelect, onSlotSelect, isSlotSelected, }) => (_jsxs("div", { style: STYLES.sectionCard, children: [_jsxs("div", { style: STYLES.sectionHeader, children: [_jsx(DateTimeIcon, {}), _jsx("span", { style: STYLES.sectionTitle, children: "Date & Time" })] }), _jsx("div", { style: STYLES.sectionBody, children: _jsxs("div", { style: STYLES.dateTimeContainer, children: [_jsx("div", { style: STYLES.calendarBox, children: _jsx(CustomCalendarWithDateSelector, { selectedDate: selectedDate, onSelect: onDateSelect, pastDisabled: true }) }), _jsxs("div", { style: STYLES.timesContainer, children: [_jsxs("p", { style: STYLES.timesLabel, children: ["Available times ", _jsx("br", {}), _jsx("span", { style: STYLES.dateLabel, children: formattedDate })] }), slots.length === 0 ? (_jsx("p", { style: STYLES.noSlots, children: "No available slots" })) : (_jsx("div", { style: STYLES.slotGrid, children: slots.map((slot) => (_jsx(SlotButton, { slot: slot, isSelected: isSlotSelected(slot), onSelect: onSlotSelect }, slot.id))) }))] })] }) })] }));
|
|
84
|
+
const SlotButton = ({ slot, isSelected, onSelect }) => {
|
|
85
|
+
const startTime = useMemo(() => new Date(slot.start).toLocaleTimeString([], {
|
|
86
|
+
hour: "2-digit",
|
|
87
|
+
minute: "2-digit",
|
|
88
|
+
}), [slot.start]);
|
|
89
|
+
return (_jsx("button", { onClick: () => onSelect(slot), style: {
|
|
90
|
+
...STYLES.slotButton,
|
|
91
|
+
background: isSelected ? "#009b4d" : "#fff",
|
|
92
|
+
color: isSelected ? "#fff" : "#009b4d",
|
|
93
|
+
}, children: startTime }));
|
|
94
|
+
};
|
|
95
|
+
const FooterSection = ({ onCancel, onContinue, isValid }) => (_jsxs("div", { style: STYLES.footer, children: [_jsx("button", { style: STYLES.backBtn, onClick: onCancel, children: "Back" }), _jsx("button", { style: { ...STYLES.continueBtn, opacity: isValid ? 1 : 0.6 }, onClick: onContinue, disabled: !isValid, children: "Continue" })] }));
|
|
96
|
+
const STYLES = {
|
|
97
|
+
modalWrapper: {
|
|
98
|
+
backgroundColor: "#fff",
|
|
99
|
+
borderRadius: 12,
|
|
100
|
+
padding: "20px 24px 24px 24px",
|
|
101
|
+
maxWidth: 800,
|
|
102
|
+
margin: "0 auto",
|
|
103
|
+
fontFamily: "'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial",
|
|
104
|
+
color: "#111827",
|
|
105
|
+
boxSizing: "border-box",
|
|
106
|
+
},
|
|
107
|
+
sectionCard: {
|
|
108
|
+
border: "1px solid #e5e7eb",
|
|
109
|
+
borderRadius: 10,
|
|
110
|
+
marginBottom: 20,
|
|
111
|
+
position: "relative",
|
|
112
|
+
},
|
|
113
|
+
sectionHeader: {
|
|
114
|
+
background: "#f9fafb",
|
|
115
|
+
borderBottom: "1px solid #e5e7eb",
|
|
116
|
+
padding: "12px 16px",
|
|
117
|
+
display: "flex",
|
|
118
|
+
alignItems: "center",
|
|
119
|
+
gap: 8,
|
|
120
|
+
},
|
|
121
|
+
sectionTitle: { fontSize: 15, fontWeight: 600 },
|
|
122
|
+
sectionBody: { padding: 16, position: "relative" },
|
|
123
|
+
label: {
|
|
124
|
+
fontSize: 14,
|
|
125
|
+
fontWeight: 500,
|
|
126
|
+
marginBottom: 4,
|
|
127
|
+
display: "block",
|
|
128
|
+
},
|
|
129
|
+
modeContainer: {
|
|
130
|
+
display: "flex",
|
|
131
|
+
gap: 24,
|
|
132
|
+
marginTop: 4,
|
|
133
|
+
},
|
|
134
|
+
radioLabel: {
|
|
135
|
+
display: "flex",
|
|
136
|
+
alignItems: "center",
|
|
137
|
+
gap: 8,
|
|
138
|
+
cursor: "pointer",
|
|
139
|
+
fontSize: 14,
|
|
140
|
+
},
|
|
141
|
+
radioInput: {
|
|
142
|
+
width: 18,
|
|
143
|
+
height: 18,
|
|
144
|
+
accentColor: "#218838",
|
|
145
|
+
cursor: "pointer",
|
|
146
|
+
},
|
|
147
|
+
rupee: {
|
|
148
|
+
fontWeight: 600,
|
|
149
|
+
fontSize: 16,
|
|
150
|
+
marginRight: 6,
|
|
151
|
+
},
|
|
152
|
+
dateTimeContainer: { display: "flex", gap: 24 },
|
|
153
|
+
calendarBox: {
|
|
154
|
+
border: "1px solid #e5e7eb",
|
|
155
|
+
borderRadius: 10,
|
|
156
|
+
padding: 8,
|
|
157
|
+
},
|
|
158
|
+
timesContainer: { flexGrow: 1 },
|
|
159
|
+
timesLabel: { fontWeight: 500 },
|
|
160
|
+
dateLabel: { color: "#6b7280", fontSize: 13 },
|
|
161
|
+
noSlots: {
|
|
162
|
+
color: "#6b7280",
|
|
163
|
+
fontSize: 14,
|
|
164
|
+
marginTop: 8,
|
|
165
|
+
},
|
|
166
|
+
slotGrid: {
|
|
167
|
+
display: "grid",
|
|
168
|
+
gridTemplateColumns: "repeat(auto-fit,minmax(100px,1fr))",
|
|
169
|
+
gap: 8,
|
|
170
|
+
marginTop: 12,
|
|
171
|
+
},
|
|
172
|
+
slotButton: {
|
|
173
|
+
borderRadius: 8,
|
|
174
|
+
padding: "8px 10px",
|
|
175
|
+
border: "1px solid #009b4d",
|
|
176
|
+
fontSize: 13,
|
|
177
|
+
fontWeight: 500,
|
|
178
|
+
cursor: "pointer",
|
|
179
|
+
transition: "0.2s",
|
|
180
|
+
},
|
|
181
|
+
footer: {
|
|
182
|
+
display: "flex",
|
|
183
|
+
justifyContent: "flex-end",
|
|
184
|
+
alignItems: "center",
|
|
185
|
+
marginTop: 20,
|
|
186
|
+
gap: 12,
|
|
187
|
+
},
|
|
188
|
+
backBtn: {
|
|
189
|
+
border: "1px solid #218838",
|
|
190
|
+
background: "#fff",
|
|
191
|
+
color: "#218838",
|
|
192
|
+
borderRadius: 6,
|
|
193
|
+
fontWeight: 600,
|
|
194
|
+
padding: "8px 20px",
|
|
195
|
+
cursor: "pointer",
|
|
196
|
+
},
|
|
197
|
+
continueBtn: {
|
|
198
|
+
background: "#218838",
|
|
199
|
+
color: "#fff",
|
|
200
|
+
border: "none",
|
|
201
|
+
borderRadius: 6,
|
|
202
|
+
fontWeight: 600,
|
|
203
|
+
padding: "8px 20px",
|
|
204
|
+
cursor: "pointer",
|
|
205
|
+
},
|
|
206
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export type ConfigurableCardProps = {
|
|
3
|
+
title: string;
|
|
4
|
+
subtitle?: string;
|
|
5
|
+
content?: React.ReactNode;
|
|
6
|
+
ctaLabel?: string;
|
|
7
|
+
onCta?: () => void;
|
|
8
|
+
variant?: "filled" | "outline";
|
|
9
|
+
className?: string;
|
|
10
|
+
};
|
|
11
|
+
export declare const ConfigurableCard: React.FC<ConfigurableCardProps>;
|
|
12
|
+
export default ConfigurableCard;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTemplate } from "../context/TemplateContext";
|
|
3
|
+
export const ConfigurableCard = ({ title, subtitle, content, ctaLabel = "Action", onCta, variant = "outline", className, }) => {
|
|
4
|
+
useTemplate();
|
|
5
|
+
const filled = variant === "filled";
|
|
6
|
+
const containerStyle = {
|
|
7
|
+
background: filled
|
|
8
|
+
? "var(--medos-primary-color)"
|
|
9
|
+
: "var(--medos-background-color)",
|
|
10
|
+
color: filled ? "#fff" : "var(--medos-text-color)",
|
|
11
|
+
border: filled ? "none" : "1px solid var(--medos-border-color)",
|
|
12
|
+
padding: 16,
|
|
13
|
+
borderRadius: 10,
|
|
14
|
+
boxShadow: "0 6px 18px rgba(16,24,40,0.06)",
|
|
15
|
+
};
|
|
16
|
+
const ctaStyle = {
|
|
17
|
+
padding: "8px 12px",
|
|
18
|
+
borderRadius: 8,
|
|
19
|
+
background: filled
|
|
20
|
+
? "rgba(255,255,255,0.12)"
|
|
21
|
+
: "var(--medos-primary-color)",
|
|
22
|
+
color: "#fff",
|
|
23
|
+
border: "none",
|
|
24
|
+
cursor: "pointer",
|
|
25
|
+
fontWeight: 600,
|
|
26
|
+
};
|
|
27
|
+
return (_jsxs("div", { className: className, style: containerStyle, children: [_jsxs("div", { style: { display: "flex", justifyContent: "space-between", gap: 8 }, children: [_jsxs("div", { children: [_jsx("div", { style: { fontSize: 16, fontWeight: 700 }, children: title }), subtitle && (_jsx("div", { style: { fontSize: 13, opacity: 0.95, marginTop: 4 }, children: subtitle }))] }), _jsx("div", { style: { display: "flex", alignItems: "center" }, children: _jsx("button", { style: ctaStyle, onClick: onCta, "aria-label": ctaLabel, children: ctaLabel }) })] }), content && _jsx("div", { style: { marginTop: 12 }, children: content })] }));
|
|
28
|
+
};
|
|
29
|
+
export default ConfigurableCard;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState, useEffect } from "react";
|
|
3
|
+
import { AppointmentService } from "../services/AppointmentService";
|
|
4
|
+
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, } from "./uiComponents/SelectDropdown";
|
|
5
|
+
export const DoctorSelectModal = ({ onCancel, onContinue, }) => {
|
|
6
|
+
const [addresses, setAddresses] = useState([]);
|
|
7
|
+
const [addressDoctorsMap, setAddressDoctorsMap] = useState({});
|
|
8
|
+
const [selectedAddressId, setSelectedAddressId] = useState("");
|
|
9
|
+
const [selectedDoctorId, setSelectedDoctorId] = useState("");
|
|
10
|
+
const [appointmentNotes, setAppointmentNotes] = useState("");
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
(async () => {
|
|
13
|
+
const res = await AppointmentService.getAddresses();
|
|
14
|
+
const map = {};
|
|
15
|
+
res.addresses.forEach((addr) => {
|
|
16
|
+
map[addr.id] = addr.doctors || [];
|
|
17
|
+
});
|
|
18
|
+
setAddresses(res.addresses);
|
|
19
|
+
setAddressDoctorsMap(map);
|
|
20
|
+
})();
|
|
21
|
+
}, []);
|
|
22
|
+
const doctorsForAddress = selectedAddressId ? addressDoctorsMap[Number(selectedAddressId)] || [] : [];
|
|
23
|
+
const canContinue = !!selectedAddressId && !!selectedDoctorId;
|
|
24
|
+
return (_jsx("div", { style: { border: "1px solid #e5e7eb", borderRadius: "2px" }, children: _jsxs("div", { style: styles.modalWrapper, children: [_jsx("div", { style: styles.headerWrapper, children: _jsx("h3", { style: styles.title, children: "Location & Doctor" }) }), _jsx("div", { style: { borderBottom: "1px solid #e5e7eb" } }), _jsxs("div", { style: styles.contentWrapper, children: [_jsxs("div", { style: styles.fieldGroup, children: [_jsxs("label", { style: styles.label, children: ["Preferred Location ", _jsx("span", { style: styles.mandatory, children: "*" })] }), _jsxs(Select, { value: selectedAddressId, onValueChange: (value) => {
|
|
25
|
+
setSelectedAddressId(value);
|
|
26
|
+
setSelectedDoctorId("");
|
|
27
|
+
}, children: [_jsx(SelectTrigger, { style: { width: '100%' }, children: _jsx(SelectValue, { placeholder: "Select Address" }) }), _jsx(SelectContent, { children: addresses.map((a) => (_jsx(SelectItem, { value: String(a.id), children: a.completeAddress || a.label || `Address ${a.id}` }, a.id))) })] })] }), _jsxs("div", { style: styles.fieldGroup, children: [_jsxs("label", { style: styles.label, children: ["Preferred Doctor ", _jsx("span", { style: styles.mandatory, children: "*" })] }), _jsxs(Select, { value: selectedDoctorId, onValueChange: setSelectedDoctorId, disabled: !selectedAddressId, children: [_jsx(SelectTrigger, { style: { width: '100%' }, children: _jsx(SelectValue, { placeholder: "Select Doctor" }) }), _jsx(SelectContent, { children: doctorsForAddress.length > 0 ? (doctorsForAddress.map((d) => (_jsxs(SelectItem, { value: String(d.id), children: [d.name, " ", d.specialty ? `- ${d.specialty}` : ""] }, d.id)))) : (_jsx(SelectItem, { value: "no-doctors", disabled: true, children: "No doctors available" })) })] })] }), _jsxs("div", { style: styles.fieldGroup, children: [_jsxs("label", { style: styles.label, children: ["Chief Complaint ", _jsx("span", { style: styles.optional, children: "(optional)" })] }), _jsx("textarea", { style: styles.textarea, placeholder: "Enter Chief Complaint or Appointment Notes", value: appointmentNotes, onChange: (e) => setAppointmentNotes(e.target.value) })] }), _jsx("div", { style: styles.footer, children: _jsx("button", { style: {
|
|
28
|
+
...styles.continueBtn,
|
|
29
|
+
opacity: canContinue ? 1 : 0.6,
|
|
30
|
+
}, disabled: !canContinue, onClick: () => onContinue(Number(selectedAddressId), Number(selectedDoctorId), appointmentNotes), children: "Next" }) })] })] }) }));
|
|
31
|
+
};
|
|
32
|
+
const styles = {
|
|
33
|
+
modalWrapper: {
|
|
34
|
+
backgroundColor: "#fff",
|
|
35
|
+
borderRadius: 12,
|
|
36
|
+
maxWidth: 840,
|
|
37
|
+
margin: "0 auto",
|
|
38
|
+
fontFamily: "'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial",
|
|
39
|
+
color: "#111827",
|
|
40
|
+
},
|
|
41
|
+
headerWrapper: {
|
|
42
|
+
padding: "20px 24px 10px 24px",
|
|
43
|
+
},
|
|
44
|
+
contentWrapper: {
|
|
45
|
+
padding: "20px 24px 0px 24px",
|
|
46
|
+
},
|
|
47
|
+
title: { fontSize: 20, fontWeight: 600, margin: 0 },
|
|
48
|
+
fieldGroup: { marginBottom: 18 },
|
|
49
|
+
label: { fontSize: 15, fontWeight: 500, marginBottom: 6, display: "block" },
|
|
50
|
+
mandatory: { color: "red", marginLeft: 4 },
|
|
51
|
+
optional: { color: "#9ca3af", fontWeight: 400, marginLeft: 4, fontSize: 13 },
|
|
52
|
+
textarea: {
|
|
53
|
+
width: "100%",
|
|
54
|
+
border: "1px solid #e5e7eb",
|
|
55
|
+
borderRadius: 6,
|
|
56
|
+
minHeight: 80,
|
|
57
|
+
padding: "10px",
|
|
58
|
+
fontSize: 14,
|
|
59
|
+
resize: "vertical",
|
|
60
|
+
boxSizing: "border-box",
|
|
61
|
+
},
|
|
62
|
+
footer: {
|
|
63
|
+
marginTop: 24,
|
|
64
|
+
marginBottom: 10,
|
|
65
|
+
display: "flex",
|
|
66
|
+
justifyContent: "flex-end",
|
|
67
|
+
alignItems: "center",
|
|
68
|
+
gap: 10,
|
|
69
|
+
},
|
|
70
|
+
brand: { color: "#009b4d", fontWeight: 600 },
|
|
71
|
+
continueBtn: {
|
|
72
|
+
background: "#218838",
|
|
73
|
+
color: "#fff",
|
|
74
|
+
border: "none",
|
|
75
|
+
borderRadius: 6,
|
|
76
|
+
fontWeight: 600,
|
|
77
|
+
padding: "8px 22px",
|
|
78
|
+
cursor: "pointer",
|
|
79
|
+
},
|
|
80
|
+
};
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const Check = ({ className, size = 16 }) => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className, children: _jsx("polyline", { points: "20 6 9 17 4 12" }) }));
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const ChevronDownIcon = ({ className }) => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "16", height: "16", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: className, children: _jsx("polyline", { points: "6 9 12 15 18 9" }) }));
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
const ChevronLeft = (props) => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className: `lucide lucide-chevron-left ${props.className ?? ""}`, ...props, children: _jsx("path", { d: "m15 18-6-6 6-6" }) }));
|
|
3
|
+
export default ChevronLeft;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
const ChevronRight = ({ ...props }) => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: 20, height: 20, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className: `lucide lucide-chevron-right-icon lucide-chevron-right`, ...props, children: _jsx("path", { d: "m9 18 6-6-6-6" }) }));
|
|
3
|
+
export default ChevronRight;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ConfirmationCheck: React.FC;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
const Check = ({ size = 16 }) => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: _jsx("polyline", { points: "20 6 9 17 4 12" }) }));
|
|
3
|
+
export const ConfirmationCheck = () => (_jsxs("div", { style: { position: 'relative', display: 'inline-block' }, children: [_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "60", height: "60", viewBox: "0 0 41 41", fill: "none", children: _jsx("path", { d: "M31.1309 4.90254C32.388 4.98797 33.0166 5.03069 33.5247 5.25288C34.2598 5.57438 34.8467 6.16126 35.1682 6.8964C35.3904 7.40445 35.4331 8.03302 35.5185 9.29016L35.7135 12.159C35.748 12.6674 35.7653 12.9217 35.8206 13.1645C35.9004 13.5154 36.0391 13.8503 36.2308 14.1549C36.3634 14.3657 36.531 14.5576 36.8661 14.9416L38.7568 17.108C39.5853 18.0574 39.9996 18.532 40.2017 19.0484C40.4942 19.7955 40.4942 20.6255 40.2017 21.3727C39.9996 21.889 39.5853 22.3637 38.7568 23.313L36.8661 25.4795C36.531 25.8634 36.3634 26.0554 36.2308 26.2662C36.0391 26.5708 35.9004 26.9056 35.8206 27.2566C35.7653 27.4994 35.748 27.7536 35.7135 28.2621L35.5185 31.1309C35.4331 32.388 35.3904 33.0166 35.1682 33.5247C34.8467 34.2598 34.2598 34.8467 33.5247 35.1682C33.0166 35.3904 32.388 35.4331 31.1309 35.5185L28.2621 35.7135C27.7536 35.748 27.4994 35.7653 27.2566 35.8206C26.9056 35.9004 26.5708 36.0391 26.2662 36.2308C26.0554 36.3634 25.8634 36.531 25.4795 36.8661L23.313 38.7568C22.3637 39.5853 21.889 39.9996 21.3727 40.2017C20.6255 40.4942 19.7955 40.4942 19.0484 40.2017C18.532 39.9996 18.0574 39.5853 17.108 38.7568L14.9416 36.8661C14.5576 36.531 14.3657 36.3634 14.1549 36.2308C13.8503 36.0391 13.5154 35.9004 13.1645 35.8206C12.9217 35.7653 12.6674 35.748 12.159 35.7135L9.29016 35.5185C8.03302 35.4331 7.40445 35.3904 6.8964 35.1682C6.16126 34.8467 5.57438 34.2598 5.25288 33.5247C5.03069 33.0166 4.98797 32.388 4.90254 31.1309L4.70759 28.2621C4.67304 27.7536 4.65576 27.4994 4.60049 27.2566C4.52063 26.9056 4.38193 26.5708 4.19028 26.2662C4.05764 26.0554 3.89009 25.8634 3.555 25.4795L1.66428 23.313C0.83576 22.3637 0.421499 21.889 0.219363 21.3727C-0.073121 20.6255 -0.0731209 19.7955 0.219363 19.0484C0.421499 18.532 0.83576 18.0574 1.66428 17.108L3.555 14.9416C3.89009 14.5576 4.05764 14.3657 4.19027 14.1549C4.38193 13.8503 4.52063 13.5154 4.60049 13.1645C4.65576 12.9217 4.67304 12.6674 4.70759 12.159L4.90254 9.29016C4.98797 8.03302 5.03069 7.40445 5.25288 6.8964C5.57438 6.16126 6.16126 5.57438 6.8964 5.25288C7.40445 5.03069 8.03302 4.98797 9.29016 4.90254L12.159 4.70759C12.6674 4.67304 12.9217 4.65577 13.1645 4.6005C13.5154 4.52063 13.8503 4.38193 14.1549 4.19028C14.3657 4.05764 14.5576 3.89009 14.9416 3.555L17.108 1.66428C18.0574 0.83576 18.532 0.421499 19.0484 0.219363C19.7955 -0.073121 20.6255 -0.073121 21.3727 0.219363C21.889 0.421499 22.3637 0.83576 23.313 1.66428L25.4795 3.555C25.8634 3.89009 26.0554 4.05764 26.2662 4.19028C26.5708 4.38193 26.9056 4.52063 27.2566 4.6005C27.4994 4.65577 27.7536 4.67304 28.2621 4.70759L31.1309 4.90254Z", fill: "#27903F" }) }), _jsx("div", { style: {
|
|
4
|
+
position: 'absolute',
|
|
5
|
+
top: '50%',
|
|
6
|
+
left: '50%',
|
|
7
|
+
transform: 'translate(-50%, -50%)',
|
|
8
|
+
color: 'white'
|
|
9
|
+
}, children: _jsx(Check, { size: 24 }) })] }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ConsultationTypeIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const ConsultationTypeIcon = () => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "20", viewBox: "0 0 18 20", fill: "none", children: _jsx("path", { d: "M2 20C1.45 20 0.979167 19.8042 0.5875 19.4125C0.195833 19.0208 0 18.55 0 18V4C0 3.45 0.195833 2.97917 0.5875 2.5875C0.979167 2.19583 1.45 2 2 2H3V0H5V2H13V0H15V2H16C16.55 2 17.0208 2.19583 17.4125 2.5875C17.8042 2.97917 18 3.45 18 4V18C18 18.55 17.8042 19.0208 17.4125 19.4125C17.0208 19.8042 16.55 20 16 20H2ZM2 18H16V8H2V18ZM2 6H16V4H2V6ZM4 12V10H14V12H4ZM4 16V14H11V16H4Z", fill: "#1E3A8A" }) }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const DateTimeIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const DateTimeIcon = () => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "18", height: "20", viewBox: "0 0 18 20", fill: "none", children: _jsx("path", { d: "M2 20C1.45 20 0.979167 19.8042 0.5875 19.4125C0.195833 19.0208 0 18.55 0 18V4C0 3.45 0.195833 2.97917 0.5875 2.5875C0.979167 2.19583 1.45 2 2 2H3V0H5V2H13V0H15V2H16C16.55 2 17.0208 2.19583 17.4125 2.5875C17.8042 2.97917 18 3.45 18 4V18C18 18.55 17.8042 19.0208 17.4125 19.4125C17.0208 19.8042 16.55 20 16 20H2ZM2 18H16V8H2V18ZM2 6H16V4H2V6ZM4 12V10H14V12H4ZM4 16V14H11V16H4Z", fill: "#C94300" }) }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const MapPinIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const MapPinIcon = () => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "14", height: "20", viewBox: "0 0 14 20", fill: "none", children: _jsx("path", { d: "M7 20C5.23333 20 3.79167 19.7208 2.675 19.1625C1.55833 18.6042 1 17.8833 1 17C1 16.6 1.12083 16.2292 1.3625 15.8875C1.60417 15.5458 1.94167 15.25 2.375 15L3.95 16.475C3.8 16.5417 3.6375 16.6167 3.4625 16.7C3.2875 16.7833 3.15 16.8833 3.05 17C3.26667 17.2667 3.76667 17.5 4.55 17.7C5.33333 17.9 6.15 18 7 18C7.85 18 8.67083 17.9 9.4625 17.7C10.2542 17.5 10.7583 17.2667 10.975 17C10.8583 16.8667 10.7083 16.7583 10.525 16.675C10.3417 16.5917 10.1667 16.5167 10 16.45L11.55 14.95C12.0167 15.2167 12.375 15.5208 12.625 15.8625C12.875 16.2042 13 16.5833 13 17C13 17.8833 12.4417 18.6042 11.325 19.1625C10.2083 19.7208 8.76667 20 7 20ZM7.025 14.5C8.675 13.2833 9.91667 12.0625 10.75 10.8375C11.5833 9.6125 12 8.38333 12 7.15C12 5.45 11.4583 4.16667 10.375 3.3C9.29167 2.43333 8.16667 2 7 2C5.83333 2 4.70833 2.43333 3.625 3.3C2.54167 4.16667 2 5.45 2 7.15C2 8.26667 2.40833 9.42917 3.225 10.6375C4.04167 11.8458 5.30833 13.1333 7.025 14.5ZM7 17C4.65 15.2667 2.89583 13.5833 1.7375 11.95C0.579167 10.3167 0 8.71667 0 7.15C0 5.96667 0.2125 4.92917 0.6375 4.0375C1.0625 3.14583 1.60833 2.4 2.275 1.8C2.94167 1.2 3.69167 0.75 4.525 0.45C5.35833 0.15 6.18333 0 7 0C7.81667 0 8.64167 0.15 9.475 0.45C10.3083 0.75 11.0583 1.2 11.725 1.8C12.3917 2.4 12.9375 3.14583 13.3625 4.0375C13.7875 4.92917 14 5.96667 14 7.15C14 8.71667 13.4208 10.3167 12.2625 11.95C11.1042 13.5833 9.35 15.2667 7 17ZM7 9C7.55 9 8.02083 8.80417 8.4125 8.4125C8.80417 8.02083 9 7.55 9 7C9 6.45 8.80417 5.97917 8.4125 5.5875C8.02083 5.19583 7.55 5 7 5C6.45 5 5.97917 5.19583 5.5875 5.5875C5.19583 5.97917 5 6.45 5 7C5 7.55 5.19583 8.02083 5.5875 8.4125C5.97917 8.80417 6.45 9 7 9Z", fill: "#087E8B" }) }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const PaymentMethodIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const PaymentMethodIcon = () => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "21", height: "15", viewBox: "0 0 21 15", fill: "none", children: _jsx("path", { d: "M11.9038 8.096C11.2051 8.096 10.6138 7.854 10.1298 7.37C9.64575 6.886 9.40375 6.29467 9.40375 5.596C9.40375 4.89733 9.64575 4.306 10.1298 3.822C10.6138 3.338 11.2051 3.096 11.9038 3.096C12.6024 3.096 13.1938 3.338 13.6778 3.822C14.1618 4.306 14.4038 4.89733 14.4038 5.596C14.4038 6.29467 14.1618 6.886 13.6778 7.37C13.1938 7.854 12.6024 8.096 11.9038 8.096ZM5.3075 11.1923C4.8105 11.1923 4.385 11.0153 4.031 10.6613C3.677 10.3073 3.5 9.88167 3.5 9.3845V1.8075C3.5 1.3105 3.677 0.885 4.031 0.531C4.385 0.177 4.8105 0 5.3075 0H18.4998C18.9969 0 19.4225 0.177 19.7765 0.531C20.1305 0.885 20.3075 1.3105 20.3075 1.8075V9.3845C20.3075 9.88167 20.1305 10.3073 19.7765 10.6613C19.4225 11.0153 18.9969 11.1923 18.4998 11.1923H5.3075ZM6.8075 9.69225H17C17 9.19358 17.177 8.76758 17.531 8.41425C17.885 8.06108 18.3105 7.8845 18.8075 7.8845V3.3075C18.3088 3.3075 17.8829 3.1305 17.5298 2.7765C17.1766 2.4225 17 1.997 17 1.5H6.8075C6.8075 1.99867 6.6305 2.42458 6.2765 2.77775C5.9225 3.13092 5.497 3.3075 5 3.3075V7.8845C5.49867 7.8845 5.92458 8.0615 6.27775 8.4155C6.63092 8.7695 6.8075 9.19508 6.8075 9.69225ZM17.3267 14.6923H1.80775C1.31058 14.6923 0.885 14.5153 0.531 14.1613C0.177 13.8073 0 13.3817 0 12.8845V2.98075H1.5V12.8845C1.5 12.9613 1.532 13.0318 1.596 13.096C1.66017 13.1602 1.73075 13.1923 1.80775 13.1923H17.3267V14.6923ZM5.3075 9.69225H5V1.5H5.3075C5.22417 1.5 5.15208 1.53042 5.09125 1.59125C5.03042 1.65208 5 1.72417 5 1.8075V9.3845C5 9.46783 5.03042 9.53992 5.09125 9.60075C5.15208 9.66175 5.22417 9.69225 5.3075 9.69225Z", fill: "#27903F" }) }));
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const UserIcon: () => import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
export const UserIcon = () => (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", children: _jsx("path", { d: "M14 13C13.1667 13 12.4583 12.7083 11.875 12.125C11.2917 11.5417 11 10.8333 11 10C11 9.16667 11.2917 8.45833 11.875 7.875C12.4583 7.29167 13.1667 7 14 7C14.8333 7 15.5417 7.29167 16.125 7.875C16.7083 8.45833 17 9.16667 17 10C17 10.8333 16.7083 11.5417 16.125 12.125C15.5417 12.7083 14.8333 13 14 13ZM14 11C14.2833 11 14.5208 10.9042 14.7125 10.7125C14.9042 10.5208 15 10.2833 15 10C15 9.71667 14.9042 9.47917 14.7125 9.2875C14.5208 9.09583 14.2833 9 14 9C13.7167 9 13.4792 9.09583 13.2875 9.2875C13.0958 9.47917 13 9.71667 13 10C13 10.2833 13.0958 10.5208 13.2875 10.7125C13.4792 10.9042 13.7167 11 14 11ZM8 20V17.1C8 16.75 8.08333 16.4208 8.25 16.1125C8.41667 15.8042 8.65 15.5583 8.95 15.375C9.48333 15.0583 10.0458 14.7958 10.6375 14.5875C11.2292 14.3792 11.8333 14.225 12.45 14.125L14 16L15.55 14.125C16.1667 14.225 16.7667 14.3792 17.35 14.5875C17.9333 14.7958 18.4917 15.0583 19.025 15.375C19.325 15.5583 19.5625 15.8042 19.7375 16.1125C19.9125 16.4208 20 16.75 20 17.1V20H8ZM9.975 18H13.05L11.7 16.35C11.4 16.4333 11.1083 16.5417 10.825 16.675C10.5417 16.8083 10.2583 16.95 9.975 17.1V18ZM14.95 18H18V17.1C17.7333 16.9333 17.4583 16.7875 17.175 16.6625C16.8917 16.5375 16.6 16.4333 16.3 16.35L14.95 18ZM2 18C1.45 18 0.979167 17.8042 0.5875 17.4125C0.195833 17.0208 0 16.55 0 16V2C0 1.45 0.195833 0.979167 0.5875 0.5875C0.979167 0.195833 1.45 0 2 0H16C16.55 0 17.0208 0.195833 17.4125 0.5875C17.8042 0.979167 18 1.45 18 2V7C17.7333 6.66667 17.4417 6.35 17.125 6.05C16.8083 5.75 16.4333 5.55 16 5.45V2H2V16H6.15C6.1 16.1833 6.0625 16.3667 6.0375 16.55C6.0125 16.7333 6 16.9167 6 17.1V18H2ZM4 6H11C11.4333 5.66667 11.9083 5.41667 12.425 5.25C12.9417 5.08333 13.4667 5 14 5V4H4V6ZM4 10H9C9 9.65 9.0375 9.30833 9.1125 8.975C9.1875 8.64167 9.29167 8.31667 9.425 8H4V10ZM4 14H7.45C7.63333 13.85 7.82917 13.7167 8.0375 13.6C8.24583 13.4833 8.45833 13.375 8.675 13.275V12H4V14ZM2 16V2V5.425V5V16Z", fill: "#06348D" }) }));
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { GENDER_OPTIONS, BLOOD_GROUP_OPTIONS, } from "./types";
|
|
3
|
+
import { BUTTON_STYLES, PATIENT_DETAILS_STYLES, CONTAINER_STYLES, } from "./styles";
|
|
4
|
+
import { UserIcon } from "./Icons/UserIcon";
|
|
5
|
+
import { MapPinIcon } from "./Icons/MapIcon";
|
|
6
|
+
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, } from "./uiComponents/SelectDropdown";
|
|
7
|
+
export const PatientDetailsStep = ({ state, dispatch, onBack, onSubmit, }) => {
|
|
8
|
+
const isFormValid = state.patientName &&
|
|
9
|
+
state.patientAge &&
|
|
10
|
+
state.patientEmail &&
|
|
11
|
+
state.patientGender &&
|
|
12
|
+
state.bloodGroup &&
|
|
13
|
+
state.patientAddress &&
|
|
14
|
+
state.patientCity &&
|
|
15
|
+
state.patientState &&
|
|
16
|
+
state.patientCountry &&
|
|
17
|
+
state.patientZipcode &&
|
|
18
|
+
state.otpVerified;
|
|
19
|
+
return (_jsxs("div", { style: CONTAINER_STYLES.section, children: [_jsx(PatientInfoSection, { state: state, dispatch: dispatch }), _jsx(AddressInfoSection, { state: state, dispatch: dispatch }), _jsxs("div", { style: CONTAINER_STYLES.actions, children: [_jsx("button", { style: BUTTON_STYLES.secondary, onClick: onBack, children: "Back" }), _jsx("button", { style: {
|
|
20
|
+
...BUTTON_STYLES.primary,
|
|
21
|
+
opacity: isFormValid ? 1 : 0.6,
|
|
22
|
+
}, disabled: !isFormValid || state.loading, onClick: onSubmit, children: state.loading ? "Booking..." : "Continue" })] })] }));
|
|
23
|
+
};
|
|
24
|
+
const PatientInfoSection = ({ state, dispatch }) => {
|
|
25
|
+
const firstName = state.patientName.split(" ")[0] || "";
|
|
26
|
+
const lastName = state.patientName.split(" ").slice(1).join(" ") || "";
|
|
27
|
+
return (_jsxs("div", { style: PATIENT_DETAILS_STYLES.sectionCard, children: [_jsxs("div", { style: PATIENT_DETAILS_STYLES.sectionHeader, children: [_jsx(UserIcon, {}), _jsx("h3", { style: PATIENT_DETAILS_STYLES.sectionTitle, children: "Patient Information" })] }), _jsxs("div", { style: PATIENT_DETAILS_STYLES.sectionBody, children: [_jsxs("div", { style: PATIENT_DETAILS_STYLES.gridRow, children: [_jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["First Name ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, placeholder: "Jane", value: firstName, onChange: (e) => {
|
|
28
|
+
dispatch({
|
|
29
|
+
type: "SET_PATIENT_NAME",
|
|
30
|
+
payload: `${e.target.value} ${lastName}`,
|
|
31
|
+
});
|
|
32
|
+
} })] }), _jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["Last Name ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, placeholder: "Doe", value: lastName, onChange: (e) => {
|
|
33
|
+
dispatch({
|
|
34
|
+
type: "SET_PATIENT_NAME",
|
|
35
|
+
payload: `${firstName} ${e.target.value}`,
|
|
36
|
+
});
|
|
37
|
+
} })] })] }), _jsxs("div", { style: PATIENT_DETAILS_STYLES.gridRow, children: [_jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["Date of Birth ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, type: "date", onChange: (e) => {
|
|
38
|
+
const birthDate = new Date(e.target.value);
|
|
39
|
+
const today = new Date();
|
|
40
|
+
const age = today.getFullYear() - birthDate.getFullYear();
|
|
41
|
+
dispatch({
|
|
42
|
+
type: "SET_PATIENT_AGE",
|
|
43
|
+
payload: String(age),
|
|
44
|
+
});
|
|
45
|
+
} })] }), _jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["Email ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, type: "email", placeholder: "jane@example.com", value: state.patientEmail, onChange: (e) => dispatch({
|
|
46
|
+
type: "SET_PATIENT_EMAIL",
|
|
47
|
+
payload: e.target.value,
|
|
48
|
+
}) })] })] }), _jsxs("div", { style: PATIENT_DETAILS_STYLES.gridRow, children: [_jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["Gender ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsxs(Select, { value: state.patientGender, onValueChange: (value) => dispatch({
|
|
49
|
+
type: "SET_PATIENT_GENDER",
|
|
50
|
+
payload: value,
|
|
51
|
+
}), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Select gender" }) }), _jsx(SelectContent, { children: GENDER_OPTIONS.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] })] }), _jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["Blood Group ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsxs(Select, { value: state.bloodGroup, onValueChange: (value) => dispatch({
|
|
52
|
+
type: "SET_BLOOD_GROUP",
|
|
53
|
+
payload: value,
|
|
54
|
+
}), children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: "Select blood group" }) }), _jsx(SelectContent, { children: BLOOD_GROUP_OPTIONS.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))) })] })] })] })] })] }));
|
|
55
|
+
};
|
|
56
|
+
const AddressInfoSection = ({ state, dispatch }) => {
|
|
57
|
+
return (_jsxs("div", { style: PATIENT_DETAILS_STYLES.sectionCard, children: [_jsxs("div", { style: PATIENT_DETAILS_STYLES.sectionHeader, children: [_jsx(MapPinIcon, {}), _jsx("h3", { style: PATIENT_DETAILS_STYLES.sectionTitle, children: "Address Information" })] }), _jsxs("div", { style: PATIENT_DETAILS_STYLES.sectionBody, children: [_jsxs("div", { style: { marginBottom: 20 }, children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["Address ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, placeholder: "123 Main Street", value: state.patientAddress, onChange: (e) => dispatch({
|
|
58
|
+
type: "SET_PATIENT_ADDRESS",
|
|
59
|
+
payload: e.target.value,
|
|
60
|
+
}) })] }), _jsxs("div", { style: PATIENT_DETAILS_STYLES.gridRow, children: [_jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["City ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, placeholder: "New York", value: state.patientCity, onChange: (e) => dispatch({
|
|
61
|
+
type: "SET_PATIENT_CITY",
|
|
62
|
+
payload: e.target.value,
|
|
63
|
+
}) })] }), _jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["State ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, placeholder: "NY", value: state.patientState, onChange: (e) => dispatch({
|
|
64
|
+
type: "SET_PATIENT_STATE",
|
|
65
|
+
payload: e.target.value,
|
|
66
|
+
}) })] })] }), _jsxs("div", { style: PATIENT_DETAILS_STYLES.gridRow, children: [_jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["Country ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, placeholder: "United States", value: state.patientCountry, onChange: (e) => dispatch({
|
|
67
|
+
type: "SET_PATIENT_COUNTRY",
|
|
68
|
+
payload: e.target.value,
|
|
69
|
+
}) })] }), _jsxs("div", { children: [_jsxs("label", { style: PATIENT_DETAILS_STYLES.label, children: ["Zipcode ", _jsx("span", { style: { color: "#EF4444" }, children: "*" })] }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, placeholder: "10001", value: state.patientZipcode, onChange: (e) => dispatch({
|
|
70
|
+
type: "SET_PATIENT_ZIPCODE",
|
|
71
|
+
payload: e.target.value,
|
|
72
|
+
}) })] })] }), _jsxs("div", { style: { marginTop: 20 }, children: [_jsx("label", { style: PATIENT_DETAILS_STYLES.label, children: "Landmark" }), _jsx("input", { style: PATIENT_DETAILS_STYLES.input, placeholder: "Near Central Park", value: state.patientLandmark, onChange: (e) => dispatch({
|
|
73
|
+
type: "SET_PATIENT_LANDMARK",
|
|
74
|
+
payload: e.target.value,
|
|
75
|
+
}) })] })] })] }));
|
|
76
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { COUNTRY_CODES, } from "./types";
|
|
3
|
+
import { BUTTON_STYLES, PHONE_VERIFY_STYLES } from "./styles";
|
|
4
|
+
import { validatePhoneNumber, validateCountryCode } from "./validation";
|
|
5
|
+
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, } from "./uiComponents/SelectDropdown";
|
|
6
|
+
export const PhoneVerificationStep = ({ state, dispatch, onSendOtp, onVerifyOtp, onBack, onContinue, }) => {
|
|
7
|
+
const isPhoneValid = validatePhoneNumber(state.patientPhone) &&
|
|
8
|
+
validateCountryCode(state.countryCode);
|
|
9
|
+
return (_jsxs("div", { style: PHONE_VERIFY_STYLES.container, children: [_jsx("div", { style: PHONE_VERIFY_STYLES.header, children: _jsx("h3", { style: PHONE_VERIFY_STYLES.title, children: "Verify Details" }) }), _jsx("div", { style: PHONE_VERIFY_STYLES.content, children: !state.otpSent ? (_jsx(PhoneInputSection, { countryCode: state.countryCode, patientPhone: state.patientPhone, onCountryCodeChange: (code) => {
|
|
10
|
+
dispatch({ type: "SET_COUNTRY_CODE", payload: code });
|
|
11
|
+
}, onPhoneChange: (phone) => dispatch({ type: "SET_PATIENT_PHONE", payload: phone }) })) : (_jsx(OtpInputSection, { countryCode: state.countryCode, patientPhone: state.patientPhone, otpCode: state.otpCode, otpVerified: state.otpVerified, onOtpChange: (code) => dispatch({ type: "SET_OTP_CODE", payload: code }) })) }), _jsx("div", { style: PHONE_VERIFY_STYLES.footer, children: !state.otpSent ? (_jsxs(_Fragment, { children: [_jsx("button", { style: BUTTON_STYLES.secondary, onClick: onBack, children: "Back" }), _jsx("button", { style: {
|
|
12
|
+
...BUTTON_STYLES.primary,
|
|
13
|
+
opacity: isPhoneValid ? 1 : 0.6,
|
|
14
|
+
}, disabled: !isPhoneValid || state.otpSending, onClick: onSendOtp, children: state.otpSending ? "Sending..." : "Continue" })] })) : !state.otpVerified ? (_jsxs(_Fragment, { children: [_jsx("button", { style: BUTTON_STYLES.secondary, onClick: () => {
|
|
15
|
+
dispatch({ type: "SET_OTP_SENT", payload: false });
|
|
16
|
+
dispatch({ type: "SET_OTP_CODE", payload: "" });
|
|
17
|
+
}, children: "Change Number" }), _jsx("button", { style: {
|
|
18
|
+
...BUTTON_STYLES.primary,
|
|
19
|
+
opacity: state.otpCode.length === 6 ? 1 : 0.6,
|
|
20
|
+
}, 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" })] })) })] }));
|
|
21
|
+
};
|
|
22
|
+
const PhoneInputSection = ({ countryCode, patientPhone, onCountryCodeChange, onPhoneChange }) => {
|
|
23
|
+
const selectedCountry = COUNTRY_CODES.find((c) => c.code === countryCode);
|
|
24
|
+
return (_jsx(_Fragment, { children: _jsxs("div", { style: { marginBottom: 20 }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Enter Phone Number" }), _jsxs("div", { style: PHONE_VERIFY_STYLES.phoneInputContainer, children: [_jsx("div", { style: { width: 120 }, children: _jsxs(Select, { value: countryCode, onValueChange: onCountryCodeChange, children: [_jsx(SelectTrigger, { children: _jsx(SelectValue, { placeholder: selectedCountry?.label || "Code" }) }), _jsx(SelectContent, { children: COUNTRY_CODES.map((item) => (_jsx(SelectItem, { value: item.code, children: item.label }, item.code))) })] }) }), _jsx("input", { type: "tel", style: PHONE_VERIFY_STYLES.phoneInput, placeholder: "0000 000 000", value: patientPhone, onChange: (e) => {
|
|
25
|
+
const value = e.target.value.replace(/\D/g, "");
|
|
26
|
+
onPhoneChange(value);
|
|
27
|
+
}, maxLength: 15 })] })] }) }));
|
|
28
|
+
};
|
|
29
|
+
const OtpInputSection = ({ countryCode, patientPhone, otpCode, otpVerified, onOtpChange }) => (_jsxs(_Fragment, { children: [_jsxs("div", { style: { marginBottom: 16 }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Phone Number" }), _jsxs("div", { style: PHONE_VERIFY_STYLES.phoneDisplay, children: [countryCode, " ", patientPhone] })] }), _jsxs("div", { style: { marginBottom: 20 }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Enter OTP" }), _jsx("input", { style: {
|
|
30
|
+
...PHONE_VERIFY_STYLES.otpInput,
|
|
31
|
+
...(otpVerified ? { opacity: 0.6, pointerEvents: "none" } : {}),
|
|
32
|
+
}, type: "text", placeholder: "Enter 6-digit OTP", value: otpCode, onChange: (e) => {
|
|
33
|
+
if (!otpVerified) {
|
|
34
|
+
const value = e.target.value.replace(/\D/g, "");
|
|
35
|
+
if (value.length <= 6) {
|
|
36
|
+
onOtpChange(value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}, maxLength: 6, disabled: otpVerified }), _jsx("div", { style: PHONE_VERIFY_STYLES.otpHint, children: "We've sent a 6-digit code to your phone number" })] }), otpVerified && (_jsxs("div", { style: PHONE_VERIFY_STYLES.successMessage, children: [_jsx("div", { style: PHONE_VERIFY_STYLES.successIcon, children: "\u2713" }), _jsxs("div", { children: [_jsx("div", { style: PHONE_VERIFY_STYLES.successTitle, children: "Phone verified successfully" }), _jsx("div", { style: PHONE_VERIFY_STYLES.successSubtitle, children: "Your phone number has been verified" })] })] }))] }));
|