@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.
- package/dist/hookmovies/HookMoviesRoutes.js +26 -6
- package/dist/hookmovies/HookMoviesRoutes.js.map +1 -1
- package/dist/hookmovies/components/index.js +7 -0
- package/dist/hookmovies/hooks/index.js +1 -0
- package/dist/hookmovies/hooks/useFiles.js +97 -0
- package/dist/hookmovies/hooks/useFiles.js.map +1 -0
- package/dist/hookmovies/hooks/useHookMoviesApi.js +204 -52
- package/dist/hookmovies/hooks/useHookMoviesApi.js.map +1 -1
- package/dist/hookmovies/pages/HomePage.js +2 -2
- package/dist/hookmovies/pages/HomePage.js.map +1 -1
- package/dist/hookmovies/pages/auditions/AuditionDetailPage.js +100 -45
- package/dist/hookmovies/pages/auditions/AuditionDetailPage.js.map +1 -1
- package/dist/hookmovies/pages/catalog/TitleDetailPage.js +1340 -266
- package/dist/hookmovies/pages/catalog/TitleDetailPage.js.map +1 -1
- package/dist/hookmovies/pages/catalog/TitlesPage.js +95 -74
- package/dist/hookmovies/pages/catalog/TitlesPage.js.map +1 -1
- package/dist/hookmovies/pages/consumer/DiscoveryPage.js +422 -0
- package/dist/hookmovies/pages/consumer/DiscoveryPage.js.map +1 -0
- package/dist/hookmovies/pages/consumer/HooksPage.js +252 -0
- package/dist/hookmovies/pages/consumer/HooksPage.js.map +1 -0
- package/dist/hookmovies/pages/consumer/PlayerPage.js +542 -0
- package/dist/hookmovies/pages/consumer/PlayerPage.js.map +1 -0
- package/dist/hookmovies/pages/consumer/TitleViewPage.js +424 -0
- package/dist/hookmovies/pages/consumer/TitleViewPage.js.map +1 -0
- package/dist/hookmovies/pages/distribution/RightsWindowsPage.js +1 -1
- package/dist/hookmovies/pages/distribution/RightsWindowsPage.js.map +1 -1
- package/dist/hookmovies/pages/library/EntitlementsPage.js +273 -75
- package/dist/hookmovies/pages/library/EntitlementsPage.js.map +1 -1
- package/dist/hookmovies/pages/library/ListsPage.js +186 -106
- package/dist/hookmovies/pages/library/ListsPage.js.map +1 -1
- 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
|
|
5
|
-
import { formatDate as
|
|
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 {
|
|
8
|
-
import { ArrowLeft as
|
|
9
|
-
import { useParams as
|
|
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 } =
|
|
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
|
|
27
|
-
e.preventDefault(),
|
|
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
|
-
}),
|
|
34
|
+
}), le(!0), R(""), B(""), H("");
|
|
34
35
|
} catch (e) {
|
|
35
|
-
|
|
36
|
+
J(e instanceof Error ? e.message : "Failed to apply");
|
|
36
37
|
}
|
|
37
|
-
},
|
|
38
|
-
|
|
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
|
-
|
|
61
|
+
X(e instanceof Error ? e.message : "Failed to score");
|
|
46
62
|
}
|
|
47
|
-
},
|
|
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(
|
|
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 }),
|
|
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(
|
|
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(
|
|
107
|
+
/* @__PURE__ */ C(ae, { className: "h-4 w-4" }),
|
|
92
108
|
"Applicants (",
|
|
93
|
-
|
|
109
|
+
$.length,
|
|
94
110
|
")"
|
|
95
111
|
]
|
|
96
112
|
}),
|
|
97
|
-
|
|
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:
|
|
115
|
+
children: Y
|
|
100
116
|
}),
|
|
101
117
|
N.isLoading ? /* @__PURE__ */ C(f, {
|
|
102
118
|
label: "Loading applicants…",
|
|
103
119
|
className: "min-h-[120px]"
|
|
104
|
-
}) :
|
|
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:
|
|
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 ",
|
|
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
|
|
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(
|
|
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:
|
|
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(
|
|
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(
|
|
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(
|
|
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:
|
|
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
|
-
}),
|
|
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
|
-
}) :
|
|
226
|
-
onSubmit:
|
|
241
|
+
}) : Q ? /* @__PURE__ */ w("form", {
|
|
242
|
+
onSubmit: ue,
|
|
227
243
|
className: "space-y-3",
|
|
228
244
|
children: [
|
|
229
|
-
|
|
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:
|
|
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__ */
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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(
|
|
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":";;;;;;;;;;;;;AAyCA,IAAM,IACJ,wMAEW,UAA+B;CAC1C,IAAM,EAAE,UAAO,IAA2B,EACpC,EAAE,kBAAe,GAAe,EAChC,EAAE,MAAM,GAAU,cAAW,YAAS,eAAY,GAAgB,EAAG,EACrE,IAAe,EAAwB,EAAG,EAC1C,IAAQ,GAAoB,EAC5B,IAAQ,GAAqB,EAC7B,IAAgB,IAAkB,EAElC,CAAC,GAAW,KAAgB,EAAS,GAAG,EACxC,CAAC,GAAgB,KAAqB,EAAS,GAAG,EAClD,CAAC,GAAc,KAAmB,EAAS,GAAG,EAC9C,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,CAAC,GAAa,KAAkB,EAAwB,KAAK,EAC7D,CAAC,GAAY,KAAiB,EAAwB,KAAK,EAC3D,CAAC,IAAS,MAAc,EAAS,GAAM,EACvC,CAAC,GAAY,KAAiB,EAAwB,KAAK,EAC3D,IAAe,EAAyB,KAAK;AAEnD,KAAI,EACF,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD,EAAc,OAAM,qBAAsB,CAAA;EAC/B,CAAA;AAIjB,KAAI,KAAW,CAAC,EACd,QACE,kBAAC,GAAD;EAAY,OAAM;YAChB,kBAAC,GAAD;GAAY,OAAM;GAAqB,eAAe,KAAK,GAAS;GAAI,CAAA;EAC7D,CAAA;CAIjB,IAAM,KAAc,OAAO,MAAiB;AAE1C,EADA,EAAE,gBAAgB,EAClB,EAAc,KAAK;AACnB,MAAI;AASF,GARA,MAAM,EAAM,YAAY;IACtB,YAAY,EAAS;IACrB,WAAW,EAAU,MAAM,IAAI,KAAA;IAC/B,gBAAgB,EAAe,MAAM,IAAI,KAAA;IAC1C,CAAC,EACF,GAAW,GAAK,EAChB,EAAa,GAAG,EAChB,EAAkB,GAAG,EACrB,EAAgB,GAAG;WACZ,GAAK;AACZ,KAAc,aAAe,QAAQ,EAAI,UAAU,kBAAkB;;IAInE,KAAuB,OAAO,MAAqC;EACvE,IAAM,IAAO,EAAE,OAAO,QAAQ;AAE9B,QAAE,OAAO,QAAQ,IACZ,GAEL;GADA,EAAe,KAAK,EACpB,EAAa,GAAK;AAClB,OAAI;IACF,IAAM,IAAW,MAAM,EAAkB,GAAM,EAAa,UAAU;AAEtE,IADA,EAAkB,EAAS,GAAG,EAC9B,EAAgB,EAAS,QAAQ,EAAK,KAAK;YACpC,GAAK;AACZ,MAAe,aAAe,QAAQ,EAAI,UAAU,6BAA6B;aACzE;AACR,MAAa,GAAM;;;IAIjB,WAAsB;AAG1B,EAFA,EAAkB,GAAG,EACrB,EAAgB,GAAG,EACnB,EAAe,KAAK;IAGhB,KAAc,OAAO,GAAuB,MAAkB;AAClE,IAAc,KAAK;AACnB,MAAI;AACF,SAAM,EAAM,YAAY;IAAE,IAAI;IAAe,OAAO;IAAO,CAAC;WACrD,GAAK;AACZ,KAAc,aAAe,QAAQ,EAAI,UAAU,kBAAkB;;IAInE,IAAS,EAAS,WAAW,QAC7B,IAAmB,EAAa,QAAQ,EAAE;AAEhD,QACE,kBAAC,GAAD;EACE,OACE,kBAAC,QAAD;GAAM,WAAU;aAAhB,CACE,kBAAC,UAAD;IACE,MAAK;IACL,eAAe,EAAW,YAAY;IACtC,WAAU;IACV,cAAW;cAEX,kBAAC,GAAD,EAAW,WAAU,WAAY,CAAA;IAC1B,CAAA,EACR,EAAS,SACL;;EAET,aAAa,EAAS,YAAY,SAAS;EAC3C,SACE,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD,EAAa,QAAQ,EAAS,QAAU,CAAA,EACvC,KACC,kBAAC,UAAD;IACE,MAAK;IACL,UAAU,EAAc;IACxB,eAAe,KAAK,EAAc,YAAY,EAAS,GAAG;IAC1D,WAAU;cAJZ,CAME,kBAAC,GAAD,EAAM,WAAU,eAAgB,CAAA,EAAA,QAEzB;MAEP;;YAGR,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACG,EAAS,eACR,kBAAC,GAAD;KAAW,WAAU;KAAS,WAAU;eAAxC,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA+C;MAAqB,CAAA,EAClF,kBAAC,KAAD;MAAG,WAAU;gBAA+C,EAAS;MAAgB,CAAA,CAC3E;QAId,kBAAC,GAAD;KAAW,WAAU;KAAS,WAAU;eAAxC;MACE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,IAAD,EAAO,WAAU,WAAY,CAAA;;QAChB,EAAiB;QAAO;QAClC;;MACJ,KACC,kBAAC,OAAD;OAAK,WAAU;iBACZ;OACG,CAAA;MAEP,EAAa,YACZ,kBAAC,GAAD;OAAc,OAAM;OAAsB,WAAU;OAAkB,CAAA,GACpE,EAAiB,WAAW,IAC9B,kBAAC,KAAD;OAAG,WAAU;iBAA8B;OAAwB,CAAA,GAEnE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAiB,KAAK,MACrB,kBAAC,MAAD;QAEE,WAAU;kBAFZ;SAIE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,OAAD;WAAK,WAAU;qBAAf,CACE,kBAAC,KAAD;YAAG,WAAU;sBAAb,CAA8D,cACjD,EAAK,YAAY,MAAM,GAAG,EAAE,CACrC;eACJ,kBAAC,KAAD;YAAG,WAAU;sBAAb,CAA2C,YAChC,EAAmB,EAAK,UAAU,CACzC;cACA;cACN,kBAAC,GAAD,EAAa,QAAQ,EAAK,QAAU,CAAA,CAChC;;SACL,EAAK,aACJ,kBAAC,KAAD;UAAG,WAAU;oBAAoC,EAAK;UAAc,CAAA;SAEtE,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAA8B;WAAa,CAAA,EAC1D;WAAC;WAAG;WAAG;WAAG;WAAG;WAAE,CAAC,KAAK,MACpB,kBAAC,UAAD;WAEE,MAAK;WACL,UAAU,EAAM;WAChB,eAAe,KAAK,GAAY,EAAK,IAAI,EAAM;WAC/C,WACE,EAAK,UAAU,IACX,2FACA;qBAGL;WACM,EAXF,EAWE,CACT,CACE;;SACH;UAnCE,EAAK,GAmCP,CACL;OACC,CAAA;MAEG;OACR;OAEN,kBAAC,OAAD;IAAK,WAAU;cAAf,CAEE,kBAAC,GAAD;KAAW,WAAU;KAAS,WAAU;eAAxC;MACE,kBAAC,MAAD;OAAI,WAAU;iBAA+C;OAAY,CAAA;MACzE,kBAAC,MAAD;OAAI,WAAU;iBAAd;QACE,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAd,CACE,kBAAC,IAAD,EAAO,WAAU,eAAgB,CAAA,EAAA,MAE9B;aACL,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAiB,EAAS,eAAe,EAAS,SAAS;UACzD,CAAA,CACD;;QACL,EAAS,YACR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAd,CACE,kBAAC,GAAD,EAAQ,WAAU,eAAgB,CAAA,EAAA,WAE/B;aACL,kBAAC,MAAD;UAAI,WAAU;oBAAiC,EAAS;UAAc,CAAA,CAClE;;QAEP,EAAS,YACR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAd,CACE,kBAAC,GAAD,EAAW,WAAU,eAAgB,CAAA,EAAA,WAElC;aACL,kBAAC,MAAD;UAAI,WAAU;oBAAiC,EAAS;UAAc,CAAA,CAClE;;QAEP,EAAS,sBACR,kBAAC,OAAD;SAAK,WAAU;mBAAf,CACE,kBAAC,MAAD;UAAI,WAAU;oBAAd,CACE,kBAAC,GAAD,EAAO,WAAU,eAAgB,CAAA,EAAA,WAE9B;aACL,kBAAC,MAAD;UAAI,WAAU;oBACX,EAAW,EAAS,oBAAoB;WACvC,MAAM,KAAA;WACN,QAAQ,KAAA;WACT,CAAC;UACC,CAAA,CACD;;QAEL;;MACJ,EAAS,eACR,kBAAC,KAAD;OAAG,WAAU;iBAAyF;OAElG,CAAA;MAEI;QAGZ,kBAAC,GAAD;KAAW,WAAU;KAAQ,WAAU;eAAvC,CACE,kBAAC,MAAD;MAAI,WAAU;gBAA+C;MAAU,CAAA,EACtE,KACC,kBAAC,KAAD;MAAG,WAAU;gBAAoF;MAE7F,CAAA,GACD,IAGH,kBAAC,QAAD;MAAM,UAAU;MAAa,WAAU;gBAAvC;OACG,KACC,kBAAC,OAAD;QAAK,WAAU;kBACZ;QACG,CAAA;OAER,kBAAC,YAAD;QACE,OAAO;QACP,WAAW,MAAM,EAAa,EAAE,OAAO,MAAM;QAC7C,MAAM;QACN,aAAY;QACZ,WAAW;QACX,CAAA;OACF,kBAAC,OAAD;QAAK,WAAU;kBAAf;SACE,kBAAC,SAAD;UACE,SAAQ;UACR,WAAU;oBACX;UAEO,CAAA;SACR,kBAAC,SAAD;UACE,KAAK;UACL,IAAG;UACH,MAAK;UACL,QAAO;UACP,WAAW,MAAM,KAAK,GAAqB,EAAE;UAC7C,UAAU;UACV,WAAU;UACV,cAAW;UACX,CAAA;SACD,IACC,kBAAC,OAAD;UAAK,WAAU;oBAAf,CACE,kBAAC,QAAD;WAAM,WAAU;qBAAhB,CACE,kBAAC,GAAD,EAAM,WAAU,6CAA8C,CAAA,EAC9D,kBAAC,QAAD;YAAM,WAAU;sBAAY,KAAgB;YAA4B,CAAA,CACnE;cACP,kBAAC,UAAD;WACE,MAAK;WACL,SAAS;WACT,WAAU;WACV,cAAW;qBAEX,kBAAC,IAAD,EAAG,WAAU,WAAY,CAAA;WAClB,CAAA,CACL;cAEN,kBAAC,UAAD;UACE,MAAK;UACL,eAAe,EAAa,SAAS,OAAO;UAC5C,UAAU;UACV,WAAU;oBAET,IACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,GAAD,EAAS,WAAU,wBAAyB,CAAA,EAAA,aAE3C,EAAA,CAAA,GAEH,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,IAAD,EAAQ,WAAU,WAAY,CAAA,EAAA,yBAE7B,EAAA,CAAA;UAEE,CAAA;SAEV,KACC,kBAAC,KAAD;UAAG,WAAU;oBACV;UACC,CAAA;SAEF;;OACN,kBAAC,UAAD;QACE,MAAK;QACL,UAAU,EAAM,aAAa;QAC7B,WAAU;kBAHZ,CAKE,kBAAC,IAAD,EAAM,WAAU,WAAY,CAAA,EAC3B,EAAM,YAAY,gBAAgB,qBAC5B;;OACJ;UAjFP,kBAAC,KAAD;MAAG,WAAU;gBAA8B;MAAoC,CAAA,CAmFvE;OACR;MACF;;EACK,CAAA"}
|