@scalemule/news-publication 0.0.53 → 0.0.56

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.
@@ -1,9 +1,13 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var react = require('react');
4
+ var React = require('react');
5
5
  var jsxRuntime = require('react/jsx-runtime');
6
6
 
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var React__default = /*#__PURE__*/_interopDefault(React);
10
+
7
11
  // src/pets.ts
8
12
  var PET_PHOTO_CATEGORIES = [
9
13
  ["cute", "Cute pets"],
@@ -141,7 +145,7 @@ async function call(url, method, data) {
141
145
  return body.data ?? body;
142
146
  }
143
147
  function PetSignIn({ returnTo = "/account" }) {
144
- const [busy, setBusy] = react.useState(false), [error, setError] = react.useState("");
148
+ const [busy, setBusy] = React.useState(false), [error, setError] = React.useState("");
145
149
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
146
150
  /* @__PURE__ */ jsxRuntime.jsx(
147
151
  "button",
@@ -170,6 +174,56 @@ function PetSignIn({ returnTo = "/account" }) {
170
174
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: "paw-safety", children: "Your existing network sign-in works here. Public browsing is always open." })
171
175
  ] });
172
176
  }
177
+ var FieldErrors = React.createContext({ errors: {}, clear: () => {
178
+ } });
179
+ function PetField({
180
+ children,
181
+ className = ""
182
+ }) {
183
+ const id = React.useId();
184
+ const { errors, clear } = React.useContext(FieldErrors);
185
+ const error = errors[id];
186
+ const nodes = React__default.default.Children.toArray(children);
187
+ const label = nodes.filter((node) => typeof node === "string").join(" ").trim();
188
+ return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: `paw-field ${className}`, htmlFor: id, children: [
189
+ nodes.map((node) => {
190
+ if (!React__default.default.isValidElement(node) || !["input", "select", "textarea", "progress"].includes(
191
+ String(node.type)
192
+ ))
193
+ return node;
194
+ const original = node.props.onChange;
195
+ return React__default.default.cloneElement(node, {
196
+ id,
197
+ "data-field-label": label,
198
+ "aria-invalid": error ? true : void 0,
199
+ "aria-describedby": [node.props["aria-describedby"], error ? `${id}-error` : void 0].filter(Boolean).join(" ") || void 0,
200
+ onChange: (event) => {
201
+ clear(id);
202
+ original?.(event);
203
+ }
204
+ });
205
+ }),
206
+ error && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "paw-field-error", id: `${id}-error`, children: error })
207
+ ] });
208
+ }
209
+ function fieldMessage(control, blank = false) {
210
+ const label = control.dataset.fieldLabel || "this field";
211
+ if (control.validity.valueMissing || blank) {
212
+ if (control instanceof HTMLInputElement && control.type === "checkbox")
213
+ return "Accept the publication permission to continue.";
214
+ if (control instanceof HTMLInputElement && control.type === "file")
215
+ return "Add at least one photograph of your pet.";
216
+ if (label === "Pet name") return "Add your pet\u2019s name.";
217
+ if (label === "Home community") return "Choose your home community.";
218
+ if (label === "Your story") return "Tell us a little about your pet.";
219
+ return `Add ${label.toLowerCase()} to continue.`;
220
+ }
221
+ if (control.validity.typeMismatch || control.validity.patternMismatch)
222
+ return "Enter a complete, valid link, including https://.";
223
+ if (control.validity.rangeUnderflow || control.validity.rangeOverflow)
224
+ return "Choose a value within the allowed range.";
225
+ return `Check ${label.toLowerCase()} and try again.`;
226
+ }
173
227
  function PetSubmissionForm({
174
228
  communities,
175
229
  policy,
@@ -180,25 +234,27 @@ function PetSubmissionForm({
180
234
  accountUrl = "/account",
181
235
  onSaved
182
236
  }) {
183
- const [deviceReady, setDeviceReady] = react.useState(false);
184
- react.useEffect(() => setDeviceReady(true), []);
185
- const [kind, setKind] = react.useState(initial?.kind || "spotlight"), [content, setContent] = react.useState(initial?.content || empty);
186
- const [community, setCommunity] = react.useState(
237
+ const [fieldErrors, setFieldErrors] = React.useState({});
238
+ const formRef = React.useRef(null);
239
+ const [deviceReady, setDeviceReady] = React.useState(false);
240
+ React.useEffect(() => setDeviceReady(true), []);
241
+ const [kind, setKind] = React.useState(initial?.kind || "spotlight"), [content, setContent] = React.useState(initial?.content || empty);
242
+ const [community, setCommunity] = React.useState(
187
243
  initial?.area_id || defaultCommunity || ""
188
- ), [visibility, setVisibility] = react.useState(
244
+ ), [visibility, setVisibility] = React.useState(
189
245
  initial?.visibility || "private"
190
246
  );
191
- const [profileId, setProfileId] = react.useState(
247
+ const [profileId, setProfileId] = React.useState(
192
248
  initial?.profile_id || null
193
249
  );
194
- const [files, setFiles] = react.useState([]);
195
- const [step, setStep] = react.useState(0), [consent, setConsent] = react.useState(false), [busy, setBusy] = react.useState(false), [error, setError] = react.useState(""), [progress, setProgress] = react.useState(0), [saved, setSaved] = react.useState();
196
- const receipt = react.useRef(
250
+ const [files, setFiles] = React.useState([]);
251
+ const [step, setStep] = React.useState(0), [consent, setConsent] = React.useState(false), [busy, setBusy] = React.useState(false), [error, setError] = React.useState(""), [progress, setProgress] = React.useState(0), [saved, setSaved] = React.useState();
252
+ const receipt = React.useRef(
197
253
  initial ? { id: initial.id, revision: initial.revision } : null
198
254
  );
199
- const key = react.useRef("");
200
- const uploads = react.useRef(/* @__PURE__ */ new Set());
201
- react.useEffect(
255
+ const key = React.useRef("");
256
+ const uploads = React.useRef(/* @__PURE__ */ new Set());
257
+ React.useEffect(
202
258
  () => () => files.forEach((f) => URL.revokeObjectURL(f.preview)),
203
259
  [files]
204
260
  );
@@ -292,499 +348,608 @@ function PetSubmissionForm({
292
348
  /* @__PURE__ */ jsxRuntime.jsx("p", { children: kind === "profile" && visibility === "private" ? "Your profile is saved privately. Only you can see it." : "Your contribution is saved for editorial review. It will appear publicly only after approval." }),
293
349
  /* @__PURE__ */ jsxRuntime.jsx("a", { href: accountUrl, children: "View your pets and submissions" })
294
350
  ] });
295
- return /* @__PURE__ */ jsxRuntime.jsxs(
296
- "form",
351
+ return /* @__PURE__ */ jsxRuntime.jsx(
352
+ FieldErrors.Provider,
297
353
  {
298
- className: "paw-form",
299
- onSubmit: (event) => {
300
- event.preventDefault();
301
- if (step === 0) {
302
- setError("");
303
- setStep(1);
304
- } else void save();
354
+ value: {
355
+ errors: fieldErrors,
356
+ clear: (id) => setFieldErrors((old) => {
357
+ const next = { ...old };
358
+ delete next[id];
359
+ return next;
360
+ })
305
361
  },
306
- children: [
307
- /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "paw-form-steps", "aria-label": "Submission progress", children: [
308
- /* @__PURE__ */ jsxRuntime.jsx("li", { "aria-current": step === 0 ? "step" : void 0, children: "1. Their story" }),
309
- /* @__PURE__ */ jsxRuntime.jsx("li", { "aria-current": step === 1 ? "step" : void 0, children: "2. Preview & permission" })
310
- ] }),
311
- /* @__PURE__ */ jsxRuntime.jsx("h1", { children: kind === "celebration" && content.category === "memorial" ? "Remember a beloved companion." : "Someone worth meeting." }),
312
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "paw-safety", children: "Choose a community, never a home address. Keep phone numbers, email addresses and microchip details out of your story." }),
313
- step === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
314
- !initial && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
315
- "What would you like to share?",
316
- /* @__PURE__ */ jsxRuntime.jsxs(
317
- "select",
318
- {
319
- value: kind,
320
- onChange: (e) => {
321
- const k = e.target.value;
322
- setKind(k);
323
- setContent((c) => ({
324
- ...c,
325
- source: ["event", "adoption"].includes(k) ? {
326
- organization: "",
327
- official_url: "",
328
- availability_confirmed: false
329
- } : null,
330
- event: k === "event" ? {
331
- starts_at: "",
332
- ends_at: "",
333
- event_type: "adoption",
334
- cost: "unknown",
335
- cost_verified: false
336
- } : null
337
- }));
338
- change(
339
- "category",
340
- k === "celebration" ? "birthday" : k === "photo" ? "cute" : ""
341
- );
342
- },
343
- children: [
344
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "spotlight", children: "Paw of the Week submission" }),
345
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "profile", children: "Pet profile" }),
346
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "photo", children: "Photo board" }),
347
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "celebration", children: "Pet celebration" }),
348
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "lost", children: "Lost pet report" }),
349
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "found", children: "Found pet report" }),
350
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "event", children: "Organization event" }),
351
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "adoption", children: "Shelter or rescue adoption listing" })
352
- ]
353
- }
354
- )
355
- ] }),
356
- !initial && kind !== "profile" && profiles.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
357
- "Start with one of your pets",
358
- /* @__PURE__ */ jsxRuntime.jsxs(
359
- "select",
360
- {
361
- value: profileId || "",
362
- onChange: (e) => {
363
- const p = profiles.find((p2) => p2.id === e.target.value);
364
- setProfileId(p?.id || null);
365
- if (p) {
366
- setContent({
367
- ...p.content,
368
- category: content.category,
369
- source: content.source,
370
- event: content.event
371
- });
372
- setCommunity(
373
- communities.some((c) => c.id === p.area_id) ? p.area_id : defaultCommunity || ""
374
- );
375
- }
376
- },
377
- children: [
378
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Enter pet details" }),
379
- profiles.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.id, children: p.content.name }, p.id))
380
- ]
381
- }
382
- )
383
- ] }),
384
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
385
- kind === "event" ? "Event title" : "Pet name",
386
- /* @__PURE__ */ jsxRuntime.jsx(
387
- "input",
388
- {
389
- required: true,
390
- maxLength: 100,
391
- value: content.name,
392
- onChange: (e) => change("name", e.target.value),
393
- autoComplete: "off"
394
- }
395
- )
396
- ] }),
397
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
398
- "Species",
399
- /* @__PURE__ */ jsxRuntime.jsx(
400
- "input",
401
- {
402
- required: true,
403
- maxLength: 50,
404
- value: content.species,
405
- onChange: (e) => change("species", e.target.value)
406
- }
407
- )
408
- ] }),
409
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
410
- "Home community",
411
- /* @__PURE__ */ jsxRuntime.jsxs(
412
- "select",
413
- {
414
- required: true,
415
- value: community,
416
- onChange: (e) => setCommunity(e.target.value),
417
- children: [
418
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Choose a community" }),
419
- communities.map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c.id, children: c.name }, c.id))
420
- ]
362
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
363
+ "form",
364
+ {
365
+ ref: formRef,
366
+ noValidate: true,
367
+ className: "paw-form paw-submission",
368
+ onSubmit: (event) => {
369
+ event.preventDefault();
370
+ const errors = {};
371
+ let first;
372
+ for (const element of Array.from(event.currentTarget.elements)) {
373
+ if (!(element instanceof HTMLInputElement || element instanceof HTMLSelectElement || element instanceof HTMLTextAreaElement))
374
+ continue;
375
+ const blank = element.required && element.type !== "checkbox" && element.type !== "file" && !element.value.trim();
376
+ if (element.willValidate && (!element.validity.valid || blank)) {
377
+ errors[element.id] = fieldMessage(element, blank);
378
+ first ||= element;
421
379
  }
422
- )
423
- ] }),
424
- kind === "profile" && /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { children: [
425
- /* @__PURE__ */ jsxRuntime.jsx("legend", { children: "A few favorite things" }),
426
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
427
- "Breed or mix (optional)",
428
- /* @__PURE__ */ jsxRuntime.jsx(
429
- "input",
430
- {
431
- value: content.breed,
432
- maxLength: 100,
433
- onChange: (e) => change("breed", e.target.value)
434
- }
435
- )
436
- ] }),
437
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
438
- "Birthday (optional)",
439
- /* @__PURE__ */ jsxRuntime.jsx(
440
- "input",
441
- {
442
- type: "date",
443
- value: content.birthday || "",
444
- onChange: (e) => change("birthday", e.target.value || null)
445
- }
446
- )
447
- ] }),
448
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
449
- "Adoption anniversary (optional)",
450
- /* @__PURE__ */ jsxRuntime.jsx(
451
- "input",
452
- {
453
- type: "date",
454
- value: content.adoption_anniversary || "",
455
- onChange: (e) => change("adoption_anniversary", e.target.value || null)
456
- }
457
- )
458
- ] }),
459
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
460
- "Personality",
461
- /* @__PURE__ */ jsxRuntime.jsx(
462
- "input",
463
- {
464
- maxLength: 300,
465
- value: content.personality,
466
- onChange: (e) => change("personality", e.target.value)
467
- }
468
- )
380
+ }
381
+ setFieldErrors(errors);
382
+ if (first) {
383
+ first.focus();
384
+ return;
385
+ }
386
+ if (step === 0) {
387
+ setError("");
388
+ setStep(1);
389
+ requestAnimationFrame(() => {
390
+ formRef.current?.querySelector("h1")?.focus({ preventScroll: true });
391
+ formRef.current?.scrollIntoView({ block: "start" });
392
+ });
393
+ } else void save();
394
+ },
395
+ children: [
396
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "paw-form-intro", children: [
397
+ /* @__PURE__ */ jsxRuntime.jsxs("ol", { className: "paw-form-steps", "aria-label": "Submission progress", children: [
398
+ /* @__PURE__ */ jsxRuntime.jsx("li", { "aria-current": step === 0 ? "step" : void 0, children: "1. Their story" }),
399
+ /* @__PURE__ */ jsxRuntime.jsx("li", { "aria-current": step === 1 ? "step" : void 0, children: "2. Preview & permission" })
400
+ ] }),
401
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { tabIndex: -1, children: kind === "celebration" && content.category === "memorial" ? "Remember a beloved companion." : ["lost", "found"].includes(kind) ? "Help them find home." : step === 1 ? "Looking good." : "Tell their story." }),
402
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "paw-form-description", children: step === 0 ? content.category === "memorial" ? "Share a memory of a companion you\u2019ll always remember." : ["lost", "found"].includes(kind) ? "A clear description and an approximate location can help neighbors recognize a missing pet." : kind === "event" ? "Help neighbors discover your organization\u2019s pet community event." : "A favorite photograph. A little personality. A story your neighbors will love." : "Take a moment to check the details. You can always go back and make changes." }),
403
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "paw-safety", children: "Choose a community, never a home address. Keep phone numbers, email addresses and microchip details out of your story." }),
404
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "paw-form-assurance", children: [
405
+ /* @__PURE__ */ jsxRuntime.jsx(PawMark, { size: 28 }),
406
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
407
+ "Yours to share.",
408
+ /* @__PURE__ */ jsxRuntime.jsx("br", {}),
409
+ "Reviewed with care."
410
+ ] })
411
+ ] })
469
412
  ] }),
470
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
471
- "Favorite activities, separated by commas",
472
- /* @__PURE__ */ jsxRuntime.jsx(
473
- "input",
474
- {
475
- value: content.activities.join(", "),
476
- onChange: (e) => change(
477
- "activities",
478
- e.target.value.split(",").map((v) => v.trim()).slice(0, 8)
413
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "paw-form-body", children: [
414
+ step === 0 ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
415
+ !initial && /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
416
+ "What would you like to share?",
417
+ /* @__PURE__ */ jsxRuntime.jsxs(
418
+ "select",
419
+ {
420
+ value: kind,
421
+ onChange: (e) => {
422
+ const k = e.target.value;
423
+ setKind(k);
424
+ setFieldErrors({});
425
+ setContent((c) => ({
426
+ ...c,
427
+ source: ["event", "adoption"].includes(k) ? {
428
+ organization: "",
429
+ official_url: "",
430
+ availability_confirmed: false
431
+ } : null,
432
+ event: k === "event" ? {
433
+ starts_at: "",
434
+ ends_at: "",
435
+ event_type: "adoption",
436
+ cost: "unknown",
437
+ cost_verified: false
438
+ } : null
439
+ }));
440
+ change(
441
+ "category",
442
+ k === "celebration" ? "birthday" : k === "photo" ? "cute" : ""
443
+ );
444
+ },
445
+ children: [
446
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "spotlight", children: "Paw of the Week submission" }),
447
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "profile", children: "Pet profile" }),
448
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "photo", children: "Photo board" }),
449
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "celebration", children: "Pet celebration" }),
450
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "lost", children: "Lost pet report" }),
451
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "found", children: "Found pet report" }),
452
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "event", children: "Organization event" }),
453
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "adoption", children: "Shelter or rescue adoption listing" })
454
+ ]
455
+ }
479
456
  )
480
- }
481
- )
482
- ] }),
483
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
484
- "Profile privacy",
485
- /* @__PURE__ */ jsxRuntime.jsxs(
486
- "select",
487
- {
488
- value: visibility,
489
- onChange: (e) => setVisibility(e.target.value),
490
- children: [
491
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "private", children: "Private \u2014 only me" }),
492
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "public", children: "Public \u2014 after editorial review" })
493
- ]
494
- }
495
- )
496
- ] })
497
- ] }),
498
- (kind === "photo" || kind === "celebration") && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
499
- kind === "photo" ? "Photo category" : "Celebration",
500
- /* @__PURE__ */ jsxRuntime.jsx(
501
- "select",
502
- {
503
- value: content.category,
504
- onChange: (e) => change("category", e.target.value),
505
- children: (kind === "photo" ? PET_PHOTO_CATEGORIES : PET_CELEBRATIONS).map(([value, label]) => /* @__PURE__ */ jsxRuntime.jsx("option", { value, children: label }, value))
506
- }
507
- )
508
- ] }),
509
- ["lost", "found", "celebration"].includes(kind) && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
510
- kind === "lost" ? "Date last seen" : kind === "found" ? "Date found" : "Celebration date (optional)",
511
- /* @__PURE__ */ jsxRuntime.jsx(
512
- "input",
513
- {
514
- required: kind !== "celebration",
515
- type: "date",
516
- value: content.date || "",
517
- onChange: (e) => change("date", e.target.value || null)
518
- }
519
- )
520
- ] }),
521
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
522
- kind === "profile" ? "A little biography" : "Your story",
523
- /* @__PURE__ */ jsxRuntime.jsx(
524
- "textarea",
525
- {
526
- required: kind !== "profile",
527
- maxLength: 4e3,
528
- value: content.story,
529
- onChange: (e) => change("story", e.target.value)
530
- }
531
- )
532
- ] }),
533
- kind === "adoption" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
534
- "Approximate age (optional)",
535
- /* @__PURE__ */ jsxRuntime.jsx(
536
- "input",
537
- {
538
- value: content.age_description || "",
539
- maxLength: 80,
540
- onChange: (e) => change("age_description", e.target.value)
541
- }
542
- )
543
- ] }),
544
- content.source && /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { children: [
545
- /* @__PURE__ */ jsxRuntime.jsx("legend", { children: "Official organization and source" }),
546
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
547
- "Organization name",
548
- /* @__PURE__ */ jsxRuntime.jsx(
549
- "input",
550
- {
551
- required: true,
552
- maxLength: 200,
553
- value: content.source.organization,
554
- onChange: (e) => change("source", {
555
- ...content.source,
556
- organization: e.target.value
557
- })
558
- }
559
- )
560
- ] }),
561
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
562
- "Official listing or registration link",
563
- /* @__PURE__ */ jsxRuntime.jsx(
564
- "input",
565
- {
566
- required: true,
567
- type: "url",
568
- pattern: "https://.*",
569
- value: content.source.official_url,
570
- onChange: (e) => change("source", {
571
- ...content.source,
572
- official_url: e.target.value
573
- })
574
- }
575
- )
576
- ] }),
577
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Editors verify the organization, permission to use photographs, and listing information. Availability and event costs are never assumed." })
578
- ] }),
579
- content.event && /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { children: [
580
- /* @__PURE__ */ jsxRuntime.jsx("legend", { children: "Event schedule" }),
581
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
582
- "Enter times in your device\u2019s timezone (",
583
- deviceReady ? Intl.DateTimeFormat().resolvedOptions().timeZone : "your device timezone",
584
- "). They display in Pacific time."
585
- ] }),
586
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
587
- "Starts",
588
- /* @__PURE__ */ jsxRuntime.jsx(
589
- "input",
590
- {
591
- type: "datetime-local",
592
- required: true,
593
- value: deviceReady ? localDateTime(content.event.starts_at) : "",
594
- onChange: (e) => {
595
- if (e.target.value)
596
- change("event", {
597
- ...content.event,
598
- starts_at: new Date(e.target.value).toISOString()
599
- });
600
- }
601
- }
602
- )
603
- ] }),
604
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
605
- "Ends",
606
- /* @__PURE__ */ jsxRuntime.jsx(
607
- "input",
608
- {
609
- type: "datetime-local",
610
- required: true,
611
- value: deviceReady ? localDateTime(content.event.ends_at) : "",
612
- onChange: (e) => {
613
- if (e.target.value)
614
- change("event", {
615
- ...content.event,
616
- ends_at: new Date(e.target.value).toISOString()
617
- });
618
- }
619
- }
620
- )
621
- ] }),
622
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
623
- "Event type",
624
- /* @__PURE__ */ jsxRuntime.jsx(
625
- "select",
626
- {
627
- value: content.event.event_type,
628
- onChange: (e) => change("event", {
629
- ...content.event,
630
- event_type: e.target.value
631
- }),
632
- children: [
633
- "adoption",
634
- "veterinary",
635
- "vaccination",
636
- "walk",
637
- "festival",
638
- "fundraiser",
639
- "workshop",
640
- "celebration"
641
- ].map((type) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: type, children: type }, type))
642
- }
643
- )
644
- ] }),
645
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
646
- "Reported cost",
647
- /* @__PURE__ */ jsxRuntime.jsxs(
648
- "select",
649
- {
650
- value: content.event.cost,
651
- onChange: (e) => change("event", {
652
- ...content.event,
653
- cost: e.target.value
654
- }),
655
- children: [
656
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "unknown", children: "Check with organization" }),
657
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "free", children: "Submitted as free \u2014 requires verification" }),
658
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "paid", children: "Paid registration" })
659
- ]
660
- }
661
- )
662
- ] })
663
- ] }),
664
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
665
- "Your public photo credit",
666
- /* @__PURE__ */ jsxRuntime.jsx(
667
- "input",
668
- {
669
- maxLength: 100,
670
- value: content.attribution,
671
- onChange: (e) => change("attribution", e.target.value),
672
- placeholder: "Name you want published"
673
- }
674
- )
675
- ] }),
676
- initial?.media.map((photo) => /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: "paw-photo", children: [
677
- /* @__PURE__ */ jsxRuntime.jsx(
678
- "img",
679
- {
680
- src: `${apiPath}/submissions/${initial.id}/media/${photo.id}`,
681
- alt: photo.caption || content.name,
682
- width: 640,
683
- height: 480
684
- }
685
- ),
686
- /* @__PURE__ */ jsxRuntime.jsx("figcaption", { children: photo.attribution })
687
- ] }, photo.id)),
688
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
689
- "Authentic photographs",
690
- /* @__PURE__ */ jsxRuntime.jsx(
691
- "input",
692
- {
693
- type: "file",
694
- accept: "image/jpeg,image/png,image/webp",
695
- multiple: true,
696
- onChange: (e) => {
697
- const selected = Array.from(e.target.files || []);
698
- if (selected.length + (initial?.media.length || 0) > 10 || selected.some((f) => f.size > 8 * 1024 * 1024)) {
699
- setError(
700
- "Choose up to ten JPEG, PNG or WebP photographs, each under 8 MB."
701
- );
702
- return;
703
- }
704
- setError("");
705
- setFiles(
706
- selected.map((file) => ({
707
- file,
708
- key: crypto.randomUUID(),
709
- preview: URL.createObjectURL(file)
710
- }))
711
- );
712
- }
713
- }
714
- )
715
- ] }),
716
- /* @__PURE__ */ jsxRuntime.jsx("small", { children: "JPEG, PNG or WebP, up to 8 MB each. Photos are checked before publication and location metadata is removed." }),
717
- ["lost", "found"].includes(kind) && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "paw-safety", children: [
718
- PET_SAFETY.recovery,
719
- " Private recovery contact is not available yet."
720
- ] })
721
- ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
722
- /* @__PURE__ */ jsxRuntime.jsxs(
723
- "article",
724
- {
725
- className: content.category === "memorial" ? "paw-memorial" : "",
726
- children: [
727
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "paw-context", children: communities.find((c) => c.id === community)?.name }),
728
- /* @__PURE__ */ jsxRuntime.jsx("h2", { children: content.name }),
729
- !files.length && initial?.media[0] && /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: "paw-photo", children: [
457
+ ] }),
458
+ !initial && kind !== "profile" && profiles.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
459
+ "Start with one of your pets",
460
+ /* @__PURE__ */ jsxRuntime.jsxs(
461
+ "select",
462
+ {
463
+ value: profileId || "",
464
+ onChange: (e) => {
465
+ const p = profiles.find((p2) => p2.id === e.target.value);
466
+ setProfileId(p?.id || null);
467
+ if (p) {
468
+ setContent({
469
+ ...p.content,
470
+ category: content.category,
471
+ source: content.source,
472
+ event: content.event
473
+ });
474
+ setCommunity(
475
+ communities.some((c) => c.id === p.area_id) ? p.area_id : defaultCommunity || ""
476
+ );
477
+ }
478
+ },
479
+ children: [
480
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Enter pet details" }),
481
+ profiles.map((p) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: p.id, children: p.content.name }, p.id))
482
+ ]
483
+ }
484
+ )
485
+ ] }),
486
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
487
+ kind === "event" ? "Event title" : "Pet name",
730
488
  /* @__PURE__ */ jsxRuntime.jsx(
731
- "img",
489
+ "input",
732
490
  {
733
- src: `${apiPath}/submissions/${initial.id}/media/${initial.media[0].id}`,
734
- alt: initial.media[0].caption || content.name,
735
- width: 800,
736
- height: 600
491
+ required: true,
492
+ maxLength: 100,
493
+ value: content.name,
494
+ onChange: (e) => change("name", e.target.value),
495
+ autoComplete: "off"
737
496
  }
738
- ),
739
- /* @__PURE__ */ jsxRuntime.jsx("figcaption", { children: initial.media[0].attribution })
497
+ )
740
498
  ] }),
741
- files[0] && /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: "paw-photo", children: [
499
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
500
+ "Species",
501
+ /* @__PURE__ */ jsxRuntime.jsx(
502
+ "input",
503
+ {
504
+ required: true,
505
+ maxLength: 50,
506
+ value: content.species,
507
+ onChange: (e) => change("species", e.target.value)
508
+ }
509
+ )
510
+ ] }),
511
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
512
+ "Home community",
513
+ /* @__PURE__ */ jsxRuntime.jsxs(
514
+ "select",
515
+ {
516
+ required: true,
517
+ value: community,
518
+ onChange: (e) => setCommunity(e.target.value),
519
+ children: [
520
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Choose a community" }),
521
+ communities.map((c) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: c.id, children: c.name }, c.id))
522
+ ]
523
+ }
524
+ )
525
+ ] }),
526
+ kind === "profile" && /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { children: [
527
+ /* @__PURE__ */ jsxRuntime.jsx("legend", { children: "A few favorite things" }),
528
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
529
+ "Breed or mix (optional)",
530
+ /* @__PURE__ */ jsxRuntime.jsx(
531
+ "input",
532
+ {
533
+ value: content.breed,
534
+ maxLength: 100,
535
+ onChange: (e) => change("breed", e.target.value)
536
+ }
537
+ )
538
+ ] }),
539
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
540
+ "Birthday (optional)",
541
+ /* @__PURE__ */ jsxRuntime.jsx(
542
+ "input",
543
+ {
544
+ type: "date",
545
+ value: content.birthday || "",
546
+ onChange: (e) => change("birthday", e.target.value || null)
547
+ }
548
+ )
549
+ ] }),
550
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
551
+ "Adoption anniversary (optional)",
552
+ /* @__PURE__ */ jsxRuntime.jsx(
553
+ "input",
554
+ {
555
+ type: "date",
556
+ value: content.adoption_anniversary || "",
557
+ onChange: (e) => change("adoption_anniversary", e.target.value || null)
558
+ }
559
+ )
560
+ ] }),
561
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
562
+ "Personality",
563
+ /* @__PURE__ */ jsxRuntime.jsx(
564
+ "input",
565
+ {
566
+ maxLength: 300,
567
+ value: content.personality,
568
+ onChange: (e) => change("personality", e.target.value)
569
+ }
570
+ )
571
+ ] }),
572
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
573
+ "Favorite activities, separated by commas",
574
+ /* @__PURE__ */ jsxRuntime.jsx(
575
+ "input",
576
+ {
577
+ value: content.activities.join(", "),
578
+ onChange: (e) => change(
579
+ "activities",
580
+ e.target.value.split(",").map((v) => v.trim()).slice(0, 8)
581
+ )
582
+ }
583
+ )
584
+ ] }),
585
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
586
+ "Profile privacy",
587
+ /* @__PURE__ */ jsxRuntime.jsxs(
588
+ "select",
589
+ {
590
+ value: visibility,
591
+ onChange: (e) => setVisibility(e.target.value),
592
+ children: [
593
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "private", children: "Private \u2014 only me" }),
594
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "public", children: "Public \u2014 after editorial review" })
595
+ ]
596
+ }
597
+ )
598
+ ] })
599
+ ] }),
600
+ (kind === "photo" || kind === "celebration") && /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
601
+ kind === "photo" ? "Photo category" : "Celebration",
602
+ /* @__PURE__ */ jsxRuntime.jsx(
603
+ "select",
604
+ {
605
+ value: content.category,
606
+ onChange: (e) => change("category", e.target.value),
607
+ children: (kind === "photo" ? PET_PHOTO_CATEGORIES : PET_CELEBRATIONS).map(([value, label]) => /* @__PURE__ */ jsxRuntime.jsx("option", { value, children: label }, value))
608
+ }
609
+ )
610
+ ] }),
611
+ ["lost", "found", "celebration"].includes(kind) && /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
612
+ kind === "lost" ? "Date last seen" : kind === "found" ? "Date found" : "Celebration date (optional)",
613
+ /* @__PURE__ */ jsxRuntime.jsx(
614
+ "input",
615
+ {
616
+ required: kind !== "celebration",
617
+ type: "date",
618
+ value: content.date || "",
619
+ onChange: (e) => change("date", e.target.value || null)
620
+ }
621
+ )
622
+ ] }),
623
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
624
+ kind === "profile" ? "A little biography" : "Your story",
625
+ /* @__PURE__ */ jsxRuntime.jsx(
626
+ "textarea",
627
+ {
628
+ required: kind !== "profile",
629
+ maxLength: 4e3,
630
+ value: content.story,
631
+ onChange: (e) => change("story", e.target.value)
632
+ }
633
+ )
634
+ ] }),
635
+ kind === "adoption" && /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
636
+ "Approximate age (optional)",
637
+ /* @__PURE__ */ jsxRuntime.jsx(
638
+ "input",
639
+ {
640
+ value: content.age_description || "",
641
+ maxLength: 80,
642
+ onChange: (e) => change("age_description", e.target.value)
643
+ }
644
+ )
645
+ ] }),
646
+ content.source && /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { children: [
647
+ /* @__PURE__ */ jsxRuntime.jsx("legend", { children: "Official organization and source" }),
648
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
649
+ "Organization name",
650
+ /* @__PURE__ */ jsxRuntime.jsx(
651
+ "input",
652
+ {
653
+ required: true,
654
+ maxLength: 200,
655
+ value: content.source.organization,
656
+ onChange: (e) => change("source", {
657
+ ...content.source,
658
+ organization: e.target.value
659
+ })
660
+ }
661
+ )
662
+ ] }),
663
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
664
+ "Official listing or registration link",
665
+ /* @__PURE__ */ jsxRuntime.jsx(
666
+ "input",
667
+ {
668
+ required: true,
669
+ type: "url",
670
+ pattern: "https://.*",
671
+ value: content.source.official_url,
672
+ onChange: (e) => change("source", {
673
+ ...content.source,
674
+ official_url: e.target.value
675
+ })
676
+ }
677
+ )
678
+ ] }),
679
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Editors verify the organization, permission to use photographs, and listing information. Availability and event costs are never assumed." })
680
+ ] }),
681
+ content.event && /* @__PURE__ */ jsxRuntime.jsxs("fieldset", { children: [
682
+ /* @__PURE__ */ jsxRuntime.jsx("legend", { children: "Event schedule" }),
683
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
684
+ "Enter times in your device\u2019s timezone (",
685
+ deviceReady ? Intl.DateTimeFormat().resolvedOptions().timeZone : "your device timezone",
686
+ "). They display in Pacific time."
687
+ ] }),
688
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
689
+ "Starts",
690
+ /* @__PURE__ */ jsxRuntime.jsx(
691
+ "input",
692
+ {
693
+ type: "datetime-local",
694
+ required: true,
695
+ value: deviceReady ? localDateTime(content.event.starts_at) : "",
696
+ onChange: (e) => {
697
+ if (e.target.value)
698
+ change("event", {
699
+ ...content.event,
700
+ starts_at: new Date(e.target.value).toISOString()
701
+ });
702
+ }
703
+ }
704
+ )
705
+ ] }),
706
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
707
+ "Ends",
708
+ /* @__PURE__ */ jsxRuntime.jsx(
709
+ "input",
710
+ {
711
+ type: "datetime-local",
712
+ required: true,
713
+ value: deviceReady ? localDateTime(content.event.ends_at) : "",
714
+ onChange: (e) => {
715
+ if (e.target.value)
716
+ change("event", {
717
+ ...content.event,
718
+ ends_at: new Date(e.target.value).toISOString()
719
+ });
720
+ }
721
+ }
722
+ )
723
+ ] }),
724
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
725
+ "Event type",
726
+ /* @__PURE__ */ jsxRuntime.jsx(
727
+ "select",
728
+ {
729
+ value: content.event.event_type,
730
+ onChange: (e) => change("event", {
731
+ ...content.event,
732
+ event_type: e.target.value
733
+ }),
734
+ children: [
735
+ "adoption",
736
+ "veterinary",
737
+ "vaccination",
738
+ "walk",
739
+ "festival",
740
+ "fundraiser",
741
+ "workshop",
742
+ "celebration"
743
+ ].map((type) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: type, children: type }, type))
744
+ }
745
+ )
746
+ ] }),
747
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
748
+ "Reported cost",
749
+ /* @__PURE__ */ jsxRuntime.jsxs(
750
+ "select",
751
+ {
752
+ value: content.event.cost,
753
+ onChange: (e) => change("event", {
754
+ ...content.event,
755
+ cost: e.target.value
756
+ }),
757
+ children: [
758
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "unknown", children: "Check with organization" }),
759
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "free", children: "Submitted as free \u2014 requires verification" }),
760
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "paid", children: "Paid registration" })
761
+ ]
762
+ }
763
+ )
764
+ ] })
765
+ ] }),
766
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
767
+ "Your public photo credit",
768
+ /* @__PURE__ */ jsxRuntime.jsx(
769
+ "input",
770
+ {
771
+ maxLength: 100,
772
+ value: content.attribution,
773
+ onChange: (e) => change("attribution", e.target.value),
774
+ placeholder: "Name you want published"
775
+ }
776
+ )
777
+ ] }),
778
+ initial?.media.map((photo) => /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: "paw-photo", children: [
742
779
  /* @__PURE__ */ jsxRuntime.jsx(
743
780
  "img",
744
781
  {
745
- src: files[0].preview,
746
- alt: `Private preview of ${content.name}`,
747
- width: 800,
748
- height: 600
782
+ src: `${apiPath}/submissions/${initial.id}/media/${photo.id}`,
783
+ alt: photo.caption || content.name,
784
+ width: 640,
785
+ height: 480
786
+ }
787
+ ),
788
+ /* @__PURE__ */ jsxRuntime.jsx("figcaption", { children: photo.attribution })
789
+ ] }, photo.id)),
790
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { className: "paw-photo-picker", children: [
791
+ "Authentic photographs",
792
+ /* @__PURE__ */ jsxRuntime.jsx(
793
+ "input",
794
+ {
795
+ type: "file",
796
+ className: "paw-upload-input",
797
+ required: ["spotlight", "photo", "adoption"].includes(kind) && !files.length && !initial?.media.length,
798
+ "aria-describedby": "paw-photo-guidance",
799
+ accept: "image/jpeg,image/png,image/webp",
800
+ multiple: true,
801
+ onChange: (e) => {
802
+ const selected = Array.from(e.target.files || []);
803
+ if (selected.length + (initial?.media.length || 0) > 10 || selected.some(
804
+ (f) => f.size > 8 * 1024 * 1024 || !["image/jpeg", "image/png", "image/webp"].includes(
805
+ f.type
806
+ )
807
+ )) {
808
+ setError(
809
+ "Choose up to ten JPEG, PNG or WebP photographs, each under 8 MB."
810
+ );
811
+ return;
812
+ }
813
+ setError("");
814
+ setFiles(
815
+ selected.map((file) => ({
816
+ file,
817
+ key: crypto.randomUUID(),
818
+ preview: URL.createObjectURL(file)
819
+ }))
820
+ );
821
+ }
749
822
  }
750
823
  ),
751
- /* @__PURE__ */ jsxRuntime.jsx("figcaption", { children: content.attribution })
824
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "paw-upload-prompt", children: [
825
+ /* @__PURE__ */ jsxRuntime.jsxs(
826
+ "svg",
827
+ {
828
+ viewBox: "0 0 32 32",
829
+ width: "32",
830
+ height: "32",
831
+ fill: "none",
832
+ stroke: "currentColor",
833
+ strokeWidth: "1.5",
834
+ "aria-hidden": "true",
835
+ children: [
836
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M11 8l2-3h6l2 3h5a3 3 0 013 3v13a3 3 0 01-3 3H6a3 3 0 01-3-3V11a3 3 0 013-3z" }),
837
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "16", cy: "17", r: "6" })
838
+ ]
839
+ }
840
+ ),
841
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: files.length ? `${files.length} ${files.length === 1 ? "photo" : "photos"} selected` : content.category === "memorial" ? "A photograph to remember them by." : ["lost", "found"].includes(kind) ? "A clear photograph helps neighbors recognize them." : "Their best angle. Their biggest personality." }),
842
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: files.length ? "Choose different photos" : "Choose photos from your device" })
843
+ ] })
752
844
  ] }),
753
- /* @__PURE__ */ jsxRuntime.jsx("p", { style: { whiteSpace: "pre-wrap" }, children: content.story })
754
- ]
755
- }
756
- ),
757
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: kind === "profile" && visibility === "private" ? "This profile will remain private." : "This is a private preview. Editors will review your contribution before anyone else can see it." }),
758
- needsPermission && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
759
- /* @__PURE__ */ jsxRuntime.jsxs("details", { children: [
760
- /* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Publication permission and guidelines" }),
761
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: policy.text }),
762
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: policy.guidelines })
763
- ] }),
764
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "paw-consent", children: [
765
- /* @__PURE__ */ jsxRuntime.jsx(
766
- "input",
767
- {
768
- type: "checkbox",
769
- required: true,
770
- checked: consent,
771
- onChange: (e) => setConsent(e.target.checked)
772
- }
773
- ),
774
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "I have read and accept the publication permission. These are authentic photographs I have permission to share." })
845
+ /* @__PURE__ */ jsxRuntime.jsx("small", { id: "paw-photo-guidance", children: "JPEG, PNG or WebP, up to 8 MB each. Photos are checked before publication and location metadata is removed." }),
846
+ files.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
847
+ "div",
848
+ {
849
+ className: "paw-upload-previews",
850
+ "aria-label": "Selected photographs",
851
+ children: files.map((file) => /* @__PURE__ */ jsxRuntime.jsxs("figure", { children: [
852
+ /* @__PURE__ */ jsxRuntime.jsx(
853
+ "img",
854
+ {
855
+ src: file.preview,
856
+ alt: `Selected photograph: ${file.file.name}`,
857
+ width: 160,
858
+ height: 160
859
+ }
860
+ ),
861
+ /* @__PURE__ */ jsxRuntime.jsx("figcaption", { children: file.file.name })
862
+ ] }, file.key))
863
+ }
864
+ ),
865
+ ["lost", "found"].includes(kind) && /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "paw-safety", children: [
866
+ PET_SAFETY.recovery,
867
+ " Private recovery contact is not available yet."
868
+ ] })
869
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
870
+ /* @__PURE__ */ jsxRuntime.jsxs(
871
+ "article",
872
+ {
873
+ className: content.category === "memorial" ? "paw-memorial" : "",
874
+ children: [
875
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "paw-context", children: communities.find((c) => c.id === community)?.name }),
876
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: content.name }),
877
+ !files.length && initial?.media[0] && /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: "paw-photo", children: [
878
+ /* @__PURE__ */ jsxRuntime.jsx(
879
+ "img",
880
+ {
881
+ src: `${apiPath}/submissions/${initial.id}/media/${initial.media[0].id}`,
882
+ alt: initial.media[0].caption || content.name,
883
+ width: 800,
884
+ height: 600
885
+ }
886
+ ),
887
+ /* @__PURE__ */ jsxRuntime.jsx("figcaption", { children: initial.media[0].attribution })
888
+ ] }),
889
+ files[0] && /* @__PURE__ */ jsxRuntime.jsxs("figure", { className: "paw-photo", children: [
890
+ /* @__PURE__ */ jsxRuntime.jsx(
891
+ "img",
892
+ {
893
+ src: files[0].preview,
894
+ alt: `Private preview of ${content.name}`,
895
+ width: 800,
896
+ height: 600
897
+ }
898
+ ),
899
+ /* @__PURE__ */ jsxRuntime.jsx("figcaption", { children: content.attribution })
900
+ ] }),
901
+ /* @__PURE__ */ jsxRuntime.jsx("p", { style: { whiteSpace: "pre-wrap" }, children: content.story })
902
+ ]
903
+ }
904
+ ),
905
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: kind === "profile" && visibility === "private" ? "This profile will remain private." : "This is a private preview. Editors will review your contribution before anyone else can see it." }),
906
+ needsPermission && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
907
+ /* @__PURE__ */ jsxRuntime.jsxs("details", { children: [
908
+ /* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Publication permission and guidelines" }),
909
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: policy.text }),
910
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: policy.guidelines })
911
+ ] }),
912
+ /* @__PURE__ */ jsxRuntime.jsxs(PetField, { className: "paw-consent", children: [
913
+ /* @__PURE__ */ jsxRuntime.jsx(
914
+ "input",
915
+ {
916
+ type: "checkbox",
917
+ required: true,
918
+ checked: consent,
919
+ onChange: (e) => setConsent(e.target.checked)
920
+ }
921
+ ),
922
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: "I have read and accept the publication permission. These are authentic photographs I have permission to share." })
923
+ ] })
924
+ ] })
925
+ ] }),
926
+ Object.keys(fieldErrors).length > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "paw-validation-summary", children: "A few details need your attention. Check the fields above." }),
927
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "paw-error", children: error }),
928
+ busy && /* @__PURE__ */ jsxRuntime.jsxs(PetField, { children: [
929
+ "Saving your contribution",
930
+ /* @__PURE__ */ jsxRuntime.jsx("progress", { value: progress, max: files.length + 2 })
931
+ ] }),
932
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "paw-form-actions", children: [
933
+ step === 1 && /* @__PURE__ */ jsxRuntime.jsx(
934
+ "button",
935
+ {
936
+ type: "button",
937
+ disabled: busy,
938
+ onClick: () => {
939
+ setFieldErrors({});
940
+ setStep(0);
941
+ formRef.current?.scrollIntoView({ block: "start" });
942
+ },
943
+ children: "Keep editing"
944
+ }
945
+ ),
946
+ /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, type: "submit", children: busy ? "Saving\u2026" : step === 0 ? "Preview your story" : kind === "profile" && visibility === "private" ? "Save private profile" : "Submit for editorial review" })
947
+ ] }),
948
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "paw-form-endnote", children: step === 0 ? "Next: a private preview. Nothing is published yet." : kind === "profile" && visibility === "private" ? "Only you can see this private profile." : "Your contribution stays private until editorial approval." })
775
949
  ] })
776
- ] })
777
- ] }),
778
- error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "paw-error", children: error }),
779
- busy && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
780
- "Saving your contribution",
781
- /* @__PURE__ */ jsxRuntime.jsx("progress", { value: progress, max: files.length + 2 })
782
- ] }),
783
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "paw-form-actions", children: [
784
- step === 1 && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", disabled: busy, onClick: () => setStep(0), children: "Keep editing" }),
785
- /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, type: "submit", children: busy ? "Saving\u2026" : step === 0 ? "Preview your story" : kind === "profile" && visibility === "private" ? "Save private profile" : "Submit for editorial review" })
786
- ] })
787
- ]
950
+ ]
951
+ }
952
+ )
788
953
  }
789
954
  );
790
955
  }
@@ -793,7 +958,7 @@ function PetOwnerActions({
793
958
  apiPath = "/api/pets",
794
959
  submitUrl = "/submit"
795
960
  }) {
796
- const [error, setError] = react.useState(""), [confirm, setConfirm] = react.useState(false), [busy, setBusy] = react.useState(false);
961
+ const [error, setError] = React.useState(""), [confirm, setConfirm] = React.useState(false), [busy, setBusy] = React.useState(false);
797
962
  async function act(action) {
798
963
  setBusy(true);
799
964
  setError("");