@scalemule/news-publication 0.0.26 → 0.0.27

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.
@@ -65,11 +65,25 @@ function EditorialNotices({ editorial }) {
65
65
  var human = (s) => s.toLowerCase().replaceAll("_", " ");
66
66
  function StoryReview({
67
67
  sessionId,
68
- publicationName
68
+ publicationName,
69
+ nameplateUrl
69
70
  }) {
70
71
  const base = `/api/news/review/${encodeURIComponent(sessionId)}`;
71
72
  const [review, setReview] = react.useState(null), [error, setError] = react.useState(""), [notice, setNotice] = react.useState(""), [busy, setBusy] = react.useState(false), [panel, setPanel] = react.useState("article"), [verification, setVerification] = react.useState(false), [code, setCode] = react.useState("");
72
73
  const [message, setMessage] = react.useState(""), [document, setDocument] = react.useState(null), [answers, setAnswers] = react.useState({}), [file, setFile] = react.useState(null), [rights, setRights] = react.useState(false), [compare, setCompare] = react.useState(""), [compareTo, setCompareTo] = react.useState(""), [editingMedia, setEditingMedia] = react.useState(""), [commentTarget, setCommentTarget] = react.useState("STORY");
74
+ const responseRef = react.useRef(null);
75
+ const thanksRef = react.useRef(null);
76
+ const [moreQuestions, setMoreQuestions] = react.useState(false);
77
+ const [correctionKind, setCorrectionKind] = react.useState("Correct a detail");
78
+ react.useEffect(() => {
79
+ if (panel !== "article") {
80
+ responseRef.current?.scrollIntoView({
81
+ block: "start",
82
+ behavior: window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? "auto" : "smooth"
83
+ });
84
+ responseRef.current?.focus({ preventScroll: true });
85
+ }
86
+ }, [panel]);
73
87
  const [mediaInfo, setMediaInfo] = react.useState({
74
88
  caption: "",
75
89
  who_is_pictured: "",
@@ -155,6 +169,21 @@ function StoryReview({
155
169
  }
156
170
  }
157
171
  const can = (p) => review?.permissions.includes(p);
172
+ const celebration = !!review?.celebration_type;
173
+ const approved = review?.decision === "APPROVED";
174
+ const finalEditor = review?.review_policy === "SUBJECT_APPROVAL_PLUS_EDITOR";
175
+ const approvalThanks = `Thank you. We're glad to help commemorate this special occasion. This version has been sent to the ${review?.publication.name || publicationName} newsroom for final editorial review. It has not been published yet.`;
176
+ react.useEffect(() => {
177
+ if (approved && finalEditor && thanksRef.current) {
178
+ thanksRef.current.scrollIntoView({ block: "start" });
179
+ thanksRef.current.focus({ preventScroll: true });
180
+ }
181
+ }, [approved, finalEditor]);
182
+ const approve = () => {
183
+ if (celebration && finalEditor && !review?.questions.some((q) => q.required))
184
+ void send({ action: "APPROVE", message: null }, approvalThanks);
185
+ else setPanel("approve");
186
+ };
158
187
  async function upload() {
159
188
  if (!review || !file || !rights) return;
160
189
  setBusy(true);
@@ -187,486 +216,637 @@ function StoryReview({
187
216
  const selected = revisions.find((r) => r.id === compare), selectedAfter = revisions.find(
188
217
  (r) => r.id === (compareTo || review?.revision.id)
189
218
  );
190
- return /* @__PURE__ */ jsxRuntime.jsxs("main", { className: "sm-story-review", children: [
191
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-review-private", children: [
192
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Private story preview" }),
193
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: review?.published ? "This revision has been published. This review link remains private." : "This article has not been published." })
194
- ] }),
195
- /* @__PURE__ */ jsxRuntime.jsx("header", { className: "sm-review-masthead", children: review?.publication.name || publicationName }),
196
- error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "sm-review-alert", children: error }),
197
- notice && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", className: "sm-review-notice", children: notice }),
198
- verification && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "sm-review-form", children: [
199
- /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Verify your email" }),
200
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: "The editor requires verification using the email address on your invitation. Your story remains private until verified." }),
201
- /* @__PURE__ */ jsxRuntime.jsx(
202
- "button",
203
- {
204
- disabled: busy,
205
- onClick: async () => {
206
- setBusy(true);
207
- setError("");
208
- try {
209
- await request("/verify", {});
210
- setNotice(
211
- "A code was sent to the email address chosen by the editor. It expires in ten minutes."
212
- );
213
- } catch (e) {
214
- setError(
215
- e instanceof Error ? e.message : "Could not send code."
216
- );
217
- } finally {
218
- setBusy(false);
219
- }
220
- },
221
- children: "Email me a verification code"
222
- }
223
- ),
224
- /* @__PURE__ */ jsxRuntime.jsxs(
225
- "form",
226
- {
227
- onSubmit: async (e) => {
228
- e.preventDefault();
229
- setBusy(true);
230
- setError("");
231
- try {
232
- await request("/verify", { code });
233
- await load();
234
- setCode("");
235
- setNotice("Email verified.");
236
- } catch (e2) {
237
- setError(
238
- e2 instanceof Error ? e2.message : "Verification failed."
239
- );
240
- } finally {
241
- setBusy(false);
242
- }
243
- },
244
- children: [
245
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
246
- "Eight-digit code",
247
- /* @__PURE__ */ jsxRuntime.jsx(
248
- "input",
249
- {
250
- inputMode: "numeric",
251
- autoComplete: "one-time-code",
252
- pattern: "[0-9]{8}",
253
- required: true,
254
- value: code,
255
- onChange: (e) => setCode(e.target.value)
256
- }
257
- )
258
- ] }),
259
- /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, children: "Verify and open preview" })
260
- ]
261
- }
262
- )
263
- ] }),
264
- !review && !error && !verification && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: "Opening your private preview\u2026" }),
265
- review && document && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
266
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-review-intro", children: [
267
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
268
- "Prepared for ",
269
- review.reviewer,
270
- " \xB7 Version ",
271
- review.revision.number
272
- ] }),
273
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: ["FACT_CHECK", "CONTRIBUTOR_REVIEW"].includes(
274
- review.review_policy
275
- ) ? "Please help us check the facts and represent your contribution accurately. The newsroom retains the final editorial decision." : "This voluntary announcement requires subject approval before publication. You may request changes or decline participation." })
276
- ] }),
277
- /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "sm-review-article", children: [
278
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
279
- review.revision.document.section,
280
- review.revision.document.community && ` \xB7 ${review.revision.document.community}`
219
+ return /* @__PURE__ */ jsxRuntime.jsxs(
220
+ "main",
221
+ {
222
+ className: `sm-story-review${celebration ? " sm-review-celebration" : ""}`,
223
+ children: [
224
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-review-private", children: [
225
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: review?.published ? "Private review" : "Private preview \xB7 Not published" }),
226
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: review?.published ? "This revision has been published. This review link remains private." : `Prepared by ${publicationName} for ${celebration ? "family " : ""}review.` })
281
227
  ] }),
282
- /* @__PURE__ */ jsxRuntime.jsx("h1", { children: review.revision.document.title }),
283
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "sm-review-dek", children: review.revision.document.subtitle }),
284
- /* @__PURE__ */ jsxRuntime.jsx(EditorialNotices, { editorial: review.revision.editorial }),
285
- review.revision.document.media.filter((m) => m.position === "hero").map((m) => /* @__PURE__ */ jsxRuntime.jsx(PrivatePhoto, { media: m, base }, m.file_id)),
286
- /* @__PURE__ */ jsxRuntime.jsx(
287
- "div",
288
- {
289
- className: "sm-review-prose",
290
- dangerouslySetInnerHTML: { __html: review.revision.content_html }
291
- }
292
- ),
293
- review.revision.document.media.filter((m) => m.position !== "hero").map((m) => /* @__PURE__ */ jsxRuntime.jsx(PrivatePhoto, { media: m, base }, m.file_id))
294
- ] }),
295
- /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "sm-review-actions", "aria-label": "Review actions", children: [
296
- can("APPROVE") && !review.published && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("approve"), children: review.review_policy === "FACT_CHECK" ? "Confirm fact check" : "Approve draft" }),
297
- can("REQUEST_CHANGES") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("changes"), children: "Request changes" }),
298
- can("PROPOSE_EDITS") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("edits"), children: "Suggest edits" }),
299
- can("ANSWER_QUESTIONS") && review.questions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("questions"), children: "Answer questions" }),
300
- can("UPLOAD_MEDIA") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("media"), children: "Add photos" }),
301
- can("COMMENT") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("comment"), children: "Leave a comment" }),
302
- can("VIEW_SELECTED_HISTORY") && review.history.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setPanel("history"), children: "Shared history" }),
303
- can("DOWNLOAD_PREVIEW") && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => window.print(), children: "Print / save preview" })
304
- ] }),
305
- panel !== "article" && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "sm-review-form", "aria-label": "Your response", children: [
306
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-review-form-heading", children: [
307
- /* @__PURE__ */ jsxRuntime.jsx("h2", { children: panel === "approve" ? "Approve this exact draft" : panel === "edits" ? "Propose changes" : panel === "media" ? "Contribute a photograph" : panel === "questions" ? "Your story, in your words" : panel === "history" ? "Selected revision history" : panel === "decline" ? "Decline participation" : panel === "changes" ? "Request changes" : "Message the newsroom" }),
308
- /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("article"), children: "Close" })
228
+ /* @__PURE__ */ jsxRuntime.jsxs("header", { className: "sm-review-masthead", children: [
229
+ nameplateUrl && /* @__PURE__ */ jsxRuntime.jsx("img", { src: nameplateUrl, alt: "", width: 80, height: 80 }),
230
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: review?.publication.name || publicationName })
309
231
  ] }),
310
- panel === "edits" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
311
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Your suggestions will be reviewed by an editor. They do not replace the newsroom\u2019s draft." }),
312
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
313
- "Headline",
314
- /* @__PURE__ */ jsxRuntime.jsx(
315
- "input",
316
- {
317
- value: document.title,
318
- onChange: (e) => setDocument({ ...document, title: e.target.value })
319
- }
320
- )
321
- ] }),
322
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
323
- "Dek",
324
- /* @__PURE__ */ jsxRuntime.jsx(
325
- "input",
326
- {
327
- value: document.subtitle,
328
- onChange: (e) => setDocument({ ...document, subtitle: e.target.value })
329
- }
330
- )
331
- ] }),
332
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
333
- "Suggested article text",
334
- /* @__PURE__ */ jsxRuntime.jsx(
335
- "textarea",
336
- {
337
- rows: 16,
338
- value: document.content_markdown,
339
- onChange: (e) => setDocument({
340
- ...document,
341
- content_markdown: e.target.value
342
- })
343
- }
344
- )
345
- ] }),
232
+ error && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "alert", className: "sm-review-alert", children: error }),
233
+ notice && !(approved && finalEditor && notice === approvalThanks) && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", className: "sm-review-notice", children: notice }),
234
+ verification && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "sm-review-form", children: [
235
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Verify your email" }),
236
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "The editor requires verification using the email address on your invitation. Your story remains private until verified." }),
346
237
  /* @__PURE__ */ jsxRuntime.jsx(
347
238
  "button",
348
239
  {
349
240
  disabled: busy,
350
- onClick: () => void send(
351
- {
352
- action: "PROPOSE_EDITS",
353
- title: document.title,
354
- subtitle: document.subtitle,
355
- content_markdown: document.content_markdown,
356
- message
357
- },
358
- "Your proposed changes have been sent to the newsroom."
359
- ),
360
- children: "Send proposed changes"
241
+ onClick: async () => {
242
+ setBusy(true);
243
+ setError("");
244
+ try {
245
+ await request("/verify", {});
246
+ setNotice(
247
+ "A code was sent to the email address chosen by the editor. It expires in ten minutes."
248
+ );
249
+ } catch (e) {
250
+ setError(
251
+ e instanceof Error ? e.message : "Could not send code."
252
+ );
253
+ } finally {
254
+ setBusy(false);
255
+ }
256
+ },
257
+ children: "Email me a verification code"
361
258
  }
362
- )
363
- ] }),
364
- panel === "questions" && /* @__PURE__ */ jsxRuntime.jsxs(
365
- "form",
366
- {
367
- onSubmit: (e) => {
368
- e.preventDefault();
369
- void send(
370
- { action: "ANSWER_QUESTIONS", answers },
371
- "Your answers have been saved for editorial review."
372
- );
373
- },
374
- children: [
375
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: "All questions are optional unless marked required. Share only what you would like considered for publication." }),
376
- review.questions.map((q) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
377
- q.prompt,
378
- q.required ? " (required)" : " (optional)",
379
- /* @__PURE__ */ jsxRuntime.jsx(
380
- "textarea",
381
- {
382
- required: q.required,
383
- rows: 3,
384
- value: answers[q.id] || "",
385
- onChange: (e) => setAnswers({ ...answers, [q.id]: e.target.value })
386
- }
387
- )
388
- ] }, q.id)),
389
- /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, children: "Send answers" })
390
- ]
391
- }
392
- ),
393
- panel === "metadata" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
394
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Caption and credit changes are proposals for the newsroom; historical captions remain intact." }),
395
- ["caption", "credit", "alt"].map((key) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
396
- key,
397
- /* @__PURE__ */ jsxRuntime.jsx(
398
- "input",
399
- {
400
- value: mediaInfo[key],
401
- onChange: (e) => setMediaInfo({ ...mediaInfo, [key]: e.target.value })
402
- }
403
- )
404
- ] }, key)),
405
- /* @__PURE__ */ jsxRuntime.jsx(
406
- "button",
259
+ ),
260
+ /* @__PURE__ */ jsxRuntime.jsxs(
261
+ "form",
407
262
  {
408
- disabled: busy,
409
- onClick: () => void send(
410
- {
411
- action: "EDIT_MEDIA_METADATA",
412
- contribution_id: editingMedia,
413
- caption: mediaInfo.caption,
414
- credit: mediaInfo.credit,
415
- alt: mediaInfo.alt
416
- },
417
- "Your proposed media descriptions have been sent to the newsroom."
418
- ),
419
- children: "Propose caption / credit changes"
420
- }
421
- )
422
- ] }),
423
- panel === "media" && /* @__PURE__ */ jsxRuntime.jsxs(
424
- "form",
425
- {
426
- onSubmit: (e) => {
427
- e.preventDefault();
428
- void upload();
429
- },
430
- children: [
431
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: "JPEG, PNG or WebP photos up to 12 MB; MP4 or WebM videos up to 25 MB. Media remain private until selected and approved by the newsroom." }),
432
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
433
- "Photograph or video",
434
- /* @__PURE__ */ jsxRuntime.jsx(
435
- "input",
436
- {
437
- type: "file",
438
- accept: "image/jpeg,image/png,image/webp,video/mp4,video/webm",
439
- required: true,
440
- onChange: (e) => setFile(e.target.files?.[0] || null)
441
- }
442
- )
443
- ] }),
444
- Object.entries({
445
- caption: "Caption",
446
- who_is_pictured: "Who is pictured?",
447
- creator: "Photographer / creator",
448
- when_taken: "When was it taken?",
449
- where_taken: "Where was it taken?",
450
- credit: "Credit line",
451
- alt: "Alt-text suggestion"
452
- }).map(([key, label]) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
453
- label,
454
- /* @__PURE__ */ jsxRuntime.jsx(
455
- "input",
456
- {
457
- value: mediaInfo[key],
458
- onChange: (e) => setMediaInfo({ ...mediaInfo, [key]: e.target.value })
459
- }
460
- )
461
- ] }, key)),
462
- /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "sm-review-check", children: [
463
- /* @__PURE__ */ jsxRuntime.jsx(
464
- "input",
465
- {
466
- type: "checkbox",
467
- required: true,
468
- checked: rights,
469
- onChange: (e) => setRights(e.target.checked)
470
- }
471
- ),
472
- "I confirm that I have the right or permission to provide this media to ",
473
- review.publication.name,
474
- " for editorial publication."
475
- ] }),
476
- /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy || !rights || !file, children: "Upload privately" })
477
- ]
478
- }
479
- ),
480
- ["approve", "changes", "comment", "decline"].includes(panel) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
481
- panel === "approve" && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
482
- "You are approving version ",
483
- review.revision.number,
484
- ". Changes to the article require a new approval.",
485
- review.review_policy === "SUBJECT_APPROVAL_AUTO_PUBLISH" ? " The editor has configured this version to publish or schedule after the required approvals are received." : " The newsroom will complete its editorial workflow before publication."
486
- ] }),
487
- panel === "decline" && /* @__PURE__ */ jsxRuntime.jsx("p", { children: ["FACT_CHECK", "CONTRIBUTOR_REVIEW"].includes(
488
- review.review_policy
489
- ) ? "You can decline this review. The newsroom may still publish its reporting." : "Declining participation prevents publication of this voluntary announcement." }),
490
- panel === "comment" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
491
- "Comment on",
492
- /* @__PURE__ */ jsxRuntime.jsxs(
493
- "select",
494
- {
495
- value: commentTarget,
496
- onChange: (e) => setCommentTarget(e.target.value),
497
- children: [
498
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "STORY", children: "Entire story" }),
499
- review.revision.document.content_markdown.split(/\n\s*\n/).slice(0, 200).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: `PARAGRAPH:${i + 1}`, children: [
500
- "Paragraph ",
501
- i + 1
502
- ] }, i)),
503
- review.revision.document.media.map((m, i) => /* @__PURE__ */ jsxRuntime.jsxs(
504
- "option",
263
+ onSubmit: async (e) => {
264
+ e.preventDefault();
265
+ setBusy(true);
266
+ setError("");
267
+ try {
268
+ await request("/verify", { code });
269
+ await load();
270
+ setCode("");
271
+ setNotice("Email verified.");
272
+ } catch (e2) {
273
+ setError(
274
+ e2 instanceof Error ? e2.message : "Verification failed."
275
+ );
276
+ } finally {
277
+ setBusy(false);
278
+ }
279
+ },
280
+ children: [
281
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
282
+ "Eight-digit code",
283
+ /* @__PURE__ */ jsxRuntime.jsx(
284
+ "input",
505
285
  {
506
- value: `MEDIA:${m.contribution_id}`,
507
- children: [
508
- "Photo / caption ",
509
- i + 1
510
- ]
511
- },
512
- m.contribution_id
513
- )),
514
- review.questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: `QUESTION:${q.id}`, children: q.prompt }, q.id))
515
- ]
516
- }
517
- )
518
- ] }),
519
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
520
- panel === "changes" ? "What should change?" : "Message (optional)",
521
- /* @__PURE__ */ jsxRuntime.jsx(
522
- "textarea",
523
- {
524
- rows: 5,
525
- value: message,
526
- onChange: (e) => setMessage(e.target.value)
527
- }
528
- )
529
- ] }),
530
- /* @__PURE__ */ jsxRuntime.jsx(
531
- "button",
532
- {
533
- disabled: busy || panel === "changes" && !message.trim() || panel === "comment" && !message.trim(),
534
- onClick: () => void send(
535
- {
536
- action: panel === "approve" ? "APPROVE" : panel === "changes" ? "REQUEST_CHANGES" : panel === "decline" ? "DECLINE" : "COMMENT",
537
- message: message || null,
538
- ...panel === "comment" ? {
539
- target: {
540
- kind: commentTarget.split(":")[0],
541
- reference: commentTarget.split(":")[1] || null
286
+ inputMode: "numeric",
287
+ autoComplete: "one-time-code",
288
+ pattern: "[0-9]{8}",
289
+ required: true,
290
+ value: code,
291
+ onChange: (e) => setCode(e.target.value)
542
292
  }
543
- } : {}
544
- },
545
- panel === "approve" ? "Your approval has been recorded for this version." : panel === "decline" ? "Your decision has been recorded." : "Your message has been sent to the newsroom."
546
- ),
547
- children: panel === "approve" ? `Approve version ${review.revision.number}` : panel === "changes" ? "Send change request" : panel === "decline" ? "Decline participation" : "Send comment"
293
+ )
294
+ ] }),
295
+ /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, children: "Verify and open preview" })
296
+ ]
548
297
  }
549
298
  )
550
299
  ] }),
551
- panel === "history" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
552
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Only revisions selected by the editor are visible here." }),
553
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
554
- "Compare from",
555
- /* @__PURE__ */ jsxRuntime.jsxs(
556
- "select",
300
+ !review && !error && !verification && /* @__PURE__ */ jsxRuntime.jsx("p", { role: "status", children: "Opening your private preview\u2026" }),
301
+ review && document && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
302
+ celebration ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-review-intro", children: [
303
+ review.revision.number > 1 ? /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
304
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "Updated preview" }),
305
+ " \u2014 We incorporated the information you sent us."
306
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("p", { children: "A special occasion, thoughtfully told. Read your announcement below." }),
307
+ /* @__PURE__ */ jsxRuntime.jsx("a", { href: "#review-options", children: "Review options" })
308
+ ] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-review-intro", children: [
309
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
310
+ "Prepared for ",
311
+ review.reviewer,
312
+ " \xB7 Version",
313
+ " ",
314
+ review.revision.number
315
+ ] }),
316
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: ["FACT_CHECK", "CONTRIBUTOR_REVIEW"].includes(
317
+ review.review_policy
318
+ ) ? "Please help us check the facts and represent your contribution accurately. The newsroom retains the final editorial decision." : "Please review this announcement. You may suggest changes or decline participation." })
319
+ ] }),
320
+ approved && finalEditor && !review.published && /* @__PURE__ */ jsxRuntime.jsxs("section", { ref: thanksRef, tabIndex: -1, className: "sm-review-thanks", role: "status", children: [
321
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Thank you." }),
322
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "We're glad to help commemorate this special occasion." }),
323
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
324
+ "This version has been sent to the ",
325
+ review.publication.name,
326
+ " ",
327
+ "newsroom for final editorial review. It has not been published yet."
328
+ ] })
329
+ ] }),
330
+ /* @__PURE__ */ jsxRuntime.jsxs("article", { className: "sm-review-article", children: [
331
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { className: "sm-review-category", children: [
332
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: review.revision.document.section }),
333
+ celebration && /* @__PURE__ */ jsxRuntime.jsx("span", { children: human(review.celebration_type || "") })
334
+ ] }),
335
+ /* @__PURE__ */ jsxRuntime.jsx("h1", { children: review.revision.document.title }),
336
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "sm-review-dek", children: review.revision.document.subtitle }),
337
+ /* @__PURE__ */ jsxRuntime.jsx(EditorialNotices, { editorial: review.revision.editorial }),
338
+ review.revision.document.media.filter((m) => m.position === "hero").map((m) => /* @__PURE__ */ jsxRuntime.jsx(PrivatePhoto, { media: m, base }, m.file_id)),
339
+ celebration && !review.revision.document.media.some(
340
+ (m) => m.position === "hero"
341
+ ) && can("UPLOAD_MEDIA") && /* @__PURE__ */ jsxRuntime.jsxs(
342
+ "aside",
557
343
  {
558
- value: compare,
559
- onChange: (e) => setCompare(e.target.value),
344
+ className: "sm-review-photo-invitation",
345
+ "aria-label": "Family photograph",
560
346
  children: [
561
- /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Choose a shared revision" }),
562
- revisions.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: r.id, children: [
563
- "Version ",
564
- r.number
565
- ] }, r.id))
347
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
348
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: "A photograph makes it yours." }),
349
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Family photograph may be added before publication." })
350
+ ] }),
351
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setPanel("media"), children: "+ Add a photograph" })
566
352
  ]
567
353
  }
568
- )
569
- ] }),
570
- /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
571
- "Compare to",
572
- /* @__PURE__ */ jsxRuntime.jsx(
573
- "select",
574
- {
575
- value: compareTo || review.revision.id,
576
- onChange: (e) => setCompareTo(e.target.value),
577
- children: revisions.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: r.id, children: [
578
- "Version ",
579
- r.number
580
- ] }, r.id))
581
- }
582
- )
583
- ] }),
584
- selected && selectedAfter && /* @__PURE__ */ jsxRuntime.jsx(ReviewDiff, { before: selected, after: selectedAfter }),
585
- /* @__PURE__ */ jsxRuntime.jsxs("details", { children: [
586
- /* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Read selected revision" }),
587
- /* @__PURE__ */ jsxRuntime.jsx("h3", { children: selected?.document.title }),
588
- /* @__PURE__ */ jsxRuntime.jsx("p", { children: selected?.document.subtitle }),
589
- /* @__PURE__ */ jsxRuntime.jsx(EditorialNotices, { editorial: selected?.editorial }),
354
+ ),
590
355
  /* @__PURE__ */ jsxRuntime.jsx(
591
356
  "div",
592
357
  {
593
358
  className: "sm-review-prose",
594
- dangerouslySetInnerHTML: {
595
- __html: selected?.content_html || ""
596
- }
359
+ dangerouslySetInnerHTML: { __html: review.revision.content_html }
597
360
  }
598
361
  ),
599
- selected?.document.media.map((m) => /* @__PURE__ */ jsxRuntime.jsx(PrivatePhoto, { media: m, base }, m.file_id))
600
- ] })
601
- ] })
602
- ] }),
603
- review.contributions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "sm-review-contributions", children: [
604
- /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Your contributions and newsroom messages" }),
605
- review.contributions.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
606
- /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
607
- /* @__PURE__ */ jsxRuntime.jsx("strong", { children: human(c.kind) }),
608
- " \xB7 ",
609
- human(c.state)
362
+ review.revision.document.media.filter((m) => m.position !== "hero").map((m) => /* @__PURE__ */ jsxRuntime.jsx(PrivatePhoto, { media: m, base }, m.file_id))
610
363
  ] }),
611
- c.payload.target && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
612
- "Regarding ",
613
- human(c.payload.target.kind),
614
- " ",
615
- c.payload.target.reference
616
- ] }),
617
- c.payload.message && /* @__PURE__ */ jsxRuntime.jsx("p", { children: c.payload.message }),
618
- c.payload.answers && Object.entries(c.payload.answers).map(([q, a]) => /* @__PURE__ */ jsxRuntime.jsx("p", { children: a }, q)),
619
- c.kind === "MEDIA" && c.payload.file_id && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
620
- /* @__PURE__ */ jsxRuntime.jsx(
621
- PrivatePhoto,
622
- {
623
- base,
624
- media: {
625
- file_id: c.payload.file_id,
626
- caption: c.payload.caption || "",
627
- credit: c.payload.credit || "",
628
- alt: c.payload.caption || "",
629
- position: "gallery",
630
- contribution_id: c.id
631
- }
632
- }
633
- ),
634
- c.state !== "WITHDRAWN" && can("EDIT_MEDIA_METADATA") && /* @__PURE__ */ jsxRuntime.jsx(
364
+ celebration && /* @__PURE__ */ jsxRuntime.jsxs("section", { id: "review-options", className: "sm-review-welcome", children: [
365
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Help us make this just right" }),
366
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "We prepared this announcement as a starting point so you don't have to write anything yourself. If everything looks right, you can simply approve it." }),
367
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "If you'd like, you can also correct a detail, add photographs, or tell us a little more about the couple. We'll take care of turning any additional information into the next draft." }),
368
+ can("ANSWER_QUESTIONS") && review.questions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
635
369
  "button",
636
370
  {
637
371
  onClick: () => {
638
- setEditingMedia(c.id);
639
- setMediaInfo({
640
- ...mediaInfo,
641
- caption: c.payload.caption || "",
642
- credit: c.payload.credit || "",
643
- alt: c.payload.caption || ""
644
- });
645
- setPanel("metadata");
372
+ setMoreQuestions(false);
373
+ setPanel("questions");
646
374
  },
647
- children: "Suggest caption / credit changes"
375
+ children: "Tell Us More"
648
376
  }
649
377
  ),
650
- c.state !== "WITHDRAWN" && can("UPLOAD_MEDIA") && /* @__PURE__ */ jsxRuntime.jsx(
378
+ can("DECLINE") && !review.published && /* @__PURE__ */ jsxRuntime.jsx(
651
379
  "button",
652
380
  {
653
- disabled: busy,
654
- onClick: () => void send(
381
+ className: "sm-review-quiet",
382
+ onClick: () => setPanel("decline"),
383
+ children: "Prefer Not to Publish"
384
+ }
385
+ ),
386
+ can("COMMENT") && /* @__PURE__ */ jsxRuntime.jsx("button", { className: "sm-review-quiet", onClick: () => setPanel("comment"), children: "Leave a Comment" })
387
+ ] }),
388
+ /* @__PURE__ */ jsxRuntime.jsxs(
389
+ "nav",
390
+ {
391
+ className: `sm-review-actions${celebration ? " sm-review-concierge-actions" : ""}${panel !== "article" ? " sm-review-actions-editing" : ""}`,
392
+ "aria-label": "Review actions",
393
+ children: [
394
+ can("APPROVE") && !review.published && /* @__PURE__ */ jsxRuntime.jsx(
395
+ "button",
655
396
  {
656
- action: "WITHDRAW_MEDIA",
657
- contribution_id: c.id
658
- },
659
- "Your media has been withdrawn from consideration."
397
+ className: "sm-review-primary",
398
+ disabled: busy || approved || review.decision === "DECLINED",
399
+ onClick: approve,
400
+ children: approved ? "Thank you \u2014 Approved" : review.review_policy === "FACT_CHECK" ? "Confirm fact check" : celebration ? "Looks Good \u2014 Approve" : "Approve draft"
401
+ }
660
402
  ),
661
- children: "Withdraw this media"
662
- }
663
- )
664
- ] })
665
- ] }, c.id))
666
- ] }),
667
- can("DECLINE") && !review.published && /* @__PURE__ */ jsxRuntime.jsx("footer", { className: "sm-review-decline", children: /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("decline"), children: "Decline participation / please don\u2019t publish this announcement" }) })
668
- ] })
669
- ] });
403
+ can("REQUEST_CHANGES") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("changes"), children: celebration ? "Suggest a Change" : "Request changes" }),
404
+ celebration && can("PROPOSE_EDITS") && !can("REQUEST_CHANGES") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("edits"), children: "Suggest a Change" }),
405
+ can("UPLOAD_MEDIA") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("media"), children: celebration ? "Add Photos" : "Add photos" }),
406
+ !celebration && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
407
+ can("PROPOSE_EDITS") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("edits"), children: "Suggest edits" }),
408
+ can("ANSWER_QUESTIONS") && review.questions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("questions"), children: "Answer questions" }),
409
+ can("COMMENT") && /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("comment"), children: "Leave a comment" })
410
+ ] })
411
+ ]
412
+ }
413
+ ),
414
+ (can("VIEW_SELECTED_HISTORY") && review.history.length > 0 || can("DOWNLOAD_PREVIEW")) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-review-utilities", children: [
415
+ can("VIEW_SELECTED_HISTORY") && review.history.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setPanel("history"), children: "See previous previews" }),
416
+ can("DOWNLOAD_PREVIEW") && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => window.print(), children: "Print / save preview" })
417
+ ] }),
418
+ panel !== "article" && /* @__PURE__ */ jsxRuntime.jsxs(
419
+ "section",
420
+ {
421
+ ref: responseRef,
422
+ tabIndex: -1,
423
+ className: "sm-review-form",
424
+ "aria-label": "Your response",
425
+ children: [
426
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sm-review-form-heading", children: [
427
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: panel === "approve" ? "Approve this exact draft" : panel === "edits" ? "Propose changes" : panel === "media" ? "Contribute a photograph" : panel === "questions" ? "Tell us a little more" : panel === "history" ? "Selected revision history" : panel === "decline" ? "Prefer not to publish" : panel === "changes" ? "Suggest a change" : "Message the newsroom" }),
428
+ /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("article"), children: "Close" })
429
+ ] }),
430
+ panel === "edits" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
431
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Your suggestions will be reviewed by an editor. They do not replace the newsroom\u2019s draft." }),
432
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
433
+ "Headline",
434
+ /* @__PURE__ */ jsxRuntime.jsx(
435
+ "input",
436
+ {
437
+ value: document.title,
438
+ onChange: (e) => setDocument({ ...document, title: e.target.value })
439
+ }
440
+ )
441
+ ] }),
442
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
443
+ "Short introduction",
444
+ /* @__PURE__ */ jsxRuntime.jsx(
445
+ "input",
446
+ {
447
+ value: document.subtitle,
448
+ onChange: (e) => setDocument({ ...document, subtitle: e.target.value })
449
+ }
450
+ )
451
+ ] }),
452
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
453
+ "Suggested article text",
454
+ /* @__PURE__ */ jsxRuntime.jsx(
455
+ "textarea",
456
+ {
457
+ rows: 16,
458
+ value: document.content_markdown,
459
+ onChange: (e) => setDocument({
460
+ ...document,
461
+ content_markdown: e.target.value
462
+ })
463
+ }
464
+ )
465
+ ] }),
466
+ /* @__PURE__ */ jsxRuntime.jsx(
467
+ "button",
468
+ {
469
+ disabled: busy,
470
+ onClick: () => void send(
471
+ {
472
+ action: "PROPOSE_EDITS",
473
+ title: document.title,
474
+ subtitle: document.subtitle,
475
+ content_markdown: document.content_markdown,
476
+ message
477
+ },
478
+ "Your proposed changes have been sent to the newsroom."
479
+ ),
480
+ children: "Send proposed changes"
481
+ }
482
+ )
483
+ ] }),
484
+ panel === "questions" && /* @__PURE__ */ jsxRuntime.jsxs(
485
+ "form",
486
+ {
487
+ onSubmit: (e) => {
488
+ e.preventDefault();
489
+ void send(
490
+ { action: "ANSWER_QUESTIONS", answers },
491
+ "Thank you for sharing. We'll take care of turning your answers into an updated draft."
492
+ );
493
+ },
494
+ children: [
495
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: review.questions.some((q) => q.required) ? "Only questions marked required must be answered. Share what you would like considered for publication." : "Completely optional. Even one answer can help us make the announcement more personal." }),
496
+ review.questions.filter((q, i) => moreQuestions || i < 5 || q.required).map((q) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
497
+ q.prompt,
498
+ q.required ? " (required)" : " (optional)",
499
+ /* @__PURE__ */ jsxRuntime.jsx(
500
+ "textarea",
501
+ {
502
+ required: q.required,
503
+ rows: 3,
504
+ value: answers[q.id] || "",
505
+ onChange: (e) => setAnswers({ ...answers, [q.id]: e.target.value })
506
+ }
507
+ )
508
+ ] }, q.id)),
509
+ /* @__PURE__ */ jsxRuntime.jsx(
510
+ "button",
511
+ {
512
+ className: "sm-review-primary",
513
+ disabled: busy || !Object.values(answers).some((a) => a.trim()),
514
+ children: "Send These Answers"
515
+ }
516
+ ),
517
+ !moreQuestions && review.questions.length > 5 && /* @__PURE__ */ jsxRuntime.jsx(
518
+ "button",
519
+ {
520
+ type: "button",
521
+ onClick: () => setMoreQuestions(true),
522
+ children: "Answer More Questions"
523
+ }
524
+ )
525
+ ]
526
+ }
527
+ ),
528
+ panel === "metadata" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
529
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Caption and credit changes are proposals for the newsroom; historical captions remain intact." }),
530
+ ["caption", "credit", "alt"].map((key) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
531
+ key,
532
+ /* @__PURE__ */ jsxRuntime.jsx(
533
+ "input",
534
+ {
535
+ value: mediaInfo[key],
536
+ onChange: (e) => setMediaInfo({ ...mediaInfo, [key]: e.target.value })
537
+ }
538
+ )
539
+ ] }, key)),
540
+ /* @__PURE__ */ jsxRuntime.jsx(
541
+ "button",
542
+ {
543
+ disabled: busy,
544
+ onClick: () => void send(
545
+ {
546
+ action: "EDIT_MEDIA_METADATA",
547
+ contribution_id: editingMedia,
548
+ caption: mediaInfo.caption,
549
+ credit: mediaInfo.credit,
550
+ alt: mediaInfo.alt
551
+ },
552
+ "Your proposed media descriptions have been sent to the newsroom."
553
+ ),
554
+ children: "Propose caption / credit changes"
555
+ }
556
+ )
557
+ ] }),
558
+ panel === "media" && /* @__PURE__ */ jsxRuntime.jsxs(
559
+ "form",
560
+ {
561
+ onSubmit: (e) => {
562
+ e.preventDefault();
563
+ void upload();
564
+ },
565
+ children: [
566
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "JPEG, PNG or WebP photos up to 12 MB; MP4 or WebM videos up to 25 MB. Media remain private until selected and approved by the newsroom." }),
567
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
568
+ "Photograph or video",
569
+ /* @__PURE__ */ jsxRuntime.jsx(
570
+ "input",
571
+ {
572
+ type: "file",
573
+ accept: "image/jpeg,image/png,image/webp,video/mp4,video/webm",
574
+ required: true,
575
+ onChange: (e) => setFile(e.target.files?.[0] || null)
576
+ }
577
+ )
578
+ ] }),
579
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "sm-review-help", children: "Choose a photograph and confirm permission below. All descriptions are optional; we can help with the caption." }),
580
+ Object.entries({
581
+ caption: "Caption (optional)",
582
+ credit: "Photographer / credit (optional)"
583
+ }).map(([key, label]) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
584
+ label,
585
+ /* @__PURE__ */ jsxRuntime.jsx(
586
+ "input",
587
+ {
588
+ value: mediaInfo[key],
589
+ onChange: (e) => setMediaInfo({ ...mediaInfo, [key]: e.target.value })
590
+ }
591
+ )
592
+ ] }, key)),
593
+ /* @__PURE__ */ jsxRuntime.jsxs("details", { className: "sm-review-media-details", children: [
594
+ /* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Add more photograph details (optional)" }),
595
+ Object.entries({
596
+ who_is_pictured: "Who is pictured?",
597
+ creator: "Photographer / creator",
598
+ when_taken: "When was it taken?",
599
+ where_taken: "Where was it taken?",
600
+ alt: "Describe the photograph for readers who cannot see it"
601
+ }).map(([key, label]) => /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
602
+ label,
603
+ /* @__PURE__ */ jsxRuntime.jsx(
604
+ "input",
605
+ {
606
+ value: mediaInfo[key],
607
+ onChange: (e) => setMediaInfo({
608
+ ...mediaInfo,
609
+ [key]: e.target.value
610
+ })
611
+ }
612
+ )
613
+ ] }, key))
614
+ ] }),
615
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "sm-review-check", children: [
616
+ /* @__PURE__ */ jsxRuntime.jsx(
617
+ "input",
618
+ {
619
+ type: "checkbox",
620
+ required: true,
621
+ checked: rights,
622
+ onChange: (e) => setRights(e.target.checked)
623
+ }
624
+ ),
625
+ "I confirm that I have the right or permission to provide this media to ",
626
+ review.publication.name,
627
+ " for editorial publication."
628
+ ] }),
629
+ /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy || !rights || !file, children: "Upload privately" })
630
+ ]
631
+ }
632
+ ),
633
+ ["approve", "changes", "comment", "decline"].includes(panel) && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
634
+ panel === "approve" && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
635
+ "You are approving version ",
636
+ review.revision.number,
637
+ ". Changes to the article require a new approval.",
638
+ review.review_policy === "SUBJECT_APPROVAL_AUTO_PUBLISH" ? " The editor has configured this version to publish or schedule after the required approvals are received." : " The newsroom will complete its editorial workflow before publication."
639
+ ] }),
640
+ panel === "decline" && /* @__PURE__ */ jsxRuntime.jsx("p", { children: ["FACT_CHECK", "CONTRIBUTOR_REVIEW"].includes(
641
+ review.review_policy
642
+ ) ? "You can decline this review. The newsroom may still publish its reporting." : "Declining participation prevents publication of this voluntary announcement." }),
643
+ panel === "comment" && /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
644
+ "Comment on",
645
+ /* @__PURE__ */ jsxRuntime.jsxs(
646
+ "select",
647
+ {
648
+ value: commentTarget,
649
+ onChange: (e) => setCommentTarget(e.target.value),
650
+ children: [
651
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "STORY", children: "Entire story" }),
652
+ review.revision.document.content_markdown.split(/\n\s*\n/).slice(0, 200).map((_, i) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: `PARAGRAPH:${i + 1}`, children: [
653
+ "Paragraph ",
654
+ i + 1
655
+ ] }, i)),
656
+ review.revision.document.media.map((m, i) => /* @__PURE__ */ jsxRuntime.jsxs(
657
+ "option",
658
+ {
659
+ value: `MEDIA:${m.contribution_id}`,
660
+ children: [
661
+ "Photo / caption ",
662
+ i + 1
663
+ ]
664
+ },
665
+ m.contribution_id
666
+ )),
667
+ review.questions.map((q) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: `QUESTION:${q.id}`, children: q.prompt }, q.id))
668
+ ]
669
+ }
670
+ )
671
+ ] }),
672
+ panel === "changes" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
673
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
674
+ "What would you like to change?",
675
+ /* @__PURE__ */ jsxRuntime.jsx(
676
+ "select",
677
+ {
678
+ value: correctionKind,
679
+ onChange: (e) => setCorrectionKind(e.target.value),
680
+ children: [
681
+ "Correct a detail",
682
+ "Correct a name",
683
+ "Correct a professional / education detail",
684
+ "Remove something",
685
+ "Rewrite something",
686
+ "Add something",
687
+ "General comment"
688
+ ].map((kind) => /* @__PURE__ */ jsxRuntime.jsx("option", { children: kind }, kind))
689
+ }
690
+ )
691
+ ] }),
692
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "A sentence or two is enough. We'll take care of the wording." }),
693
+ can("PROPOSE_EDITS") && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => setPanel("edits"), children: "Or edit the wording directly" })
694
+ ] }),
695
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
696
+ panel === "changes" ? "What should change?" : "Message (optional)",
697
+ /* @__PURE__ */ jsxRuntime.jsx(
698
+ "textarea",
699
+ {
700
+ rows: 5,
701
+ value: message,
702
+ onChange: (e) => setMessage(e.target.value)
703
+ }
704
+ )
705
+ ] }),
706
+ /* @__PURE__ */ jsxRuntime.jsx(
707
+ "button",
708
+ {
709
+ disabled: busy || panel === "changes" && !message.trim() || panel === "comment" && !message.trim(),
710
+ onClick: () => void send(
711
+ {
712
+ action: panel === "approve" ? "APPROVE" : panel === "changes" ? "REQUEST_CHANGES" : panel === "decline" ? "DECLINE" : "COMMENT",
713
+ message: panel === "changes" ? `${correctionKind}: ${message}` : message || null,
714
+ ...panel === "comment" ? {
715
+ target: {
716
+ kind: commentTarget.split(":")[0],
717
+ reference: commentTarget.split(":")[1] || null
718
+ }
719
+ } : {}
720
+ },
721
+ panel === "approve" ? celebration && finalEditor ? approvalThanks : "Your approval has been recorded for this version." : panel === "decline" ? "Thank you for letting us know. The newsroom has received your decision." : "Your message has been sent to the newsroom."
722
+ ),
723
+ children: panel === "approve" ? `Approve version ${review.revision.number}` : panel === "changes" ? "Send change request" : panel === "decline" ? "Prefer not to publish" : "Send comment"
724
+ }
725
+ )
726
+ ] }),
727
+ panel === "history" && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
728
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: "Only revisions selected by the editor are visible here." }),
729
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
730
+ "Compare from",
731
+ /* @__PURE__ */ jsxRuntime.jsxs(
732
+ "select",
733
+ {
734
+ value: compare,
735
+ onChange: (e) => setCompare(e.target.value),
736
+ children: [
737
+ /* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Choose a shared revision" }),
738
+ revisions.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: r.id, children: [
739
+ "Version ",
740
+ r.number
741
+ ] }, r.id))
742
+ ]
743
+ }
744
+ )
745
+ ] }),
746
+ /* @__PURE__ */ jsxRuntime.jsxs("label", { children: [
747
+ "Compare to",
748
+ /* @__PURE__ */ jsxRuntime.jsx(
749
+ "select",
750
+ {
751
+ value: compareTo || review.revision.id,
752
+ onChange: (e) => setCompareTo(e.target.value),
753
+ children: revisions.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: r.id, children: [
754
+ "Version ",
755
+ r.number
756
+ ] }, r.id))
757
+ }
758
+ )
759
+ ] }),
760
+ selected && selectedAfter && /* @__PURE__ */ jsxRuntime.jsx(ReviewDiff, { before: selected, after: selectedAfter }),
761
+ /* @__PURE__ */ jsxRuntime.jsxs("details", { children: [
762
+ /* @__PURE__ */ jsxRuntime.jsx("summary", { children: "Read selected revision" }),
763
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { children: selected?.document.title }),
764
+ /* @__PURE__ */ jsxRuntime.jsx("p", { children: selected?.document.subtitle }),
765
+ /* @__PURE__ */ jsxRuntime.jsx(EditorialNotices, { editorial: selected?.editorial }),
766
+ /* @__PURE__ */ jsxRuntime.jsx(
767
+ "div",
768
+ {
769
+ className: "sm-review-prose",
770
+ dangerouslySetInnerHTML: {
771
+ __html: selected?.content_html || ""
772
+ }
773
+ }
774
+ ),
775
+ selected?.document.media.map((m) => /* @__PURE__ */ jsxRuntime.jsx(PrivatePhoto, { media: m, base }, m.file_id))
776
+ ] })
777
+ ] })
778
+ ]
779
+ }
780
+ ),
781
+ review.contributions.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("section", { className: "sm-review-contributions", children: [
782
+ /* @__PURE__ */ jsxRuntime.jsx("h2", { children: "Your contributions and newsroom messages" }),
783
+ review.contributions.map((c) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
784
+ /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
785
+ /* @__PURE__ */ jsxRuntime.jsx("strong", { children: human(c.kind) }),
786
+ " \xB7 ",
787
+ human(c.state)
788
+ ] }),
789
+ c.payload.target && /* @__PURE__ */ jsxRuntime.jsxs("p", { children: [
790
+ "Regarding ",
791
+ human(c.payload.target.kind),
792
+ " ",
793
+ c.payload.target.reference
794
+ ] }),
795
+ c.payload.message && /* @__PURE__ */ jsxRuntime.jsx("p", { children: c.payload.message }),
796
+ c.payload.answers && Object.entries(c.payload.answers).map(([q, a]) => /* @__PURE__ */ jsxRuntime.jsx("p", { children: a }, q)),
797
+ c.kind === "MEDIA" && c.payload.file_id && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
798
+ /* @__PURE__ */ jsxRuntime.jsx(
799
+ PrivatePhoto,
800
+ {
801
+ base,
802
+ media: {
803
+ file_id: c.payload.file_id,
804
+ caption: c.payload.caption || "",
805
+ credit: c.payload.credit || "",
806
+ alt: c.payload.caption || "",
807
+ position: "gallery",
808
+ contribution_id: c.id
809
+ }
810
+ }
811
+ ),
812
+ c.state !== "WITHDRAWN" && can("EDIT_MEDIA_METADATA") && /* @__PURE__ */ jsxRuntime.jsx(
813
+ "button",
814
+ {
815
+ onClick: () => {
816
+ setEditingMedia(c.id);
817
+ setMediaInfo({
818
+ ...mediaInfo,
819
+ caption: c.payload.caption || "",
820
+ credit: c.payload.credit || "",
821
+ alt: c.payload.caption || ""
822
+ });
823
+ setPanel("metadata");
824
+ },
825
+ children: "Suggest caption / credit changes"
826
+ }
827
+ ),
828
+ c.state !== "WITHDRAWN" && can("UPLOAD_MEDIA") && /* @__PURE__ */ jsxRuntime.jsx(
829
+ "button",
830
+ {
831
+ disabled: busy,
832
+ onClick: () => void send(
833
+ {
834
+ action: "WITHDRAW_MEDIA",
835
+ contribution_id: c.id
836
+ },
837
+ "Your media has been withdrawn from consideration."
838
+ ),
839
+ children: "Withdraw this media"
840
+ }
841
+ )
842
+ ] })
843
+ ] }, c.id))
844
+ ] }),
845
+ !celebration && can("DECLINE") && !review.published && /* @__PURE__ */ jsxRuntime.jsx("footer", { className: "sm-review-decline", children: /* @__PURE__ */ jsxRuntime.jsx("button", { disabled: busy, onClick: () => setPanel("decline"), children: "Decline participation / please don\u2019t publish this announcement" }) })
846
+ ] })
847
+ ]
848
+ }
849
+ );
670
850
  }
671
851
  function PrivatePhoto({ base, media }) {
672
852
  const [url, setUrl] = react.useState("");