@burdenoff/microfe-hookmovies 2026.705.2 → 2026.706.2

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.
Files changed (31) hide show
  1. package/dist/hookmovies/HookMoviesRoutes.js +26 -6
  2. package/dist/hookmovies/HookMoviesRoutes.js.map +1 -1
  3. package/dist/hookmovies/components/index.js +7 -0
  4. package/dist/hookmovies/hooks/index.js +1 -0
  5. package/dist/hookmovies/hooks/useFiles.js +97 -0
  6. package/dist/hookmovies/hooks/useFiles.js.map +1 -0
  7. package/dist/hookmovies/hooks/useHookMoviesApi.js +204 -52
  8. package/dist/hookmovies/hooks/useHookMoviesApi.js.map +1 -1
  9. package/dist/hookmovies/pages/HomePage.js +2 -2
  10. package/dist/hookmovies/pages/HomePage.js.map +1 -1
  11. package/dist/hookmovies/pages/auditions/AuditionDetailPage.js +100 -45
  12. package/dist/hookmovies/pages/auditions/AuditionDetailPage.js.map +1 -1
  13. package/dist/hookmovies/pages/catalog/TitleDetailPage.js +1340 -266
  14. package/dist/hookmovies/pages/catalog/TitleDetailPage.js.map +1 -1
  15. package/dist/hookmovies/pages/catalog/TitlesPage.js +95 -74
  16. package/dist/hookmovies/pages/catalog/TitlesPage.js.map +1 -1
  17. package/dist/hookmovies/pages/consumer/DiscoveryPage.js +422 -0
  18. package/dist/hookmovies/pages/consumer/DiscoveryPage.js.map +1 -0
  19. package/dist/hookmovies/pages/consumer/HooksPage.js +252 -0
  20. package/dist/hookmovies/pages/consumer/HooksPage.js.map +1 -0
  21. package/dist/hookmovies/pages/consumer/PlayerPage.js +542 -0
  22. package/dist/hookmovies/pages/consumer/PlayerPage.js.map +1 -0
  23. package/dist/hookmovies/pages/consumer/TitleViewPage.js +424 -0
  24. package/dist/hookmovies/pages/consumer/TitleViewPage.js.map +1 -0
  25. package/dist/hookmovies/pages/distribution/RightsWindowsPage.js +1 -1
  26. package/dist/hookmovies/pages/distribution/RightsWindowsPage.js.map +1 -1
  27. package/dist/hookmovies/pages/library/EntitlementsPage.js +273 -75
  28. package/dist/hookmovies/pages/library/EntitlementsPage.js.map +1 -1
  29. package/dist/hookmovies/pages/library/ListsPage.js +186 -106
  30. package/dist/hookmovies/pages/library/ListsPage.js.map +1 -1
  31. package/package.json +1 -1
@@ -1,17 +1,18 @@
1
1
  import { useHookMovies as e } from "../../context/HookMoviesContext.js";
2
2
  import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { StatusBadge as n } from "../../components/StatusBadge.js";
4
- import { useApplyToAudition as r, useAuditionApplications as i, useAuditionById as a, useCloseAudition as o, useScoreApplication as s } from "../../hooks/useHookMoviesApi.js";
5
- import { formatDate as c, formatMinorUnits as l, formatRelativeTime as u } from "../../utils/formatters.js";
4
+ import { useApplyToAudition as r, useAuditionApplications as i, useAuditionById as ee, useCloseAudition as te, useScoreApplication as a } from "../../hooks/useHookMoviesApi.js";
5
+ import { formatDate as o, formatMinorUnits as s, formatRelativeTime as c } from "../../utils/formatters.js";
6
+ import { FILE_FOLDERS as l, uploadFileToFiles as u } from "../../hooks/useFiles.js";
6
7
  import { ErrorState as d, LoadingState as f } from "../../components/StateViews.js";
7
- import { useState as p } from "react";
8
- import { ArrowLeft as m, Clock as h, Coins as g, Languages as _, Lock as v, MapPin as y, Send as b, Users as x } from "lucide-react";
9
- import { useParams as S } from "react-router-dom";
10
- import { jsx as C, jsxs as w } from "react/jsx-runtime";
8
+ import { useRef as p, useState as m } from "react";
9
+ import { ArrowLeft as h, Clock as g, Coins as ne, Film as _, Languages as v, Loader2 as y, Lock as b, MapPin as x, Send as re, Upload as ie, Users as ae, X as oe } from "lucide-react";
10
+ import { useParams as se } from "react-router-dom";
11
+ import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
11
12
  import { GlassCard as T } from "@burdenoff/fe-libs/ui";
12
13
  //#region src/hookmovies/pages/auditions/AuditionDetailPage.tsx
13
14
  var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]", D = () => {
14
- let { id: D } = S(), { navigateTo: O } = e(), { data: k, isLoading: A, isError: j, refetch: M } = a(D), N = i(D), P = r(), F = s(), I = o(), [L, R] = p(""), [z, B] = p(""), [V, H] = p(null), [U, W] = p(!1), [G, K] = p(null);
15
+ let { id: D } = se(), { navigateTo: O } = e(), { data: k, isLoading: A, isError: j, refetch: M } = ee(D), N = i(D), P = r(), F = a(), I = te(), [L, R] = m(""), [z, B] = m(""), [V, H] = m(""), [U, W] = m(!1), [G, K] = m(null), [q, J] = m(null), [ce, le] = m(!1), [Y, X] = m(null), Z = p(null);
15
16
  if (A) return /* @__PURE__ */ C(t, {
16
17
  title: "Audition",
17
18
  children: /* @__PURE__ */ C(f, { label: "Loading audition…" })
@@ -23,28 +24,43 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
23
24
  onRetry: () => void M()
24
25
  })
25
26
  });
26
- let q = async (e) => {
27
- e.preventDefault(), H(null);
27
+ let ue = async (e) => {
28
+ e.preventDefault(), J(null);
28
29
  try {
29
30
  await P.mutateAsync({
30
31
  auditionId: k.id,
31
32
  coverNote: L.trim() || void 0,
32
33
  selfTapeFileId: z.trim() || void 0
33
- }), W(!0), R(""), B("");
34
+ }), le(!0), R(""), B(""), H("");
34
35
  } catch (e) {
35
- H(e instanceof Error ? e.message : "Failed to apply");
36
+ J(e instanceof Error ? e.message : "Failed to apply");
36
37
  }
37
- }, J = async (e, t) => {
38
- K(null);
38
+ }, de = async (e) => {
39
+ let t = e.target.files?.[0];
40
+ if (e.target.value = "", t) {
41
+ K(null), W(!0);
42
+ try {
43
+ let e = await u(t, l.selfTapes);
44
+ B(e.id), H(e.name || t.name);
45
+ } catch (e) {
46
+ K(e instanceof Error ? e.message : "Failed to upload self-tape");
47
+ } finally {
48
+ W(!1);
49
+ }
50
+ }
51
+ }, fe = () => {
52
+ B(""), H(""), K(null);
53
+ }, pe = async (e, t) => {
54
+ X(null);
39
55
  try {
40
56
  await F.mutateAsync({
41
57
  id: e,
42
58
  score: t
43
59
  });
44
60
  } catch (e) {
45
- K(e instanceof Error ? e.message : "Failed to score");
61
+ X(e instanceof Error ? e.message : "Failed to score");
46
62
  }
47
- }, Y = k.status === "OPEN", X = N.data ?? [];
63
+ }, Q = k.status === "OPEN", $ = N.data ?? [];
48
64
  return /* @__PURE__ */ C(t, {
49
65
  title: /* @__PURE__ */ w("span", {
50
66
  className: "flex items-center gap-3",
@@ -53,18 +69,18 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
53
69
  onClick: () => O("auditions"),
54
70
  className: "rounded-md p-1 text-text-secondary hover:text-text-primary",
55
71
  "aria-label": "Back to auditions",
56
- children: /* @__PURE__ */ C(m, { className: "h-5 w-5" })
72
+ children: /* @__PURE__ */ C(h, { className: "h-5 w-5" })
57
73
  }), k.roleName]
58
74
  }),
59
75
  description: k.production?.title ?? "Casting call",
60
76
  actions: /* @__PURE__ */ w("div", {
61
77
  className: "flex items-center gap-2",
62
- children: [/* @__PURE__ */ C(n, { status: k.status }), Y && /* @__PURE__ */ w("button", {
78
+ children: [/* @__PURE__ */ C(n, { status: k.status }), Q && /* @__PURE__ */ w("button", {
63
79
  type: "button",
64
80
  disabled: I.isPending,
65
81
  onClick: () => void I.mutateAsync(k.id),
66
82
  className: "inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50 transition-colors",
67
- children: [/* @__PURE__ */ C(v, { className: "h-3.5 w-3.5" }), "Close"]
83
+ children: [/* @__PURE__ */ C(b, { className: "h-3.5 w-3.5" }), "Close"]
68
84
  })]
69
85
  }),
70
86
  children: /* @__PURE__ */ w("div", {
@@ -88,25 +104,25 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
88
104
  /* @__PURE__ */ w("h2", {
89
105
  className: "mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary",
90
106
  children: [
91
- /* @__PURE__ */ C(x, { className: "h-4 w-4" }),
107
+ /* @__PURE__ */ C(ae, { className: "h-4 w-4" }),
92
108
  "Applicants (",
93
- X.length,
109
+ $.length,
94
110
  ")"
95
111
  ]
96
112
  }),
97
- G && /* @__PURE__ */ C("div", {
113
+ Y && /* @__PURE__ */ C("div", {
98
114
  className: "mb-3 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text",
99
- children: G
115
+ children: Y
100
116
  }),
101
117
  N.isLoading ? /* @__PURE__ */ C(f, {
102
118
  label: "Loading applicants…",
103
119
  className: "min-h-[120px]"
104
- }) : X.length === 0 ? /* @__PURE__ */ C("p", {
120
+ }) : $.length === 0 ? /* @__PURE__ */ C("p", {
105
121
  className: "text-sm text-text-secondary",
106
122
  children: "No applications yet."
107
123
  }) : /* @__PURE__ */ C("ul", {
108
124
  className: "space-y-3",
109
- children: X.map((e) => /* @__PURE__ */ w("li", {
125
+ children: $.map((e) => /* @__PURE__ */ w("li", {
110
126
  className: "rounded-lg border border-border-seam bg-bg-surface p-3",
111
127
  children: [
112
128
  /* @__PURE__ */ w("div", {
@@ -118,7 +134,7 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
118
134
  children: ["Applicant ", e.applicantId.slice(0, 8)]
119
135
  }), /* @__PURE__ */ w("p", {
120
136
  className: "text-xs text-text-secondary",
121
- children: ["Applied ", u(e.createdAt)]
137
+ children: ["Applied ", c(e.createdAt)]
122
138
  })]
123
139
  }), /* @__PURE__ */ C(n, { status: e.status })]
124
140
  }),
@@ -140,7 +156,7 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
140
156
  ].map((t) => /* @__PURE__ */ C("button", {
141
157
  type: "button",
142
158
  disabled: F.isPending,
143
- onClick: () => void J(e.id, t),
159
+ onClick: () => void pe(e.id, t),
144
160
  className: e.score === t ? "h-7 w-7 rounded-md bg-action-primary-bg text-xs font-semibold text-action-primary-text" : "h-7 w-7 rounded-md border border-border-seam text-xs text-text-primary hover:bg-bg-sunken transition-colors",
145
161
  children: t
146
162
  }, t))]
@@ -167,17 +183,17 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
167
183
  className: "flex items-center justify-between",
168
184
  children: [/* @__PURE__ */ w("dt", {
169
185
  className: "flex items-center gap-2 text-text-secondary",
170
- children: [/* @__PURE__ */ C(g, { className: "h-3.5 w-3.5" }), "Pay"]
186
+ children: [/* @__PURE__ */ C(ne, { className: "h-3.5 w-3.5" }), "Pay"]
171
187
  }), /* @__PURE__ */ C("dd", {
172
188
  className: "font-medium text-text-primary",
173
- children: l(k.payMinorUnits, k.currency)
189
+ children: s(k.payMinorUnits, k.currency)
174
190
  })]
175
191
  }),
176
192
  k.location && /* @__PURE__ */ w("div", {
177
193
  className: "flex items-center justify-between",
178
194
  children: [/* @__PURE__ */ w("dt", {
179
195
  className: "flex items-center gap-2 text-text-secondary",
180
- children: [/* @__PURE__ */ C(y, { className: "h-3.5 w-3.5" }), "Location"]
196
+ children: [/* @__PURE__ */ C(x, { className: "h-3.5 w-3.5" }), "Location"]
181
197
  }), /* @__PURE__ */ C("dd", {
182
198
  className: "font-medium text-text-primary",
183
199
  children: k.location
@@ -187,7 +203,7 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
187
203
  className: "flex items-center justify-between",
188
204
  children: [/* @__PURE__ */ w("dt", {
189
205
  className: "flex items-center gap-2 text-text-secondary",
190
- children: [/* @__PURE__ */ C(_, { className: "h-3.5 w-3.5" }), "Language"]
206
+ children: [/* @__PURE__ */ C(v, { className: "h-3.5 w-3.5" }), "Language"]
191
207
  }), /* @__PURE__ */ C("dd", {
192
208
  className: "font-medium text-text-primary",
193
209
  children: k.language
@@ -197,10 +213,10 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
197
213
  className: "flex items-center justify-between",
198
214
  children: [/* @__PURE__ */ w("dt", {
199
215
  className: "flex items-center gap-2 text-text-secondary",
200
- children: [/* @__PURE__ */ C(h, { className: "h-3.5 w-3.5" }), "Deadline"]
216
+ children: [/* @__PURE__ */ C(g, { className: "h-3.5 w-3.5" }), "Deadline"]
201
217
  }), /* @__PURE__ */ C("dd", {
202
218
  className: "font-medium text-text-primary",
203
- children: c(k.submissionDeadline, {
219
+ children: o(k.submissionDeadline, {
204
220
  hour: void 0,
205
221
  minute: void 0
206
222
  })
@@ -219,16 +235,16 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
219
235
  children: [/* @__PURE__ */ C("h2", {
220
236
  className: "mb-3 text-sm font-semibold text-text-primary",
221
237
  children: "Apply"
222
- }), U ? /* @__PURE__ */ C("p", {
238
+ }), ce ? /* @__PURE__ */ C("p", {
223
239
  className: "rounded-lg bg-status-success-bg-subtle px-3 py-2 text-sm text-status-success-text",
224
240
  children: "Your application has been submitted."
225
- }) : Y ? /* @__PURE__ */ w("form", {
226
- onSubmit: q,
241
+ }) : Q ? /* @__PURE__ */ w("form", {
242
+ onSubmit: ue,
227
243
  className: "space-y-3",
228
244
  children: [
229
- V && /* @__PURE__ */ C("div", {
245
+ q && /* @__PURE__ */ C("div", {
230
246
  className: "rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text",
231
- children: V
247
+ children: q
232
248
  }),
233
249
  /* @__PURE__ */ C("textarea", {
234
250
  value: L,
@@ -237,18 +253,57 @@ var E = "w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 t
237
253
  placeholder: "Cover note (why you're right for this role)",
238
254
  className: E
239
255
  }),
240
- /* @__PURE__ */ C("input", {
241
- type: "text",
242
- value: z,
243
- onChange: (e) => B(e.target.value),
244
- placeholder: "Self-tape file ID (optional)",
245
- className: E
256
+ /* @__PURE__ */ w("div", {
257
+ className: "space-y-2",
258
+ children: [
259
+ /* @__PURE__ */ C("label", {
260
+ htmlFor: "self-tape-upload",
261
+ className: "block text-xs font-medium text-text-secondary",
262
+ children: "Self-tape (optional)"
263
+ }),
264
+ /* @__PURE__ */ C("input", {
265
+ ref: Z,
266
+ id: "self-tape-upload",
267
+ type: "file",
268
+ accept: "video/*",
269
+ onChange: (e) => void de(e),
270
+ disabled: U,
271
+ className: "sr-only",
272
+ "aria-label": "Upload self-tape video"
273
+ }),
274
+ z ? /* @__PURE__ */ w("div", {
275
+ className: "flex items-center justify-between gap-2 rounded-lg border border-border-seam bg-bg-surface px-3 py-2",
276
+ children: [/* @__PURE__ */ w("span", {
277
+ className: "flex min-w-0 items-center gap-2 text-sm text-text-primary",
278
+ children: [/* @__PURE__ */ C(_, { className: "h-4 w-4 shrink-0 text-status-success-text" }), /* @__PURE__ */ C("span", {
279
+ className: "truncate",
280
+ children: V || "Self-tape uploaded"
281
+ })]
282
+ }), /* @__PURE__ */ C("button", {
283
+ type: "button",
284
+ onClick: fe,
285
+ className: "rounded-md p-1 text-text-secondary hover:text-text-primary",
286
+ "aria-label": "Remove self-tape",
287
+ children: /* @__PURE__ */ C(oe, { className: "h-4 w-4" })
288
+ })]
289
+ }) : /* @__PURE__ */ C("button", {
290
+ type: "button",
291
+ onClick: () => Z.current?.click(),
292
+ disabled: U,
293
+ className: "inline-flex w-full items-center justify-center gap-2 rounded-lg border border-dashed border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-secondary hover:border-border-seam hover:text-text-primary disabled:opacity-50 transition-colors",
294
+ children: U ? /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(y, { className: "h-4 w-4 animate-spin" }), "Uploading…"] }) : /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C(ie, { className: "h-4 w-4" }), "Upload self-tape video"] })
295
+ }),
296
+ G && /* @__PURE__ */ C("p", {
297
+ className: "rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text",
298
+ children: G
299
+ })
300
+ ]
246
301
  }),
247
302
  /* @__PURE__ */ w("button", {
248
303
  type: "submit",
249
- disabled: P.isPending,
304
+ disabled: P.isPending || U,
250
305
  className: "inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50 transition-opacity",
251
- children: [/* @__PURE__ */ C(b, { className: "h-4 w-4" }), P.isPending ? "Submitting…" : "Submit Application"]
306
+ children: [/* @__PURE__ */ C(re, { className: "h-4 w-4" }), P.isPending ? "Submitting…" : "Submit Application"]
252
307
  })
253
308
  ]
254
309
  }) : /* @__PURE__ */ C("p", {
@@ -1 +1 @@
1
- {"version":3,"file":"AuditionDetailPage.js","names":[],"sources":["../../../../src/hookmovies/pages/auditions/AuditionDetailPage.tsx"],"sourcesContent":["/**\n * Audition detail (Casting marketplace)\n * @module hookmovies/pages/auditions\n *\n * Two-sided surface:\n * - Talent can apply via `hokApplyToAudition` (self-scoped).\n * - Casting teams screen applicants from `hokListApplications`, score them via\n * `hokScoreApplication`, and close the call with `hokCloseAudition`.\n */\n\nimport { type FC, type FormEvent, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport { ArrowLeft, MapPin, Languages, Clock, Coins, Send, Lock, Users } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingState, ErrorState } from '../../components/StateViews';\nimport { useHookMovies } from '../../context/HookMoviesContext';\nimport {\n useAuditionById,\n useAuditionApplications,\n useApplyToAudition,\n useScoreApplication,\n useCloseAudition,\n} from '../../hooks/useHookMoviesApi';\nimport { formatDate, formatMinorUnits, formatRelativeTime } from '../../utils/formatters';\n\nconst fieldClass =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\nexport const AuditionDetailPage: FC = () => {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useHookMovies();\n const { data: audition, isLoading, isError, refetch } = useAuditionById(id);\n const applications = useAuditionApplications(id);\n const apply = useApplyToAudition();\n const score = useScoreApplication();\n const closeAudition = useCloseAudition();\n\n const [coverNote, setCoverNote] = useState('');\n const [selfTapeFileId, setSelfTapeFileId] = useState('');\n const [applyError, setApplyError] = useState<string | null>(null);\n const [applied, setApplied] = useState(false);\n const [scoreError, setScoreError] = useState<string | null>(null);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Audition\">\n <LoadingState label=\"Loading audition…\" />\n </PageLayout>\n );\n }\n\n if (isError || !audition) {\n return (\n <PageLayout title=\"Audition\">\n <ErrorState title=\"Audition not found\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n const handleApply = async (e: FormEvent) => {\n e.preventDefault();\n setApplyError(null);\n try {\n await apply.mutateAsync({\n auditionId: audition.id,\n coverNote: coverNote.trim() || undefined,\n selfTapeFileId: selfTapeFileId.trim() || undefined,\n });\n setApplied(true);\n setCoverNote('');\n setSelfTapeFileId('');\n } catch (err) {\n setApplyError(err instanceof Error ? err.message : 'Failed to apply');\n }\n };\n\n const handleScore = async (applicationId: string, value: number) => {\n setScoreError(null);\n try {\n await score.mutateAsync({ id: applicationId, score: value });\n } catch (err) {\n setScoreError(err instanceof Error ? err.message : 'Failed to score');\n }\n };\n\n const isOpen = audition.status === 'OPEN';\n const applicationItems = applications.data ?? [];\n\n return (\n <PageLayout\n title={\n <span className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('auditions')}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n aria-label=\"Back to auditions\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n {audition.roleName}\n </span>\n }\n description={audition.production?.title ?? 'Casting call'}\n actions={\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={audition.status} />\n {isOpen && (\n <button\n type=\"button\"\n disabled={closeAudition.isPending}\n onClick={() => void closeAudition.mutateAsync(audition.id)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50 transition-colors\"\n >\n <Lock className=\"h-3.5 w-3.5\" />\n Close\n </button>\n )}\n </div>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"space-y-6 lg:col-span-2\">\n {audition.description && (\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h2 className=\"mb-2 text-sm font-semibold text-text-primary\">Role Description</h2>\n <p className=\"text-sm leading-relaxed text-text-secondary\">{audition.description}</p>\n </GlassCard>\n )}\n\n {/* Applicants (casting view) */}\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h2 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Users className=\"h-4 w-4\" />\n Applicants ({applicationItems.length})\n </h2>\n {scoreError && (\n <div className=\"mb-3 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {scoreError}\n </div>\n )}\n {applications.isLoading ? (\n <LoadingState label=\"Loading applicants…\" className=\"min-h-[120px]\" />\n ) : applicationItems.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">No applications yet.</p>\n ) : (\n <ul className=\"space-y-3\">\n {applicationItems.map((appn) => (\n <li\n key={appn.id}\n className=\"rounded-lg border border-border-seam bg-bg-surface p-3\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n Applicant {appn.applicantId.slice(0, 8)}\n </p>\n <p className=\"text-xs text-text-secondary\">\n Applied {formatRelativeTime(appn.createdAt)}\n </p>\n </div>\n <StatusBadge status={appn.status} />\n </div>\n {appn.coverNote && (\n <p className=\"mt-2 text-sm text-text-secondary\">{appn.coverNote}</p>\n )}\n <div className=\"mt-3 flex items-center gap-2\">\n <span className=\"text-xs text-text-secondary\">Score:</span>\n {[1, 2, 3, 4, 5].map((value) => (\n <button\n key={value}\n type=\"button\"\n disabled={score.isPending}\n onClick={() => void handleScore(appn.id, value)}\n className={\n appn.score === value\n ? 'h-7 w-7 rounded-md bg-action-primary-bg text-xs font-semibold text-action-primary-text'\n : 'h-7 w-7 rounded-md border border-border-seam text-xs text-text-primary hover:bg-bg-sunken transition-colors'\n }\n >\n {value}\n </button>\n ))}\n </div>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n </div>\n\n <div className=\"space-y-6\">\n {/* Details */}\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h2 className=\"mb-3 text-sm font-semibold text-text-primary\">Details</h2>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex items-center justify-between\">\n <dt className=\"flex items-center gap-2 text-text-secondary\">\n <Coins className=\"h-3.5 w-3.5\" />\n Pay\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {formatMinorUnits(audition.payMinorUnits, audition.currency)}\n </dd>\n </div>\n {audition.location && (\n <div className=\"flex items-center justify-between\">\n <dt className=\"flex items-center gap-2 text-text-secondary\">\n <MapPin className=\"h-3.5 w-3.5\" />\n Location\n </dt>\n <dd className=\"font-medium text-text-primary\">{audition.location}</dd>\n </div>\n )}\n {audition.language && (\n <div className=\"flex items-center justify-between\">\n <dt className=\"flex items-center gap-2 text-text-secondary\">\n <Languages className=\"h-3.5 w-3.5\" />\n Language\n </dt>\n <dd className=\"font-medium text-text-primary\">{audition.language}</dd>\n </div>\n )}\n {audition.submissionDeadline && (\n <div className=\"flex items-center justify-between\">\n <dt className=\"flex items-center gap-2 text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" />\n Deadline\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDate(audition.submissionDeadline, {\n hour: undefined,\n minute: undefined,\n })}\n </dd>\n </div>\n )}\n </dl>\n {audition.isMinorRole && (\n <p className=\"mt-3 rounded-lg bg-status-warning-bg-subtle px-3 py-2 text-xs text-status-warning-text\">\n This is a minor role. Guardian consent and restricted communications apply.\n </p>\n )}\n </GlassCard>\n\n {/* Apply (talent view) */}\n <GlassCard treatment=\"glass\" className=\"border-border-seam p-5\">\n <h2 className=\"mb-3 text-sm font-semibold text-text-primary\">Apply</h2>\n {applied ? (\n <p className=\"rounded-lg bg-status-success-bg-subtle px-3 py-2 text-sm text-status-success-text\">\n Your application has been submitted.\n </p>\n ) : !isOpen ? (\n <p className=\"text-sm text-text-secondary\">This audition is no longer open.</p>\n ) : (\n <form onSubmit={handleApply} className=\"space-y-3\">\n {applyError && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {applyError}\n </div>\n )}\n <textarea\n value={coverNote}\n onChange={(e) => setCoverNote(e.target.value)}\n rows={3}\n placeholder=\"Cover note (why you're right for this role)\"\n className={fieldClass}\n />\n <input\n type=\"text\"\n value={selfTapeFileId}\n onChange={(e) => setSelfTapeFileId(e.target.value)}\n placeholder=\"Self-tape file ID (optional)\"\n className={fieldClass}\n />\n <button\n type=\"submit\"\n disabled={apply.isPending}\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50 transition-opacity\"\n >\n <Send className=\"h-4 w-4\" />\n {apply.isPending ? 'Submitting…' : 'Submit Application'}\n </button>\n </form>\n )}\n </GlassCard>\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"AuditionDetailPage.js","names":[],"sources":["../../../../src/hookmovies/pages/auditions/AuditionDetailPage.tsx"],"sourcesContent":["/**\n * Audition detail (Casting marketplace)\n * @module hookmovies/pages/auditions\n *\n * Two-sided surface:\n * - Talent can apply via `hokApplyToAudition` (self-scoped).\n * - Casting teams screen applicants from `hokListApplications`, score them via\n * `hokScoreApplication`, and close the call with `hokCloseAudition`.\n */\n\nimport { type ChangeEvent, type FC, type FormEvent, useRef, useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n MapPin,\n Languages,\n Clock,\n Coins,\n Send,\n Lock,\n Users,\n Upload,\n Film,\n Loader2,\n X,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { LoadingState, ErrorState } from '../../components/StateViews';\nimport { useHookMovies } from '../../context/HookMoviesContext';\nimport {\n useAuditionById,\n useAuditionApplications,\n useApplyToAudition,\n useScoreApplication,\n useCloseAudition,\n} from '../../hooks/useHookMoviesApi';\nimport { uploadFileToFiles, FILE_FOLDERS } from '../../hooks/useFiles';\nimport { formatDate, formatMinorUnits, formatRelativeTime } from '../../utils/formatters';\n\nconst fieldClass =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\nexport const AuditionDetailPage: FC = () => {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useHookMovies();\n const { data: audition, isLoading, isError, refetch } = useAuditionById(id);\n const applications = useAuditionApplications(id);\n const apply = useApplyToAudition();\n const score = useScoreApplication();\n const closeAudition = useCloseAudition();\n\n const [coverNote, setCoverNote] = useState('');\n const [selfTapeFileId, setSelfTapeFileId] = useState('');\n const [selfTapeName, setSelfTapeName] = useState('');\n const [uploading, setUploading] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n const [applyError, setApplyError] = useState<string | null>(null);\n const [applied, setApplied] = useState(false);\n const [scoreError, setScoreError] = useState<string | null>(null);\n const fileInputRef = useRef<HTMLInputElement>(null);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Audition\">\n <LoadingState label=\"Loading audition…\" />\n </PageLayout>\n );\n }\n\n if (isError || !audition) {\n return (\n <PageLayout title=\"Audition\">\n <ErrorState title=\"Audition not found\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n const handleApply = async (e: FormEvent) => {\n e.preventDefault();\n setApplyError(null);\n try {\n await apply.mutateAsync({\n auditionId: audition.id,\n coverNote: coverNote.trim() || undefined,\n selfTapeFileId: selfTapeFileId.trim() || undefined,\n });\n setApplied(true);\n setCoverNote('');\n setSelfTapeFileId('');\n setSelfTapeName('');\n } catch (err) {\n setApplyError(err instanceof Error ? err.message : 'Failed to apply');\n }\n };\n\n const handleSelfTapeChange = async (e: ChangeEvent<HTMLInputElement>) => {\n const file = e.target.files?.[0];\n // Reset the input so re-selecting the same file re-triggers change.\n e.target.value = '';\n if (!file) return;\n setUploadError(null);\n setUploading(true);\n try {\n const uploaded = await uploadFileToFiles(file, FILE_FOLDERS.selfTapes);\n setSelfTapeFileId(uploaded.id);\n setSelfTapeName(uploaded.name || file.name);\n } catch (err) {\n setUploadError(err instanceof Error ? err.message : 'Failed to upload self-tape');\n } finally {\n setUploading(false);\n }\n };\n\n const clearSelfTape = () => {\n setSelfTapeFileId('');\n setSelfTapeName('');\n setUploadError(null);\n };\n\n const handleScore = async (applicationId: string, value: number) => {\n setScoreError(null);\n try {\n await score.mutateAsync({ id: applicationId, score: value });\n } catch (err) {\n setScoreError(err instanceof Error ? err.message : 'Failed to score');\n }\n };\n\n const isOpen = audition.status === 'OPEN';\n const applicationItems = applications.data ?? [];\n\n return (\n <PageLayout\n title={\n <span className=\"flex items-center gap-3\">\n <button\n type=\"button\"\n onClick={() => navigateTo('auditions')}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n aria-label=\"Back to auditions\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n {audition.roleName}\n </span>\n }\n description={audition.production?.title ?? 'Casting call'}\n actions={\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={audition.status} />\n {isOpen && (\n <button\n type=\"button\"\n disabled={closeAudition.isPending}\n onClick={() => void closeAudition.mutateAsync(audition.id)}\n className=\"inline-flex items-center gap-1 rounded-lg border border-border-seam px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken disabled:opacity-50 transition-colors\"\n >\n <Lock className=\"h-3.5 w-3.5\" />\n Close\n </button>\n )}\n </div>\n }\n >\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"space-y-6 lg:col-span-2\">\n {audition.description && (\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h2 className=\"mb-2 text-sm font-semibold text-text-primary\">Role Description</h2>\n <p className=\"text-sm leading-relaxed text-text-secondary\">{audition.description}</p>\n </GlassCard>\n )}\n\n {/* Applicants (casting view) */}\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h2 className=\"mb-3 flex items-center gap-2 text-sm font-semibold text-text-primary\">\n <Users className=\"h-4 w-4\" />\n Applicants ({applicationItems.length})\n </h2>\n {scoreError && (\n <div className=\"mb-3 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {scoreError}\n </div>\n )}\n {applications.isLoading ? (\n <LoadingState label=\"Loading applicants…\" className=\"min-h-[120px]\" />\n ) : applicationItems.length === 0 ? (\n <p className=\"text-sm text-text-secondary\">No applications yet.</p>\n ) : (\n <ul className=\"space-y-3\">\n {applicationItems.map((appn) => (\n <li\n key={appn.id}\n className=\"rounded-lg border border-border-seam bg-bg-surface p-3\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"min-w-0\">\n <p className=\"truncate text-sm font-medium text-text-primary\">\n Applicant {appn.applicantId.slice(0, 8)}\n </p>\n <p className=\"text-xs text-text-secondary\">\n Applied {formatRelativeTime(appn.createdAt)}\n </p>\n </div>\n <StatusBadge status={appn.status} />\n </div>\n {appn.coverNote && (\n <p className=\"mt-2 text-sm text-text-secondary\">{appn.coverNote}</p>\n )}\n <div className=\"mt-3 flex items-center gap-2\">\n <span className=\"text-xs text-text-secondary\">Score:</span>\n {[1, 2, 3, 4, 5].map((value) => (\n <button\n key={value}\n type=\"button\"\n disabled={score.isPending}\n onClick={() => void handleScore(appn.id, value)}\n className={\n appn.score === value\n ? 'h-7 w-7 rounded-md bg-action-primary-bg text-xs font-semibold text-action-primary-text'\n : 'h-7 w-7 rounded-md border border-border-seam text-xs text-text-primary hover:bg-bg-sunken transition-colors'\n }\n >\n {value}\n </button>\n ))}\n </div>\n </li>\n ))}\n </ul>\n )}\n </GlassCard>\n </div>\n\n <div className=\"space-y-6\">\n {/* Details */}\n <GlassCard treatment=\"metric\" className=\"border-border-seam p-5\">\n <h2 className=\"mb-3 text-sm font-semibold text-text-primary\">Details</h2>\n <dl className=\"space-y-2 text-sm\">\n <div className=\"flex items-center justify-between\">\n <dt className=\"flex items-center gap-2 text-text-secondary\">\n <Coins className=\"h-3.5 w-3.5\" />\n Pay\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {formatMinorUnits(audition.payMinorUnits, audition.currency)}\n </dd>\n </div>\n {audition.location && (\n <div className=\"flex items-center justify-between\">\n <dt className=\"flex items-center gap-2 text-text-secondary\">\n <MapPin className=\"h-3.5 w-3.5\" />\n Location\n </dt>\n <dd className=\"font-medium text-text-primary\">{audition.location}</dd>\n </div>\n )}\n {audition.language && (\n <div className=\"flex items-center justify-between\">\n <dt className=\"flex items-center gap-2 text-text-secondary\">\n <Languages className=\"h-3.5 w-3.5\" />\n Language\n </dt>\n <dd className=\"font-medium text-text-primary\">{audition.language}</dd>\n </div>\n )}\n {audition.submissionDeadline && (\n <div className=\"flex items-center justify-between\">\n <dt className=\"flex items-center gap-2 text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" />\n Deadline\n </dt>\n <dd className=\"font-medium text-text-primary\">\n {formatDate(audition.submissionDeadline, {\n hour: undefined,\n minute: undefined,\n })}\n </dd>\n </div>\n )}\n </dl>\n {audition.isMinorRole && (\n <p className=\"mt-3 rounded-lg bg-status-warning-bg-subtle px-3 py-2 text-xs text-status-warning-text\">\n This is a minor role. Guardian consent and restricted communications apply.\n </p>\n )}\n </GlassCard>\n\n {/* Apply (talent view) */}\n <GlassCard treatment=\"glass\" className=\"border-border-seam p-5\">\n <h2 className=\"mb-3 text-sm font-semibold text-text-primary\">Apply</h2>\n {applied ? (\n <p className=\"rounded-lg bg-status-success-bg-subtle px-3 py-2 text-sm text-status-success-text\">\n Your application has been submitted.\n </p>\n ) : !isOpen ? (\n <p className=\"text-sm text-text-secondary\">This audition is no longer open.</p>\n ) : (\n <form onSubmit={handleApply} className=\"space-y-3\">\n {applyError && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {applyError}\n </div>\n )}\n <textarea\n value={coverNote}\n onChange={(e) => setCoverNote(e.target.value)}\n rows={3}\n placeholder=\"Cover note (why you're right for this role)\"\n className={fieldClass}\n />\n <div className=\"space-y-2\">\n <label\n htmlFor=\"self-tape-upload\"\n className=\"block text-xs font-medium text-text-secondary\"\n >\n Self-tape (optional)\n </label>\n <input\n ref={fileInputRef}\n id=\"self-tape-upload\"\n type=\"file\"\n accept=\"video/*\"\n onChange={(e) => void handleSelfTapeChange(e)}\n disabled={uploading}\n className=\"sr-only\"\n aria-label=\"Upload self-tape video\"\n />\n {selfTapeFileId ? (\n <div className=\"flex items-center justify-between gap-2 rounded-lg border border-border-seam bg-bg-surface px-3 py-2\">\n <span className=\"flex min-w-0 items-center gap-2 text-sm text-text-primary\">\n <Film className=\"h-4 w-4 shrink-0 text-status-success-text\" />\n <span className=\"truncate\">{selfTapeName || 'Self-tape uploaded'}</span>\n </span>\n <button\n type=\"button\"\n onClick={clearSelfTape}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n aria-label=\"Remove self-tape\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n ) : (\n <button\n type=\"button\"\n onClick={() => fileInputRef.current?.click()}\n disabled={uploading}\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg border border-dashed border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-secondary hover:border-border-seam hover:text-text-primary disabled:opacity-50 transition-colors\"\n >\n {uploading ? (\n <>\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n Uploading…\n </>\n ) : (\n <>\n <Upload className=\"h-4 w-4\" />\n Upload self-tape video\n </>\n )}\n </button>\n )}\n {uploadError && (\n <p className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-xs text-status-error-text\">\n {uploadError}\n </p>\n )}\n </div>\n <button\n type=\"submit\"\n disabled={apply.isPending || uploading}\n className=\"inline-flex w-full items-center justify-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50 transition-opacity\"\n >\n <Send className=\"h-4 w-4\" />\n {apply.isPending ? 'Submitting…' : 'Submit Application'}\n </button>\n </form>\n )}\n </GlassCard>\n </div>\n </div>\n </PageLayout>\n );\n};\n"],"mappings":"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"}