@scalemule/news-publication 0.0.27 → 0.0.29

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