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.
Files changed (97) 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 +19 -22
  4. package/dist/components/AppointmentConfirmationStep.d.ts +1 -0
  5. package/dist/components/AppointmentConfirmationStep.js +34 -42
  6. package/dist/components/AppointmentDateTimeModal.d.ts +1 -0
  7. package/dist/components/AppointmentDateTimeModal.js +201 -168
  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 +10 -4
  13. package/dist/components/ContactPreferenceStep.js +10 -1
  14. package/dist/components/DoctorSelectModal.js +105 -59
  15. package/dist/components/EnquiryForm.js +81 -69
  16. package/dist/components/Icons/CloseIcon.d.ts +9 -0
  17. package/dist/components/Icons/CloseIcon.js +5 -0
  18. package/dist/components/InquiryDetailsStep.js +5 -1
  19. package/dist/components/PatientDetailsStep.js +17 -12
  20. package/dist/components/PatientSelectionStep.d.ts +12 -0
  21. package/dist/components/PatientSelectionStep.js +254 -0
  22. package/dist/components/PhoneVerificationStep.js +1 -1
  23. package/dist/components/SuccessStep.js +1 -1
  24. package/dist/components/appointment-booking/AppointmentCalender.js +200 -60
  25. package/dist/components/appointment-booking/hooks/useAppointmentFlow.d.ts +0 -1
  26. package/dist/components/appointment-booking/hooks/useAppointmentFlow.js +110 -25
  27. package/dist/components/appointment-booking/hooks/useAppointmentState.js +32 -0
  28. package/dist/components/appointment-booking/hooks/useInitializeAddresses.js +0 -1
  29. package/dist/components/appointment-booking/types.d.ts +163 -0
  30. package/dist/components/appointment-booking/types.js +16 -0
  31. package/dist/components/appointment-modal-styles.d.ts +259 -0
  32. package/dist/components/appointment-modal-styles.js +395 -0
  33. package/dist/components/constant.d.ts +2 -0
  34. package/dist/components/constant.js +15 -0
  35. package/dist/components/custom-calendar.js +20 -11
  36. package/dist/components/styles.js +93 -52
  37. package/dist/components/theme-styles.d.ts +5 -4
  38. package/dist/components/theme-styles.js +221 -125
  39. package/dist/components/types.d.ts +3 -1
  40. package/dist/components/types.js +15 -0
  41. package/dist/components/utils.d.ts +3 -0
  42. package/dist/components/utils.js +59 -0
  43. package/dist/components/validation.d.ts +2 -0
  44. package/dist/components/validation.js +41 -0
  45. package/dist/core/theme/index.d.ts +1 -0
  46. package/dist/core/theme/index.js +1 -0
  47. package/dist/core/theme/responsive.d.ts +15 -0
  48. package/dist/core/theme/responsive.js +113 -0
  49. package/dist/core/theme/themes.js +16 -4
  50. package/dist/core/theme/types.d.ts +8 -0
  51. package/dist/index.d.ts +2 -0
  52. package/dist/index.js +1 -0
  53. package/dist/react/ThemeProvider.d.ts +2 -1
  54. package/dist/react/ThemeProvider.js +49 -10
  55. package/dist/services/AppointmentService.d.ts +80 -2
  56. package/dist/services/AppointmentService.js +114 -5
  57. package/dist/services/WorkspaceService.d.ts +58 -3
  58. package/dist/services/WorkspaceService.js +10 -1
  59. package/dist/vanilla/AppointmentCalendarWidget.d.ts +9 -7
  60. package/dist/vanilla/AppointmentCalendarWidget.js +820 -377
  61. package/dist/vanilla/EnquiryFormWidget.d.ts +1 -0
  62. package/dist/vanilla/EnquiryFormWidget.js +25 -43
  63. package/dist/vanilla/client/MedosClient.d.ts +1 -0
  64. package/dist/vanilla/components/AppointmentConfirmationStep.d.ts +1 -0
  65. package/dist/vanilla/components/AppointmentDateTimeModal.d.ts +1 -0
  66. package/dist/vanilla/components/AppointmentSummaryStep.d.ts +12 -0
  67. package/dist/vanilla/components/BookingOptionStep.d.ts +14 -0
  68. package/dist/vanilla/components/Icons/CloseIcon.d.ts +9 -0
  69. package/dist/vanilla/components/PatientSelectionStep.d.ts +12 -0
  70. package/dist/vanilla/components/VanillaCalendar.js +33 -18
  71. package/dist/vanilla/components/VanillaIcons.d.ts +5 -0
  72. package/dist/vanilla/components/VanillaIcons.js +92 -0
  73. package/dist/vanilla/components/VanillaSelect.d.ts +3 -0
  74. package/dist/vanilla/components/VanillaSelect.js +93 -5
  75. package/dist/vanilla/components/appointment-booking/hooks/useAppointmentFlow.d.ts +0 -1
  76. package/dist/vanilla/components/appointment-booking/types.d.ts +163 -0
  77. package/dist/vanilla/components/appointment-modal-styles.d.ts +259 -0
  78. package/dist/vanilla/components/constant.d.ts +2 -0
  79. package/dist/vanilla/components/theme-styles.d.ts +5 -4
  80. package/dist/vanilla/components/types.d.ts +3 -1
  81. package/dist/vanilla/components/utils.d.ts +3 -0
  82. package/dist/vanilla/components/validation.d.ts +2 -0
  83. package/dist/vanilla/core/theme/index.d.ts +1 -0
  84. package/dist/vanilla/core/theme/responsive.d.ts +15 -0
  85. package/dist/vanilla/core/theme/types.d.ts +8 -0
  86. package/dist/vanilla/enquiry-widget.js +373 -52
  87. package/dist/vanilla/index.d.ts +2 -0
  88. package/dist/vanilla/react/ThemeProvider.d.ts +2 -1
  89. package/dist/vanilla/services/AppointmentService.d.ts +80 -2
  90. package/dist/vanilla/services/WorkspaceService.d.ts +58 -3
  91. package/dist/vanilla/vanilla/AppointmentCalendarWidget.d.ts +9 -7
  92. package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +1 -0
  93. package/dist/vanilla/vanilla/components/VanillaIcons.d.ts +5 -0
  94. package/dist/vanilla/vanilla/components/VanillaSelect.d.ts +3 -0
  95. package/dist/vanilla/widget.css +833 -207
  96. package/dist/vanilla/widget.js +6444 -5676
  97. 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
+ };
@@ -1,3 +1,4 @@
1
1
  export * from "./types";
2
2
  export * from "./themes";
3
3
  export * from "./utils";
4
+ export * from "./responsive";
@@ -1,3 +1,4 @@
1
1
  export * from "./types";
2
2
  export * from "./themes";
3
3
  export * from "./utils";
4
+ export * from "./responsive";
@@ -0,0 +1,15 @@
1
+ import { MedosTheme } from "./types";
2
+ export type Breakpoint = "mobile" | "tablet" | "desktop" | "wide";
3
+ export declare function useMediaQuery(query: string): boolean;
4
+ export declare function useBreakpoint(theme: MedosTheme): Breakpoint;
5
+ export declare function useIsMobile(theme: MedosTheme): boolean;
6
+ export declare function useIsTablet(theme: MedosTheme): boolean;
7
+ export declare function useIsDesktop(theme: MedosTheme): boolean;
8
+ export declare function useResponsiveValue<T>(theme: MedosTheme, values: Partial<Record<Breakpoint, T>>): T | undefined;
9
+ export declare function responsiveStyles(styles: Partial<Record<Breakpoint | "base", React.CSSProperties>>, currentBreakpoint: Breakpoint): React.CSSProperties;
10
+ export declare function getResponsiveMaxWidth(theme: MedosTheme, breakpoint: Breakpoint, customMaxWidths?: Partial<Record<Breakpoint, string>>): string;
11
+ export declare function getResponsivePadding(theme: MedosTheme, breakpoint: Breakpoint): string;
12
+ export declare function getResponsiveFontSize(theme: MedosTheme, breakpoint: Breakpoint, size?: keyof MedosTheme["typography"]): string;
13
+ export declare function isTouchDevice(): boolean;
14
+ export declare const MIN_TOUCH_TARGET_SIZE = "44px";
15
+ export declare function getResponsiveInputHeight(breakpoint: Breakpoint): string;
@@ -0,0 +1,113 @@
1
+ import { useState, useEffect } from "react";
2
+ export function useMediaQuery(query) {
3
+ const [matches, setMatches] = useState(false);
4
+ useEffect(() => {
5
+ const mediaQuery = window.matchMedia(query);
6
+ setMatches(mediaQuery.matches);
7
+ const handler = (event) => {
8
+ setMatches(event.matches);
9
+ };
10
+ if (mediaQuery.addEventListener) {
11
+ mediaQuery.addEventListener("change", handler);
12
+ return () => mediaQuery.removeEventListener("change", handler);
13
+ }
14
+ else {
15
+ mediaQuery.addListener(handler);
16
+ return () => mediaQuery.removeListener(handler);
17
+ }
18
+ }, [query]);
19
+ return matches;
20
+ }
21
+ export function useBreakpoint(theme) {
22
+ const isWide = useMediaQuery(`(min-width: ${theme.breakpoints.wide})`);
23
+ const isDesktop = useMediaQuery(`(min-width: ${theme.breakpoints.desktop})`);
24
+ const isTablet = useMediaQuery(`(min-width: ${theme.breakpoints.tablet})`);
25
+ if (isWide)
26
+ return "wide";
27
+ if (isDesktop)
28
+ return "desktop";
29
+ if (isTablet)
30
+ return "tablet";
31
+ return "mobile";
32
+ }
33
+ export function useIsMobile(theme) {
34
+ return useMediaQuery(`(max-width: ${parseInt(theme.breakpoints.tablet) - 1}px)`);
35
+ }
36
+ export function useIsTablet(theme) {
37
+ const minWidth = theme.breakpoints.tablet;
38
+ const maxWidth = `${parseInt(theme.breakpoints.desktop) - 1}px`;
39
+ return useMediaQuery(`(min-width: ${minWidth}) and (max-width: ${maxWidth})`);
40
+ }
41
+ export function useIsDesktop(theme) {
42
+ return useMediaQuery(`(min-width: ${theme.breakpoints.desktop})`);
43
+ }
44
+ export function useResponsiveValue(theme, values) {
45
+ const breakpoint = useBreakpoint(theme);
46
+ if (values[breakpoint] !== undefined) {
47
+ return values[breakpoint];
48
+ }
49
+ if (breakpoint === "wide" && values.desktop !== undefined) {
50
+ return values.desktop;
51
+ }
52
+ if ((breakpoint === "desktop" || breakpoint === "wide") &&
53
+ values.tablet !== undefined) {
54
+ return values.tablet;
55
+ }
56
+ if (values.mobile !== undefined) {
57
+ return values.mobile;
58
+ }
59
+ return undefined;
60
+ }
61
+ export function responsiveStyles(styles, currentBreakpoint) {
62
+ const baseStyles = styles.base || {};
63
+ const breakpointStyles = styles[currentBreakpoint] || {};
64
+ return {
65
+ ...baseStyles,
66
+ ...breakpointStyles,
67
+ };
68
+ }
69
+ export function getResponsiveMaxWidth(theme, breakpoint, customMaxWidths) {
70
+ if (customMaxWidths?.[breakpoint]) {
71
+ return customMaxWidths[breakpoint];
72
+ }
73
+ const defaults = {
74
+ mobile: "100%",
75
+ tablet: "100%",
76
+ desktop: "840px",
77
+ wide: "1200px",
78
+ };
79
+ return defaults[breakpoint];
80
+ }
81
+ export function getResponsivePadding(theme, breakpoint) {
82
+ const paddingMap = {
83
+ mobile: "md",
84
+ tablet: "lg",
85
+ desktop: "xl",
86
+ wide: "2xl",
87
+ };
88
+ return theme.spacing[paddingMap[breakpoint]];
89
+ }
90
+ export function getResponsiveFontSize(theme, breakpoint, size = "fontSizeMd") {
91
+ if (breakpoint === "mobile" && size.startsWith("fontSize")) {
92
+ const sizeMap = {
93
+ fontSize3xl: "fontSize2xl",
94
+ fontSize2xl: "fontSizeXl",
95
+ fontSizeXl: "fontSizeLg",
96
+ fontSizeLg: "fontSizeMd",
97
+ };
98
+ const adjustedSize = sizeMap[size] || size;
99
+ return theme.typography[adjustedSize];
100
+ }
101
+ return theme.typography[size];
102
+ }
103
+ export function isTouchDevice() {
104
+ return ("ontouchstart" in window ||
105
+ navigator.maxTouchPoints > 0 ||
106
+ navigator.msMaxTouchPoints > 0);
107
+ }
108
+ export const MIN_TOUCH_TARGET_SIZE = "44px";
109
+ export function getResponsiveInputHeight(breakpoint) {
110
+ return breakpoint === "mobile" && isTouchDevice()
111
+ ? MIN_TOUCH_TARGET_SIZE
112
+ : "40px";
113
+ }
@@ -18,11 +18,11 @@ export const defaultTheme = {
18
18
  borderFocus: "#27903F",
19
19
  text: "#111827",
20
20
  textSecondary: "#374151",
21
- textTertiary: "#6b7280",
21
+ textTertiary: "#4E8F50",
22
22
  textDisabled: "#9ca3af",
23
23
  textOnPrimary: "#fff",
24
24
  textOnSecondary: "#fff",
25
- success: "#10b981",
25
+ success: "#4E8F50",
26
26
  successBackground: "#ecfdf5",
27
27
  successBorder: "#6ee7b7",
28
28
  error: "#ef4444",
@@ -84,6 +84,12 @@ export const defaultTheme = {
84
84
  normal: "200ms cubic-bezier(0.4, 0, 0.2, 1)",
85
85
  slow: "300ms cubic-bezier(0.4, 0, 0.2, 1)",
86
86
  },
87
+ breakpoints: {
88
+ mobile: "320px",
89
+ tablet: "768px",
90
+ desktop: "1024px",
91
+ wide: "1280px",
92
+ },
87
93
  };
88
94
  export const modernTheme = {
89
95
  name: "modern",
@@ -95,7 +101,7 @@ export const modernTheme = {
95
101
  secondaryHover: "#ff5722",
96
102
  accent: "#3b82f6",
97
103
  accentHover: "#2563eb",
98
- background: "#ffffff",
104
+ background: "#fff",
99
105
  backgroundSecondary: "#f8fafc",
100
106
  backgroundTertiary: "#f1f5f9",
101
107
  surface: "#ffffff",
@@ -109,7 +115,7 @@ export const modernTheme = {
109
115
  textDisabled: "#cbd5e1",
110
116
  textOnPrimary: "#ffffff",
111
117
  textOnSecondary: "#ffffff",
112
- success: "#10b981",
118
+ success: "#4E8F50",
113
119
  successBackground: "#ecfdf5",
114
120
  successBorder: "#6ee7b7",
115
121
  error: "#ef4444",
@@ -171,6 +177,12 @@ export const modernTheme = {
171
177
  normal: "200ms cubic-bezier(0.4, 0, 0.2, 1)",
172
178
  slow: "300ms cubic-bezier(0.4, 0, 0.2, 1)",
173
179
  },
180
+ breakpoints: {
181
+ mobile: "320px",
182
+ tablet: "768px",
183
+ desktop: "1024px",
184
+ wide: "1280px",
185
+ },
174
186
  };
175
187
  export const themes = {
176
188
  default: defaultTheme,
@@ -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
@@ -12,3 +12,4 @@ export * from "./appointment-calendar/types";
12
12
  export * from "./enquiry-form/provider";
13
13
  export * from "./enquiry-form/types";
14
14
  export { PatientService, } from "./services/PatientService";
15
+ export { WorkspaceService } from "./services/WorkspaceService";
@@ -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 resolvedTheme = useMemo(() => {
8
- if (!theme) {
9
- return defaultTheme;
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
- if (typeof theme === "string") {
12
- return themes[theme] || defaultTheme;
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 ("name" in theme && "colors" in theme && "typography" in theme) {
15
- return theme;
53
+ if (apiTheme) {
54
+ return themes[apiTheme] || defaultTheme;
16
55
  }
17
- return mergeTheme(theme);
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
- createAppointment(payload: BookAppointmentPayload): Promise<any>;
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
- async createAppointment(payload) {
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 appointmentData = {
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 || "0",
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(appointmentData);
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", appointmentData, {
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
  },