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