@burdenoff/website-sdk 0.0.0-dev
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/LICENSE +24 -0
- package/README.md +357 -0
- package/dist/analytics/index.d.mts +27 -0
- package/dist/analytics/index.d.ts +27 -0
- package/dist/analytics/index.js +36 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/analytics/index.mjs +34 -0
- package/dist/analytics/index.mjs.map +1 -0
- package/dist/client/index.d.mts +29 -0
- package/dist/client/index.d.ts +29 -0
- package/dist/client/index.js +261 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/index.mjs +255 -0
- package/dist/client/index.mjs.map +1 -0
- package/dist/components/contact.d.mts +144 -0
- package/dist/components/contact.d.ts +144 -0
- package/dist/components/contact.js +806 -0
- package/dist/components/contact.js.map +1 -0
- package/dist/components/contact.mjs +780 -0
- package/dist/components/contact.mjs.map +1 -0
- package/dist/components/electron-download.d.mts +32 -0
- package/dist/components/electron-download.d.ts +32 -0
- package/dist/components/electron-download.js +131 -0
- package/dist/components/electron-download.js.map +1 -0
- package/dist/components/electron-download.mjs +108 -0
- package/dist/components/electron-download.mjs.map +1 -0
- package/dist/components/launch-countdown.d.mts +15 -0
- package/dist/components/launch-countdown.d.ts +15 -0
- package/dist/components/launch-countdown.js +89 -0
- package/dist/components/launch-countdown.js.map +1 -0
- package/dist/components/launch-countdown.mjs +87 -0
- package/dist/components/launch-countdown.mjs.map +1 -0
- package/dist/components/newsletter.d.mts +155 -0
- package/dist/components/newsletter.d.ts +155 -0
- package/dist/components/newsletter.js +880 -0
- package/dist/components/newsletter.js.map +1 -0
- package/dist/components/newsletter.mjs +854 -0
- package/dist/components/newsletter.mjs.map +1 -0
- package/dist/components/partners.d.mts +88 -0
- package/dist/components/partners.d.ts +88 -0
- package/dist/components/partners.js +1169 -0
- package/dist/components/partners.js.map +1 -0
- package/dist/components/partners.mjs +1143 -0
- package/dist/components/partners.mjs.map +1 -0
- package/dist/components/pricing.d.mts +194 -0
- package/dist/components/pricing.d.ts +194 -0
- package/dist/components/pricing.js +813 -0
- package/dist/components/pricing.js.map +1 -0
- package/dist/components/pricing.mjs +791 -0
- package/dist/components/pricing.mjs.map +1 -0
- package/dist/components/problems-solved.d.mts +37 -0
- package/dist/components/problems-solved.d.ts +37 -0
- package/dist/components/problems-solved.js +157 -0
- package/dist/components/problems-solved.js.map +1 -0
- package/dist/components/problems-solved.mjs +135 -0
- package/dist/components/problems-solved.mjs.map +1 -0
- package/dist/components/resource-links.d.mts +28 -0
- package/dist/components/resource-links.d.ts +28 -0
- package/dist/components/resource-links.js +229 -0
- package/dist/components/resource-links.js.map +1 -0
- package/dist/components/resource-links.mjs +227 -0
- package/dist/components/resource-links.mjs.map +1 -0
- package/dist/components/social-links.d.mts +37 -0
- package/dist/components/social-links.d.ts +37 -0
- package/dist/components/social-links.js +268 -0
- package/dist/components/social-links.js.map +1 -0
- package/dist/components/social-links.mjs +266 -0
- package/dist/components/social-links.mjs.map +1 -0
- package/dist/components/unsubscribe.d.mts +14 -0
- package/dist/components/unsubscribe.d.ts +14 -0
- package/dist/components/unsubscribe.js +538 -0
- package/dist/components/unsubscribe.js.map +1 -0
- package/dist/components/unsubscribe.mjs +517 -0
- package/dist/components/unsubscribe.mjs.map +1 -0
- package/dist/components/waitlist.d.mts +70 -0
- package/dist/components/waitlist.d.ts +70 -0
- package/dist/components/waitlist.js +864 -0
- package/dist/components/waitlist.js.map +1 -0
- package/dist/components/waitlist.mjs +841 -0
- package/dist/components/waitlist.mjs.map +1 -0
- package/dist/components/website-switcher.d.mts +27 -0
- package/dist/components/website-switcher.d.ts +27 -0
- package/dist/components/website-switcher.js +168 -0
- package/dist/components/website-switcher.js.map +1 -0
- package/dist/components/website-switcher.mjs +146 -0
- package/dist/components/website-switcher.mjs.map +1 -0
- package/dist/content/index.d.mts +247 -0
- package/dist/content/index.d.ts +247 -0
- package/dist/content/index.js +2458 -0
- package/dist/content/index.js.map +1 -0
- package/dist/content/index.mjs +2428 -0
- package/dist/content/index.mjs.map +1 -0
- package/dist/index.d.mts +72 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +6273 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +6204 -0
- package/dist/index.mjs.map +1 -0
- package/dist/product/index.d.mts +94 -0
- package/dist/product/index.d.ts +94 -0
- package/dist/product/index.js +282 -0
- package/dist/product/index.js.map +1 -0
- package/dist/product/index.mjs +278 -0
- package/dist/product/index.mjs.map +1 -0
- package/dist/provider-D7Rij9UM.d.mts +86 -0
- package/dist/provider-D7Rij9UM.d.ts +86 -0
- package/dist/seo/index.d.mts +64 -0
- package/dist/seo/index.d.ts +64 -0
- package/dist/seo/index.js +61 -0
- package/dist/seo/index.js.map +1 -0
- package/dist/seo/index.mjs +59 -0
- package/dist/seo/index.mjs.map +1 -0
- package/dist/utils/index.d.mts +21 -0
- package/dist/utils/index.d.ts +21 -0
- package/dist/utils/index.js +12 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/index.mjs +10 -0
- package/dist/utils/index.mjs.map +1 -0
- package/package.json +168 -0
|
@@ -0,0 +1,1169 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var React = require('react');
|
|
4
|
+
var lucideReact = require('lucide-react');
|
|
5
|
+
var ReCAPTCHA = require('react-google-recaptcha');
|
|
6
|
+
var sonner = require('sonner');
|
|
7
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
8
|
+
var reactHelmetAsync = require('react-helmet-async');
|
|
9
|
+
var reactSlot = require('@radix-ui/react-slot');
|
|
10
|
+
var classVarianceAuthority = require('class-variance-authority');
|
|
11
|
+
var clsx = require('clsx');
|
|
12
|
+
var tailwindMerge = require('tailwind-merge');
|
|
13
|
+
var LabelPrimitive = require('@radix-ui/react-label');
|
|
14
|
+
|
|
15
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
|
+
|
|
17
|
+
function _interopNamespace(e) {
|
|
18
|
+
if (e && e.__esModule) return e;
|
|
19
|
+
var n = Object.create(null);
|
|
20
|
+
if (e) {
|
|
21
|
+
Object.keys(e).forEach(function (k) {
|
|
22
|
+
if (k !== 'default') {
|
|
23
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
24
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
25
|
+
enumerable: true,
|
|
26
|
+
get: function () { return e[k]; }
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
n.default = e;
|
|
32
|
+
return Object.freeze(n);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
var React__namespace = /*#__PURE__*/_interopNamespace(React);
|
|
36
|
+
var ReCAPTCHA__default = /*#__PURE__*/_interopDefault(ReCAPTCHA);
|
|
37
|
+
var LabelPrimitive__namespace = /*#__PURE__*/_interopNamespace(LabelPrimitive);
|
|
38
|
+
|
|
39
|
+
var __defProp = Object.defineProperty;
|
|
40
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
41
|
+
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
42
|
+
|
|
43
|
+
// src/client/security.ts
|
|
44
|
+
var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1"]);
|
|
45
|
+
var RESERVED_HEADERS = /* @__PURE__ */ new Set([
|
|
46
|
+
"authorization",
|
|
47
|
+
"cookie",
|
|
48
|
+
"x-actor-id",
|
|
49
|
+
"x-actor-type",
|
|
50
|
+
"x-consent-granted-by",
|
|
51
|
+
"x-consent-scope",
|
|
52
|
+
"x-consent-granted-at",
|
|
53
|
+
"x-consent-expires-at"
|
|
54
|
+
]);
|
|
55
|
+
function validateGatewayUrl(value) {
|
|
56
|
+
let url;
|
|
57
|
+
try {
|
|
58
|
+
url = new URL(value);
|
|
59
|
+
} catch {
|
|
60
|
+
throw new Error("Gateway URL must be a valid absolute URL");
|
|
61
|
+
}
|
|
62
|
+
if (url.protocol === "https:") {
|
|
63
|
+
return url.toString();
|
|
64
|
+
}
|
|
65
|
+
if (url.protocol === "http:" && LOOPBACK_HOSTS.has(url.hostname.toLowerCase())) {
|
|
66
|
+
return url.toString();
|
|
67
|
+
}
|
|
68
|
+
throw new Error("Gateway URL must use HTTPS unless it targets localhost");
|
|
69
|
+
}
|
|
70
|
+
function sanitizeHeaders(headers) {
|
|
71
|
+
if (!headers) return void 0;
|
|
72
|
+
return Object.fromEntries(
|
|
73
|
+
Object.entries(headers).filter(
|
|
74
|
+
([key]) => !RESERVED_HEADERS.has(key.toLowerCase())
|
|
75
|
+
)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// src/client/graphql-client.ts
|
|
80
|
+
var _WebSDKClient = class _WebSDKClient {
|
|
81
|
+
constructor(config) {
|
|
82
|
+
__publicField(this, "config");
|
|
83
|
+
__publicField(this, "queryCache", /* @__PURE__ */ new Map());
|
|
84
|
+
__publicField(this, "inflight", /* @__PURE__ */ new Map());
|
|
85
|
+
this.config = {
|
|
86
|
+
...config,
|
|
87
|
+
gatewayUrl: validateGatewayUrl(config.gatewayUrl),
|
|
88
|
+
headers: sanitizeHeaders(config.headers)
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
getConfig() {
|
|
92
|
+
return this.config;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Execute a GraphQL query (with deduplication and caching)
|
|
96
|
+
*/
|
|
97
|
+
async query(query, variables) {
|
|
98
|
+
const cacheKey = JSON.stringify({ query, variables });
|
|
99
|
+
const cached = this.queryCache.get(cacheKey);
|
|
100
|
+
if (cached) {
|
|
101
|
+
if (Date.now() - cached.ts < _WebSDKClient.CACHE_TTL) {
|
|
102
|
+
return cached.data;
|
|
103
|
+
}
|
|
104
|
+
this.queryCache.delete(cacheKey);
|
|
105
|
+
}
|
|
106
|
+
const existing = this.inflight.get(cacheKey);
|
|
107
|
+
if (existing) {
|
|
108
|
+
return existing;
|
|
109
|
+
}
|
|
110
|
+
const promise = this.request(query, variables).then((result) => {
|
|
111
|
+
if (result.data && !result.errors?.length) {
|
|
112
|
+
if (this.queryCache.size >= _WebSDKClient.MAX_CACHE_ENTRIES) {
|
|
113
|
+
const oldestEntry = this.queryCache.keys().next().value;
|
|
114
|
+
if (oldestEntry) {
|
|
115
|
+
this.queryCache.delete(oldestEntry);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
this.queryCache.set(cacheKey, { data: result, ts: Date.now() });
|
|
119
|
+
}
|
|
120
|
+
return result;
|
|
121
|
+
}).finally(() => {
|
|
122
|
+
this.inflight.delete(cacheKey);
|
|
123
|
+
});
|
|
124
|
+
this.inflight.set(cacheKey, promise);
|
|
125
|
+
return promise;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Execute a GraphQL mutation
|
|
129
|
+
*/
|
|
130
|
+
async mutate(mutation, variables) {
|
|
131
|
+
return this.request(mutation, variables);
|
|
132
|
+
}
|
|
133
|
+
async request(query, variables) {
|
|
134
|
+
try {
|
|
135
|
+
const response = await fetch(this.config.gatewayUrl, {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: {
|
|
138
|
+
"Content-Type": "application/json",
|
|
139
|
+
"x-product-id": this.config.productId,
|
|
140
|
+
...this.config.headers
|
|
141
|
+
},
|
|
142
|
+
body: JSON.stringify({ query, variables })
|
|
143
|
+
});
|
|
144
|
+
if (!response.ok) {
|
|
145
|
+
console.error(
|
|
146
|
+
"[WebSDK] GraphQL request failed",
|
|
147
|
+
response.status,
|
|
148
|
+
response.statusText
|
|
149
|
+
);
|
|
150
|
+
return {
|
|
151
|
+
errors: [
|
|
152
|
+
{
|
|
153
|
+
message: `HTTP ${response.status}: ${response.statusText}`,
|
|
154
|
+
extensions: { code: `HTTP_${response.status}` }
|
|
155
|
+
}
|
|
156
|
+
]
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return await response.json();
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error(
|
|
162
|
+
"[WebSDK] Network error",
|
|
163
|
+
error instanceof Error ? error.message : "unknown error"
|
|
164
|
+
);
|
|
165
|
+
return {
|
|
166
|
+
errors: [
|
|
167
|
+
{
|
|
168
|
+
message: error instanceof Error ? error.message : "Network error",
|
|
169
|
+
extensions: { code: "NETWORK_ERROR" }
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
__publicField(_WebSDKClient, "CACHE_TTL", 5 * 60 * 1e3);
|
|
177
|
+
// 5 minutes
|
|
178
|
+
__publicField(_WebSDKClient, "MAX_CACHE_ENTRIES", 100);
|
|
179
|
+
var WebSDKContext = React.createContext(null);
|
|
180
|
+
function useWebSDK() {
|
|
181
|
+
const client = React.useContext(WebSDKContext);
|
|
182
|
+
if (!client) {
|
|
183
|
+
throw new Error("useWebSDK must be used within a WebSDKProvider");
|
|
184
|
+
}
|
|
185
|
+
return client;
|
|
186
|
+
}
|
|
187
|
+
function useWebSDKConfig() {
|
|
188
|
+
const client = useWebSDK();
|
|
189
|
+
return client.getConfig();
|
|
190
|
+
}
|
|
191
|
+
var ProductContext = React.createContext({
|
|
192
|
+
product: null,
|
|
193
|
+
loading: true,
|
|
194
|
+
error: null,
|
|
195
|
+
hasProvider: false,
|
|
196
|
+
refetch: () => {
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
function useProduct() {
|
|
200
|
+
return React.useContext(ProductContext);
|
|
201
|
+
}
|
|
202
|
+
function PageHead({
|
|
203
|
+
title,
|
|
204
|
+
description,
|
|
205
|
+
productName,
|
|
206
|
+
keywords,
|
|
207
|
+
image,
|
|
208
|
+
url,
|
|
209
|
+
favicon,
|
|
210
|
+
robots = "index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1",
|
|
211
|
+
locale = "en_US",
|
|
212
|
+
twitterHandle,
|
|
213
|
+
themeColor = "#000000",
|
|
214
|
+
structuredData,
|
|
215
|
+
additionalMeta
|
|
216
|
+
}) {
|
|
217
|
+
const fullTitle = productName && !title.includes(productName) ? `${title} | ${productName}` : title;
|
|
218
|
+
const fullImageUrl = image && !image.startsWith("http") && url ? `${url.replace(/\/$/, "")}${image}` : image;
|
|
219
|
+
const structuredDataItems = structuredData ? Array.isArray(structuredData) ? structuredData : [structuredData] : [];
|
|
220
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactHelmetAsync.Helmet, { children: [
|
|
221
|
+
/* @__PURE__ */ jsxRuntime.jsx("title", { children: fullTitle }),
|
|
222
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { name: "title", content: fullTitle }),
|
|
223
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("meta", { name: "description", content: description }),
|
|
224
|
+
keywords && /* @__PURE__ */ jsxRuntime.jsx("meta", { name: "keywords", content: keywords }),
|
|
225
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { name: "author", content: "Burdenoff Consultancy Services Pvt Ltd" }),
|
|
226
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { name: "robots", content: robots }),
|
|
227
|
+
url && /* @__PURE__ */ jsxRuntime.jsx("link", { rel: "canonical", href: url }),
|
|
228
|
+
favicon && /* @__PURE__ */ jsxRuntime.jsx("link", { rel: "icon", href: favicon }),
|
|
229
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { property: "og:type", content: "website" }),
|
|
230
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { property: "og:title", content: fullTitle }),
|
|
231
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("meta", { property: "og:description", content: description }),
|
|
232
|
+
fullImageUrl && /* @__PURE__ */ jsxRuntime.jsx("meta", { property: "og:image", content: fullImageUrl }),
|
|
233
|
+
url && /* @__PURE__ */ jsxRuntime.jsx("meta", { property: "og:url", content: url }),
|
|
234
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { property: "og:locale", content: locale }),
|
|
235
|
+
productName && /* @__PURE__ */ jsxRuntime.jsx("meta", { property: "og:site_name", content: productName }),
|
|
236
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { name: "twitter:card", content: "summary_large_image" }),
|
|
237
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { name: "twitter:title", content: fullTitle }),
|
|
238
|
+
description && /* @__PURE__ */ jsxRuntime.jsx("meta", { name: "twitter:description", content: description }),
|
|
239
|
+
fullImageUrl && /* @__PURE__ */ jsxRuntime.jsx("meta", { name: "twitter:image", content: fullImageUrl }),
|
|
240
|
+
twitterHandle && /* @__PURE__ */ jsxRuntime.jsx("meta", { name: "twitter:creator", content: twitterHandle }),
|
|
241
|
+
/* @__PURE__ */ jsxRuntime.jsx("meta", { name: "theme-color", content: themeColor }),
|
|
242
|
+
structuredDataItems.map((data, index) => /* @__PURE__ */ jsxRuntime.jsx("script", { type: "application/ld+json", children: JSON.stringify(data) }, `ld-${index}`)),
|
|
243
|
+
additionalMeta?.map((meta, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
244
|
+
"meta",
|
|
245
|
+
{
|
|
246
|
+
...meta.name ? { name: meta.name } : {},
|
|
247
|
+
...meta.property ? { property: meta.property } : {},
|
|
248
|
+
content: meta.content
|
|
249
|
+
},
|
|
250
|
+
`meta-${index}`
|
|
251
|
+
))
|
|
252
|
+
] });
|
|
253
|
+
}
|
|
254
|
+
function cn(...inputs) {
|
|
255
|
+
return tailwindMerge.twMerge(clsx.clsx(inputs));
|
|
256
|
+
}
|
|
257
|
+
var buttonVariants = classVarianceAuthority.cva(
|
|
258
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
|
|
259
|
+
{
|
|
260
|
+
variants: {
|
|
261
|
+
variant: {
|
|
262
|
+
default: "bg-primary text-primary-foreground shadow hover:bg-primary/90",
|
|
263
|
+
destructive: "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90",
|
|
264
|
+
outline: "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground",
|
|
265
|
+
secondary: "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80",
|
|
266
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
267
|
+
link: "text-primary underline-offset-4 hover:underline"
|
|
268
|
+
},
|
|
269
|
+
size: {
|
|
270
|
+
default: "h-9 px-4 py-2",
|
|
271
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
272
|
+
lg: "h-10 rounded-md px-8",
|
|
273
|
+
icon: "h-9 w-9"
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
defaultVariants: {
|
|
277
|
+
variant: "default",
|
|
278
|
+
size: "default"
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
);
|
|
282
|
+
var Button = React__namespace.forwardRef(
|
|
283
|
+
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
284
|
+
const Comp = asChild ? reactSlot.Slot : "button";
|
|
285
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
286
|
+
Comp,
|
|
287
|
+
{
|
|
288
|
+
className: cn(buttonVariants({ variant, size, className })),
|
|
289
|
+
ref,
|
|
290
|
+
...props
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
);
|
|
295
|
+
Button.displayName = "Button";
|
|
296
|
+
var Input = React__namespace.forwardRef(
|
|
297
|
+
({ className, type, ...props }, ref) => {
|
|
298
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
299
|
+
"input",
|
|
300
|
+
{
|
|
301
|
+
type,
|
|
302
|
+
className: cn(
|
|
303
|
+
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
304
|
+
className
|
|
305
|
+
),
|
|
306
|
+
ref,
|
|
307
|
+
...props
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
);
|
|
312
|
+
Input.displayName = "Input";
|
|
313
|
+
var labelVariants = classVarianceAuthority.cva(
|
|
314
|
+
"text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
|
|
315
|
+
);
|
|
316
|
+
var Label = React__namespace.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
317
|
+
LabelPrimitive__namespace.Root,
|
|
318
|
+
{
|
|
319
|
+
ref,
|
|
320
|
+
className: cn(labelVariants(), className),
|
|
321
|
+
...props
|
|
322
|
+
}
|
|
323
|
+
));
|
|
324
|
+
Label.displayName = LabelPrimitive__namespace.Root.displayName;
|
|
325
|
+
var Select = React__namespace.forwardRef(({ className, children, ...props }, ref) => {
|
|
326
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
327
|
+
"select",
|
|
328
|
+
{
|
|
329
|
+
className: cn(
|
|
330
|
+
"flex h-9 w-full appearance-none rounded-md border border-input bg-transparent bg-[length:1rem_1rem] bg-[right_0.75rem_center] bg-no-repeat px-3 py-1 pr-8 text-base shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
331
|
+
// Inline SVG chevron: SVG inside a `background-image: url(data:…)`
|
|
332
|
+
// does NOT inherit `currentColor` from the host element (the SVG is
|
|
333
|
+
// its own document with no parent CSS context), so the stroke is
|
|
334
|
+
// hardcoded to a muted slate-400 (#94a3b8). Matches the muted
|
|
335
|
+
// foreground token visually in both light and dark themes well
|
|
336
|
+
// enough for a passive chevron — addresses #9 review feedback.
|
|
337
|
+
`bg-[url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><polyline points='6 9 12 15 18 9'/></svg>")]`,
|
|
338
|
+
className
|
|
339
|
+
),
|
|
340
|
+
ref,
|
|
341
|
+
...props,
|
|
342
|
+
children
|
|
343
|
+
}
|
|
344
|
+
);
|
|
345
|
+
});
|
|
346
|
+
Select.displayName = "Select";
|
|
347
|
+
var Textarea = React__namespace.forwardRef(({ className, ...props }, ref) => {
|
|
348
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
349
|
+
"textarea",
|
|
350
|
+
{
|
|
351
|
+
className: cn(
|
|
352
|
+
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-base shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
353
|
+
className
|
|
354
|
+
),
|
|
355
|
+
ref,
|
|
356
|
+
...props
|
|
357
|
+
}
|
|
358
|
+
);
|
|
359
|
+
});
|
|
360
|
+
Textarea.displayName = "Textarea";
|
|
361
|
+
var SUBMIT_CONTACT_INQUIRY_MUTATION = (
|
|
362
|
+
/* GraphQL */
|
|
363
|
+
`
|
|
364
|
+
mutation SubmitContactInquiry($input: SubmitContactInquiryInput!) {
|
|
365
|
+
submitContactInquiry(input: $input) {
|
|
366
|
+
success
|
|
367
|
+
message
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
`
|
|
371
|
+
);
|
|
372
|
+
async function submitContactForm(client, data, productId) {
|
|
373
|
+
try {
|
|
374
|
+
const result = await client.mutate(SUBMIT_CONTACT_INQUIRY_MUTATION, {
|
|
375
|
+
input: {
|
|
376
|
+
name: `${data.firstName} ${data.lastName}`,
|
|
377
|
+
email: data.email.trim().toLowerCase(),
|
|
378
|
+
company: data.company || void 0,
|
|
379
|
+
subject: data.subject,
|
|
380
|
+
message: data.message,
|
|
381
|
+
productId,
|
|
382
|
+
// Send `category` only when the user actually picked one. Older
|
|
383
|
+
// backend deployments without the `category` field in the
|
|
384
|
+
// `SubmitContactInquiryInput` schema would reject any unknown
|
|
385
|
+
// field; spreading conditionally keeps the SDK forward-
|
|
386
|
+
// compatible.
|
|
387
|
+
...data.category ? { category: data.category } : {},
|
|
388
|
+
...data.recaptchaToken ? { recaptchaToken: data.recaptchaToken } : {}
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
if (result.errors?.length) {
|
|
392
|
+
const errorMsg = result.errors[0]?.message ?? "Failed to send message";
|
|
393
|
+
return { success: false, message: errorMsg };
|
|
394
|
+
}
|
|
395
|
+
const response = result.data?.submitContactInquiry;
|
|
396
|
+
if (response?.success) {
|
|
397
|
+
return {
|
|
398
|
+
success: true,
|
|
399
|
+
message: response.message || "Message sent successfully!"
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
success: false,
|
|
404
|
+
message: response?.message || "Failed to send message"
|
|
405
|
+
};
|
|
406
|
+
} catch (error) {
|
|
407
|
+
console.error("Contact form submission error:", error);
|
|
408
|
+
return {
|
|
409
|
+
success: false,
|
|
410
|
+
message: "Network error. Please try again."
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
function replacePlaceholders(text, productName, email) {
|
|
415
|
+
return text.replace(/{productName}/g, productName).replace(/{email}/g, email);
|
|
416
|
+
}
|
|
417
|
+
function ContactPage({
|
|
418
|
+
productName,
|
|
419
|
+
recaptchaSiteKey,
|
|
420
|
+
contactEmail,
|
|
421
|
+
contactPhone,
|
|
422
|
+
officeAddress,
|
|
423
|
+
responseTime = "We typically respond within 24 hours",
|
|
424
|
+
heroTitle = "Get in Touch",
|
|
425
|
+
heroDescription = "Have questions about {productName}? We're here to help. Reach out to our team and we'll get back to you as soon as possible.",
|
|
426
|
+
headingLevel = 1,
|
|
427
|
+
// Backward-compatibility: default to `[]` so existing consumers
|
|
428
|
+
// (fluidgrids/burdenoff/algoshred websites) that don't pass
|
|
429
|
+
// `categories` continue to render with NO dropdown — same behavior
|
|
430
|
+
// they had before this SDK version. To opt in, pass an explicit
|
|
431
|
+
// `categories={…}` array (or the exported `DEFAULT_CONTACT_CATEGORIES`
|
|
432
|
+
// constant for the sane Burdenoff-generic vocabulary).
|
|
433
|
+
categories = [],
|
|
434
|
+
categoryLabel = "Category",
|
|
435
|
+
categoryPlaceholder = "Select a category",
|
|
436
|
+
categoryRequired = true,
|
|
437
|
+
additionalOptions = [
|
|
438
|
+
{
|
|
439
|
+
title: "Sales Inquiries",
|
|
440
|
+
description: "Ready to see {productName} in action? Our sales team is here to help.",
|
|
441
|
+
buttonText: "Contact Sales",
|
|
442
|
+
buttonLink: `mailto:${contactEmail}`
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
title: "Technical Support",
|
|
446
|
+
description: "Need help with your {productName} setup? Our support team is ready.",
|
|
447
|
+
buttonText: "Get Support",
|
|
448
|
+
buttonLink: `mailto:${contactEmail}`
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
title: "Partnership",
|
|
452
|
+
description: "Interested in partnering with {productName}? Let's explore opportunities.",
|
|
453
|
+
buttonText: "Partner With Us",
|
|
454
|
+
buttonLink: `mailto:${contactEmail}`
|
|
455
|
+
}
|
|
456
|
+
],
|
|
457
|
+
seo
|
|
458
|
+
}) {
|
|
459
|
+
const client = useWebSDK();
|
|
460
|
+
const config = useWebSDKConfig();
|
|
461
|
+
const { product } = useProduct();
|
|
462
|
+
const resolvedProductId = product?.id || config.productId;
|
|
463
|
+
const displayName = productName ?? product?.name ?? config.productId;
|
|
464
|
+
const effectiveRecaptchaSiteKey = recaptchaSiteKey ?? product?.recaptchaSiteKey ?? config.recaptchaSiteKey ?? "";
|
|
465
|
+
const recaptchaRef = React.useRef(null);
|
|
466
|
+
const [isSubmitting, setIsSubmitting] = React.useState(false);
|
|
467
|
+
const [submitStatus, setSubmitStatus] = React.useState("idle");
|
|
468
|
+
const handleSubmit = async (e) => {
|
|
469
|
+
e.preventDefault();
|
|
470
|
+
const recaptchaToken = recaptchaRef.current?.getValue() ?? "";
|
|
471
|
+
if (effectiveRecaptchaSiteKey && !recaptchaToken) {
|
|
472
|
+
sonner.toast.error("Please complete the reCAPTCHA verification");
|
|
473
|
+
return;
|
|
474
|
+
}
|
|
475
|
+
setIsSubmitting(true);
|
|
476
|
+
setSubmitStatus("idle");
|
|
477
|
+
const form = e.currentTarget;
|
|
478
|
+
try {
|
|
479
|
+
const formData = new FormData(form);
|
|
480
|
+
const showCategory = categories.length > 0;
|
|
481
|
+
const rawCategory = showCategory ? (formData.get("category") ?? "").trim() : "";
|
|
482
|
+
if (showCategory && categoryRequired && !rawCategory) {
|
|
483
|
+
sonner.toast.error("Please select a category");
|
|
484
|
+
setIsSubmitting(false);
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
const contactData = {
|
|
488
|
+
firstName: formData.get("firstName"),
|
|
489
|
+
lastName: formData.get("lastName"),
|
|
490
|
+
email: formData.get("email"),
|
|
491
|
+
company: formData.get("company"),
|
|
492
|
+
category: rawCategory || void 0,
|
|
493
|
+
subject: formData.get("subject"),
|
|
494
|
+
message: formData.get("message"),
|
|
495
|
+
recaptchaToken
|
|
496
|
+
};
|
|
497
|
+
const result = await submitContactForm(
|
|
498
|
+
client,
|
|
499
|
+
contactData,
|
|
500
|
+
resolvedProductId
|
|
501
|
+
);
|
|
502
|
+
if (result.success) {
|
|
503
|
+
setSubmitStatus("success");
|
|
504
|
+
sonner.toast.success(
|
|
505
|
+
result.message ?? `Thank you for contacting ${displayName}. We'll get back to you within 24 hours.`
|
|
506
|
+
);
|
|
507
|
+
if (form) {
|
|
508
|
+
form.reset();
|
|
509
|
+
}
|
|
510
|
+
recaptchaRef.current?.reset();
|
|
511
|
+
} else {
|
|
512
|
+
setSubmitStatus("error");
|
|
513
|
+
sonner.toast.error(
|
|
514
|
+
result.message ?? "Failed to send message. Please try again."
|
|
515
|
+
);
|
|
516
|
+
recaptchaRef.current?.reset();
|
|
517
|
+
}
|
|
518
|
+
} catch (error) {
|
|
519
|
+
console.error("Error submitting form:", error);
|
|
520
|
+
setSubmitStatus("error");
|
|
521
|
+
sonner.toast.error("Failed to send message. Please try again later.");
|
|
522
|
+
recaptchaRef.current?.reset();
|
|
523
|
+
} finally {
|
|
524
|
+
setIsSubmitting(false);
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full", children: [
|
|
528
|
+
seo && /* @__PURE__ */ jsxRuntime.jsx(
|
|
529
|
+
PageHead,
|
|
530
|
+
{
|
|
531
|
+
title: seo.title ?? `Contact ${displayName} - Get in Touch With Our Team`,
|
|
532
|
+
description: seo.description ?? `Ready to transform your business? Contact our team for sales inquiries, technical support, or partnership opportunities. We're here to help you succeed.`,
|
|
533
|
+
productName: displayName,
|
|
534
|
+
keywords: seo.keywords ?? `contact ${displayName.toLowerCase()}, sales inquiries, customer support, technical support, partnership opportunities, get in touch`,
|
|
535
|
+
image: seo.image ?? "/og-image-contact.png",
|
|
536
|
+
url: seo.url
|
|
537
|
+
}
|
|
538
|
+
),
|
|
539
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
540
|
+
"section",
|
|
541
|
+
{
|
|
542
|
+
className: headingLevel === 2 ? "py-12 md:py-16" : "bg-gradient-to-b from-background to-muted/20 py-12 sm:py-16 md:py-20 lg:py-24",
|
|
543
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-center max-w-3xl mx-auto", children: [
|
|
544
|
+
headingLevel === 2 ? /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl md:text-3xl font-bold mb-3", children: heroTitle }) : /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-3xl sm:text-4xl md:text-5xl font-bold mb-4 sm:mb-6", children: heroTitle }),
|
|
545
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg sm:text-xl text-muted-foreground leading-relaxed", children: replacePlaceholders(heroDescription, displayName, contactEmail) })
|
|
546
|
+
] }) })
|
|
547
|
+
}
|
|
548
|
+
),
|
|
549
|
+
/* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12 sm:py-16 md:py-20 lg:py-24", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid sm:grid-cols-1 lg:grid-cols-3 gap-8 sm:gap-10 lg:gap-12", children: [
|
|
550
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:col-span-1 order-2 lg:order-1", children: [
|
|
551
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl sm:text-2xl font-bold mb-4 sm:mb-6", children: "Contact Information" }),
|
|
552
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4 sm:space-y-6", children: [
|
|
553
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start space-x-3 sm:space-x-4", children: [
|
|
554
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 sm:w-10 sm:h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mail, { className: "h-4 w-4 sm:h-5 sm:w-5 text-primary" }) }),
|
|
555
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
556
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold mb-1 text-sm sm:text-base", children: "Email" }),
|
|
557
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm sm:text-base break-all", children: contactEmail })
|
|
558
|
+
] })
|
|
559
|
+
] }),
|
|
560
|
+
contactPhone && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start space-x-3 sm:space-x-4", children: [
|
|
561
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 sm:w-10 sm:h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Phone, { className: "h-4 w-4 sm:h-5 sm:w-5 text-primary" }) }),
|
|
562
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
563
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold mb-1 text-sm sm:text-base", children: "Phone" }),
|
|
564
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm sm:text-base", children: contactPhone })
|
|
565
|
+
] })
|
|
566
|
+
] }),
|
|
567
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start space-x-3 sm:space-x-4", children: [
|
|
568
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 sm:w-10 sm:h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MapPin, { className: "h-4 w-4 sm:h-5 sm:w-5 text-primary" }) }),
|
|
569
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
570
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold mb-1 text-sm sm:text-base", children: "Office" }),
|
|
571
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-muted-foreground text-sm sm:text-base leading-relaxed", children: [
|
|
572
|
+
officeAddress.line1,
|
|
573
|
+
/* @__PURE__ */ jsxRuntime.jsx("br", {}),
|
|
574
|
+
officeAddress.line2,
|
|
575
|
+
/* @__PURE__ */ jsxRuntime.jsx("br", {}),
|
|
576
|
+
officeAddress.line3,
|
|
577
|
+
/* @__PURE__ */ jsxRuntime.jsx("br", {}),
|
|
578
|
+
officeAddress.country
|
|
579
|
+
] })
|
|
580
|
+
] })
|
|
581
|
+
] }),
|
|
582
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start space-x-3 sm:space-x-4", children: [
|
|
583
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-8 h-8 sm:w-10 sm:h-10 bg-primary/10 rounded-lg flex items-center justify-center flex-shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clock, { className: "h-4 w-4 sm:h-5 sm:w-5 text-primary" }) }),
|
|
584
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
585
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold mb-1 text-sm sm:text-base", children: "Response Time" }),
|
|
586
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm sm:text-base", children: responseTime })
|
|
587
|
+
] })
|
|
588
|
+
] })
|
|
589
|
+
] })
|
|
590
|
+
] }),
|
|
591
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "lg:col-span-2 order-1 lg:order-2", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-card border rounded-lg p-4 sm:p-6 md:p-8", children: [
|
|
592
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-xl sm:text-2xl font-bold mb-4 sm:mb-6", children: "Send us a Message" }),
|
|
593
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
594
|
+
"form",
|
|
595
|
+
{
|
|
596
|
+
onSubmit: handleSubmit,
|
|
597
|
+
className: "space-y-4 sm:space-y-6",
|
|
598
|
+
children: [
|
|
599
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid sm:grid-cols-2 gap-4 sm:gap-6", children: [
|
|
600
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
601
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
602
|
+
Label,
|
|
603
|
+
{
|
|
604
|
+
htmlFor: "firstName",
|
|
605
|
+
className: "text-sm sm:text-base",
|
|
606
|
+
children: "First Name *"
|
|
607
|
+
}
|
|
608
|
+
),
|
|
609
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
610
|
+
Input,
|
|
611
|
+
{
|
|
612
|
+
id: "firstName",
|
|
613
|
+
name: "firstName",
|
|
614
|
+
required: true,
|
|
615
|
+
placeholder: "John",
|
|
616
|
+
className: "text-sm sm:text-base"
|
|
617
|
+
}
|
|
618
|
+
)
|
|
619
|
+
] }),
|
|
620
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
621
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
622
|
+
Label,
|
|
623
|
+
{
|
|
624
|
+
htmlFor: "lastName",
|
|
625
|
+
className: "text-sm sm:text-base",
|
|
626
|
+
children: "Last Name *"
|
|
627
|
+
}
|
|
628
|
+
),
|
|
629
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
630
|
+
Input,
|
|
631
|
+
{
|
|
632
|
+
id: "lastName",
|
|
633
|
+
name: "lastName",
|
|
634
|
+
required: true,
|
|
635
|
+
placeholder: "Doe",
|
|
636
|
+
className: "text-sm sm:text-base"
|
|
637
|
+
}
|
|
638
|
+
)
|
|
639
|
+
] })
|
|
640
|
+
] }),
|
|
641
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
642
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "email", className: "text-sm sm:text-base", children: "Email *" }),
|
|
643
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
644
|
+
Input,
|
|
645
|
+
{
|
|
646
|
+
id: "email",
|
|
647
|
+
name: "email",
|
|
648
|
+
type: "email",
|
|
649
|
+
required: true,
|
|
650
|
+
placeholder: "john@company.com",
|
|
651
|
+
className: "text-sm sm:text-base"
|
|
652
|
+
}
|
|
653
|
+
)
|
|
654
|
+
] }),
|
|
655
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
656
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "company", className: "text-sm sm:text-base", children: "Company" }),
|
|
657
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
658
|
+
Input,
|
|
659
|
+
{
|
|
660
|
+
id: "company",
|
|
661
|
+
name: "company",
|
|
662
|
+
placeholder: "Acme Inc.",
|
|
663
|
+
className: "text-sm sm:text-base"
|
|
664
|
+
}
|
|
665
|
+
)
|
|
666
|
+
] }),
|
|
667
|
+
categories.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
668
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
669
|
+
Label,
|
|
670
|
+
{
|
|
671
|
+
htmlFor: "category",
|
|
672
|
+
className: "text-sm sm:text-base",
|
|
673
|
+
children: [
|
|
674
|
+
categoryLabel,
|
|
675
|
+
categoryRequired ? " *" : ""
|
|
676
|
+
]
|
|
677
|
+
}
|
|
678
|
+
),
|
|
679
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
680
|
+
Select,
|
|
681
|
+
{
|
|
682
|
+
id: "category",
|
|
683
|
+
name: "category",
|
|
684
|
+
required: categoryRequired,
|
|
685
|
+
defaultValue: "",
|
|
686
|
+
className: "text-sm sm:text-base",
|
|
687
|
+
children: [
|
|
688
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", disabled: categoryRequired, children: categoryPlaceholder }),
|
|
689
|
+
categories.map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c.value, children: c.label }, c.value))
|
|
690
|
+
]
|
|
691
|
+
}
|
|
692
|
+
)
|
|
693
|
+
] }),
|
|
694
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
695
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "subject", className: "text-sm sm:text-base", children: "Subject *" }),
|
|
696
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
697
|
+
Input,
|
|
698
|
+
{
|
|
699
|
+
id: "subject",
|
|
700
|
+
name: "subject",
|
|
701
|
+
required: true,
|
|
702
|
+
placeholder: "How can we help you?",
|
|
703
|
+
className: "text-sm sm:text-base"
|
|
704
|
+
}
|
|
705
|
+
)
|
|
706
|
+
] }),
|
|
707
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
708
|
+
/* @__PURE__ */ jsxRuntime.jsx(Label, { htmlFor: "message", className: "text-sm sm:text-base", children: "Message *" }),
|
|
709
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
710
|
+
Textarea,
|
|
711
|
+
{
|
|
712
|
+
id: "message",
|
|
713
|
+
name: "message",
|
|
714
|
+
required: true,
|
|
715
|
+
placeholder: "Tell us more about your needs...",
|
|
716
|
+
rows: 5,
|
|
717
|
+
className: "text-sm sm:text-base min-h-[120px] sm:min-h-[150px] resize-y"
|
|
718
|
+
}
|
|
719
|
+
)
|
|
720
|
+
] }),
|
|
721
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
|
|
722
|
+
effectiveRecaptchaSiteKey && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex justify-center sm:justify-start", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
723
|
+
ReCAPTCHA__default.default,
|
|
724
|
+
{
|
|
725
|
+
ref: recaptchaRef,
|
|
726
|
+
sitekey: effectiveRecaptchaSiteKey
|
|
727
|
+
}
|
|
728
|
+
) }),
|
|
729
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
730
|
+
Button,
|
|
731
|
+
{
|
|
732
|
+
type: "submit",
|
|
733
|
+
size: "lg",
|
|
734
|
+
disabled: isSubmitting,
|
|
735
|
+
className: "w-full sm:w-auto min-w-[200px]",
|
|
736
|
+
children: isSubmitting ? "Sending..." : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
737
|
+
"Send Message ",
|
|
738
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Send, { className: "ml-2 h-4 w-4" })
|
|
739
|
+
] })
|
|
740
|
+
}
|
|
741
|
+
)
|
|
742
|
+
] }),
|
|
743
|
+
submitStatus === "success" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 sm:p-4 bg-green-50 border border-green-200 rounded-lg text-green-800 mt-4", children: [
|
|
744
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-sm sm:text-base", children: "Message sent successfully!" }),
|
|
745
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs sm:text-sm mt-1", children: [
|
|
746
|
+
"Thank you for contacting ",
|
|
747
|
+
displayName,
|
|
748
|
+
". We'll get back to you within 24 hours."
|
|
749
|
+
] })
|
|
750
|
+
] }),
|
|
751
|
+
submitStatus === "error" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-3 sm:p-4 bg-red-50 border border-red-200 rounded-lg text-red-800 mt-4", children: [
|
|
752
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-medium text-sm sm:text-base", children: "Failed to send message" }),
|
|
753
|
+
/* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs sm:text-sm mt-1", children: [
|
|
754
|
+
"Please try again later or contact us directly at",
|
|
755
|
+
" ",
|
|
756
|
+
contactEmail
|
|
757
|
+
] })
|
|
758
|
+
] })
|
|
759
|
+
]
|
|
760
|
+
}
|
|
761
|
+
)
|
|
762
|
+
] }) })
|
|
763
|
+
] }) }) }),
|
|
764
|
+
additionalOptions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12 sm:py-16 md:py-20 lg:py-24 bg-muted/30", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "max-w-7xl mx-auto px-4 sm:px-6 lg:px-8", children: [
|
|
765
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl sm:text-3xl font-bold text-center mb-8 sm:mb-12", children: "More Ways to Connect" }),
|
|
766
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid sm:grid-cols-2 lg:grid-cols-3 gap-6 sm:gap-8 max-w-5xl mx-auto", children: additionalOptions.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
767
|
+
"div",
|
|
768
|
+
{
|
|
769
|
+
className: "text-center p-4 sm:p-6 bg-card border rounded-lg",
|
|
770
|
+
children: [
|
|
771
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-base sm:text-lg mb-2", children: option.title }),
|
|
772
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground text-sm sm:text-base mb-4 leading-relaxed", children: replacePlaceholders(
|
|
773
|
+
option.description,
|
|
774
|
+
displayName,
|
|
775
|
+
contactEmail
|
|
776
|
+
) }),
|
|
777
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
778
|
+
Button,
|
|
779
|
+
{
|
|
780
|
+
variant: "outline",
|
|
781
|
+
asChild: true,
|
|
782
|
+
className: "text-sm sm:text-base",
|
|
783
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("a", { href: option.buttonLink, children: option.buttonText })
|
|
784
|
+
}
|
|
785
|
+
)
|
|
786
|
+
]
|
|
787
|
+
},
|
|
788
|
+
index
|
|
789
|
+
)) })
|
|
790
|
+
] }) })
|
|
791
|
+
] });
|
|
792
|
+
}
|
|
793
|
+
function renderMarkdown(md) {
|
|
794
|
+
let html = md;
|
|
795
|
+
html = html.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
796
|
+
html = html.replace(/```(\w*)\n([\s\S]*?)```/g, (_m, _lang, code) => {
|
|
797
|
+
return `<pre><code>${code.trim()}</code></pre>`;
|
|
798
|
+
});
|
|
799
|
+
html = html.replace(/`([^`]+)`/g, "<code>$1</code>");
|
|
800
|
+
html = html.replace(/^###### (.+)$/gm, "<h6>$1</h6>");
|
|
801
|
+
html = html.replace(/^##### (.+)$/gm, "<h5>$1</h5>");
|
|
802
|
+
html = html.replace(/^#### (.+)$/gm, "<h4>$1</h4>");
|
|
803
|
+
html = html.replace(/^### (.+)$/gm, "<h3>$1</h3>");
|
|
804
|
+
html = html.replace(/^## (.+)$/gm, "<h2>$1</h2>");
|
|
805
|
+
html = html.replace(/^# (.+)$/gm, "<h1>$1</h1>");
|
|
806
|
+
html = html.replace(/\*\*\*(.+?)\*\*\*/g, "<strong><em>$1</em></strong>");
|
|
807
|
+
html = html.replace(/\*\*(.+?)\*\*/g, "<strong>$1</strong>");
|
|
808
|
+
html = html.replace(/\*(.+?)\*/g, "<em>$1</em>");
|
|
809
|
+
html = html.replace(
|
|
810
|
+
/\[([^\]]+)\]\(([^)]+)\)/g,
|
|
811
|
+
'<a href="$2" target="_blank" rel="noopener noreferrer">$1</a>'
|
|
812
|
+
);
|
|
813
|
+
html = html.replace(/^> (.+)$/gm, "<blockquote>$1</blockquote>");
|
|
814
|
+
html = html.replace(/(^- .+$(\n^- .+$)*)/gm, (block) => {
|
|
815
|
+
const items = block.split("\n").map((line) => `<li>${line.replace(/^- /, "")}</li>`).join("");
|
|
816
|
+
return `<ul>${items}</ul>`;
|
|
817
|
+
});
|
|
818
|
+
html = html.replace(/(^\d+\. .+$(\n^\d+\. .+$)*)/gm, (block) => {
|
|
819
|
+
const items = block.split("\n").map((line) => `<li>${line.replace(/^\d+\. /, "")}</li>`).join("");
|
|
820
|
+
return `<ol>${items}</ol>`;
|
|
821
|
+
});
|
|
822
|
+
html = html.replace(/^---$/gm, "<hr />");
|
|
823
|
+
html = html.split(/\n\n+/).map((block) => {
|
|
824
|
+
const trimmed = block.trim();
|
|
825
|
+
if (!trimmed) return "";
|
|
826
|
+
if (/^<(h[1-6]|ul|ol|pre|blockquote|hr)/.test(trimmed)) return trimmed;
|
|
827
|
+
return `<p>${trimmed.replace(/\n/g, "<br />")}</p>`;
|
|
828
|
+
}).join("\n");
|
|
829
|
+
return html;
|
|
830
|
+
}
|
|
831
|
+
function ContentRenderer({
|
|
832
|
+
content,
|
|
833
|
+
format = "markdown",
|
|
834
|
+
className
|
|
835
|
+
}) {
|
|
836
|
+
if (format === "markdown") {
|
|
837
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
838
|
+
"div",
|
|
839
|
+
{
|
|
840
|
+
className,
|
|
841
|
+
dangerouslySetInnerHTML: { __html: renderMarkdown(content) }
|
|
842
|
+
}
|
|
843
|
+
);
|
|
844
|
+
}
|
|
845
|
+
if (format === "html") {
|
|
846
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
847
|
+
"div",
|
|
848
|
+
{
|
|
849
|
+
className,
|
|
850
|
+
dangerouslySetInnerHTML: { __html: content }
|
|
851
|
+
}
|
|
852
|
+
);
|
|
853
|
+
}
|
|
854
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, children: /* @__PURE__ */ jsxRuntime.jsx("pre", { style: { whiteSpace: "pre-wrap", fontFamily: "inherit" }, children: content }) });
|
|
855
|
+
}
|
|
856
|
+
var PARTNER_CONTENT_QUERY = `
|
|
857
|
+
query PartnerContent($productId: String!, $limit: Int) {
|
|
858
|
+
publicContentPages(productId: $productId, limit: $limit, offset: 0) {
|
|
859
|
+
items {
|
|
860
|
+
id
|
|
861
|
+
title
|
|
862
|
+
slug
|
|
863
|
+
excerpt
|
|
864
|
+
content
|
|
865
|
+
contentFormat
|
|
866
|
+
thumbnail
|
|
867
|
+
tags
|
|
868
|
+
publishedAt
|
|
869
|
+
lastUpdated
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
`;
|
|
874
|
+
var PARTNER_DOCUMENTS_QUERY = `
|
|
875
|
+
query PartnerDocuments($productId: String!, $limit: Int) {
|
|
876
|
+
publicPressKitAssets(productId: $productId, limit: $limit, offset: 0) {
|
|
877
|
+
items {
|
|
878
|
+
id
|
|
879
|
+
category
|
|
880
|
+
title
|
|
881
|
+
description
|
|
882
|
+
fileUrl
|
|
883
|
+
fileName
|
|
884
|
+
fileSize
|
|
885
|
+
mimeType
|
|
886
|
+
version
|
|
887
|
+
tags
|
|
888
|
+
sortOrder
|
|
889
|
+
updatedAt
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
`;
|
|
894
|
+
function formatFileSize(bytes) {
|
|
895
|
+
if (!bytes || bytes <= 0) return "";
|
|
896
|
+
const units = ["B", "KB", "MB", "GB"];
|
|
897
|
+
let i = 0;
|
|
898
|
+
let n = bytes;
|
|
899
|
+
while (n >= 1024 && i < units.length - 1) {
|
|
900
|
+
n /= 1024;
|
|
901
|
+
i++;
|
|
902
|
+
}
|
|
903
|
+
return `${n.toFixed(n >= 10 || i === 0 ? 0 : 1)} ${units[i]}`;
|
|
904
|
+
}
|
|
905
|
+
async function downloadDocument(e, doc) {
|
|
906
|
+
e.preventDefault();
|
|
907
|
+
const name = doc.fileName || doc.fileUrl.split("/").pop()?.split("?")[0] || doc.title || "partner-document";
|
|
908
|
+
const openInTab = () => window.open(doc.fileUrl, "_blank", "noopener,noreferrer");
|
|
909
|
+
try {
|
|
910
|
+
const res = await fetch(doc.fileUrl, { mode: "cors" });
|
|
911
|
+
if (!res.ok) {
|
|
912
|
+
openInTab();
|
|
913
|
+
return;
|
|
914
|
+
}
|
|
915
|
+
const blob = await res.blob();
|
|
916
|
+
const objUrl = URL.createObjectURL(blob);
|
|
917
|
+
const a = document.createElement("a");
|
|
918
|
+
a.href = objUrl;
|
|
919
|
+
a.download = name;
|
|
920
|
+
document.body.appendChild(a);
|
|
921
|
+
a.click();
|
|
922
|
+
a.remove();
|
|
923
|
+
URL.revokeObjectURL(objUrl);
|
|
924
|
+
} catch {
|
|
925
|
+
openInTab();
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
function PartnerHero({
|
|
929
|
+
title,
|
|
930
|
+
subtitle
|
|
931
|
+
}) {
|
|
932
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "bg-gradient-to-b from-background to-muted/20 py-16 md:py-24", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "container mx-auto px-4 max-w-4xl text-center", children: [
|
|
933
|
+
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-4xl md:text-5xl font-bold tracking-tight text-foreground mb-4", children: title }),
|
|
934
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-lg md:text-xl text-muted-foreground max-w-2xl mx-auto", children: subtitle })
|
|
935
|
+
] }) });
|
|
936
|
+
}
|
|
937
|
+
function stripLeadingHeading(content, format) {
|
|
938
|
+
if (format === "html") {
|
|
939
|
+
return content.replace(/^\s*<h1\b[^>]*>[\s\S]*?<\/h1>\s*/i, "");
|
|
940
|
+
}
|
|
941
|
+
return content.replace(/^\s*#\s+.*(?:\r?\n)*/, "");
|
|
942
|
+
}
|
|
943
|
+
function PartnerContentSection({
|
|
944
|
+
page
|
|
945
|
+
}) {
|
|
946
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12 md:py-16", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
947
|
+
"div",
|
|
948
|
+
{
|
|
949
|
+
className: [
|
|
950
|
+
"mx-auto max-w-3xl px-4",
|
|
951
|
+
// Headings
|
|
952
|
+
"[&_h1]:text-3xl [&_h1]:font-bold [&_h1]:tracking-tight [&_h1]:mt-0 [&_h1]:mb-6",
|
|
953
|
+
"[&_h2]:text-2xl [&_h2]:font-bold [&_h2]:tracking-tight [&_h2]:mt-10 [&_h2]:mb-4",
|
|
954
|
+
"[&_h3]:text-xl [&_h3]:font-semibold [&_h3]:mt-7 [&_h3]:mb-3",
|
|
955
|
+
"[&_h4]:text-lg [&_h4]:font-semibold [&_h4]:mt-6 [&_h4]:mb-2",
|
|
956
|
+
// Block elements
|
|
957
|
+
"[&_p]:my-4 [&_p]:leading-relaxed [&_p]:text-base",
|
|
958
|
+
"[&_ul]:my-4 [&_ul]:pl-6 [&_ul]:list-disc [&_ul]:space-y-1",
|
|
959
|
+
"[&_ol]:my-4 [&_ol]:pl-6 [&_ol]:list-decimal [&_ol]:space-y-1",
|
|
960
|
+
"[&_li]:leading-relaxed",
|
|
961
|
+
"[&_li>p]:my-1",
|
|
962
|
+
"[&_blockquote]:border-l-4 [&_blockquote]:border-border [&_blockquote]:pl-4 [&_blockquote]:italic [&_blockquote]:my-4 [&_blockquote]:text-muted-foreground",
|
|
963
|
+
"[&_hr]:my-8 [&_hr]:border-border",
|
|
964
|
+
// Inline elements
|
|
965
|
+
"[&_strong]:font-semibold [&_strong]:text-foreground",
|
|
966
|
+
"[&_em]:italic",
|
|
967
|
+
"[&_a]:underline [&_a]:underline-offset-2 [&_a]:text-accent hover:[&_a]:text-accent/80 [&_a]:transition-colors",
|
|
968
|
+
"[&_code]:rounded [&_code]:bg-muted [&_code]:px-1.5 [&_code]:py-0.5 [&_code]:text-sm [&_code]:font-mono",
|
|
969
|
+
"[&_pre]:my-4 [&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:bg-muted [&_pre]:p-4 [&_pre]:text-sm",
|
|
970
|
+
"[&_pre>code]:bg-transparent [&_pre>code]:p-0"
|
|
971
|
+
].join(" "),
|
|
972
|
+
children: page.content && /* @__PURE__ */ jsxRuntime.jsx(
|
|
973
|
+
ContentRenderer,
|
|
974
|
+
{
|
|
975
|
+
content: stripLeadingHeading(page.content, page.contentFormat),
|
|
976
|
+
format: (
|
|
977
|
+
// Validate before passing; unknown formats fall through to
|
|
978
|
+
// ContentRenderer's default behavior (markdown rendering)
|
|
979
|
+
// rather than getting silently force-cast to an
|
|
980
|
+
// unsupported variant.
|
|
981
|
+
page.contentFormat === "markdown" || page.contentFormat === "html" ? page.contentFormat : void 0
|
|
982
|
+
)
|
|
983
|
+
}
|
|
984
|
+
)
|
|
985
|
+
}
|
|
986
|
+
) });
|
|
987
|
+
}
|
|
988
|
+
function PartnerDocumentCard({ doc }) {
|
|
989
|
+
const sizeLabel = formatFileSize(doc.fileSize);
|
|
990
|
+
const ext = doc.fileName?.split(".").pop()?.toUpperCase();
|
|
991
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "flex flex-col gap-3 rounded-xl border border-border bg-card p-5 shadow-sm hover:shadow-md transition-shadow", children: [
|
|
992
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-3", children: [
|
|
993
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "rounded-lg bg-muted p-2.5 shrink-0", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileText, { size: 20, className: "text-muted-foreground" }) }),
|
|
994
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
|
|
995
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { className: "font-semibold text-foreground truncate", children: doc.title }),
|
|
996
|
+
doc.version && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground mt-0.5", children: [
|
|
997
|
+
"Version ",
|
|
998
|
+
doc.version
|
|
999
|
+
] })
|
|
1000
|
+
] })
|
|
1001
|
+
] }),
|
|
1002
|
+
doc.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground line-clamp-3", children: doc.description }),
|
|
1003
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 mt-auto pt-2 border-t border-border/60", children: [
|
|
1004
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-xs text-muted-foreground flex items-center gap-2", children: [
|
|
1005
|
+
ext && /* @__PURE__ */ jsxRuntime.jsx("span", { children: ext }),
|
|
1006
|
+
sizeLabel && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1007
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\xB7" }),
|
|
1008
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: sizeLabel })
|
|
1009
|
+
] })
|
|
1010
|
+
] }),
|
|
1011
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1012
|
+
"a",
|
|
1013
|
+
{
|
|
1014
|
+
href: doc.fileUrl,
|
|
1015
|
+
download: doc.fileName ?? void 0,
|
|
1016
|
+
onClick: (e) => void downloadDocument(e, doc),
|
|
1017
|
+
className: "inline-flex items-center gap-1.5 rounded-md border border-border bg-background px-3 py-1.5 text-sm font-medium text-foreground hover:bg-muted transition-colors",
|
|
1018
|
+
children: [
|
|
1019
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Download, { size: 14 }),
|
|
1020
|
+
"Download"
|
|
1021
|
+
]
|
|
1022
|
+
}
|
|
1023
|
+
)
|
|
1024
|
+
] })
|
|
1025
|
+
] });
|
|
1026
|
+
}
|
|
1027
|
+
function PartnerDocumentsSection({
|
|
1028
|
+
title,
|
|
1029
|
+
subtitle,
|
|
1030
|
+
docs
|
|
1031
|
+
}) {
|
|
1032
|
+
return /* @__PURE__ */ jsxRuntime.jsx("section", { className: "py-12 md:py-16 bg-muted/20", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "container mx-auto px-4 max-w-5xl", children: [
|
|
1033
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "mb-8 md:mb-10 text-center", children: [
|
|
1034
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-2xl md:text-3xl font-bold text-foreground mb-2", children: title }),
|
|
1035
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground max-w-2xl mx-auto", children: subtitle })
|
|
1036
|
+
] }),
|
|
1037
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4", children: docs.map((doc) => /* @__PURE__ */ jsxRuntime.jsx(PartnerDocumentCard, { doc }, doc.id)) })
|
|
1038
|
+
] }) });
|
|
1039
|
+
}
|
|
1040
|
+
var DEFAULT_PARTNER_CATEGORY = {
|
|
1041
|
+
value: "partnership",
|
|
1042
|
+
label: "Partner program"
|
|
1043
|
+
};
|
|
1044
|
+
function PartnersPage(props) {
|
|
1045
|
+
const {
|
|
1046
|
+
productName: productNameProp,
|
|
1047
|
+
heroTitle = "Partner with us",
|
|
1048
|
+
heroSubtitle,
|
|
1049
|
+
contentTag = "partner",
|
|
1050
|
+
contentSlug,
|
|
1051
|
+
documentsTag = "partner",
|
|
1052
|
+
documentsTitle = "Partner Documents",
|
|
1053
|
+
documentsSubtitle,
|
|
1054
|
+
showContactForm = true,
|
|
1055
|
+
contactCategory,
|
|
1056
|
+
formTitle = "Become a partner",
|
|
1057
|
+
formSubtitle,
|
|
1058
|
+
contactEmail,
|
|
1059
|
+
contactPhone,
|
|
1060
|
+
officeAddress,
|
|
1061
|
+
responseTime,
|
|
1062
|
+
recaptchaSiteKey,
|
|
1063
|
+
additionalOptions,
|
|
1064
|
+
seoTitle,
|
|
1065
|
+
seoDescription,
|
|
1066
|
+
seoKeywords,
|
|
1067
|
+
className
|
|
1068
|
+
} = props;
|
|
1069
|
+
const client = useWebSDK();
|
|
1070
|
+
const config = useWebSDKConfig();
|
|
1071
|
+
const { product } = useProduct();
|
|
1072
|
+
const resolvedProductId = product?.id ?? config?.productId ?? productNameProp ?? "";
|
|
1073
|
+
const resolvedProductName = productNameProp ?? product?.name ?? config?.productId ?? "our team";
|
|
1074
|
+
const [contentPage, setContentPage] = React.useState(null);
|
|
1075
|
+
const [docs, setDocs] = React.useState([]);
|
|
1076
|
+
const [loading, setLoading] = React.useState(true);
|
|
1077
|
+
React.useEffect(() => {
|
|
1078
|
+
if (!client || !resolvedProductId) {
|
|
1079
|
+
setContentPage(null);
|
|
1080
|
+
setDocs([]);
|
|
1081
|
+
setLoading(false);
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
let cancelled = false;
|
|
1085
|
+
setLoading(true);
|
|
1086
|
+
void Promise.allSettled([
|
|
1087
|
+
client.query(PARTNER_CONTENT_QUERY, { productId: resolvedProductId, limit: 50 }),
|
|
1088
|
+
client.query(
|
|
1089
|
+
PARTNER_DOCUMENTS_QUERY,
|
|
1090
|
+
{ productId: resolvedProductId, limit: 50 }
|
|
1091
|
+
)
|
|
1092
|
+
]).then(([contentResult, docsResult]) => {
|
|
1093
|
+
if (cancelled) return;
|
|
1094
|
+
if (contentResult.status === "rejected") {
|
|
1095
|
+
setContentPage(null);
|
|
1096
|
+
} else if (contentResult.status === "fulfilled") {
|
|
1097
|
+
const items = contentResult.value.data?.publicContentPages?.items ?? [];
|
|
1098
|
+
const match = contentSlug ? items.find((p) => p.slug === contentSlug) : items.find((p) => p.tags?.includes(contentTag));
|
|
1099
|
+
setContentPage(match ?? null);
|
|
1100
|
+
}
|
|
1101
|
+
if (docsResult.status === "rejected") {
|
|
1102
|
+
setDocs([]);
|
|
1103
|
+
} else if (docsResult.status === "fulfilled") {
|
|
1104
|
+
const items = docsResult.value.data?.publicPressKitAssets?.items ?? [];
|
|
1105
|
+
const filtered = items.filter(
|
|
1106
|
+
(d) => d.category === "DOCUMENT" && d.tags?.includes(documentsTag) && !!d.fileUrl
|
|
1107
|
+
).sort(
|
|
1108
|
+
(a, b) => a.sortOrder - b.sortOrder
|
|
1109
|
+
);
|
|
1110
|
+
setDocs(filtered);
|
|
1111
|
+
}
|
|
1112
|
+
setLoading(false);
|
|
1113
|
+
});
|
|
1114
|
+
return () => {
|
|
1115
|
+
cancelled = true;
|
|
1116
|
+
};
|
|
1117
|
+
}, [client, resolvedProductId, contentSlug, contentTag, documentsTag]);
|
|
1118
|
+
let partnerCategories;
|
|
1119
|
+
if (contactCategory === false) {
|
|
1120
|
+
partnerCategories = [];
|
|
1121
|
+
} else if (Array.isArray(contactCategory)) {
|
|
1122
|
+
partnerCategories = contactCategory.length > 0 ? contactCategory : [DEFAULT_PARTNER_CATEGORY];
|
|
1123
|
+
} else {
|
|
1124
|
+
partnerCategories = [contactCategory ?? DEFAULT_PARTNER_CATEGORY];
|
|
1125
|
+
}
|
|
1126
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, children: [
|
|
1127
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1128
|
+
PageHead,
|
|
1129
|
+
{
|
|
1130
|
+
title: seoTitle ?? `${heroTitle} \u2014 ${resolvedProductName}`,
|
|
1131
|
+
description: seoDescription ?? heroSubtitle ?? `Join the ${resolvedProductName} partner programme.`,
|
|
1132
|
+
keywords: seoKeywords
|
|
1133
|
+
}
|
|
1134
|
+
),
|
|
1135
|
+
/* @__PURE__ */ jsxRuntime.jsx(PartnerHero, { title: heroTitle, subtitle: heroSubtitle }),
|
|
1136
|
+
!loading && contentPage && /* @__PURE__ */ jsxRuntime.jsx(PartnerContentSection, { page: contentPage }),
|
|
1137
|
+
!loading && docs.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1138
|
+
PartnerDocumentsSection,
|
|
1139
|
+
{
|
|
1140
|
+
title: documentsTitle,
|
|
1141
|
+
subtitle: documentsSubtitle,
|
|
1142
|
+
docs
|
|
1143
|
+
}
|
|
1144
|
+
),
|
|
1145
|
+
showContactForm && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1146
|
+
ContactPage,
|
|
1147
|
+
{
|
|
1148
|
+
productName: resolvedProductName,
|
|
1149
|
+
heroTitle: formTitle,
|
|
1150
|
+
headingLevel: 2,
|
|
1151
|
+
heroDescription: formSubtitle ?? `Tell us about your organisation and a partner manager from ${resolvedProductName} will be in touch.`,
|
|
1152
|
+
contactEmail,
|
|
1153
|
+
contactPhone,
|
|
1154
|
+
officeAddress,
|
|
1155
|
+
responseTime,
|
|
1156
|
+
recaptchaSiteKey,
|
|
1157
|
+
additionalOptions,
|
|
1158
|
+
categories: partnerCategories,
|
|
1159
|
+
categoryLabel: "Partnership type",
|
|
1160
|
+
categoryRequired: partnerCategories.length > 0
|
|
1161
|
+
}
|
|
1162
|
+
)
|
|
1163
|
+
] });
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
exports.PartnersPage = PartnersPage;
|
|
1167
|
+
exports.stripLeadingHeading = stripLeadingHeading;
|
|
1168
|
+
//# sourceMappingURL=partners.js.map
|
|
1169
|
+
//# sourceMappingURL=partners.js.map
|