1// GENERATED FILE -- DO NOT EDIT. 2// Source: components/Registration.jsx. Rebuild with: npm run build:jsx 3const SIG_LIB_URL = "https://cdn.jsdelivr.net/npm/signature_pad@4/dist/signature_pad.umd.min.js"; 4function loadSigPad() { 5 if (window.SignaturePad) return Promise.resolve(window.SignaturePad); 6 return new Promise((resolve, reject) => { 7 const s = document.createElement("script"); 8 s.src = SIG_LIB_URL; 9 s.async = true; 10 s.onload = () => resolve(window.SignaturePad); 11 s.onerror = () => reject(new Error("signature_pad_failed_to_load")); 12 document.head.appendChild(s); 13 }); 14} 15const FACILITIES = [ 16 "", 17 "Athletic Recreation Center", 18 "Hawthorne Cultural Center", 19 "Holmesburg Recreation Center", 20 "Kingsessing Recreation Center", 21 "Kendrick Recreation Center", 22 "Venice Island Performing Arts Center", 23 "Other" 24]; 25const PROGRAMS = ["", "Dance@Athletic", "Other"]; 26const PROGRAM_LINKS = { "dance-athletic": "Dance@Athletic" }; 27const GRADES = ["", "K", "1st", "2nd", "3rd", "4th", "5th", "6th", "7th", "8th", "9th", "10th", "11th", "12th"]; 28const SHIRT_OPTS = [ 29 ["", "\u2014"], 30 ["cs", "Child's small"], 31 ["cm", "Child's medium"], 32 ["cl", "Child's large"], 33 ["as", "Adult small"], 34 ["am", "Adult medium"], 35 ["al", "Adult large"], 36 ["axl", "Adult XL"], 37 ["other", "Other (specify)"] 38]; 39const RACES = [ 40 ["ai_an", "American Indian or Alaska Native"], 41 ["asian", "Asian"], 42 ["black", "Black or African American"], 43 ["hispanic", "Hispanic or Latino"], 44 ["mena", "Middle Eastern or North African"], 45 ["nh_pi", "Native Hawaiian or Pacific Islander"], 46 ["white", "White"] 47]; 48const WAIVERS = [ 49 { key: "dismissal", title: "Dismissal", required: true, body: "By signing below, I acknowledge that it is my and my child's responsibility to arrange transport home." }, 50 { key: "release", title: "Release & Assumption of Risk", required: true, body: "I grant permission for my child/ward to attend the program and participate in any and all of its activities, including fieldtrips. I release the City of Philadelphia from all liabilities in case of an injury or illness suffered by the above child resulting from participating in the Program. I voluntarily assume all risks of loss, damage and all injuries that may be sustained by myself and/or my minor child/ward." }, 51 { key: "emergency", title: "Emergency Clause", required: false, body: "In the event that my minor child suffers an injury or illness that requires immediate medical attention, I/my minor child will be taken to the nearest hospital. No employee, official, agent or representative of the City will be held responsible for injuries or damages arising from such emergency medical treatment." }, 52 { key: "media", title: "Media Release", required: false, body: "I authorize, without compensation, the use by the City of my or my minor child/ward's image and/or voice recordings during the Program. This includes permission to reproduce, publicize, broadcast or display visual images or voice recordings, with or without my name, throughout the world, in perpetuity." } 53]; 54function linkedProgram() { 55 const q = (window.location.hash || "").split("?")[1] || ""; 56 return PROGRAM_LINKS[new URLSearchParams(q).get("program")] || ""; 57} 58function linkedCamp() { 59 const q = (window.location.hash || "").split("?")[1] || ""; 60 return new URLSearchParams(q).get("camp") || ""; 61} 62const CAMP_ERRORS = { 63 registration_not_open: "Camp registration isn't open right now.", 64 registration_closed: "That site is full. Pick another site.", 65 site_required: "Please choose a camp site.", 66 unavailable: "We couldn't reach the registration system. Try again in a minute." 67}; 68function cmsGet(key, fallback) { 69 return (window.CMS || { get: (_k, fb) => fb }).get(key, fallback); 70} 71function ParticipantRegistrationPage() { 72 const [query, setQuery] = React.useState(() => (window.location.hash || "").split("?")[1] || ""); 73 React.useEffect(() => { 74 const on = () => setQuery((window.location.hash || "").split("?")[1] || ""); 75 window.addEventListener("hashchange", on); 76 return () => window.removeEventListener("hashchange", on); 77 }, []); 78 return /* @__PURE__ */ React.createElement(ParticipantRegistrationForm, { key: query }); 79} 80function ParticipantRegistrationForm() { 81 const campSlug = linkedCamp(); 82 const campMode = !!campSlug; 83 const linked = campMode ? "" : linkedProgram(); 84 const blank = { 85 facility: linked === "Dance@Athletic" ? "Athletic Recreation Center" : "", 86 facility_other: "", 87 program_choice: linked, 88 program: "", 89 season_year: "Fall 2026", 90 participant_name: "", 91 date_of_birth: "", 92 age: "", 93 address: "", 94 city: "Philadelphia", 95 state: "PA", 96 zip: "", 97 primary_language: "English", 98 gender: "", 99 race: {}, 100 home_phone: "", 101 cell_phone: "", 102 email: "", 103 school: "", 104 grade: "", 105 shirt_size: "", 106 shirt_size_other: "", 107 contacts: [{ name: "", relationship: "", email: "", phone: "", caregiver: true, emergency_contact: false, authorized_pickup: false }], 108 staff_alerts: "", 109 site_id: campSlug, 110 returning: false 111 }; 112 const [data, setData] = React.useState(blank); 113 const [, bumpCms] = React.useState(0); 114 React.useEffect(() => { 115 if (!campMode || window.CMS && window.CMS._ready) return; 116 const on = () => bumpCms((n) => n + 1); 117 window.addEventListener("cms:ready", on); 118 return () => window.removeEventListener("cms:ready", on); 119 }, [campMode]); 120 const [campSites, setCampSites] = React.useState(() => window.CAMP_SITES || []); 121 React.useEffect(() => { 122 if (!campMode) return;
123 let cancelled = false; 124 fetch("/api/camps").then((r) => r.ok ? r.json() : null).then((j) => { 125 if (cancelled || !j || !j.ok || !Array.isArray(j.rows) || !j.rows.length) return; 126 setCampSites(j.rows.map((r) => ({ 127 id: r.slug, 128 name: r.name, 129 type: r.type, 130 ageRange: r.age_range, 131 registrationClosed: !!r.registration_closed 132 }))); 133 }).catch(() => { 134 }); 135 return () => { 136 cancelled = true; 137 }; 138 }, [campMode]); 139 const campOpenRaw = cmsGet("camps.registration_open", false); 140 const campOpen = campOpenRaw === true || campOpenRaw === "true"; 141 const campYear = String(cmsGet("camps.season_year", "2027")); 142 const feeRaw = String(cmsGet("camps.registration_fee_dollars", "")).trim(); 143 const campFee = /^\d+(\.\d{1,2})?$/.test(feeRaw) && Number(feeRaw) > 0 ? `$${feeRaw}` : ""; 144 const [submitted, setSubmitted] = React.useState(null); 145 const [submitting, setSubmitting] = React.useState(false); 146 const [error, setError] = React.useState(""); 147 const canvasRefs = React.useRef({}); 148 const padsRef = React.useRef({}); 149 const [sigMeta, setSigMeta] = React.useState( 150 () => Object.fromEntries(WAIVERS.map((w) => [w.key, { relationship: "", date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10) }])) 151 ); 152 React.useEffect(() => {
153 let cancelled = false; 154 loadSigPad().then((SignaturePad) => { 155 if (cancelled) return; 156 WAIVERS.forEach((w) => { 157 const canvas = canvasRefs.current[w.key]; 158 if (!canvas || padsRef.current[w.key]) return; 159 const ratio = Math.max(window.devicePixelRatio || 1, 1); 160 canvas.width = canvas.offsetWidth * ratio; 161 canvas.height = canvas.offsetHeight * ratio; 162 canvas.getContext("2d").scale(ratio, ratio); 163 padsRef.current[w.key] = new SignaturePad(canvas, { 164 backgroundColor: "rgba(255,255,255,0)", 165 penColor: "#2A1820" 166 }); 167 }); 168 }).catch(() => setError("Couldn't load signature pad \u2014 please refresh and try again.")); 169 return () => { 170 cancelled = true; 171 }; 172 }, []); 173 const update = (k, v) => setData((d) => ({ ...d, [k]: v })); 174 const pickProgram = (v) => setData((d) => ({ 175 ...d, 176 program_choice: v, 177 facility: v === "Dance@Athletic" && !d.facility ? "Athletic Recreation Center" : d.facility 178 })); 179 const updateRace = (k, v) => setData((d) => ({ ...d, race: { ...d.race, [k]: v } })); 180 const updateContact = (i, k, v) => setData((d) => { 181 const next = d.contacts.slice(); 182 next[i] = { ...next[i], [k]: v }; 183 return { ...d, contacts: next }; 184 }); 185 const addContact = () => setData((d) => ({ 186 ...d, 187 contacts: d.contacts.length >= 4 ? d.contacts : [...d.contacts, { 188 name: "", 189 relationship: "", 190 email: "", 191 phone: "", 192 caregiver: false, 193 emergency_contact: false, 194 authorized_pickup: false 195 }] 196 })); 197 const clearSig = (key) => padsRef.current[key]?.clear(); 198 const onSubmit = async (e) => { 199 e.preventDefault(); 200 setError(""); 201 const nameTokens = String(data.participant_name || "").trim().split(/\s+/).filter(Boolean); 202 if (nameTokens.length < 2) { 203 setError("Please enter both a first and last name for the participant."); 204 return; 205 } 206 let age = data.age; 207 if (!age && data.date_of_birth) { 208 const dob = new Date(data.date_of_birth); 209 if (!isNaN(dob)) { 210 const today = /* @__PURE__ */ new Date(); 211 let a = today.getFullYear() - dob.getFullYear(); 212 if (today.getMonth() < dob.getMonth() || today.getMonth() === dob.getMonth() && today.getDate() < dob.getDate()) a -= 1; 213 if (a >= 0) age = a; 214 } 215 } 216 const signatures = {}; 217 for (const w of WAIVERS) { 218 const pad = padsRef.current[w.key]; 219 const empty = !pad || pad.isEmpty(); 220 if (empty && w.required) { 221 setError(`Please sign the ${w.title} waiver before submitting.`); 222 return; 223 } 224 signatures[w.key] = empty ? "" : pad.toDataURL("image/png"); 225 } 226 if (campMode && !data.site_id) { 227 setError("Please choose a camp site."); 228 return; 229 } 230 if (!campMode && !data.program_choice) { 231 setError("Please choose a program."); 232 return; 233 } 234 const program = data.program_choice === "Other" ? data.program : data.program_choice; 235 setSubmitting(true); 236 try { 237 const res = await fetch(campMode ? "/api/register-camp" : "/api/registration", { 238 method: "POST", 239 headers: { "Content-Type": "application/json" }, 240 body: JSON.stringify({ ...data, program, age, signatures, signature_meta: sigMeta }) 241 }); 242 const json = await res.json().catch(() => ({})); 243 if (!res.ok || !json.ok) { 244 const known = campMode && CAMP_ERRORS[json.error]; 245 const e2 = new Error(known || json.details && json.details.join(", ") || json.error || `error_${res.status}`); 246 e2.known = !!known; 247 throw e2; 248 } 249 setSubmitted({ ref: json.ref, emailStatus: json.email_status, pdfBase64: json.pdf_base64, pdfFilename: json.pdf_filename }); 250 } catch (err) { 251 setError(err.known ? err.message : `Couldn't submit: ${err.message}. Try again, or email [email protected].`); 252 } finally { 253 setSubmitting(false); 254 } 255 }; 256 if (submitted) { 257 const downloadPdf = () => { 258 if (!submitted.pdfBase64) return; 259 try { 260 const bytes = Uint8Array.from(atob(submitted.pdfBase64), (c) =>
260 c.charCodeAt(0)); 261 const blob = new Blob([bytes], { type: "application/pdf" }); 262 const url = URL.createObjectURL(blob); 263 const a = document.createElement("a"); 264 a.href = url; 265 a.download = submitted.pdfFilename || `participant-registration-${submitted.ref}.pdf`; 266 document.body.appendChild(a); 267 a.click(); 268 a.remove(); 269 setTimeout(() => URL.revokeObjectURL(url), 1e4); 270 } catch (_) { 271 } 272 }; 273 if (campMode) { 274 return /* @__PURE__ */ React.createElement( 275 ConfirmationView, 276 { 277 title: "Registration received.", 278 body: `Reference: ${submitted.ref}. Your registration is pending until we receive the ${campFee ? `${campFee} ` : ""}registration fee. The spot is not held until it is paid. We've emailed you a copy of the signed form and how to reach the office to pay.`, 279 ctaLabel: "Register another camper", 280 onCta: () => { 281 setSubmitted(null); 282 setData(blank); 283 padsRef.current = {}; 284 }, 285 secondary: submitted.pdfBase64 ? { label: "Download for your records", onClick: downloadPdf } : null 286 } 287 ); 288 } 289 return /* @__PURE__ */ React.createElement( 290 ConfirmationView, 291 { 292 title: "Registration submitted.", 293 body: `Reference: ${submitted.ref}. A signed copy of the form has been emailed to the program coordinator. Save this reference for your records.`, 294 ctaLabel: "Submit another registration", 295 onCta: () => { 296 setSubmitted(null); 297 setData(blank); 298 padsRef.current = {}; 299 }, 300 secondary: submitted.pdfBase64 ? { label: "Download for your records \u2193", onClick: downloadPdf } : null 301 } 302 ); 303 } 304 const todayIso = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10); 305 const dobMin = (() => { 306 const d = /* @__PURE__ */ new Date(); 307 d.setFullYear(d.getFullYear() - 100); 308 return d.toISOString().slice(0, 10); 309 })(); 310 const dobMax = (() => { 311 const d = /* @__PURE__ */ new Date(); 312 d.setFullYear(d.getFullYear() - 1); 313 return d.toISOString().slice(0, 10); 314 })(); 315 if (campMode && !campOpen && window.CMS && window.CMS._ready) { 316 return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement( 317 FormHero, 318 { 319 eyebrow: `Summer Camp ${campYear}`, 320 title: /* @__PURE__ */ React.createElement(React.Fragment, null, "Registration", /* @__PURE__ */ React.createElement("br", null), "opens soon."), 321 body: `Camp registration for ${campYear} isn't open yet. The camp page has the sites, dates and a sign-up to hear when it opens.`, 322 bg: "var(--c-cream-deep)" 323 } 324 ), /* @__PURE__ */ React.createElement("section", { className: "section" }, /* @__PURE__ */ React.createElement("div", { className: "container", style: { maxWidth: 920 } }, /* @__PURE__ */ React.createElement("a", { href: "#camps", className: "btn" }, "Back to summer camp")))); 325 } 326 const siteOptions = campSites.filter((c) => !c.registrationClosed || c.id === data.site_id); 327 return /* @__PURE__ */ React.createElement("div", null, campMode ? /* @__PURE__ */ React.createElement( 328 FormHero, 329 { 330 eyebrow: `Summer Camp ${campYear}`, 331 title: /* @__PURE__ */ React.createElement(React.Fragment, null, "Register for", /* @__PURE__ */ React.createElement("br", null), "summer camp."), 332 body: `Fill out and sign the City of Philadelphia Parks & Recreation registration form below. Your registration stays pending until the ${campFee ? `${campFee} ` : ""}registration fee is paid to the Performing Arts office.`, 333 bg: "var(--c-cream-deep)" 334 } 335 ) : /* @__PURE__ */ React.createElement( 336 FormHero, 337 { 338 eyebrow: "Participant Registration", 339 title: /* @__PURE__ */ React.createElement(React.Fragment, null, "Register for", /* @__PURE__ */ React.createElement("br", null), "a program."), 340 body: "Fill out and sign the City of Philadelphia Parks & Recreation participant registration form below. A signed copy is emailed to the program coordinator on submission.", 341 bg: "var(--c-cream-deep)" 342 }
343 ), /* @__PURE__ */ React.createElement("section", { className: "section" }, /* @__PURE__ */ React.createElement("div", { className: "container", style: { maxWidth: 920 } }, /* @__PURE__ */ React.createElement("form", { onSubmit }, campMode ? /* @__PURE__ */ React.createElement(FormSection, { number: "01", title: "Camp" }, /* @__PURE__ */ React.createElement( 344 Field, 345 { 346 label: "Camp site", 347 type: "select", 348 options: ["", ...siteOptions.map((c) => c.id)], 349 optionLabels: ["Choose a site", ...siteOptions.map((c) => `${c.name} (${c.type === "YPTC" ? "Young Performers Theatre Camp" : "Intro to Performing Arts"}${c.ageRange ? `, ${c.ageRange}` : ""})`)], 350 value: data.site_id, 351 onChange: (v) => update("site_id", v), 352 required: true 353 } 354 ), /* @__PURE__ */ React.createElement(Checkbox, { label: "Returning camper (attended a PPR camp before)", checked: data.returning, onChange: (v) => update("returning", v) })) : /* @__PURE__ */ React.createElement(FormSection, { number: "01", title: "Program & enrollment" }, data.facility === "Other" ? ( 355 /* CR #225: when Other is picked, the "Please specify" 356 box should appear ABOVE the Program name box. Break 357 the row apart so the order reads facility -> 358 please-specify -> program. */ 359 /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(Field, { label: "Facility", type: "select", options: FACILITIES, value: data.facility, onChange: (v) => update("facility", v), required: true }), /* @__PURE__ */ React.createElement( 360 Field, 361 { 362 label: "Please specify the recreation center or playground", 363 value: data.facility_other, 364 onChange: (v) => update("facility_other", v), 365 required: true 366 } 367 ), /* @__PURE__ */ React.createElement(Field, { label: "Program", type: "select", options: PROGRAMS, value: data.program_choice, onChange: pickProgram, required: true })) 368 ) : /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement(Field, { label: "Facility", type: "select", options: FACILITIES, value: data.facility, onChange: (v) => update("facility", v), required: true }), /* @__PURE__ */ React.createElement(Field, { label: "Program", type: "select", options: PROGRAMS, value: data.program_choice, onChange: pickProgram, required: true })), data.program_choice === "Other" && /* @__PURE__ */ React.createElement(Field, { label: "Program name", value: data.program, onChange: (v) => update("program", v), required: true }), /* @__PURE__ */ React.createElement(Field, { label: "Season / Year", value: data.season_year, onChange: (v) => update("season_year", v) })), /* @__PURE__ */ React.createElement(FormSection, { number: "02", title: "Participant" }, /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement( 369 Field, 370 { 371 label: "First and last name", 372 value: data.participant_name, 373 onChange: (v) => update("participant_name", v), 374 required: true, 375 pattern: "^\\s*\\S+\\s+\\S.*$", 376 title: "Please enter both a first and last name." 377 } 378 ), /* @__PURE__ */ React.createElement(Field, { label: "Date of birth", type: "date", value: data.date_of_birth, onChange: (v) => update("date_of_birth", v), required: true, min: dobMin, max: dobMax, title: `Must be between ${dobMin} and ${dobMax}` })), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement(Field, { label: "Residential address", value: data.address, onChange: (v) => update("address", v), required: true }), /* @__PURE__ */ React.createElement(Field, { label: "City", value: data.city, onChange: (v) => update("city", v) })), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement(Field, { label: "State", value: data.state, onChange: (v) => update("state", v) }
378), /* @__PURE__ */ React.createElement(Field, { label: "ZIP code", value: data.zip, onChange: (v) => update("zip", v), required: true, inputMode: "numeric", maxLength: 5, pattern: "\\d{5}", title: "5-digit ZIP code", placeholder: "19102" })), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement(Field, { label: "Primary language at home", value: data.primary_language, onChange: (v) => update("primary_language", v) }), /* @__PURE__ */ React.createElement(Field, { label: "Gender", value: data.gender, onChange: (v) => update("gender", v) })), /* @__PURE__ */ React.createElement(CheckboxGrid, { label: "Race (check all that apply)", items: RACES, state: data.race, onToggle: (k, v) => updateRace(k, v) }), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement( 379 Field, 380 { 381 label: "Home phone", 382 type: "tel", 383 value: data.home_phone, 384 onChange: (v) => update("home_phone", v), 385 placeholder: "215-555-0100", 386 inputMode: "tel", 387 maxLength: 12, 388 pattern: "\\d{3}-\\d{3}-\\d{4}", 389 title: "Use XXX-XXX-XXXX format", 390 formatter: window.formatPhone 391 } 392 ), /* @__PURE__ */ React.createElement( 393 Field, 394 { 395 label: "Cell phone", 396 type: "tel", 397 value: data.cell_phone, 398 onChange: (v) => update("cell_phone", v), 399 placeholder: "215-555-0100", 400 inputMode: "tel", 401 maxLength: 12, 402 pattern: "\\d{3}-\\d{3}-\\d{4}", 403 title: "Use XXX-XXX-XXXX format", 404 formatter: window.formatPhone 405 }
406 )), /* @__PURE__ */ React.createElement(Field, { label: "Email", type: "email", value: data.email, onChange: (v) => update("email", v) }), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement(Field, { label: "School name", value: data.school, onChange: (v) => update("school", v) }), /* @__PURE__ */ React.createElement(Field, { label: "Grade", type: "select", options: GRADES, value: data.grade, onChange: (v) => update("grade", v) })), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement( 407 Field, 408 { 409 label: "Shirt size", 410 type: "select", 411 options: SHIRT_OPTS.map((o) => o[0]), 412 optionLabels: SHIRT_OPTS.map((o) => o[1]), 413 value: data.shirt_size, 414 onChange: (v) => update("shirt_size", v) 415 } 416 ), data.shirt_size === "other" && /* @__PURE__ */ React.createElement(Field, { label: "Other shirt size", value: data.shirt_size_other, onChange: (v) => update("shirt_size_other", v) }))), /* @__PURE__ */ React.createElement(FormSection, { number: "03", title: "Parent / guardian / emergency contacts" }, data.contacts.map((c, i) => /* @__PURE__ */ React.createElement("div", { key: i, style: { border: "2px solid var(--c-ink-soft)", borderRadius: 12, padding: 18, background: "var(--c-paper)" } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--c-ink-soft)", marginBottom: 10 } }, "Contact ", i + 1, i === 0 ? " \xB7 primary" : ""), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement(Field, { label: "First and last name", value: c.name, onChange: (v) => updateContact(i, "name", v), required: i === 0 }
416), /* @__PURE__ */ React.createElement(Field, { label: "Relationship", value: c.relationship, onChange: (v) => updateContact(i, "relationship", v), required: i === 0 })), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement(Field, { label: "Email", type: "email", value: c.email, onChange: (v) => updateContact(i, "email", v), required: i === 0 }), /* @__PURE__ */ React.createElement( 417 Field, 418 { 419 label: "Phone", 420 type: "tel", 421 value: c.phone, 422 onChange: (v) => updateContact(i, "phone", v), 423 required: i === 0, 424 placeholder: "215-555-0100", 425 inputMode: "tel", 426 maxLength: 12, 427 pattern: "\\d{3}-\\d{3}-\\d{4}", 428 title: "Use XXX-XXX-XXXX format", 429 formatter: window.formatPhone 430 } 431 )), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", gap: 18, flexWrap: "wrap", marginTop: 8 } }, /* @__PURE__ */ React.createElement(Checkbox, { label: "Caregiver", checked: c.caregiver, onChange: (v) => updateContact(i, "caregiver", v) }
431), /* @__PURE__ */ React.createElement(Checkbox, { label: "Emergency contact", checked: c.emergency_contact, onChange: (v) => updateContact(i, "emergency_contact", v) }), /* @__PURE__ */ React.createElement(Checkbox, { label: "Authorized for pick up", checked: c.authorized_pickup, onChange: (v) => updateContact(i, "authorized_pickup", v) })))), data.contacts.length < 4 && /* @__PURE__ */ React.createElement("button", { type: "button", onClick: addContact, className: "btn small ghost", style: { alignSelf: "flex-start" } }, "+ Add another contact")), /* @__PURE__ */ React.createElement(FormSection, { number: "04", title: "Waivers & signatures" }, /* @__PURE__ */ React.createElement("p", { style: { fontSize: 14, color: "var(--c-ink-soft)", marginTop: -4, lineHeight: 1.55 } }, "A parent or legal guardian signs the Dismissal and Release waivers below. Emergency Clause and Media Release are optional \u2014 sign them only if you agree. Use a finger or stylus on touch devices, or click and drag with a mouse."), WAIVERS.map((w) => /* @__PURE__ */ React.createElement("div", { key: w.key, style: { border: "2px solid var(--c-ink)", borderRadius: 14, padding: 20, background: "var(--c-cream-deep)" } }, /* @__PURE__ */ React.createElement("div", { className: "display", style: { fontSize: 22, marginBottom: 8 } }
431, w.title, !w.required && /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--c-ink-soft)", marginLeft: 12, fontWeight: 400 } }, "Optional")), /* @__PURE__ */ React.createElement("p", { style: { fontSize: 13, color: "var(--c-ink)", lineHeight: 1.55, marginBottom: 14 } }, w.body), /* @__PURE__ */ React.createElement(Row, null, /* @__PURE__ */ React.createElement( 432 Field, 433 { 434 label: "Relationship to participant", 435 value: sigMeta[w.key].relationship, 436 onChange: (v) => setSigMeta((s) => ({ ...s, [w.key]: { ...s[w.key], relationship: v } })) 437 } 438 ), /* @__PURE__ */ React.createElement( 439 Field, 440 { 441 label: "Date", 442 type: "date", 443 value: sigMeta[w.key].date, 444 onChange: (v) => setSigMeta((s) => ({ ...s, [w.key]: { ...s[w.key], date: v } })) 445 } 446 )), /* @__PURE__ */ React.createElement("div", { style: { marginTop: 12 } }, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--c-ink-soft)", marginBottom: 6 } }, "Signature of parent or legal guardian"), /* @__PURE__ */ React.createElement( 447 "canvas", 448 { 449 ref: (el) => { 450 canvasRefs.current[w.key] = el; 451 }, 452 style: { width: "100%", height: 140, display: "block", border: "2px solid var(--c-ink)", borderRadius: 10, background: "var(--c-paper)", touchAction: "none" } 453 } 454 ), /* @__PURE__ */ React.createElement("button", { type: "button", onClick: () => clearSig(w.key), className: "btn small ghost", style: { marginTop: 8 } }, "Clear signature"))))), /* @__PURE__ */ React.createElement(FormSection, { number: "05", title: "Anything staff should know?" }, /* @__PURE__ */ React.createElement( 455 Field, 456 { 457 label: "Behavioral, dietary, medical, or transit-assistance notes (optional)", 458 type: "textarea", 459 value: data.staff_alerts, 460 onChange: (v) => update("staff_alerts", v) 461 } 462 )), error && /* @__PURE__ */ React.createElement("div", { style: { marginTop: 24, padding: 14, background: "#FBE4DC", border: "2px solid var(--c-primary)", borderRadius: 12, fontSize: 14, color: "var(--c-ink)" } }, error), /* @__PURE__ */ React.createElement("div", { className: "card", style: { background: "var(--c-cream-deep)", marginTop: 32, display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: 14 } }, /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { className: "display", style: { fontSize: 20 } }, "Submit registration"), /* @__PURE__ */ React.createElement("div", { style: { fontSize: 13, color: "var(--c-ink-soft)" } }, campMode ? "A signed copy is emailed to you and the office. Pending until the registration fee is paid." : "A signed copy is emailed to the program coordinator on submit.")), /* @__PURE__ */ React.createElement("button", { type: "submit", className: "btn", disabled: submitting }, submitting ? "Submitting\u2026" : "Submit registration")))))); 463} 464function CheckboxGrid({ label, items, state, onToggle }) { 465 return /* @__PURE__ */ React.createElement("div", null, /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--f-mono)", fontSize: 11, letterSpacing: "0.1em", textTransform: "uppercase", color: "var(--c-ink-soft)", marginBottom: 8 } }, label), /* @__PURE__ */ React.createElement("div", { style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(220px, 1fr))", gap: 8 } }, items.map(([k, lbl]) => /* @__PURE__ */ React.createElement(Checkbox, { key: k, label: lbl, checked: !!state[k], onChange: (v) => onToggle(k, v) })))); 466} 467function Checkbox({ label, checked, onChange }) { 468 return /* @__PURE__ */ React.createElement("label", { style: { display: "inline-flex", alignItems: "center", gap: 8, fontSize: 14, cursor: "pointer", userSelect: "none" } }, /* @__PURE__ */ React.createElement("input", { type: "checkbox", checked: !!checked, onChange: (e) => onChange(e.target.checked), style: { width: 18, height: 18, accentColor: "var(--c-primary)" } }), label); 469} 470Object.assign(window, { ParticipantRegistrationPage }); 471//# sourceMappingURL=Registration.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.