@indirecttek/essentials-engine 1.3.0 → 1.4.0
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/components/CalendlyWidget.astro +45 -0
- package/dist/components/ProviderBio.astro +137 -0
- package/dist/index.ts +5 -0
- package/dist/types.ts +22 -2
- package/package.json +1 -1
|
@@ -72,6 +72,51 @@ const getCalendlyPath = (url: string) => {
|
|
|
72
72
|
</a>
|
|
73
73
|
)}
|
|
74
74
|
|
|
75
|
+
{isEnabled && scheduling.provider === "nexhealth" && (
|
|
76
|
+
inline ? (
|
|
77
|
+
<!-- NexHealth Inline Booking Widget -->
|
|
78
|
+
<div class="nexhealth-booking-widget rounded-lg overflow-hidden shadow-lg">
|
|
79
|
+
<iframe
|
|
80
|
+
src={`https://app.nexhealth.com/appt/${scheduling.practiceSlug || ''}${scheduling.locationId ? `?location_id=${scheduling.locationId}` : ''}`}
|
|
81
|
+
title="Book Appointment"
|
|
82
|
+
width="100%"
|
|
83
|
+
height="700"
|
|
84
|
+
frameborder="0"
|
|
85
|
+
class="rounded-lg"
|
|
86
|
+
style="min-height: 700px;"
|
|
87
|
+
></iframe>
|
|
88
|
+
</div>
|
|
89
|
+
) : (
|
|
90
|
+
<!-- NexHealth Popup Button -->
|
|
91
|
+
<a
|
|
92
|
+
href={`https://app.nexhealth.com/appt/${scheduling.practiceSlug || ''}`}
|
|
93
|
+
target="_blank"
|
|
94
|
+
rel="noopener noreferrer"
|
|
95
|
+
class="inline-flex items-center justify-center gap-2 bg-[color:var(--color-primary)] text-white px-6 py-3 rounded-lg font-semibold hover:opacity-90 transition-opacity"
|
|
96
|
+
>
|
|
97
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
98
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
|
99
|
+
</svg>
|
|
100
|
+
{buttonText}
|
|
101
|
+
</a>
|
|
102
|
+
)
|
|
103
|
+
)}
|
|
104
|
+
|
|
105
|
+
{isEnabled && scheduling.provider === "zocdoc" && (
|
|
106
|
+
<!-- ZocDoc Booking Button -->
|
|
107
|
+
<a
|
|
108
|
+
href={scheduling.url}
|
|
109
|
+
target="_blank"
|
|
110
|
+
rel="noopener noreferrer"
|
|
111
|
+
class="inline-flex items-center justify-center gap-2 bg-[color:var(--color-primary)] text-white px-6 py-3 rounded-lg font-semibold hover:opacity-90 transition-opacity"
|
|
112
|
+
>
|
|
113
|
+
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
|
114
|
+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" />
|
|
115
|
+
</svg>
|
|
116
|
+
{buttonText}
|
|
117
|
+
</a>
|
|
118
|
+
)}
|
|
119
|
+
|
|
75
120
|
{!isEnabled && (
|
|
76
121
|
<!-- Fallback when scheduling not configured -->
|
|
77
122
|
<p class="text-sm text-[color:var(--color-foreground)]/60 italic">
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
---
|
|
2
|
+
import type { SiteConfig, ProviderInfo } from "../types";
|
|
3
|
+
|
|
4
|
+
export interface Props {
|
|
5
|
+
config: SiteConfig;
|
|
6
|
+
layout?: "card" | "full-width" | "side-by-side";
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const { config, layout = "card" } = Astro.props;
|
|
10
|
+
|
|
11
|
+
const providers = config.medical?.providers || [];
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
{providers.length > 0 && (
|
|
15
|
+
<section class="provider-bio-section">
|
|
16
|
+
{layout === "full-width" && providers.map((provider: ProviderInfo) => (
|
|
17
|
+
<div class="bg-white rounded-2xl shadow-lg overflow-hidden">
|
|
18
|
+
<div class="md:flex">
|
|
19
|
+
<!-- Provider Image -->
|
|
20
|
+
<div class="md:w-1/3">
|
|
21
|
+
<img
|
|
22
|
+
src={provider.imageUrl}
|
|
23
|
+
alt={`${provider.name}, ${provider.title}`}
|
|
24
|
+
class="w-full h-64 md:h-full object-cover"
|
|
25
|
+
/>
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
<!-- Provider Info -->
|
|
29
|
+
<div class="md:w-2/3 p-8 md:p-12">
|
|
30
|
+
<div class="mb-4">
|
|
31
|
+
<h3 class="text-2xl md:text-3xl font-serif font-bold text-[color:var(--color-primary)]">
|
|
32
|
+
{provider.name}, {provider.title}
|
|
33
|
+
</h3>
|
|
34
|
+
{provider.specialty && (
|
|
35
|
+
<p class="text-lg text-[color:var(--color-secondary)] font-medium mt-1">
|
|
36
|
+
{provider.specialty}
|
|
37
|
+
</p>
|
|
38
|
+
)}
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<p class="text-[color:var(--color-foreground)]/80 leading-relaxed mb-6">
|
|
42
|
+
{provider.bio}
|
|
43
|
+
</p>
|
|
44
|
+
|
|
45
|
+
{provider.credentials && provider.credentials.length > 0 && (
|
|
46
|
+
<div class="border-t border-gray-100 pt-6">
|
|
47
|
+
<h4 class="text-sm font-semibold text-[color:var(--color-foreground)]/60 uppercase tracking-wide mb-3">
|
|
48
|
+
Education & Credentials
|
|
49
|
+
</h4>
|
|
50
|
+
<ul class="space-y-2">
|
|
51
|
+
{provider.credentials.map((credential: string) => (
|
|
52
|
+
<li class="flex items-center gap-2 text-[color:var(--color-foreground)]/70">
|
|
53
|
+
<svg class="w-4 h-4 text-[color:var(--color-secondary)]" fill="currentColor" viewBox="0 0 20 20">
|
|
54
|
+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
55
|
+
</svg>
|
|
56
|
+
{credential}
|
|
57
|
+
</li>
|
|
58
|
+
))}
|
|
59
|
+
</ul>
|
|
60
|
+
</div>
|
|
61
|
+
)}
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
65
|
+
))}
|
|
66
|
+
|
|
67
|
+
{layout === "card" && (
|
|
68
|
+
<div class="grid md:grid-cols-2 lg:grid-cols-3 gap-8">
|
|
69
|
+
{providers.map((provider: ProviderInfo) => (
|
|
70
|
+
<div class="bg-white rounded-xl shadow-lg overflow-hidden hover:shadow-xl transition-shadow">
|
|
71
|
+
<img
|
|
72
|
+
src={provider.imageUrl}
|
|
73
|
+
alt={`${provider.name}, ${provider.title}`}
|
|
74
|
+
class="w-full h-64 object-cover"
|
|
75
|
+
/>
|
|
76
|
+
<div class="p-6">
|
|
77
|
+
<h3 class="text-xl font-serif font-bold text-[color:var(--color-primary)]">
|
|
78
|
+
{provider.name}, {provider.title}
|
|
79
|
+
</h3>
|
|
80
|
+
{provider.specialty && (
|
|
81
|
+
<p class="text-[color:var(--color-secondary)] font-medium mt-1">
|
|
82
|
+
{provider.specialty}
|
|
83
|
+
</p>
|
|
84
|
+
)}
|
|
85
|
+
<p class="text-[color:var(--color-foreground)]/70 mt-3 line-clamp-3">
|
|
86
|
+
{provider.bio}
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
))}
|
|
91
|
+
</div>
|
|
92
|
+
)}
|
|
93
|
+
|
|
94
|
+
{layout === "side-by-side" && providers.map((provider: ProviderInfo, index: number) => (
|
|
95
|
+
<div class={`flex flex-col ${index % 2 === 0 ? 'md:flex-row' : 'md:flex-row-reverse'} gap-8 items-center py-12 ${index > 0 ? 'border-t border-gray-100' : ''}`}>
|
|
96
|
+
<div class="md:w-1/2">
|
|
97
|
+
<img
|
|
98
|
+
src={provider.imageUrl}
|
|
99
|
+
alt={`${provider.name}, ${provider.title}`}
|
|
100
|
+
class="w-full max-w-md mx-auto rounded-2xl shadow-lg"
|
|
101
|
+
/>
|
|
102
|
+
</div>
|
|
103
|
+
<div class="md:w-1/2">
|
|
104
|
+
<h3 class="text-2xl md:text-3xl font-serif font-bold text-[color:var(--color-primary)] mb-2">
|
|
105
|
+
{provider.name}, {provider.title}
|
|
106
|
+
</h3>
|
|
107
|
+
{provider.specialty && (
|
|
108
|
+
<p class="text-lg text-[color:var(--color-secondary)] font-medium mb-4">
|
|
109
|
+
{provider.specialty}
|
|
110
|
+
</p>
|
|
111
|
+
)}
|
|
112
|
+
<p class="text-[color:var(--color-foreground)]/80 leading-relaxed mb-6">
|
|
113
|
+
{provider.bio}
|
|
114
|
+
</p>
|
|
115
|
+
{provider.credentials && provider.credentials.length > 0 && (
|
|
116
|
+
<ul class="space-y-2">
|
|
117
|
+
{provider.credentials.map((credential: string) => (
|
|
118
|
+
<li class="flex items-center gap-2 text-[color:var(--color-foreground)]/70">
|
|
119
|
+
<svg class="w-4 h-4 text-[color:var(--color-secondary)]" fill="currentColor" viewBox="0 0 20 20">
|
|
120
|
+
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd" />
|
|
121
|
+
</svg>
|
|
122
|
+
{credential}
|
|
123
|
+
</li>
|
|
124
|
+
))}
|
|
125
|
+
</ul>
|
|
126
|
+
)}
|
|
127
|
+
</div>
|
|
128
|
+
</div>
|
|
129
|
+
))}
|
|
130
|
+
</section>
|
|
131
|
+
)}
|
|
132
|
+
|
|
133
|
+
{providers.length === 0 && (
|
|
134
|
+
<p class="text-center text-[color:var(--color-foreground)]/60 italic py-8">
|
|
135
|
+
Provider information coming soon.
|
|
136
|
+
</p>
|
|
137
|
+
)}
|
package/dist/index.ts
CHANGED
|
@@ -13,6 +13,8 @@ export type {
|
|
|
13
13
|
PaymentsConfig,
|
|
14
14
|
EmailConfig,
|
|
15
15
|
IntegrationsConfig,
|
|
16
|
+
ProviderInfo,
|
|
17
|
+
MedicalConfig,
|
|
16
18
|
SiteConfig,
|
|
17
19
|
} from "./types";
|
|
18
20
|
|
|
@@ -29,3 +31,6 @@ export { default as Footer } from "./components/Footer.astro";
|
|
|
29
31
|
// Integration Components
|
|
30
32
|
export { default as CalendlyWidget } from "./components/CalendlyWidget.astro";
|
|
31
33
|
export { default as PaymentButton } from "./components/PaymentButton.astro";
|
|
34
|
+
|
|
35
|
+
// Medical/Healthcare Components
|
|
36
|
+
export { default as ProviderBio } from "./components/ProviderBio.astro";
|
package/dist/types.ts
CHANGED
|
@@ -56,11 +56,30 @@ export interface LayoutOptions {
|
|
|
56
56
|
|
|
57
57
|
// Integration configurations
|
|
58
58
|
export interface SchedulingConfig {
|
|
59
|
-
provider: "calendly" | "acuity" | "square" | "none";
|
|
60
|
-
url?: string; // Calendly/Acuity booking URL
|
|
59
|
+
provider: "calendly" | "acuity" | "square" | "nexhealth" | "zocdoc" | "none";
|
|
60
|
+
url?: string; // Calendly/Acuity/ZocDoc booking URL
|
|
61
|
+
practiceSlug?: string; // NexHealth practice slug (e.g., "waterstone-family-dentistry")
|
|
62
|
+
locationId?: string; // NexHealth location ID
|
|
61
63
|
buttonText?: string; // Custom CTA text, defaults to "Schedule Now"
|
|
62
64
|
}
|
|
63
65
|
|
|
66
|
+
// Medical/Healthcare specific configurations
|
|
67
|
+
export interface ProviderInfo {
|
|
68
|
+
name: string;
|
|
69
|
+
title: string; // e.g., "DDS", "MD", "DMD"
|
|
70
|
+
specialty?: string;
|
|
71
|
+
bio: string;
|
|
72
|
+
imageUrl: string;
|
|
73
|
+
credentials?: string[]; // e.g., ["University of North Carolina", "ADA Member"]
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface MedicalConfig {
|
|
77
|
+
providers?: ProviderInfo[];
|
|
78
|
+
acceptedInsurance?: string[];
|
|
79
|
+
emergencyPhone?: string;
|
|
80
|
+
officeHours?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
64
83
|
export interface PaymentsConfig {
|
|
65
84
|
provider: "stripe" | "square" | "none";
|
|
66
85
|
mode?: "deposit" | "full" | "quote"; // What kind of payment flow
|
|
@@ -91,4 +110,5 @@ export interface SiteConfig {
|
|
|
91
110
|
socialLinks?: SocialLinks;
|
|
92
111
|
layoutOptions?: LayoutOptions;
|
|
93
112
|
integrations?: IntegrationsConfig;
|
|
113
|
+
medical?: MedicalConfig; // For healthcare/dental practices
|
|
94
114
|
}
|