medos-sdk 1.1.10 → 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.
- package/dist/client/MedosClient.d.ts +1 -0
- package/dist/client/MedosClient.js +7 -0
- package/dist/components/AppointmentCalender.js +19 -22
- package/dist/components/AppointmentConfirmationStep.d.ts +1 -0
- package/dist/components/AppointmentConfirmationStep.js +34 -42
- package/dist/components/AppointmentDateTimeModal.d.ts +1 -0
- package/dist/components/AppointmentDateTimeModal.js +201 -168
- package/dist/components/AppointmentSummaryStep.d.ts +12 -0
- package/dist/components/AppointmentSummaryStep.js +168 -0
- package/dist/components/BookingOptionStep.d.ts +14 -0
- package/dist/components/BookingOptionStep.js +346 -0
- package/dist/components/ContactInformationStep.js +10 -4
- package/dist/components/ContactPreferenceStep.js +10 -1
- package/dist/components/DoctorSelectModal.js +105 -59
- package/dist/components/EnquiryForm.js +81 -69
- package/dist/components/Icons/CloseIcon.d.ts +9 -0
- package/dist/components/Icons/CloseIcon.js +5 -0
- package/dist/components/InquiryDetailsStep.js +5 -1
- package/dist/components/PatientDetailsStep.js +17 -12
- package/dist/components/PatientSelectionStep.d.ts +12 -0
- package/dist/components/PatientSelectionStep.js +254 -0
- package/dist/components/PhoneVerificationStep.js +1 -1
- package/dist/components/SuccessStep.js +1 -1
- package/dist/components/appointment-booking/AppointmentCalender.js +200 -60
- package/dist/components/appointment-booking/hooks/useAppointmentFlow.d.ts +0 -1
- package/dist/components/appointment-booking/hooks/useAppointmentFlow.js +110 -25
- package/dist/components/appointment-booking/hooks/useAppointmentState.js +32 -0
- package/dist/components/appointment-booking/hooks/useInitializeAddresses.js +0 -1
- package/dist/components/appointment-booking/types.d.ts +163 -0
- package/dist/components/appointment-booking/types.js +16 -0
- package/dist/components/appointment-modal-styles.d.ts +259 -0
- package/dist/components/appointment-modal-styles.js +395 -0
- package/dist/components/constant.d.ts +2 -0
- package/dist/components/constant.js +15 -0
- package/dist/components/custom-calendar.js +20 -11
- package/dist/components/styles.js +93 -52
- package/dist/components/theme-styles.d.ts +5 -4
- package/dist/components/theme-styles.js +221 -125
- package/dist/components/types.d.ts +3 -1
- package/dist/components/types.js +15 -0
- package/dist/components/utils.d.ts +3 -0
- package/dist/components/utils.js +59 -0
- package/dist/components/validation.d.ts +2 -0
- package/dist/components/validation.js +41 -0
- package/dist/core/theme/index.d.ts +1 -0
- package/dist/core/theme/index.js +1 -0
- package/dist/core/theme/responsive.d.ts +15 -0
- package/dist/core/theme/responsive.js +113 -0
- package/dist/core/theme/themes.js +16 -4
- package/dist/core/theme/types.d.ts +8 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/react/ThemeProvider.d.ts +2 -1
- package/dist/react/ThemeProvider.js +49 -10
- package/dist/services/AppointmentService.d.ts +80 -2
- package/dist/services/AppointmentService.js +114 -5
- package/dist/services/WorkspaceService.d.ts +58 -3
- package/dist/services/WorkspaceService.js +10 -1
- package/dist/vanilla/AppointmentCalendarWidget.d.ts +9 -7
- package/dist/vanilla/AppointmentCalendarWidget.js +820 -377
- package/dist/vanilla/EnquiryFormWidget.d.ts +1 -0
- package/dist/vanilla/EnquiryFormWidget.js +25 -43
- package/dist/vanilla/client/MedosClient.d.ts +1 -0
- package/dist/vanilla/components/AppointmentConfirmationStep.d.ts +1 -0
- package/dist/vanilla/components/AppointmentDateTimeModal.d.ts +1 -0
- package/dist/vanilla/components/AppointmentSummaryStep.d.ts +12 -0
- package/dist/vanilla/components/BookingOptionStep.d.ts +14 -0
- package/dist/vanilla/components/Icons/CloseIcon.d.ts +9 -0
- package/dist/vanilla/components/PatientSelectionStep.d.ts +12 -0
- package/dist/vanilla/components/VanillaCalendar.js +33 -18
- package/dist/vanilla/components/VanillaIcons.d.ts +5 -0
- package/dist/vanilla/components/VanillaIcons.js +92 -0
- package/dist/vanilla/components/VanillaSelect.d.ts +3 -0
- package/dist/vanilla/components/VanillaSelect.js +93 -5
- package/dist/vanilla/components/appointment-booking/hooks/useAppointmentFlow.d.ts +0 -1
- package/dist/vanilla/components/appointment-booking/types.d.ts +163 -0
- package/dist/vanilla/components/appointment-modal-styles.d.ts +259 -0
- package/dist/vanilla/components/constant.d.ts +2 -0
- package/dist/vanilla/components/theme-styles.d.ts +5 -4
- package/dist/vanilla/components/types.d.ts +3 -1
- package/dist/vanilla/components/utils.d.ts +3 -0
- package/dist/vanilla/components/validation.d.ts +2 -0
- package/dist/vanilla/core/theme/index.d.ts +1 -0
- package/dist/vanilla/core/theme/responsive.d.ts +15 -0
- package/dist/vanilla/core/theme/types.d.ts +8 -0
- package/dist/vanilla/enquiry-widget.js +373 -52
- package/dist/vanilla/index.d.ts +2 -0
- package/dist/vanilla/react/ThemeProvider.d.ts +2 -1
- package/dist/vanilla/services/AppointmentService.d.ts +80 -2
- package/dist/vanilla/services/WorkspaceService.d.ts +58 -3
- package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +9 -7
- package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +1 -0
- package/dist/vanilla/vanilla/components/VanillaIcons.d.ts +5 -0
- package/dist/vanilla/vanilla/components/VanillaSelect.d.ts +3 -0
- package/dist/vanilla/widget.css +833 -207
- package/dist/vanilla/widget.js +6444 -5676
- package/package.json +1 -1
|
@@ -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
|
+
};
|
package/dist/core/theme/index.js
CHANGED
|
@@ -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: "#
|
|
21
|
+
textTertiary: "#4E8F50",
|
|
22
22
|
textDisabled: "#9ca3af",
|
|
23
23
|
textOnPrimary: "#fff",
|
|
24
24
|
textOnSecondary: "#fff",
|
|
25
|
-
success: "#
|
|
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: "#
|
|
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: "#
|
|
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,
|
|
@@ -82,6 +82,12 @@ export interface ThemeTransitions {
|
|
|
82
82
|
normal: string;
|
|
83
83
|
slow: string;
|
|
84
84
|
}
|
|
85
|
+
export interface ThemeBreakpoints {
|
|
86
|
+
mobile: string;
|
|
87
|
+
tablet: string;
|
|
88
|
+
desktop: string;
|
|
89
|
+
wide: string;
|
|
90
|
+
}
|
|
85
91
|
export interface MedosTheme {
|
|
86
92
|
name: string;
|
|
87
93
|
colors: ThemeColors;
|
|
@@ -90,6 +96,7 @@ export interface MedosTheme {
|
|
|
90
96
|
shadows: ThemeShadows;
|
|
91
97
|
radii: ThemeRadii;
|
|
92
98
|
transitions: ThemeTransitions;
|
|
99
|
+
breakpoints: ThemeBreakpoints;
|
|
93
100
|
}
|
|
94
101
|
export type PartialTheme = {
|
|
95
102
|
name?: string;
|
|
@@ -99,6 +106,7 @@ export type PartialTheme = {
|
|
|
99
106
|
shadows?: Partial<ThemeShadows>;
|
|
100
107
|
radii?: Partial<ThemeRadii>;
|
|
101
108
|
transitions?: Partial<ThemeTransitions>;
|
|
109
|
+
breakpoints?: Partial<ThemeBreakpoints>;
|
|
102
110
|
};
|
|
103
111
|
export interface ThemeConfig {
|
|
104
112
|
theme?: MedosTheme | PartialTheme;
|
package/dist/index.d.ts
CHANGED
|
@@ -14,3 +14,5 @@ export * from "./appointment-calendar/types";
|
|
|
14
14
|
export * from "./enquiry-form/provider";
|
|
15
15
|
export * from "./enquiry-form/types";
|
|
16
16
|
export { PatientService, SendPhoneVerificationOtpPayload, VerifyPhoneVerificationOtpPayload, } from "./services/PatientService";
|
|
17
|
+
export { WorkspaceService } from "./services/WorkspaceService";
|
|
18
|
+
export type { WorkspaceResponse, Address, ConsultationType, User, Doctor, AddressDoctor, } from "./services/WorkspaceService";
|
package/dist/index.js
CHANGED
|
@@ -10,8 +10,9 @@ export interface MedosThemeProviderProps {
|
|
|
10
10
|
children: React.ReactNode;
|
|
11
11
|
theme?: ThemeName | MedosTheme | PartialTheme;
|
|
12
12
|
cssVariablePrefix?: string;
|
|
13
|
+
onThemeError?: (error: Error) => void;
|
|
13
14
|
}
|
|
14
|
-
export declare function MedosThemeProvider({ children, theme, cssVariablePrefix, }: MedosThemeProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
15
|
+
export declare function MedosThemeProvider({ children, theme, cssVariablePrefix, onThemeError, }: Readonly<MedosThemeProviderProps>): import("react/jsx-runtime").JSX.Element;
|
|
15
16
|
export declare function useThemeContext(): ThemeContextValue;
|
|
16
17
|
export declare function useTheme(): MedosTheme;
|
|
17
18
|
export declare function useCssVar(category: string, key: string, fallback?: string): string;
|
|
@@ -2,20 +2,59 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
2
2
|
import React, { createContext, useMemo } from "react";
|
|
3
3
|
import { defaultTheme, themes } from "../core/theme/themes";
|
|
4
4
|
import { mergeTheme, generateCssVariablesObject } from "../core/theme/utils";
|
|
5
|
+
import { MedosClient } from "../client/MedosClient";
|
|
5
6
|
const ThemeContext = createContext(undefined);
|
|
6
|
-
export function MedosThemeProvider({ children, theme, cssVariablePrefix = "medos", }) {
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
export function MedosThemeProvider({ children, theme, cssVariablePrefix = "medos", onThemeError, }) {
|
|
8
|
+
const [apiTheme, setApiTheme] = React.useState(null);
|
|
9
|
+
React.useEffect(() => {
|
|
10
|
+
if (theme !== undefined) {
|
|
11
|
+
return;
|
|
10
12
|
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
+
let isMounted = true;
|
|
14
|
+
const fetchThemeFromApi = async () => {
|
|
15
|
+
try {
|
|
16
|
+
const fetchedTheme = await MedosClient.fetchTheme();
|
|
17
|
+
if (isMounted) {
|
|
18
|
+
if (fetchedTheme &&
|
|
19
|
+
(fetchedTheme === "default" || fetchedTheme === "modern")) {
|
|
20
|
+
setApiTheme(fetchedTheme);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
setApiTheme(null);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
if (isMounted) {
|
|
29
|
+
if (onThemeError) {
|
|
30
|
+
onThemeError(error);
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
console.warn("Failed to fetch theme from API, using default theme:", error);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
fetchThemeFromApi();
|
|
39
|
+
return () => {
|
|
40
|
+
isMounted = false;
|
|
41
|
+
};
|
|
42
|
+
}, [theme, onThemeError]);
|
|
43
|
+
const resolvedTheme = useMemo(() => {
|
|
44
|
+
if (theme !== undefined) {
|
|
45
|
+
if (typeof theme === "string") {
|
|
46
|
+
return themes[theme] || defaultTheme;
|
|
47
|
+
}
|
|
48
|
+
if ("name" in theme && "colors" in theme && "typography" in theme) {
|
|
49
|
+
return theme;
|
|
50
|
+
}
|
|
51
|
+
return mergeTheme(theme);
|
|
13
52
|
}
|
|
14
|
-
if (
|
|
15
|
-
return
|
|
53
|
+
if (apiTheme) {
|
|
54
|
+
return themes[apiTheme] || defaultTheme;
|
|
16
55
|
}
|
|
17
|
-
return
|
|
18
|
-
}, [theme]);
|
|
56
|
+
return defaultTheme;
|
|
57
|
+
}, [theme, apiTheme]);
|
|
19
58
|
const cssVars = useMemo(() => generateCssVariablesObject(resolvedTheme, cssVariablePrefix), [resolvedTheme, cssVariablePrefix]);
|
|
20
59
|
const contextValue = useMemo(() => ({
|
|
21
60
|
theme: resolvedTheme,
|
|
@@ -11,6 +11,7 @@ export type Slot = {
|
|
|
11
11
|
[key: string]: any;
|
|
12
12
|
};
|
|
13
13
|
type PatientPayload = {
|
|
14
|
+
id?: number;
|
|
14
15
|
firstName: string;
|
|
15
16
|
lastName: string;
|
|
16
17
|
email?: string;
|
|
@@ -18,6 +19,8 @@ type PatientPayload = {
|
|
|
18
19
|
phoneNumber: string;
|
|
19
20
|
age?: number;
|
|
20
21
|
gender?: "MALE" | "FEMALE" | "OTHER";
|
|
22
|
+
dob?: string;
|
|
23
|
+
bloodGroup?: string;
|
|
21
24
|
};
|
|
22
25
|
type PatientAddressPayload = {
|
|
23
26
|
addressLine1: string;
|
|
@@ -26,6 +29,11 @@ type PatientAddressPayload = {
|
|
|
26
29
|
country: string;
|
|
27
30
|
zipcode: string;
|
|
28
31
|
landmark?: string;
|
|
32
|
+
addressLine2?: string;
|
|
33
|
+
completeAddress?: string;
|
|
34
|
+
countryCode?: string;
|
|
35
|
+
phoneNumber?: string;
|
|
36
|
+
patientId?: number;
|
|
29
37
|
};
|
|
30
38
|
type BookAppointmentPayload = {
|
|
31
39
|
workspaceId?: string | number;
|
|
@@ -35,13 +43,79 @@ type BookAppointmentPayload = {
|
|
|
35
43
|
appointmentDate: string;
|
|
36
44
|
fromDateTimeTs: string;
|
|
37
45
|
toDateTimeTs: string;
|
|
38
|
-
consultationCharge?: string;
|
|
46
|
+
consultationCharge?: string | number;
|
|
39
47
|
type?: "CONSULTATION" | string;
|
|
40
48
|
source?: string;
|
|
49
|
+
bookingType?: "PACKAGE_PURCHASE" | "ONE_TIME_APPOINTMENT" | "USE_ACTIVE_PACKAGE";
|
|
50
|
+
paymentMode?: "CASH" | "CARD" | string;
|
|
51
|
+
packageConfigId?: number;
|
|
52
|
+
patientPackageId?: number;
|
|
53
|
+
packageAmount?: number;
|
|
41
54
|
patientPayload: PatientPayload;
|
|
42
55
|
patientAddress: PatientAddressPayload;
|
|
43
56
|
attachments?: File[];
|
|
44
57
|
};
|
|
58
|
+
export type UnifiedBookAppointmentPayload = {
|
|
59
|
+
workspaceId: number;
|
|
60
|
+
workspaceAddressId: number;
|
|
61
|
+
doctorId: number;
|
|
62
|
+
mode: "ONLINE" | "OFFLINE";
|
|
63
|
+
appointmentDate: string;
|
|
64
|
+
fromDateTimeTs: string;
|
|
65
|
+
toDateTimeTs: string;
|
|
66
|
+
bookingType: "PACKAGE_PURCHASE" | "ONE_TIME_APPOINTMENT" | "USE_ACTIVE_PACKAGE";
|
|
67
|
+
consultationCharge: number;
|
|
68
|
+
packageConfigId?: number;
|
|
69
|
+
patientPackageId?: number;
|
|
70
|
+
packageAmount?: number;
|
|
71
|
+
paymentMode: "CASH" | "CARD" | string;
|
|
72
|
+
type: "CONSULTATION" | string;
|
|
73
|
+
source: string;
|
|
74
|
+
patientPayload: {
|
|
75
|
+
id?: number;
|
|
76
|
+
firstName: string;
|
|
77
|
+
lastName: string;
|
|
78
|
+
email: string;
|
|
79
|
+
countryCode: string;
|
|
80
|
+
phoneNumber: string;
|
|
81
|
+
dob: string;
|
|
82
|
+
age: number;
|
|
83
|
+
gender: "MALE" | "FEMALE" | "OTHER";
|
|
84
|
+
bloodGroup: string;
|
|
85
|
+
};
|
|
86
|
+
patientAddress: {
|
|
87
|
+
completeAddress: string;
|
|
88
|
+
addressLine1: string;
|
|
89
|
+
addressLine2?: string;
|
|
90
|
+
city: string;
|
|
91
|
+
state: string;
|
|
92
|
+
country: string;
|
|
93
|
+
zipcode: string;
|
|
94
|
+
landmark?: string;
|
|
95
|
+
countryCode: string;
|
|
96
|
+
phoneNumber: string;
|
|
97
|
+
patientId: number;
|
|
98
|
+
};
|
|
99
|
+
};
|
|
100
|
+
export type AppointmentResponse = {
|
|
101
|
+
id: number;
|
|
102
|
+
patientName: string;
|
|
103
|
+
patientEmail: string;
|
|
104
|
+
patientPhone: string;
|
|
105
|
+
doctorId: number;
|
|
106
|
+
addressId: number;
|
|
107
|
+
appointmentDate: string;
|
|
108
|
+
startTime: string;
|
|
109
|
+
endTime: string;
|
|
110
|
+
status: string;
|
|
111
|
+
consultationCharge: number;
|
|
112
|
+
paymentMode: string;
|
|
113
|
+
type: string;
|
|
114
|
+
mode: string;
|
|
115
|
+
notes?: string;
|
|
116
|
+
createdAt: string;
|
|
117
|
+
[key: string]: any;
|
|
118
|
+
};
|
|
45
119
|
type AppointmentPayload = {
|
|
46
120
|
workspaceId?: string | number;
|
|
47
121
|
workspaceAddressId: string | number;
|
|
@@ -78,8 +152,12 @@ type AddressesResponse = {
|
|
|
78
152
|
addresses: AddressItem[];
|
|
79
153
|
};
|
|
80
154
|
declare const AppointmentService: {
|
|
155
|
+
arePackagesConfigured(): Promise<boolean>;
|
|
81
156
|
getAddresses(): Promise<AddressesResponse>;
|
|
82
157
|
fetchSlots(workspaceId: number, addressId: number, doctorId: number, appointmentDate: string): Promise<Slot[]>;
|
|
83
|
-
|
|
158
|
+
transformToUnifiedPayload(payload: BookAppointmentPayload): UnifiedBookAppointmentPayload;
|
|
159
|
+
createLegacyAppointment(payload: BookAppointmentPayload): Promise<AppointmentResponse>;
|
|
160
|
+
createAppointment(payload: BookAppointmentPayload): Promise<AppointmentResponse>;
|
|
161
|
+
createUnifiedAppointment(payload: BookAppointmentPayload): Promise<AppointmentResponse>;
|
|
84
162
|
};
|
|
85
163
|
export { AppointmentService, AppointmentPayload, BookAppointmentPayload, PatientPayload, PatientAddressPayload, AddressesResponse, AddressItem, };
|
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
import { MedosClient } from "../client/MedosClient";
|
|
2
|
+
import { mapBloodGroupToApi } from "../components/types";
|
|
3
|
+
import { WorkspaceService } from "./WorkspaceService";
|
|
2
4
|
const AppointmentService = {
|
|
5
|
+
async arePackagesConfigured() {
|
|
6
|
+
try {
|
|
7
|
+
const workspace = await WorkspaceService.fetchWorkspace();
|
|
8
|
+
return workspace.arePackagesConfigured === true;
|
|
9
|
+
}
|
|
10
|
+
catch (error) {
|
|
11
|
+
console.warn("Failed to check package configuration, defaulting to legacy endpoint:", error);
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
},
|
|
3
15
|
async getAddresses() {
|
|
4
16
|
const client = await MedosClient.ensureInitialized();
|
|
5
17
|
const res = await client.get("/workspaces");
|
|
@@ -73,16 +85,82 @@ const AppointmentService = {
|
|
|
73
85
|
}
|
|
74
86
|
return [];
|
|
75
87
|
},
|
|
76
|
-
|
|
88
|
+
transformToUnifiedPayload(payload) {
|
|
89
|
+
const consultationCharge = typeof payload.consultationCharge === "string"
|
|
90
|
+
? Number.parseFloat(payload.consultationCharge) || 0
|
|
91
|
+
: payload.consultationCharge || 0;
|
|
92
|
+
const completeAddress = [
|
|
93
|
+
payload.patientAddress.addressLine1,
|
|
94
|
+
payload.patientAddress.addressLine2,
|
|
95
|
+
payload.patientAddress.city,
|
|
96
|
+
payload.patientAddress.state,
|
|
97
|
+
payload.patientAddress.country,
|
|
98
|
+
payload.patientAddress.zipcode,
|
|
99
|
+
]
|
|
100
|
+
.filter(Boolean)
|
|
101
|
+
.join(", ");
|
|
102
|
+
const unifiedPayload = {
|
|
103
|
+
workspaceId: Number(payload.workspaceId || 0),
|
|
104
|
+
workspaceAddressId: Number(payload.workspaceAddressId),
|
|
105
|
+
doctorId: Number(payload.doctorId),
|
|
106
|
+
mode: (payload.mode || "OFFLINE"),
|
|
107
|
+
appointmentDate: payload.appointmentDate,
|
|
108
|
+
fromDateTimeTs: payload.fromDateTimeTs,
|
|
109
|
+
toDateTimeTs: payload.toDateTimeTs,
|
|
110
|
+
bookingType: payload.bookingType || "ONE_TIME_APPOINTMENT",
|
|
111
|
+
consultationCharge,
|
|
112
|
+
paymentMode: payload.paymentMode || "CASH",
|
|
113
|
+
type: payload.type || "CONSULTATION",
|
|
114
|
+
source: payload.source || "SDK_POWERED_WEBSITE",
|
|
115
|
+
patientPayload: {
|
|
116
|
+
id: payload.patientPayload.id,
|
|
117
|
+
firstName: payload.patientPayload.firstName,
|
|
118
|
+
lastName: payload.patientPayload.lastName,
|
|
119
|
+
email: payload.patientPayload.email || "",
|
|
120
|
+
countryCode: payload.patientPayload.countryCode,
|
|
121
|
+
phoneNumber: payload.patientPayload.phoneNumber,
|
|
122
|
+
dob: payload.patientPayload.dob || "",
|
|
123
|
+
age: payload.patientPayload.age || 0,
|
|
124
|
+
gender: (payload.patientPayload.gender || "OTHER"),
|
|
125
|
+
bloodGroup: payload.patientPayload.bloodGroup
|
|
126
|
+
? mapBloodGroupToApi(payload.patientPayload.bloodGroup)
|
|
127
|
+
: "UNKNOWN",
|
|
128
|
+
},
|
|
129
|
+
patientAddress: {
|
|
130
|
+
completeAddress,
|
|
131
|
+
addressLine1: payload.patientAddress.addressLine1,
|
|
132
|
+
addressLine2: payload.patientAddress.addressLine2,
|
|
133
|
+
city: payload.patientAddress.city,
|
|
134
|
+
state: payload.patientAddress.state,
|
|
135
|
+
country: payload.patientAddress.country,
|
|
136
|
+
zipcode: payload.patientAddress.zipcode,
|
|
137
|
+
landmark: payload.patientAddress.landmark,
|
|
138
|
+
countryCode: payload.patientAddress.countryCode || "",
|
|
139
|
+
phoneNumber: payload.patientAddress.phoneNumber || "",
|
|
140
|
+
patientId: payload.patientAddress.patientId || 0,
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
if (payload.packageConfigId) {
|
|
144
|
+
unifiedPayload.packageConfigId = payload.packageConfigId;
|
|
145
|
+
}
|
|
146
|
+
if (payload.patientPackageId) {
|
|
147
|
+
unifiedPayload.patientPackageId = payload.patientPackageId;
|
|
148
|
+
}
|
|
149
|
+
if (payload.packageAmount) {
|
|
150
|
+
unifiedPayload.packageAmount = payload.packageAmount;
|
|
151
|
+
}
|
|
152
|
+
return unifiedPayload;
|
|
153
|
+
},
|
|
154
|
+
async createLegacyAppointment(payload) {
|
|
77
155
|
const client = await MedosClient.ensureInitialized();
|
|
78
|
-
const
|
|
156
|
+
const legacyPayload = {
|
|
79
157
|
workspaceAddressId: payload.workspaceAddressId,
|
|
80
158
|
doctorId: payload.doctorId,
|
|
81
159
|
mode: payload.mode || "OFFLINE",
|
|
82
160
|
appointmentDate: payload.appointmentDate,
|
|
83
161
|
fromDateTimeTs: payload.fromDateTimeTs,
|
|
84
162
|
toDateTimeTs: payload.toDateTimeTs,
|
|
85
|
-
consultationCharge: payload.consultationCharge
|
|
163
|
+
consultationCharge: payload.consultationCharge,
|
|
86
164
|
type: payload.type || "CONSULTATION",
|
|
87
165
|
source: payload.source || "SDK_POWERED_WEBSITE",
|
|
88
166
|
patientPayload: payload.patientPayload,
|
|
@@ -90,7 +168,7 @@ const AppointmentService = {
|
|
|
90
168
|
};
|
|
91
169
|
if (payload.attachments && payload.attachments.length > 0) {
|
|
92
170
|
const formData = new FormData();
|
|
93
|
-
const payloadString = JSON.stringify(
|
|
171
|
+
const payloadString = JSON.stringify(legacyPayload);
|
|
94
172
|
formData.append("payload", payloadString);
|
|
95
173
|
payload.attachments.forEach((file) => {
|
|
96
174
|
formData.append("attachments", file);
|
|
@@ -99,7 +177,38 @@ const AppointmentService = {
|
|
|
99
177
|
return res.data;
|
|
100
178
|
}
|
|
101
179
|
else {
|
|
102
|
-
const res = await client.post("/appointments/book-appointment",
|
|
180
|
+
const res = await client.post("/appointments/book-appointment", legacyPayload, {
|
|
181
|
+
headers: {
|
|
182
|
+
"Content-Type": "application/json",
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
return res.data;
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
async createAppointment(payload) {
|
|
189
|
+
const packagesConfigured = await this.arePackagesConfigured();
|
|
190
|
+
if (packagesConfigured) {
|
|
191
|
+
return this.createUnifiedAppointment(payload);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
return this.createLegacyAppointment(payload);
|
|
195
|
+
}
|
|
196
|
+
},
|
|
197
|
+
async createUnifiedAppointment(payload) {
|
|
198
|
+
const client = await MedosClient.ensureInitialized();
|
|
199
|
+
const unifiedPayload = this.transformToUnifiedPayload(payload);
|
|
200
|
+
if (payload.attachments && payload.attachments.length > 0) {
|
|
201
|
+
const formData = new FormData();
|
|
202
|
+
const payloadString = JSON.stringify(unifiedPayload);
|
|
203
|
+
formData.append("payload", payloadString);
|
|
204
|
+
payload.attachments.forEach((file) => {
|
|
205
|
+
formData.append("attachments", file);
|
|
206
|
+
});
|
|
207
|
+
const res = await client.post("/appointments/book-appointment-unified", formData);
|
|
208
|
+
return res.data;
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
const res = await client.post("/appointments/book-appointment-unified", unifiedPayload, {
|
|
103
212
|
headers: {
|
|
104
213
|
"Content-Type": "application/json",
|
|
105
214
|
},
|