medos-sdk 1.0.3 → 1.1.1
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/README.md +80 -8
- package/dist/client/MedosClient.d.ts +2 -4
- package/dist/client/MedosClient.js +4 -4
- package/dist/components/AppointmentCalender.js +43 -2
- package/dist/components/AppointmentDateTimeModal.js +45 -31
- package/dist/components/ContactInformationStep.d.ts +13 -0
- package/dist/components/ContactInformationStep.js +14 -0
- package/dist/components/ContactPreferenceStep.d.ts +9 -0
- package/dist/components/ContactPreferenceStep.js +16 -0
- package/dist/components/DoctorSelectModal.js +30 -17
- package/dist/components/EnquiryForm.d.ts +7 -0
- package/dist/components/EnquiryForm.js +212 -0
- package/dist/components/Icons/ConsultationType.js +1 -1
- package/dist/components/Icons/Date&TimeIcon.js +1 -1
- package/dist/components/Icons/MapIcon.js +1 -1
- package/dist/components/Icons/PaymentMethodIcon.js +1 -1
- package/dist/components/Icons/UserIcon.js +1 -1
- package/dist/components/InquiryDetailsStep.d.ts +10 -0
- package/dist/components/InquiryDetailsStep.js +15 -0
- package/dist/components/PatientDetailsStep.js +9 -1
- package/dist/components/PhoneVerificationStep.js +22 -12
- package/dist/components/SuccessStep.d.ts +3 -1
- package/dist/components/SuccessStep.js +7 -15
- package/dist/components/custom-calendar.js +42 -24
- package/dist/components/theme-styles.d.ts +12 -0
- package/dist/components/theme-styles.js +319 -0
- package/dist/components/types.d.ts +0 -1
- package/dist/core/index.d.ts +4 -0
- package/dist/core/index.js +4 -0
- package/dist/core/theme/index.d.ts +3 -0
- package/dist/core/theme/index.js +3 -0
- package/dist/core/theme/themes.d.ts +8 -0
- package/dist/core/theme/themes.js +178 -0
- package/dist/core/theme/types.d.ts +106 -0
- package/dist/core/theme/types.js +1 -0
- package/dist/core/theme/utils.d.ts +8 -0
- package/dist/core/theme/utils.js +135 -0
- package/dist/enquiry-form/index.d.ts +4 -0
- package/dist/enquiry-form/index.js +4 -0
- package/dist/enquiry-form/provider.d.ts +3 -0
- package/dist/enquiry-form/provider.js +9 -0
- package/dist/enquiry-form/serialization.d.ts +4 -0
- package/dist/enquiry-form/serialization.js +57 -0
- package/dist/enquiry-form/types.d.ts +38 -0
- package/dist/enquiry-form/types.js +1 -0
- package/dist/enquiry-form/validation.d.ts +6 -0
- package/dist/enquiry-form/validation.js +21 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +7 -0
- package/dist/react/ThemeProvider.d.ts +18 -0
- package/dist/react/ThemeProvider.js +45 -0
- package/dist/react/hooks/useTheme.d.ts +1 -0
- package/dist/react/hooks/useTheme.js +1 -0
- package/dist/react/index.d.ts +5 -0
- package/dist/react/index.js +3 -0
- package/dist/services/EnquiryService.d.ts +5 -0
- package/dist/services/EnquiryService.js +30 -0
- package/dist/vanilla/AppointmentCalendarWidget.js +0 -2
- package/dist/vanilla/EnquiryFormWidget.d.ts +35 -0
- package/dist/vanilla/EnquiryFormWidget.js +425 -0
- package/dist/vanilla/client/MedosClient.d.ts +2 -4
- package/dist/vanilla/components/ContactInformationStep.d.ts +13 -0
- package/dist/vanilla/components/ContactPreferenceStep.d.ts +9 -0
- package/dist/vanilla/components/EnquiryForm.d.ts +7 -0
- package/dist/vanilla/components/InquiryDetailsStep.d.ts +10 -0
- package/dist/vanilla/components/SuccessStep.d.ts +3 -1
- package/dist/vanilla/components/theme-styles.d.ts +12 -0
- package/dist/vanilla/components/types.d.ts +0 -1
- package/dist/vanilla/core/index.d.ts +4 -0
- package/dist/vanilla/core/theme/index.d.ts +3 -0
- package/dist/vanilla/core/theme/themes.d.ts +8 -0
- package/dist/vanilla/core/theme/types.d.ts +106 -0
- package/dist/vanilla/core/theme/utils.d.ts +8 -0
- package/dist/vanilla/enquiry-form/index.d.ts +4 -0
- package/dist/vanilla/enquiry-form/provider.d.ts +3 -0
- package/dist/vanilla/enquiry-form/serialization.d.ts +4 -0
- package/dist/vanilla/enquiry-form/types.d.ts +38 -0
- package/dist/vanilla/enquiry-form/validation.d.ts +6 -0
- package/dist/vanilla/enquiry-widget.js +4650 -0
- package/dist/vanilla/index.d.ts +9 -0
- package/dist/vanilla/index.js +3 -1
- package/dist/vanilla/react/ThemeProvider.d.ts +18 -0
- package/dist/vanilla/react/hooks/useTheme.d.ts +1 -0
- package/dist/vanilla/react/index.d.ts +5 -0
- package/dist/vanilla/services/EnquiryService.d.ts +5 -0
- package/dist/vanilla/theme-injector.d.ts +6 -0
- package/dist/vanilla/theme-injector.js +44 -0
- package/dist/vanilla/vanilla/EnquiryFormWidget.d.ts +35 -0
- package/dist/vanilla/vanilla/index.d.ts +3 -1
- package/dist/vanilla/vanilla/theme-injector.d.ts +6 -0
- package/dist/vanilla/vanilla/widget.d.ts +6 -1
- package/dist/vanilla/widget.css +173 -0
- package/dist/vanilla/widget.d.ts +6 -1
- package/dist/vanilla/widget.js +489 -12
- package/package.json +13 -2
package/README.md
CHANGED
|
@@ -1,13 +1,87 @@
|
|
|
1
1
|
# Medos SDK
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/medos-sdk)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
6
|
+
|
|
3
7
|
A JavaScript/TypeScript SDK for integrating healthcare appointment booking into your applications. Built for clinics, hospitals, and healthcare platforms.
|
|
4
8
|
|
|
9
|
+
## ✨ Features
|
|
10
|
+
|
|
11
|
+
- 🎨 **Powerful Theming System** - Customize appearance with built-in themes or create your own
|
|
12
|
+
- ⚛️ **React & Vanilla JS** - Works with React or pure JavaScript
|
|
13
|
+
- 🔒 **Secure Authentication** - API key and session token support
|
|
14
|
+
- 📱 **Responsive Design** - Mobile-first, works on all screen sizes
|
|
15
|
+
- 🎯 **TypeScript-First** - Full type safety and IntelliSense support
|
|
16
|
+
- ♿ **Accessible** - WCAG compliant components
|
|
17
|
+
|
|
5
18
|
## Installation
|
|
6
19
|
|
|
7
20
|
```bash
|
|
8
21
|
npm install medos-sdk
|
|
9
22
|
```
|
|
10
23
|
|
|
24
|
+
## Table of Contents
|
|
25
|
+
|
|
26
|
+
- [Quick Start](#quick-start)
|
|
27
|
+
- [Getting Started](#getting-started)
|
|
28
|
+
- [Usage](#usage)
|
|
29
|
+
- [React Integration](#react-integration)
|
|
30
|
+
- [Vanilla JavaScript](#vanilla-javascript--html-integration)
|
|
31
|
+
- [TypeScript](#typescript)
|
|
32
|
+
- [API Reference](#api-reference)
|
|
33
|
+
- [Error Handling](#error-handling)
|
|
34
|
+
- [Requirements](#requirements)
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
### React
|
|
39
|
+
|
|
40
|
+
```tsx
|
|
41
|
+
import { MedosThemeProvider, AppointmentCalender } from "medos-sdk/react";
|
|
42
|
+
|
|
43
|
+
function App() {
|
|
44
|
+
return (
|
|
45
|
+
<MedosThemeProvider theme="modern">
|
|
46
|
+
<AppointmentCalender onError={(err) => console.error(err)} />
|
|
47
|
+
</MedosThemeProvider>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Vanilla JavaScript
|
|
53
|
+
|
|
54
|
+
```javascript
|
|
55
|
+
import { initAppointmentCalendar } from "medos-sdk/vanilla";
|
|
56
|
+
|
|
57
|
+
initAppointmentCalendar({
|
|
58
|
+
containerId: "appointment-widget",
|
|
59
|
+
apiKey: "your-api-key",
|
|
60
|
+
theme: "modern", // or 'default'
|
|
61
|
+
});
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### HTML/CSS/JS
|
|
65
|
+
|
|
66
|
+
```html
|
|
67
|
+
<!DOCTYPE html>
|
|
68
|
+
<html>
|
|
69
|
+
<head>
|
|
70
|
+
<link rel="stylesheet" href="path/to/widget.css" />
|
|
71
|
+
</head>
|
|
72
|
+
<body>
|
|
73
|
+
<div id="appointment-calendar"></div>
|
|
74
|
+
<script src="path/to/widget.js"></script>
|
|
75
|
+
<script>
|
|
76
|
+
window.MedosAppointmentCalendar.init({
|
|
77
|
+
containerId: "appointment-calendar",
|
|
78
|
+
apiKey: "your-api-key",
|
|
79
|
+
});
|
|
80
|
+
</script>
|
|
81
|
+
</body>
|
|
82
|
+
</html>
|
|
83
|
+
```
|
|
84
|
+
|
|
11
85
|
## Getting Started
|
|
12
86
|
|
|
13
87
|
### Authentication
|
|
@@ -394,7 +468,7 @@ See `dist/vanilla/widget.css` for all available classes.
|
|
|
394
468
|
|
|
395
469
|
### Package Exports
|
|
396
470
|
|
|
397
|
-
The SDK provides multiple entry points:
|
|
471
|
+
The SDK provides multiple entry points for different use cases:
|
|
398
472
|
|
|
399
473
|
- `medos-sdk` - Default export (includes React components)
|
|
400
474
|
- `medos-sdk/react` - React-specific exports
|
|
@@ -402,8 +476,6 @@ The SDK provides multiple entry points:
|
|
|
402
476
|
- `medos-sdk/core` - Core services only (no framework dependencies)
|
|
403
477
|
- `medos-sdk/widget` - Widget bundle with CSS
|
|
404
478
|
|
|
405
|
-
For more details, see [Vanilla Widget Documentation](./docs/VANILLA_WIDGET.md).
|
|
406
|
-
|
|
407
479
|
## API Reference
|
|
408
480
|
|
|
409
481
|
### MedosClient
|
|
@@ -551,18 +623,18 @@ try {
|
|
|
551
623
|
- **React:** v19 or higher (only required for React components, not for vanilla widget)
|
|
552
624
|
- **TypeScript:** v5 or higher (optional)
|
|
553
625
|
|
|
554
|
-
## License
|
|
555
|
-
|
|
556
|
-
UNLICENSED
|
|
557
|
-
|
|
558
626
|
## Support
|
|
559
627
|
|
|
560
628
|
For bug reports and feature requests, please visit our [GitHub Issues](https://github.com/MediLaunch/medos-sdk-react/issues).
|
|
561
629
|
|
|
630
|
+
## License
|
|
631
|
+
|
|
632
|
+
UNLICENSED
|
|
633
|
+
|
|
562
634
|
## Author
|
|
563
635
|
|
|
564
636
|
Pooranjoy Bhattacharya
|
|
565
637
|
|
|
566
638
|
---
|
|
567
639
|
|
|
568
|
-
|
|
640
|
+
**Built for healthcare providers worldwide.**
|
|
@@ -3,11 +3,9 @@ import { AddressesResponse } from "../services/AppointmentService";
|
|
|
3
3
|
import { SendPhoneVerificationOtpPayload, VerifyPhoneVerificationOtpPayload } from "../services/PatientService";
|
|
4
4
|
interface MedosClientConfig {
|
|
5
5
|
apiKey: string;
|
|
6
|
-
baseURL?: string;
|
|
7
6
|
}
|
|
8
7
|
interface MedosClientSessionConfig {
|
|
9
8
|
sessionToken: string;
|
|
10
|
-
baseURL?: string;
|
|
11
9
|
}
|
|
12
10
|
declare class MedosClient {
|
|
13
11
|
private static instance;
|
|
@@ -16,8 +14,8 @@ declare class MedosClient {
|
|
|
16
14
|
private static isRefreshing;
|
|
17
15
|
private static pendingRequests;
|
|
18
16
|
private static initPromise;
|
|
19
|
-
static init({ apiKey
|
|
20
|
-
static initWithSession({ sessionToken
|
|
17
|
+
static init({ apiKey }: MedosClientConfig): Promise<void>;
|
|
18
|
+
static initWithSession({ sessionToken }: MedosClientSessionConfig): Promise<void>;
|
|
21
19
|
private static initializeAxiosInstance;
|
|
22
20
|
static fetchAllAddressesAndDoctors(): Promise<AddressesResponse>;
|
|
23
21
|
static fetchAppointments(workspaceId: number, addressId: number, doctorId: number, appointmentDate: string): Promise<any[]>;
|
|
@@ -3,7 +3,7 @@ import { AuthService } from "../services/AuthService";
|
|
|
3
3
|
import { AppointmentService, } from "../services/AppointmentService";
|
|
4
4
|
import { PatientService, } from "../services/PatientService";
|
|
5
5
|
class MedosClient {
|
|
6
|
-
static async init({ apiKey
|
|
6
|
+
static async init({ apiKey }) {
|
|
7
7
|
if (!apiKey) {
|
|
8
8
|
throw new Error("MedosClient.init() requires 'apiKey'");
|
|
9
9
|
}
|
|
@@ -13,7 +13,7 @@ class MedosClient {
|
|
|
13
13
|
this.initPromise = (async () => {
|
|
14
14
|
try {
|
|
15
15
|
const sessionToken = await AuthService.init(apiKey);
|
|
16
|
-
this.initializeAxiosInstance(sessionToken,
|
|
16
|
+
this.initializeAxiosInstance(sessionToken, "https://api.medos.one");
|
|
17
17
|
}
|
|
18
18
|
catch (e) {
|
|
19
19
|
this.initPromise = null;
|
|
@@ -22,7 +22,7 @@ class MedosClient {
|
|
|
22
22
|
})();
|
|
23
23
|
return this.initPromise;
|
|
24
24
|
}
|
|
25
|
-
static async initWithSession({ sessionToken
|
|
25
|
+
static async initWithSession({ sessionToken }) {
|
|
26
26
|
if (!sessionToken) {
|
|
27
27
|
throw new Error("MedosClient.initWithSession() requires 'sessionToken'");
|
|
28
28
|
}
|
|
@@ -31,7 +31,7 @@ class MedosClient {
|
|
|
31
31
|
}
|
|
32
32
|
this.initPromise = (async () => {
|
|
33
33
|
try {
|
|
34
|
-
this.initializeAxiosInstance(sessionToken,
|
|
34
|
+
this.initializeAxiosInstance(sessionToken, "https://api.medos.one");
|
|
35
35
|
}
|
|
36
36
|
catch (e) {
|
|
37
37
|
this.initPromise = null;
|
|
@@ -8,9 +8,9 @@ import { PhoneVerificationStep } from "./PhoneVerificationStep";
|
|
|
8
8
|
import { PatientDetailsStep } from "./PatientDetailsStep";
|
|
9
9
|
import { SuccessStep } from "./SuccessStep";
|
|
10
10
|
import { INITIAL_STATE, } from "./types";
|
|
11
|
-
import { CONTAINER_STYLES } from "./styles";
|
|
12
11
|
import { validatePhoneNumber, validateCountryCode } from "./validation";
|
|
13
12
|
import { formatDateToISO, parsePatientName } from "./utils";
|
|
13
|
+
import { useTheme } from "../react/hooks/useTheme";
|
|
14
14
|
const appointmentReducer = (state, action) => {
|
|
15
15
|
switch (action.type) {
|
|
16
16
|
case "SET_STEP":
|
|
@@ -362,5 +362,46 @@ export const AppointmentCalender = ({ onError, }) => {
|
|
|
362
362
|
dispatch({ type: "SET_CONSULTATION_CHARGE", payload: charge });
|
|
363
363
|
dispatch({ type: "SET_STEP", payload: 3 });
|
|
364
364
|
}, []);
|
|
365
|
-
|
|
365
|
+
const theme = useTheme();
|
|
366
|
+
const styles = getStyles(theme);
|
|
367
|
+
return (_jsx("div", { style: styles.container, children: _jsxs("div", { style: styles.card, children: [_jsx("div", { style: styles.header, children: _jsx("h2", { style: styles.title, children: "Book Appointment" }) }), _jsx("hr", {}), _jsxs("div", { style: styles.content, children: [state.loading && _jsx("div", { style: { marginBottom: 12 }, children: "Loading..." }), state.error && _jsx("div", { style: styles.errorMessage, children: state.error }), state.step === 0 && (_jsx(DoctorSelectModal, { onCancel: () => dispatch({ type: "SET_STEP", payload: 0 }), onContinue: handleDoctorSelect })), state.step === 1 && (_jsx(AppointmentDateTimeModal, { onlineFee: 500, offlineFee: 300, slots: state.slots, onCancel: goBack, onDateChange: handleDateChange, onContinue: handleDateTimeModalContinue })), state.step === 3 && (_jsx(PhoneVerificationStep, { state: state, dispatch: dispatch, onSendOtp: sendOtp, onVerifyOtp: verifyOtp, onBack: goBack, onContinue: goToNext })), state.step === 4 && (_jsx(PatientDetailsStep, { state: state, dispatch: dispatch, onBack: goBack, onSubmit: submitAppointment })), state.step === 5 && _jsx(SuccessStep, { onReset: resetForm })] })] }) }));
|
|
366
368
|
};
|
|
369
|
+
const getStyles = (theme) => ({
|
|
370
|
+
container: {
|
|
371
|
+
display: "flex",
|
|
372
|
+
justifyContent: "center",
|
|
373
|
+
padding: 20,
|
|
374
|
+
fontFamily: theme.typography.fontFamily,
|
|
375
|
+
background: theme.colors.background,
|
|
376
|
+
},
|
|
377
|
+
card: {
|
|
378
|
+
width: "100%",
|
|
379
|
+
maxWidth: 840,
|
|
380
|
+
background: theme.colors.surface,
|
|
381
|
+
borderRadius: theme.radii.lg,
|
|
382
|
+
boxShadow: theme.shadows.lg,
|
|
383
|
+
overflow: "hidden",
|
|
384
|
+
boxSizing: "border-box",
|
|
385
|
+
},
|
|
386
|
+
header: {
|
|
387
|
+
padding: "20px 24px",
|
|
388
|
+
},
|
|
389
|
+
title: {
|
|
390
|
+
margin: 0,
|
|
391
|
+
fontSize: theme.typography.fontSizeXl,
|
|
392
|
+
fontWeight: theme.typography.fontWeightSemibold,
|
|
393
|
+
},
|
|
394
|
+
content: {
|
|
395
|
+
padding: 24,
|
|
396
|
+
},
|
|
397
|
+
errorMessage: {
|
|
398
|
+
marginBottom: 12,
|
|
399
|
+
color: theme.colors.error,
|
|
400
|
+
fontWeight: 600,
|
|
401
|
+
padding: "12px",
|
|
402
|
+
background: theme.colors.errorBackground,
|
|
403
|
+
borderRadius: theme.radii.md,
|
|
404
|
+
border: `1px solid ${theme.colors.errorBorder}`,
|
|
405
|
+
fontSize: theme.typography.fontSizeSm,
|
|
406
|
+
},
|
|
407
|
+
});
|
|
@@ -4,6 +4,7 @@ import { CustomCalendarWithDateSelector } from "./custom-calendar";
|
|
|
4
4
|
import { PaymentMethodIcon } from "./Icons/PaymentMethodIcon";
|
|
5
5
|
import { DateTimeIcon } from "./Icons/Date&TimeIcon";
|
|
6
6
|
import { ConsultationTypeIcon } from "./Icons/ConsultationType";
|
|
7
|
+
import { useTheme } from "../react/hooks/useTheme";
|
|
7
8
|
const MONTHS = [
|
|
8
9
|
"January",
|
|
9
10
|
"February",
|
|
@@ -39,6 +40,7 @@ const formatDate = (date) => {
|
|
|
39
40
|
return `${day}${getOrdinalSuffix(day)} ${month} ${year}`;
|
|
40
41
|
};
|
|
41
42
|
export const AppointmentDateTimeModal = ({ onlineFee, offlineFee, slots, onCancel, onContinue, onDateChange, }) => {
|
|
43
|
+
const theme = useTheme();
|
|
42
44
|
const [mode, setMode] = useState("OFFLINE");
|
|
43
45
|
const [consultationCharge, setConsultationCharge] = useState("");
|
|
44
46
|
const [paymentMode, setPaymentMode] = useState("CASH");
|
|
@@ -72,47 +74,56 @@ export const AppointmentDateTimeModal = ({ onlineFee, offlineFee, slots, onCance
|
|
|
72
74
|
const isSlotSelected = useCallback((slot) => selectedSlot?.start === slot.start && selectedSlot?.end === slot.end, [selectedSlot]);
|
|
73
75
|
const formattedDate = useMemo(() => formatDate(selectedDate), [selectedDate]);
|
|
74
76
|
const isFormValid = selectedDate && selectedSlot && consultationCharge;
|
|
75
|
-
|
|
77
|
+
const STYLES = getStyles(theme);
|
|
78
|
+
return (_jsxs("div", { style: STYLES.modalWrapper, children: [_jsx(ConsultationTypeSection, { mode: mode, onlineFee: onlineFee, offlineFee: offlineFee, onModeChange: setMode, STYLES: STYLES }), _jsx(ChargesSection, { charge: consultationCharge, STYLES: STYLES }), _jsx(DateTimeSection, { selectedDate: selectedDate, formattedDate: formattedDate, slots: slots, selectedSlot: selectedSlot, onDateSelect: handleDateSelect, onSlotSelect: setSelectedSlot, isSlotSelected: isSlotSelected, STYLES: STYLES }), _jsx(FooterSection, { onCancel: onCancel, onContinue: handleContinue, isValid: !!isFormValid, STYLES: STYLES })] }));
|
|
76
79
|
};
|
|
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) => {
|
|
80
|
+
const ConsultationTypeSection = ({ mode, onlineFee, offlineFee, onModeChange, STYLES }) => (_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
81
|
const disabled = (item === "ONLINE" && (!onlineFee || onlineFee <= 0)) ||
|
|
79
82
|
(item === "OFFLINE" && (!offlineFee || offlineFee <= 0));
|
|
80
83
|
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
84
|
}) })] })] }));
|
|
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))) }))] })] }) })] }));
|
|
85
|
+
const ChargesSection = ({ charge, STYLES }) => (_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] }) })] }));
|
|
86
|
+
const DateTimeSection = ({ selectedDate, formattedDate, slots, selectedSlot, onDateSelect, onSlotSelect, isSlotSelected, STYLES, }) => (_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
87
|
const SlotButton = ({ slot, isSelected, onSelect }) => {
|
|
85
88
|
const startTime = useMemo(() => new Date(slot.start).toLocaleTimeString([], {
|
|
86
89
|
hour: "2-digit",
|
|
87
90
|
minute: "2-digit",
|
|
88
91
|
}), [slot.start]);
|
|
92
|
+
const theme = useTheme();
|
|
93
|
+
const STYLES = getStyles(theme);
|
|
89
94
|
return (_jsx("button", { onClick: () => onSelect(slot), style: {
|
|
90
95
|
...STYLES.slotButton,
|
|
91
|
-
background: isSelected
|
|
92
|
-
|
|
96
|
+
background: isSelected
|
|
97
|
+
? theme.colors.secondary
|
|
98
|
+
: theme.colors.background,
|
|
99
|
+
color: isSelected
|
|
100
|
+
? theme.colors.textOnSecondary
|
|
101
|
+
: theme.colors.secondary,
|
|
102
|
+
borderColor: theme.colors.secondary,
|
|
93
103
|
}, children: startTime }));
|
|
94
104
|
};
|
|
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
|
|
105
|
+
const FooterSection = ({ onCancel, onContinue, isValid, STYLES }) => (_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" })] }));
|
|
106
|
+
const getStyles = (theme) => ({
|
|
97
107
|
modalWrapper: {
|
|
98
|
-
backgroundColor:
|
|
99
|
-
borderRadius:
|
|
108
|
+
backgroundColor: theme.colors.background,
|
|
109
|
+
borderRadius: theme.radii.lg,
|
|
100
110
|
padding: "20px 24px 24px 24px",
|
|
101
111
|
maxWidth: 800,
|
|
102
112
|
margin: "0 auto",
|
|
103
|
-
fontFamily:
|
|
104
|
-
color:
|
|
113
|
+
fontFamily: theme.typography.fontFamily,
|
|
114
|
+
color: theme.colors.text,
|
|
105
115
|
boxSizing: "border-box",
|
|
106
116
|
},
|
|
107
117
|
sectionCard: {
|
|
108
|
-
border:
|
|
109
|
-
borderRadius:
|
|
118
|
+
border: `1px solid ${theme.colors.border}`,
|
|
119
|
+
borderRadius: theme.radii.lg,
|
|
110
120
|
marginBottom: 20,
|
|
111
121
|
position: "relative",
|
|
112
122
|
},
|
|
113
123
|
sectionHeader: {
|
|
114
|
-
background:
|
|
115
|
-
|
|
124
|
+
background: theme.colors.primary,
|
|
125
|
+
color: theme.colors.textOnPrimary,
|
|
126
|
+
borderBottom: `1px solid ${theme.colors.border}`,
|
|
116
127
|
padding: "12px 16px",
|
|
117
128
|
display: "flex",
|
|
118
129
|
alignItems: "center",
|
|
@@ -141,7 +152,7 @@ const STYLES = {
|
|
|
141
152
|
radioInput: {
|
|
142
153
|
width: 18,
|
|
143
154
|
height: 18,
|
|
144
|
-
accentColor:
|
|
155
|
+
accentColor: theme.colors.secondary,
|
|
145
156
|
cursor: "pointer",
|
|
146
157
|
},
|
|
147
158
|
rupee: {
|
|
@@ -151,15 +162,18 @@ const STYLES = {
|
|
|
151
162
|
},
|
|
152
163
|
dateTimeContainer: { display: "flex", gap: 24 },
|
|
153
164
|
calendarBox: {
|
|
154
|
-
border:
|
|
155
|
-
borderRadius:
|
|
165
|
+
border: `1px solid ${theme.colors.border}`,
|
|
166
|
+
borderRadius: theme.radii.lg,
|
|
156
167
|
padding: 8,
|
|
157
168
|
},
|
|
158
169
|
timesContainer: { flexGrow: 1 },
|
|
159
170
|
timesLabel: { fontWeight: 500 },
|
|
160
|
-
dateLabel: {
|
|
171
|
+
dateLabel: {
|
|
172
|
+
color: theme.colors.textSecondary,
|
|
173
|
+
fontSize: 13,
|
|
174
|
+
},
|
|
161
175
|
noSlots: {
|
|
162
|
-
color:
|
|
176
|
+
color: theme.colors.textSecondary,
|
|
163
177
|
fontSize: 14,
|
|
164
178
|
marginTop: 8,
|
|
165
179
|
},
|
|
@@ -170,9 +184,9 @@ const STYLES = {
|
|
|
170
184
|
marginTop: 12,
|
|
171
185
|
},
|
|
172
186
|
slotButton: {
|
|
173
|
-
borderRadius:
|
|
187
|
+
borderRadius: theme.radii.md,
|
|
174
188
|
padding: "8px 10px",
|
|
175
|
-
border:
|
|
189
|
+
border: `1px solid ${theme.colors.secondary}`,
|
|
176
190
|
fontSize: 13,
|
|
177
191
|
fontWeight: 500,
|
|
178
192
|
cursor: "pointer",
|
|
@@ -186,21 +200,21 @@ const STYLES = {
|
|
|
186
200
|
gap: 12,
|
|
187
201
|
},
|
|
188
202
|
backBtn: {
|
|
189
|
-
border:
|
|
190
|
-
background:
|
|
191
|
-
color:
|
|
192
|
-
borderRadius:
|
|
203
|
+
border: `1px solid ${theme.colors.primary}`,
|
|
204
|
+
background: theme.colors.background,
|
|
205
|
+
color: theme.colors.primary,
|
|
206
|
+
borderRadius: theme.radii.md,
|
|
193
207
|
fontWeight: 600,
|
|
194
208
|
padding: "8px 20px",
|
|
195
209
|
cursor: "pointer",
|
|
196
210
|
},
|
|
197
211
|
continueBtn: {
|
|
198
|
-
background:
|
|
199
|
-
color:
|
|
212
|
+
background: theme.colors.secondary,
|
|
213
|
+
color: theme.colors.textOnSecondary,
|
|
200
214
|
border: "none",
|
|
201
|
-
borderRadius:
|
|
215
|
+
borderRadius: theme.radii.md,
|
|
202
216
|
fontWeight: 600,
|
|
203
217
|
padding: "8px 20px",
|
|
204
218
|
cursor: "pointer",
|
|
205
219
|
},
|
|
206
|
-
};
|
|
220
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface ContactInformationStepProps {
|
|
3
|
+
patientName: string;
|
|
4
|
+
patientEmail: string;
|
|
5
|
+
countryCode: string;
|
|
6
|
+
patientPhone: string;
|
|
7
|
+
onNameChange: (value: string) => void;
|
|
8
|
+
onEmailChange: (value: string) => void;
|
|
9
|
+
onCountryCodeChange: (value: string) => void;
|
|
10
|
+
onPhoneChange: (value: string) => void;
|
|
11
|
+
onNext: () => void;
|
|
12
|
+
}
|
|
13
|
+
export declare const ContactInformationStep: React.FC<ContactInformationStepProps>;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTheme } from "../react/hooks/useTheme";
|
|
3
|
+
import { getContainerStyles, getPhoneVerifyStyles, getButtonStyles, } from "./theme-styles";
|
|
4
|
+
export const ContactInformationStep = ({ patientName, patientEmail, countryCode, patientPhone, onNameChange, onEmailChange, onCountryCodeChange, onPhoneChange, onNext, }) => {
|
|
5
|
+
const theme = useTheme();
|
|
6
|
+
const PHONE_VERIFY_STYLES = getPhoneVerifyStyles(theme);
|
|
7
|
+
const BUTTON_STYLES = getButtonStyles(theme);
|
|
8
|
+
const CONTAINER_STYLES = getContainerStyles(theme);
|
|
9
|
+
return (_jsxs("div", { children: [_jsxs("div", { style: { marginBottom: "16px" }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Name" }), _jsx("input", { type: "text", value: patientName, onChange: (e) => onNameChange(e.target.value), placeholder: "Enter your full name", style: PHONE_VERIFY_STYLES.phoneInput })] }), _jsxs("div", { style: { marginBottom: "16px" }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Email" }), _jsx("input", { type: "email", value: patientEmail, onChange: (e) => onEmailChange(e.target.value), placeholder: "Enter your email", style: PHONE_VERIFY_STYLES.phoneInput })] }), _jsxs("div", { style: { marginBottom: "16px" }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Phone Number" }), _jsxs("div", { style: PHONE_VERIFY_STYLES.phoneInputContainer, children: [_jsx("input", { type: "text", value: countryCode, onChange: (e) => onCountryCodeChange(e.target.value), placeholder: "+91", style: {
|
|
10
|
+
...PHONE_VERIFY_STYLES.phoneInput,
|
|
11
|
+
width: "80px",
|
|
12
|
+
flex: "none",
|
|
13
|
+
} }), _jsx("input", { type: "tel", value: patientPhone, onChange: (e) => onPhoneChange(e.target.value), placeholder: "Enter phone number", style: PHONE_VERIFY_STYLES.phoneInput })] })] }), _jsx("div", { style: CONTAINER_STYLES.actions, children: _jsx("button", { onClick: onNext, style: BUTTON_STYLES.primary, children: "Next" }) })] }));
|
|
14
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
export interface ContactPreferenceStepProps {
|
|
3
|
+
preferredContactMethod: "PHONE" | "EMAIL" | "BOTH";
|
|
4
|
+
onContactMethodChange: (method: "PHONE" | "EMAIL" | "BOTH") => void;
|
|
5
|
+
onBack: () => void;
|
|
6
|
+
onSubmit: () => void;
|
|
7
|
+
isLoading?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export declare const ContactPreferenceStep: React.FC<ContactPreferenceStepProps>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useTheme } from "../react/hooks/useTheme";
|
|
3
|
+
import { getPhoneVerifyStyles, getButtonStyles, getContainerStyles, } from "./theme-styles";
|
|
4
|
+
export const ContactPreferenceStep = ({ preferredContactMethod, onContactMethodChange, onBack, onSubmit, isLoading = false, }) => {
|
|
5
|
+
const theme = useTheme();
|
|
6
|
+
const PHONE_VERIFY_STYLES = getPhoneVerifyStyles(theme);
|
|
7
|
+
const BUTTON_STYLES = getButtonStyles(theme);
|
|
8
|
+
const CONTAINER_STYLES = getContainerStyles(theme);
|
|
9
|
+
return (_jsxs("div", { children: [_jsxs("div", { style: { marginBottom: "16px" }, children: [_jsx("label", { style: PHONE_VERIFY_STYLES.label, children: "Preferred Contact Method" }), _jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "8px" }, children: [_jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "PHONE", checked: preferredContactMethod === "PHONE", onChange: (e) => onContactMethodChange(e.target.value) }), "Phone"] }), _jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "EMAIL", checked: preferredContactMethod === "EMAIL", onChange: (e) => onContactMethodChange(e.target.value) }), "Email"] }), _jsxs("label", { style: { display: "flex", alignItems: "center", gap: "8px" }, children: [_jsx("input", { type: "radio", name: "contactMethod", value: "BOTH", checked: preferredContactMethod === "BOTH", onChange: (e) => onContactMethodChange(e.target.value) }), "Both"] })] })] }), _jsxs("div", { style: CONTAINER_STYLES.actions, children: [_jsx("button", { onClick: onBack, style: BUTTON_STYLES.secondary, children: "Back" }), _jsx("button", { onClick: onSubmit, disabled: isLoading, style: {
|
|
10
|
+
...BUTTON_STYLES.primary,
|
|
11
|
+
backgroundColor: isLoading
|
|
12
|
+
? "#ccc"
|
|
13
|
+
: BUTTON_STYLES.primary.backgroundColor,
|
|
14
|
+
cursor: isLoading ? "not-allowed" : "pointer",
|
|
15
|
+
}, children: isLoading ? "Submitting..." : "Submit" })] })] }));
|
|
16
|
+
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect } from "react";
|
|
3
|
-
import { AppointmentService } from "../services/AppointmentService";
|
|
3
|
+
import { AppointmentService, } from "../services/AppointmentService";
|
|
4
4
|
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, } from "./uiComponents/SelectDropdown";
|
|
5
|
+
import { useTheme } from "../react/hooks/useTheme";
|
|
5
6
|
export const DoctorSelectModal = ({ onCancel, onContinue, }) => {
|
|
7
|
+
const theme = useTheme();
|
|
6
8
|
const [addresses, setAddresses] = useState([]);
|
|
7
9
|
const [addressDoctorsMap, setAddressDoctorsMap] = useState({});
|
|
8
10
|
const [selectedAddressId, setSelectedAddressId] = useState("");
|
|
@@ -19,24 +21,30 @@ export const DoctorSelectModal = ({ onCancel, onContinue, }) => {
|
|
|
19
21
|
setAddressDoctorsMap(map);
|
|
20
22
|
})();
|
|
21
23
|
}, []);
|
|
22
|
-
const doctorsForAddress = selectedAddressId
|
|
24
|
+
const doctorsForAddress = selectedAddressId
|
|
25
|
+
? addressDoctorsMap[Number(selectedAddressId)] || []
|
|
26
|
+
: [];
|
|
23
27
|
const canContinue = !!selectedAddressId && !!selectedDoctorId;
|
|
24
|
-
|
|
28
|
+
const styles = getStyles(theme);
|
|
29
|
+
return (_jsx("div", { style: {
|
|
30
|
+
border: `1px solid ${theme.colors.border}`,
|
|
31
|
+
borderRadius: "2px",
|
|
32
|
+
}, 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 ${theme.colors.border}` } }), _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
33
|
setSelectedAddressId(value);
|
|
26
34
|
setSelectedDoctorId("");
|
|
27
|
-
}, children: [_jsx(SelectTrigger, { style: { width:
|
|
35
|
+
}, 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
36
|
...styles.continueBtn,
|
|
29
37
|
opacity: canContinue ? 1 : 0.6,
|
|
30
38
|
}, disabled: !canContinue, onClick: () => onContinue(Number(selectedAddressId), Number(selectedDoctorId), appointmentNotes), children: "Next" }) })] })] }) }));
|
|
31
39
|
};
|
|
32
|
-
const
|
|
40
|
+
const getStyles = (theme) => ({
|
|
33
41
|
modalWrapper: {
|
|
34
|
-
backgroundColor:
|
|
42
|
+
backgroundColor: theme.colors.background,
|
|
35
43
|
borderRadius: 12,
|
|
36
44
|
maxWidth: 840,
|
|
37
45
|
margin: "0 auto",
|
|
38
|
-
fontFamily:
|
|
39
|
-
color:
|
|
46
|
+
fontFamily: theme.typography.fontFamily,
|
|
47
|
+
color: theme.colors.text,
|
|
40
48
|
},
|
|
41
49
|
headerWrapper: {
|
|
42
50
|
padding: "20px 24px 10px 24px",
|
|
@@ -47,12 +55,17 @@ const styles = {
|
|
|
47
55
|
title: { fontSize: 20, fontWeight: 600, margin: 0 },
|
|
48
56
|
fieldGroup: { marginBottom: 18 },
|
|
49
57
|
label: { fontSize: 15, fontWeight: 500, marginBottom: 6, display: "block" },
|
|
50
|
-
mandatory: { color:
|
|
51
|
-
optional: {
|
|
58
|
+
mandatory: { color: theme.colors.error, marginLeft: 4 },
|
|
59
|
+
optional: {
|
|
60
|
+
color: theme.colors.textSecondary,
|
|
61
|
+
fontWeight: 400,
|
|
62
|
+
marginLeft: 4,
|
|
63
|
+
fontSize: 13,
|
|
64
|
+
},
|
|
52
65
|
textarea: {
|
|
53
66
|
width: "100%",
|
|
54
|
-
border:
|
|
55
|
-
borderRadius:
|
|
67
|
+
border: `1px solid ${theme.colors.border}`,
|
|
68
|
+
borderRadius: theme.radii.md,
|
|
56
69
|
minHeight: 80,
|
|
57
70
|
padding: "10px",
|
|
58
71
|
fontSize: 14,
|
|
@@ -67,14 +80,14 @@ const styles = {
|
|
|
67
80
|
alignItems: "center",
|
|
68
81
|
gap: 10,
|
|
69
82
|
},
|
|
70
|
-
brand: { color:
|
|
83
|
+
brand: { color: theme.colors.primary, fontWeight: 600 },
|
|
71
84
|
continueBtn: {
|
|
72
|
-
background:
|
|
73
|
-
color:
|
|
85
|
+
background: theme.colors.secondary,
|
|
86
|
+
color: theme.colors.textOnSecondary,
|
|
74
87
|
border: "none",
|
|
75
|
-
borderRadius:
|
|
88
|
+
borderRadius: theme.radii.md,
|
|
76
89
|
fontWeight: 600,
|
|
77
90
|
padding: "8px 22px",
|
|
78
91
|
cursor: "pointer",
|
|
79
92
|
},
|
|
80
|
-
};
|
|
93
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { EnquirySubmission } from "../enquiry-form/types";
|
|
3
|
+
export interface EnquiryFormProps {
|
|
4
|
+
onSuccess?: (enquiry: EnquirySubmission) => void;
|
|
5
|
+
onError?: (error: Error) => void;
|
|
6
|
+
}
|
|
7
|
+
export declare const EnquiryForm: React.FC<EnquiryFormProps>;
|