@burdenoff/website-sdk 2026.817.1 → 2026.824.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/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import { createContext, useMemo, useContext, useState, useCallback, useLayoutEffect, useRef, useEffect } from 'react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import { Instagram, Youtube, Facebook, Github, Linkedin, Twitter, Mail, Phone, MapPin, Clock, Send, CheckCircle, Upload, Globe, ChevronDown, Search, Rocket, ArrowRight, Download, History, ChevronLeft, ChevronRight, FileText } from 'lucide-react';
5
- import ReCAPTCHA3 from 'react-google-recaptcha';
5
+ import ReCAPTCHA4 from 'react-google-recaptcha';
6
6
  import { toast } from 'sonner';
7
7
  import { Helmet } from 'react-helmet-async';
8
8
  import { Slot } from '@radix-ui/react-slot';
@@ -981,7 +981,7 @@ function ContactPage({
981
981
  ] }),
982
982
  /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
983
983
  effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx("div", { className: "flex justify-center sm:justify-start", children: /* @__PURE__ */ jsx(
984
- ReCAPTCHA3,
984
+ ReCAPTCHA4,
985
985
  {
986
986
  ref: recaptchaRef,
987
987
  sitekey: effectiveRecaptchaSiteKey
@@ -1155,16 +1155,38 @@ var PUBLIC_CONTENT_PAGES_QUERY = `
1155
1155
  }
1156
1156
  }
1157
1157
  `;
1158
+ function resolveContentPageGate(resolvedProductId, hasProvider, productLoading) {
1159
+ if (resolvedProductId) return "fetch";
1160
+ return hasProvider && productLoading ? "wait" : "unavailable";
1161
+ }
1158
1162
  function useContentPage(slug, options) {
1159
1163
  const client = useWebSDK();
1160
1164
  const config = useWebSDKConfig();
1161
- const { product } = useProduct();
1165
+ const {
1166
+ product,
1167
+ loading: productLoading,
1168
+ error: productError,
1169
+ hasProvider
1170
+ } = useProduct();
1162
1171
  const resolvedProductId = product?.id || config.productId;
1172
+ const gate = resolveContentPageGate(
1173
+ resolvedProductId,
1174
+ hasProvider,
1175
+ productLoading
1176
+ );
1163
1177
  const [data, setData] = useState(null);
1164
1178
  const [loading, setLoading] = useState(true);
1165
1179
  const [error, setError] = useState(null);
1166
1180
  const fetchPage = useCallback(async () => {
1167
- if (!resolvedProductId) return;
1181
+ if (gate === "wait") return;
1182
+ if (gate === "unavailable") {
1183
+ setData(null);
1184
+ setError(
1185
+ productError ?? "Product unavailable \u2014 cannot load content page"
1186
+ );
1187
+ setLoading(false);
1188
+ return;
1189
+ }
1168
1190
  setLoading(true);
1169
1191
  setError(null);
1170
1192
  try {
@@ -1189,7 +1211,7 @@ function useContentPage(slug, options) {
1189
1211
  } finally {
1190
1212
  setLoading(false);
1191
1213
  }
1192
- }, [client, resolvedProductId, slug, options?.resolve]);
1214
+ }, [client, gate, productError, resolvedProductId, slug, options?.resolve]);
1193
1215
  useEffect(() => {
1194
1216
  fetchPage();
1195
1217
  }, [fetchPage]);
@@ -1947,7 +1969,7 @@ function CareersApplyForm({
1947
1969
  )
1948
1970
  ] }),
1949
1971
  effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx(
1950
- ReCAPTCHA3,
1972
+ ReCAPTCHA4,
1951
1973
  {
1952
1974
  ref: recaptchaRef,
1953
1975
  sitekey: effectiveRecaptchaSiteKey
@@ -1972,6 +1994,313 @@ function CareersApplyForm({
1972
1994
  )
1973
1995
  ] });
1974
1996
  }
1997
+ var SUBMIT_ASSIGNMENT_RESPONSE_MUTATION = (
1998
+ /* GraphQL */
1999
+ `
2000
+ mutation SubmitAssignmentResponse($input: SubmitAssignmentResponseInput!) {
2001
+ submitAssignmentResponse(input: $input) {
2002
+ success
2003
+ message
2004
+ applicationId
2005
+ roundId
2006
+ }
2007
+ }
2008
+ `
2009
+ );
2010
+ function isValidUrl(value) {
2011
+ try {
2012
+ const url = new URL(value);
2013
+ return url.protocol === "http:" || url.protocol === "https:";
2014
+ } catch {
2015
+ return false;
2016
+ }
2017
+ }
2018
+ async function submitAssignmentResponse(client, data) {
2019
+ try {
2020
+ const result = await client.mutate(SUBMIT_ASSIGNMENT_RESPONSE_MUTATION, {
2021
+ input: {
2022
+ email: data.email.trim().toLowerCase(),
2023
+ repoUrl: data.repoUrl.trim(),
2024
+ videoUrl: data.videoUrl.trim(),
2025
+ recaptchaToken: data.recaptchaToken ?? "",
2026
+ ...data.name ? { name: data.name } : {},
2027
+ ...data.position ? { position: data.position } : {},
2028
+ ...data.jobPostingId ? { jobPostingId: data.jobPostingId } : {},
2029
+ ...data.notes ? { notes: data.notes } : {}
2030
+ }
2031
+ });
2032
+ if (result.errors?.length) {
2033
+ return {
2034
+ success: false,
2035
+ message: result.errors[0]?.message ?? "Failed to submit assignment"
2036
+ };
2037
+ }
2038
+ const response = result.data?.submitAssignmentResponse;
2039
+ return response?.success ? { success: true, message: response.message || "Assignment submitted!" } : {
2040
+ success: false,
2041
+ message: response?.message || "Failed to submit assignment"
2042
+ };
2043
+ } catch (error) {
2044
+ console.error("Assignment submission error:", error);
2045
+ return { success: false, message: "Network error. Please try again." };
2046
+ }
2047
+ }
2048
+ var NO_APPLICATION_HINT = "Please use the same email address you applied with \u2014 or submit an application first.";
2049
+ function isNoApplicationError(message) {
2050
+ return /no application|not found/i.test(message);
2051
+ }
2052
+ var OTHER_POSITION = "__other__";
2053
+ function CareersSubmissionForm({
2054
+ productName,
2055
+ recaptchaSiteKey,
2056
+ postings = [],
2057
+ heroTitle = "Submit your assignment",
2058
+ heroDescription = "Share your GitHub repo and a short video walkthrough \u2014 make sure to use the same email you applied with.",
2059
+ headingLevel = 1,
2060
+ className,
2061
+ seo
2062
+ }) {
2063
+ const client = useWebSDK();
2064
+ const config = useWebSDKConfig();
2065
+ const { product } = useProduct();
2066
+ const displayName = productName ?? product?.name ?? config.productId;
2067
+ const effectiveRecaptchaSiteKey = recaptchaSiteKey ?? product?.recaptchaSiteKey ?? config.recaptchaSiteKey ?? "";
2068
+ const recaptchaRef = useRef(null);
2069
+ const [isSubmitting, setIsSubmitting] = useState(false);
2070
+ const [submittedMessage, setSubmittedMessage] = useState(null);
2071
+ const [formError, setFormError] = useState(null);
2072
+ const [useFreeTextPosition, setUseFreeTextPosition] = useState(
2073
+ postings.length === 0
2074
+ );
2075
+ const handleSubmit = async (e) => {
2076
+ e.preventDefault();
2077
+ setFormError(null);
2078
+ const recaptchaToken = recaptchaRef.current?.getValue() ?? "";
2079
+ if (effectiveRecaptchaSiteKey && !recaptchaToken) {
2080
+ toast.error("Please complete the reCAPTCHA verification");
2081
+ return;
2082
+ }
2083
+ const form = e.currentTarget;
2084
+ const formData = new FormData(form);
2085
+ const name = (formData.get("name") ?? "").trim();
2086
+ const email = (formData.get("email") ?? "").trim();
2087
+ const positionValue = (formData.get("position") ?? "").trim();
2088
+ const repoUrl = (formData.get("repoUrl") ?? "").trim();
2089
+ const videoUrl = (formData.get("videoUrl") ?? "").trim();
2090
+ const notes = (formData.get("notes") ?? "").trim();
2091
+ const selectedPosting = postings.length > 0 && !useFreeTextPosition ? postings.find((p) => p.id === positionValue) : void 0;
2092
+ const position = selectedPosting ? selectedPosting.title : positionValue;
2093
+ if (!email) {
2094
+ setFormError("Please enter the email address you applied with.");
2095
+ return;
2096
+ }
2097
+ if (!position) {
2098
+ setFormError("Please select or enter the position you applied for.");
2099
+ return;
2100
+ }
2101
+ if (!repoUrl || !isValidUrl(repoUrl)) {
2102
+ setFormError(
2103
+ "Please enter a valid GitHub repository URL (e.g. https://github.com/you/project)."
2104
+ );
2105
+ return;
2106
+ }
2107
+ if (!videoUrl || !isValidUrl(videoUrl)) {
2108
+ setFormError(
2109
+ "Please enter a valid video URL (e.g. a Jam or Loom link starting with https://)."
2110
+ );
2111
+ return;
2112
+ }
2113
+ setIsSubmitting(true);
2114
+ try {
2115
+ const result = await submitAssignmentResponse(client, {
2116
+ name: name || void 0,
2117
+ email,
2118
+ position,
2119
+ jobPostingId: selectedPosting?.id,
2120
+ repoUrl,
2121
+ videoUrl,
2122
+ notes: notes || void 0,
2123
+ recaptchaToken
2124
+ });
2125
+ if (result.success) {
2126
+ setSubmittedMessage(result.message ?? "Assignment submitted!");
2127
+ toast.success(result.message ?? "Assignment submitted!");
2128
+ } else {
2129
+ const message = result.message ?? "Failed to submit assignment";
2130
+ setFormError(
2131
+ isNoApplicationError(message) ? `${message} ${NO_APPLICATION_HINT}` : message
2132
+ );
2133
+ toast.error(message);
2134
+ recaptchaRef.current?.reset();
2135
+ }
2136
+ } catch (err) {
2137
+ console.error("Careers submission form error:", err);
2138
+ setFormError("Something went wrong. Please try again.");
2139
+ toast.error("Something went wrong. Please try again.");
2140
+ recaptchaRef.current?.reset();
2141
+ } finally {
2142
+ setIsSubmitting(false);
2143
+ }
2144
+ };
2145
+ const Heading = headingLevel === 2 ? "h2" : "h1";
2146
+ const headingClass = headingLevel === 2 ? "text-2xl md:text-3xl font-bold mb-3" : "text-3xl sm:text-4xl md:text-5xl font-bold mb-4 sm:mb-6";
2147
+ return /* @__PURE__ */ jsxs("div", { className, children: [
2148
+ seo && /* @__PURE__ */ jsx(
2149
+ PageHead,
2150
+ {
2151
+ title: seo.title ?? `Submit your assignment \u2014 ${displayName}`,
2152
+ description: seo.description ?? heroDescription,
2153
+ keywords: seo.keywords
2154
+ }
2155
+ ),
2156
+ /* @__PURE__ */ jsx(
2157
+ "section",
2158
+ {
2159
+ 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",
2160
+ children: /* @__PURE__ */ jsxs("div", { className: "max-w-3xl mx-auto px-4 sm:px-6 lg:px-8", children: [
2161
+ /* @__PURE__ */ jsxs("div", { className: "text-center mb-8 sm:mb-10", children: [
2162
+ /* @__PURE__ */ jsx(Heading, { className: headingClass, children: heroTitle }),
2163
+ /* @__PURE__ */ jsx("p", { className: "text-lg text-muted-foreground leading-relaxed", children: heroDescription })
2164
+ ] }),
2165
+ submittedMessage ? /* @__PURE__ */ jsxs("div", { className: "text-center rounded-xl border border-border bg-card p-10", children: [
2166
+ /* @__PURE__ */ jsx(CheckCircle, { className: "mx-auto mb-4 h-12 w-12 text-accent" }),
2167
+ /* @__PURE__ */ jsx("h3", { className: "text-xl font-semibold text-foreground mb-2", children: "Assignment received" }),
2168
+ /* @__PURE__ */ jsx("p", { className: "text-muted-foreground", children: submittedMessage })
2169
+ ] }) : /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className: "space-y-5", children: [
2170
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 sm:grid-cols-2 gap-5", children: [
2171
+ /* @__PURE__ */ jsxs("div", { children: [
2172
+ /* @__PURE__ */ jsx(Label, { htmlFor: "name", children: "Name" }),
2173
+ /* @__PURE__ */ jsx(Input, { id: "name", name: "name", placeholder: "Ada Lovelace" })
2174
+ ] }),
2175
+ /* @__PURE__ */ jsxs("div", { children: [
2176
+ /* @__PURE__ */ jsx(Label, { htmlFor: "email", children: "Email *" }),
2177
+ /* @__PURE__ */ jsx(
2178
+ Input,
2179
+ {
2180
+ id: "email",
2181
+ name: "email",
2182
+ type: "email",
2183
+ required: true,
2184
+ placeholder: "ada@example.com"
2185
+ }
2186
+ )
2187
+ ] })
2188
+ ] }),
2189
+ /* @__PURE__ */ jsxs("div", { children: [
2190
+ /* @__PURE__ */ jsx(Label, { htmlFor: "position", children: "Position *" }),
2191
+ postings.length > 0 && !useFreeTextPosition ? /* @__PURE__ */ jsxs(Fragment, { children: [
2192
+ /* @__PURE__ */ jsxs(
2193
+ "select",
2194
+ {
2195
+ id: "position",
2196
+ name: "position",
2197
+ required: true,
2198
+ defaultValue: "",
2199
+ onChange: (e) => {
2200
+ if (e.target.value === OTHER_POSITION) {
2201
+ setUseFreeTextPosition(true);
2202
+ }
2203
+ },
2204
+ className: "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-ring",
2205
+ children: [
2206
+ /* @__PURE__ */ jsx("option", { value: "", disabled: true, children: "Select a role" }),
2207
+ postings.map((p) => /* @__PURE__ */ jsx("option", { value: p.id, children: p.title }, p.id)),
2208
+ /* @__PURE__ */ jsx("option", { value: OTHER_POSITION, children: "My role isn't listed" })
2209
+ ]
2210
+ }
2211
+ ),
2212
+ /* @__PURE__ */ jsxs("p", { className: "mt-1 text-xs text-muted-foreground", children: [
2213
+ "Applied to a role that's since closed? Choose",
2214
+ " ",
2215
+ /* @__PURE__ */ jsx("em", { children: "My role isn't listed" }),
2216
+ " and type it in \u2014 you can still submit."
2217
+ ] })
2218
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2219
+ /* @__PURE__ */ jsx(
2220
+ Input,
2221
+ {
2222
+ id: "position",
2223
+ name: "position",
2224
+ required: true,
2225
+ placeholder: "Role you applied for"
2226
+ }
2227
+ ),
2228
+ postings.length > 0 && /* @__PURE__ */ jsx(
2229
+ "button",
2230
+ {
2231
+ type: "button",
2232
+ onClick: () => setUseFreeTextPosition(false),
2233
+ className: "mt-1 text-xs text-accent hover:underline",
2234
+ children: "Choose from open roles instead"
2235
+ }
2236
+ )
2237
+ ] })
2238
+ ] }),
2239
+ /* @__PURE__ */ jsxs("div", { children: [
2240
+ /* @__PURE__ */ jsx(Label, { htmlFor: "repoUrl", children: "GitHub repository URL *" }),
2241
+ /* @__PURE__ */ jsx(
2242
+ Input,
2243
+ {
2244
+ id: "repoUrl",
2245
+ name: "repoUrl",
2246
+ type: "url",
2247
+ required: true,
2248
+ placeholder: "https://github.com/you/assignment"
2249
+ }
2250
+ )
2251
+ ] }),
2252
+ /* @__PURE__ */ jsxs("div", { children: [
2253
+ /* @__PURE__ */ jsx(Label, { htmlFor: "videoUrl", children: "Video walkthrough URL (Jam, Loom, \u2026) *" }),
2254
+ /* @__PURE__ */ jsx(
2255
+ Input,
2256
+ {
2257
+ id: "videoUrl",
2258
+ name: "videoUrl",
2259
+ type: "url",
2260
+ required: true,
2261
+ placeholder: "https://jam.dev/c/\u2026"
2262
+ }
2263
+ )
2264
+ ] }),
2265
+ /* @__PURE__ */ jsxs("div", { children: [
2266
+ /* @__PURE__ */ jsx(Label, { htmlFor: "notes", children: "Notes" }),
2267
+ /* @__PURE__ */ jsx(
2268
+ Textarea,
2269
+ {
2270
+ id: "notes",
2271
+ name: "notes",
2272
+ rows: 4,
2273
+ placeholder: "Anything we should know before reviewing\u2026"
2274
+ }
2275
+ )
2276
+ ] }),
2277
+ formError && /* @__PURE__ */ jsx("p", { role: "alert", className: "text-sm text-destructive", children: formError }),
2278
+ effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx(
2279
+ ReCAPTCHA4,
2280
+ {
2281
+ ref: recaptchaRef,
2282
+ sitekey: effectiveRecaptchaSiteKey
2283
+ }
2284
+ ),
2285
+ /* @__PURE__ */ jsx(
2286
+ Button,
2287
+ {
2288
+ type: "submit",
2289
+ size: "lg",
2290
+ disabled: isSubmitting,
2291
+ className: "w-full sm:w-auto",
2292
+ children: isSubmitting ? "Submitting\u2026" : /* @__PURE__ */ jsxs(Fragment, { children: [
2293
+ /* @__PURE__ */ jsx(Send, { className: "mr-2 h-4 w-4" }),
2294
+ " Submit assignment"
2295
+ ] })
2296
+ }
2297
+ )
2298
+ ] })
2299
+ ] })
2300
+ }
2301
+ )
2302
+ ] });
2303
+ }
1975
2304
  var newsletterSchema = z.object({
1976
2305
  email: z.string().email("Please enter a valid email address")
1977
2306
  });
@@ -2261,7 +2590,7 @@ function NewsletterPage({
2261
2590
  errors.email && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: errors.email.message })
2262
2591
  ] }),
2263
2592
  effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx("div", { className: "flex justify-center", children: /* @__PURE__ */ jsx(
2264
- ReCAPTCHA3,
2593
+ ReCAPTCHA4,
2265
2594
  {
2266
2595
  ref: recaptchaRef,
2267
2596
  sitekey: effectiveRecaptchaSiteKey
@@ -2313,7 +2642,7 @@ function NewsletterPage({
2313
2642
  errors.email && /* @__PURE__ */ jsx("p", { className: "text-sm text-destructive", children: errors.email.message })
2314
2643
  ] }),
2315
2644
  effectiveRecaptchaSiteKey && /* @__PURE__ */ jsx("div", { className: "flex justify-center sm:justify-start", children: /* @__PURE__ */ jsx(
2316
- ReCAPTCHA3,
2645
+ ReCAPTCHA4,
2317
2646
  {
2318
2647
  ref: recaptchaRef,
2319
2648
  sitekey: effectiveRecaptchaSiteKey
@@ -2491,7 +2820,7 @@ function NewsletterForm({
2491
2820
  justifyContent: "flex-start"
2492
2821
  },
2493
2822
  children: /* @__PURE__ */ jsx(
2494
- ReCAPTCHA3,
2823
+ ReCAPTCHA4,
2495
2824
  {
2496
2825
  ref: recaptchaRef,
2497
2826
  sitekey: effectiveRecaptchaSiteKey,
@@ -9233,6 +9562,6 @@ var ECOSYSTEM_PRODUCTS = [
9233
9562
  }
9234
9563
  ];
9235
9564
 
9236
- export { BlogListPage, BlogPostPage, Button, CareersApplyForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, ECOSYSTEM_PRODUCTS, ElectronDownloadLink, Input, Label, LaunchCountdown, Markdown, NewsletterForm, NewsletterPage, PageHead, PartnersPage, PressKitPage, PricingPage, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, buttonVariants, cn, detectElectronPlatform, fetchPublicJobPosting, fetchPublicJobPostings, formatDownloads, formatPrice2 as formatPrice, useContentPage, useContentPages, useProduct, useProductConfig, usePublicJobPosting, usePublicJobPostings, useWebSDK, useWebSDKConfig };
9565
+ export { BlogListPage, BlogPostPage, Button, CareersApplyForm, CareersSubmissionForm, CaseStudiesListPage, CaseStudyPage, ChangelogPage, ContactPage, ContentRenderer, ContractsPage, DEFAULT_CONTACT_CATEGORIES, ECOSYSTEM_PRODUCTS, ElectronDownloadLink, Input, Label, LaunchCountdown, Markdown, NewsletterForm, NewsletterPage, PageHead, PartnersPage, PressKitPage, PricingPage, PricingSection, ProblemsSolvedSection, ProductCard, ProductProvider, ResourceLinks, RybbitAnalytics, Select, SocialLinks, StarRating, StoreBrowsePage, StoreHomePage, StoreProductDetailPage, Textarea, TypeBadge, UnsubscribePage, WaitlistForm, WaitlistPage, WebSDKClient, WebSDKProvider, WebsiteSwitcher, buttonVariants, cn, detectElectronPlatform, fetchPublicJobPosting, fetchPublicJobPostings, formatDownloads, formatPrice2 as formatPrice, isValidUrl, useContentPage, useContentPages, useProduct, useProductConfig, usePublicJobPosting, usePublicJobPostings, useWebSDK, useWebSDKConfig };
9237
9566
  //# sourceMappingURL=index.mjs.map
9238
9567
  //# sourceMappingURL=index.mjs.map