@burdenoff/microfe-hookmovies 2026.629.1 → 2026.705.1

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.
@@ -2,8 +2,9 @@ import { useHookMovies as e } from "../context/HookMoviesContext.js";
2
2
  import "../context/index.js";
3
3
  import { useMutation as t, useQuery as n, useQueryClient as r } from "@tanstack/react-query";
4
4
  import { graphqlFetch as i } from "@burdenoff/fe-libs/shared/graphql";
5
+ import { clearGraphqlFetchResponseCache as a } from "@burdenoff/fe-libs/shared/graphql/fetch";
5
6
  //#region src/hookmovies/hooks/useHookMoviesApi.ts
6
- var a = async (e, t, n) => {
7
+ var o = async (e, t, n) => {
7
8
  let r = await i({
8
9
  gateway: "workspace",
9
10
  baseUrl: n,
@@ -13,23 +14,23 @@ var a = async (e, t, n) => {
13
14
  });
14
15
  if (r.errors?.length) throw Error(r.errors[0]?.message ?? "GraphQL request failed");
15
16
  if (!r.data) throw Error("GraphQL response did not include data");
16
- return r.data;
17
- }, o = "hookmovies", s = "\n id title slug type status synopsis genres tags originalLanguage originCountry\n releaseYear releaseDate runtimeMinutes certification aiDisclosure studioId\n createdAt updatedAt\n", c = "\n id name slug description country websiteUrl isVerified tags createdAt updatedAt\n", l = "\n id name biography knownFor primaryLanguage portfolioRef tags createdAt updatedAt\n", u = "\n id title logline synopsis status currency budgetMinorUnits studioId producerId\n resultingTitleId artistrybaseProjectRef tags startDate endDate createdAt updatedAt\n", d = "\n id productionId roleName description status isMinorRole payMinorUnits currency\n location language submissionDeadline createdAt updatedAt\n", f = "\n id titleId authorId score body hasSpoilers helpfulCount verifiedWatch status\n createdAt updatedAt\n", p = "\n id titleId status modes territories exclusive currency licenseeId startsAt endsAt\n createdAt updatedAt\n", m = "\n id name description kind visibility ownerId itemCount createdAt updatedAt\n", h = "pageInfo { cursor hasMore }", g = (t = {}, r = {
17
+ return e.trimStart().startsWith("mutation") && a(), r.data;
18
+ }, s = "hookmovies", c = "\n id title slug type status synopsis genres tags originalLanguage originCountry\n releaseYear releaseDate runtimeMinutes certification aiDisclosure studioId\n createdAt updatedAt\n", l = "\n id name slug description country websiteUrl isVerified tags createdAt updatedAt\n", u = "\n id name biography knownFor primaryLanguage portfolioRef tags createdAt updatedAt\n", d = "\n id title logline synopsis status currency budgetMinorUnits studioId producerId\n resultingTitleId artistrybaseProjectRef tags startDate endDate createdAt updatedAt\n", f = "\n id productionId roleName description status isMinorRole payMinorUnits currency\n location language submissionDeadline createdAt updatedAt\n", p = "\n id titleId authorId score body hasSpoilers helpfulCount verifiedWatch status\n createdAt updatedAt\n", m = "\n id titleId status modes territories exclusive currency licenseeId startsAt endsAt\n createdAt updatedAt\n", h = "\n id name description kind visibility ownerId itemCount createdAt updatedAt\n", g = "pageInfo { cursor hasMore }", _ = (t = {}, r = {
18
19
  limit: 50,
19
20
  offset: 0
20
21
  }) => {
21
22
  let { apiGatewayUrl: i } = e();
22
23
  return n({
23
24
  queryKey: [
24
- o,
25
+ s,
25
26
  "titles",
26
27
  t,
27
28
  r
28
29
  ],
29
- queryFn: async () => (await a(`query HokTitles($pagination: PaginationInput, $status: HokTitleStatus, $type: HokTitleType, $studioId: ID) {
30
+ queryFn: async () => (await o(`query HokTitles($pagination: PaginationInput, $status: HokTitleStatus, $type: HokTitleType, $studioId: ID) {
30
31
  hokListTitles(pagination: $pagination, status: $status, type: $type, studioId: $studioId) {
31
- items { ${s} }
32
- ${h}
32
+ items { ${c} }
33
+ ${g}
33
34
  }
34
35
  }`, {
35
36
  pagination: r,
@@ -38,17 +39,17 @@ var a = async (e, t, n) => {
38
39
  studioId: t.studioId
39
40
  }, i)).hokListTitles
40
41
  });
41
- }, _ = (t) => {
42
+ }, v = (t) => {
42
43
  let { apiGatewayUrl: r } = e();
43
44
  return n({
44
45
  queryKey: [
45
- o,
46
+ s,
46
47
  "title",
47
48
  t
48
49
  ],
49
- queryFn: async () => (await a(`query HokTitle($id: ID!) {
50
+ queryFn: async () => (await o(`query HokTitle($id: ID!) {
50
51
  hokTitle(id: $id) {
51
- ${s}
52
+ ${c}
52
53
  studio { id name }
53
54
  credits {
54
55
  id personId titleId role characterName billingOrder
@@ -60,130 +61,134 @@ var a = async (e, t, n) => {
60
61
  }`, { id: t }, r)).hokTitle,
61
62
  enabled: !!t
62
63
  });
63
- }, v = () => {
64
+ }, y = () => {
64
65
  let n = r(), { apiGatewayUrl: i } = e();
65
66
  return t({
66
- mutationFn: async (e) => (await a(`mutation HokCreateTitle($input: HokCreateTitleInput!) {
67
- hokCreateTitle(input: $input) { ${s} }
67
+ mutationFn: async (e) => (await o(`mutation HokCreateTitle($input: HokCreateTitleInput!) {
68
+ hokCreateTitle(input: $input) { ${c} }
68
69
  }`, { input: e }, i)).hokCreateTitle,
69
70
  onSuccess: () => {
70
- n.invalidateQueries({ queryKey: [o, "titles"] });
71
+ n.invalidateQueries({ queryKey: [s, "titles"] });
71
72
  }
72
73
  });
73
- }, y = () => {
74
+ }, b = () => {
74
75
  let n = r(), { apiGatewayUrl: i } = e();
75
76
  return t({
76
- mutationFn: async ({ id: e, input: t }) => (await a(`mutation HokUpdateTitle($id: ID!, $input: HokUpdateTitleInput!) {
77
- hokUpdateTitle(id: $id, input: $input) { ${s} }
77
+ mutationFn: async ({ id: e, input: t }) => (await o(`mutation HokUpdateTitle($id: ID!, $input: HokUpdateTitleInput!) {
78
+ hokUpdateTitle(id: $id, input: $input) { ${c} }
78
79
  }`, {
79
80
  id: e,
80
81
  input: t
81
82
  }, i)).hokUpdateTitle,
82
83
  onSuccess: (e) => {
83
- n.invalidateQueries({ queryKey: [o, "titles"] }), n.invalidateQueries({ queryKey: [
84
- o,
84
+ n.invalidateQueries({ queryKey: [s, "titles"] }), n.invalidateQueries({ queryKey: [
85
+ s,
85
86
  "title",
86
87
  e.id
87
88
  ] });
88
89
  }
89
90
  });
90
- }, b = () => {
91
+ }, x = () => {
91
92
  let n = r(), { apiGatewayUrl: i } = e();
92
93
  return t({
93
- mutationFn: async ({ id: e, status: t }) => (await a(`mutation HokTransitionTitle($id: ID!, $status: HokTitleStatus!) {
94
- hokTransitionTitle(id: $id, status: $status) { ${s} }
94
+ mutationFn: async ({ id: e, status: t }) => (await o(`mutation HokTransitionTitle($id: ID!, $status: HokTitleStatus!) {
95
+ hokTransitionTitle(id: $id, status: $status) { ${c} }
95
96
  }`, {
96
97
  id: e,
97
98
  status: t
98
99
  }, i)).hokTransitionTitle,
99
100
  onSuccess: (e) => {
100
- n.invalidateQueries({ queryKey: [o, "titles"] }), n.invalidateQueries({ queryKey: [
101
- o,
101
+ n.invalidateQueries({ queryKey: [s, "titles"] }), n.invalidateQueries({ queryKey: [
102
+ s,
102
103
  "title",
103
104
  e.id
104
105
  ] });
105
106
  }
106
107
  });
107
- }, x = () => {
108
+ }, S = () => {
108
109
  let n = r(), { apiGatewayUrl: i } = e();
109
110
  return t({
110
- mutationFn: async (e) => (await a("mutation HokArchiveTitle($id: ID!) { hokArchiveTitle(id: $id) }", { id: e }, i)).hokArchiveTitle,
111
- onSuccess: () => {
112
- n.invalidateQueries({ queryKey: [o, "titles"] });
111
+ mutationFn: async (e) => (await o("mutation HokArchiveTitle($id: ID!) { hokArchiveTitle(id: $id) }", { id: e }, i)).hokArchiveTitle,
112
+ onSuccess: (e, t) => {
113
+ n.invalidateQueries({ queryKey: [s, "titles"] }), n.invalidateQueries({ queryKey: [
114
+ s,
115
+ "title",
116
+ t
117
+ ] });
113
118
  }
114
119
  });
115
- }, S = (t = {
120
+ }, C = (t = {
116
121
  limit: 50,
117
122
  offset: 0
118
123
  }) => {
119
124
  let { apiGatewayUrl: r } = e();
120
125
  return n({
121
126
  queryKey: [
122
- o,
127
+ s,
123
128
  "studios",
124
129
  t
125
130
  ],
126
- queryFn: async () => (await a(`query HokStudios($pagination: PaginationInput) {
131
+ queryFn: async () => (await o(`query HokStudios($pagination: PaginationInput) {
127
132
  hokListStudios(pagination: $pagination) {
128
- items { ${c} }
129
- ${h}
133
+ items { ${l} }
134
+ ${g}
130
135
  }
131
136
  }`, { pagination: t }, r)).hokListStudios
132
137
  });
133
- }, C = () => {
138
+ }, w = () => {
134
139
  let n = r(), { apiGatewayUrl: i } = e();
135
140
  return t({
136
- mutationFn: async (e) => (await a(`mutation HokCreateStudio($input: HokCreateStudioInput!) {
137
- hokCreateStudio(input: $input) { ${c} }
141
+ mutationFn: async (e) => (await o(`mutation HokCreateStudio($input: HokCreateStudioInput!) {
142
+ hokCreateStudio(input: $input) { ${l} }
138
143
  }`, { input: e }, i)).hokCreateStudio,
139
144
  onSuccess: () => {
140
- n.invalidateQueries({ queryKey: [o, "studios"] });
145
+ n.invalidateQueries({ queryKey: [s, "studios"] });
141
146
  }
142
147
  });
143
- }, w = (t = {
148
+ }, T = (t = {
144
149
  limit: 50,
145
150
  offset: 0
146
151
  }) => {
147
152
  let { apiGatewayUrl: r } = e();
148
153
  return n({
149
154
  queryKey: [
150
- o,
155
+ s,
151
156
  "people",
152
157
  t
153
158
  ],
154
- queryFn: async () => (await a(`query HokPeople($pagination: PaginationInput) {
159
+ queryFn: async () => (await o(`query HokPeople($pagination: PaginationInput) {
155
160
  hokListPeople(pagination: $pagination) {
156
- items { ${l} }
157
- ${h}
161
+ items { ${u} }
162
+ ${g}
158
163
  }
159
164
  }`, { pagination: t }, r)).hokListPeople
160
165
  });
161
- }, T = () => {
166
+ }, E = () => {
162
167
  let n = r(), { apiGatewayUrl: i } = e();
163
168
  return t({
164
- mutationFn: async (e) => (await a(`mutation HokCreatePerson($input: HokCreatePersonInput!) {
165
- hokCreatePerson(input: $input) { ${l} }
169
+ mutationFn: async (e) => (await o(`mutation HokCreatePerson($input: HokCreatePersonInput!) {
170
+ hokCreatePerson(input: $input) { ${u} }
166
171
  }`, { input: e }, i)).hokCreatePerson,
167
172
  onSuccess: () => {
168
- n.invalidateQueries({ queryKey: [o, "people"] });
173
+ n.invalidateQueries({ queryKey: [s, "people"] });
169
174
  }
170
175
  });
171
- }, E = (t = {}, r = {
176
+ }, D = (t = {}, r = {
172
177
  limit: 50,
173
178
  offset: 0
174
179
  }) => {
175
180
  let { apiGatewayUrl: i } = e();
176
181
  return n({
177
182
  queryKey: [
178
- o,
183
+ s,
179
184
  "productions",
180
185
  t,
181
186
  r
182
187
  ],
183
- queryFn: async () => (await a(`query HokProductions($pagination: PaginationInput, $status: HokProductionStatus, $studioId: ID) {
188
+ queryFn: async () => (await o(`query HokProductions($pagination: PaginationInput, $status: HokProductionStatus, $studioId: ID) {
184
189
  hokListProductions(pagination: $pagination, status: $status, studioId: $studioId) {
185
- items { ${u} }
186
- ${h}
190
+ items { ${d} }
191
+ ${g}
187
192
  }
188
193
  }`, {
189
194
  pagination: r,
@@ -191,17 +196,17 @@ var a = async (e, t, n) => {
191
196
  studioId: t.studioId
192
197
  }, i)).hokListProductions
193
198
  });
194
- }, D = (t) => {
199
+ }, O = (t) => {
195
200
  let { apiGatewayUrl: r } = e();
196
201
  return n({
197
202
  queryKey: [
198
- o,
203
+ s,
199
204
  "production",
200
205
  t
201
206
  ],
202
- queryFn: async () => (await a(`query HokProduction($id: ID!) {
207
+ queryFn: async () => (await o(`query HokProduction($id: ID!) {
203
208
  hokProduction(id: $id) {
204
- ${u}
209
+ ${d}
205
210
  auditions {
206
211
  id roleName status isMinorRole payMinorUnits currency location language submissionDeadline
207
212
  }
@@ -209,52 +214,52 @@ var a = async (e, t, n) => {
209
214
  }`, { id: t }, r)).hokProduction,
210
215
  enabled: !!t
211
216
  });
212
- }, O = () => {
217
+ }, k = () => {
213
218
  let n = r(), { apiGatewayUrl: i } = e();
214
219
  return t({
215
- mutationFn: async (e) => (await a(`mutation HokCreateProduction($input: HokCreateProductionInput!) {
216
- hokCreateProduction(input: $input) { ${u} }
220
+ mutationFn: async (e) => (await o(`mutation HokCreateProduction($input: HokCreateProductionInput!) {
221
+ hokCreateProduction(input: $input) { ${d} }
217
222
  }`, { input: e }, i)).hokCreateProduction,
218
223
  onSuccess: () => {
219
- n.invalidateQueries({ queryKey: [o, "productions"] });
224
+ n.invalidateQueries({ queryKey: [s, "productions"] });
220
225
  }
221
226
  });
222
- }, k = () => {
227
+ }, A = () => {
223
228
  let n = r(), { apiGatewayUrl: i } = e();
224
229
  return t({
225
- mutationFn: async ({ id: e, status: t }) => (await a(`mutation HokTransitionProduction($id: ID!, $status: HokProductionStatus!) {
226
- hokTransitionProduction(id: $id, status: $status) { ${u} }
230
+ mutationFn: async ({ id: e, status: t }) => (await o(`mutation HokTransitionProduction($id: ID!, $status: HokProductionStatus!) {
231
+ hokTransitionProduction(id: $id, status: $status) { ${d} }
227
232
  }`, {
228
233
  id: e,
229
234
  status: t
230
235
  }, i)).hokTransitionProduction,
231
236
  onSuccess: (e) => {
232
- n.invalidateQueries({ queryKey: [o, "productions"] }), n.invalidateQueries({ queryKey: [
233
- o,
237
+ n.invalidateQueries({ queryKey: [s, "productions"] }), n.invalidateQueries({ queryKey: [
238
+ s,
234
239
  "production",
235
240
  e.id
236
241
  ] });
237
242
  }
238
243
  });
239
- }, A = (t = {}, r = {
244
+ }, j = (t = {}, r = {
240
245
  limit: 50,
241
246
  offset: 0
242
247
  }) => {
243
248
  let { apiGatewayUrl: i } = e();
244
249
  return n({
245
250
  queryKey: [
246
- o,
251
+ s,
247
252
  "auditions",
248
253
  t,
249
254
  r
250
255
  ],
251
- queryFn: async () => (await a(`query HokAuditions($pagination: PaginationInput, $status: HokAuditionStatus, $productionId: ID) {
256
+ queryFn: async () => (await o(`query HokAuditions($pagination: PaginationInput, $status: HokAuditionStatus, $productionId: ID) {
252
257
  hokListAuditions(pagination: $pagination, status: $status, productionId: $productionId) {
253
258
  items {
254
- ${d}
259
+ ${f}
255
260
  production { id title }
256
261
  }
257
- ${h}
262
+ ${g}
258
263
  }
259
264
  }`, {
260
265
  pagination: r,
@@ -262,21 +267,21 @@ var a = async (e, t, n) => {
262
267
  productionId: t.productionId
263
268
  }, i)).hokListAuditions
264
269
  });
265
- }, j = (t) => {
270
+ }, M = (t) => {
266
271
  let { apiGatewayUrl: r } = e();
267
272
  return n({
268
273
  queryKey: [
269
- o,
274
+ s,
270
275
  "audition-by-id",
271
276
  t
272
277
  ],
273
- queryFn: async () => (await a(`query HokAuditionLookup($pagination: PaginationInput) {
278
+ queryFn: async () => (await o(`query HokAuditionLookup($pagination: PaginationInput) {
274
279
  hokListAuditions(pagination: $pagination) {
275
280
  items {
276
- ${d}
281
+ ${f}
277
282
  production { id title }
278
283
  }
279
- ${h}
284
+ ${g}
280
285
  }
281
286
  }`, { pagination: {
282
287
  limit: 200,
@@ -284,83 +289,87 @@ var a = async (e, t, n) => {
284
289
  } }, r)).hokListAuditions.items.find((e) => e.id === t) ?? null,
285
290
  enabled: !!t
286
291
  });
287
- }, M = (t) => {
292
+ }, N = (t) => {
288
293
  let { apiGatewayUrl: r } = e();
289
294
  return n({
290
295
  queryKey: [
291
- o,
296
+ s,
292
297
  "applications",
293
298
  t
294
299
  ],
295
- queryFn: async () => (await a("query HokApplications($auditionId: ID!) {\n hokListApplications(auditionId: $auditionId) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }", { auditionId: t }, r)).hokListApplications,
300
+ queryFn: async () => (await o("query HokApplications($auditionId: ID!) {\n hokListApplications(auditionId: $auditionId) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }", { auditionId: t }, r)).hokListApplications,
296
301
  enabled: !!t
297
302
  });
298
- }, N = () => {
303
+ }, P = () => {
299
304
  let n = r(), { apiGatewayUrl: i } = e();
300
305
  return t({
301
- mutationFn: async (e) => (await a(`mutation HokCreateAudition($input: HokCreateAuditionInput!) {
302
- hokCreateAudition(input: $input) { ${d} }
306
+ mutationFn: async (e) => (await o(`mutation HokCreateAudition($input: HokCreateAuditionInput!) {
307
+ hokCreateAudition(input: $input) { ${f} }
303
308
  }`, { input: e }, i)).hokCreateAudition,
304
309
  onSuccess: () => {
305
- n.invalidateQueries({ queryKey: [o, "auditions"] });
310
+ n.invalidateQueries({ queryKey: [s, "auditions"] });
306
311
  }
307
312
  });
308
- }, P = () => {
313
+ }, F = () => {
309
314
  let n = r(), { apiGatewayUrl: i } = e();
310
315
  return t({
311
- mutationFn: async (e) => (await a(`mutation HokCloseAudition($id: ID!) {
312
- hokCloseAudition(id: $id) { ${d} }
316
+ mutationFn: async (e) => (await o(`mutation HokCloseAudition($id: ID!) {
317
+ hokCloseAudition(id: $id) { ${f} }
313
318
  }`, { id: e }, i)).hokCloseAudition,
314
- onSuccess: () => {
315
- n.invalidateQueries({ queryKey: [o, "auditions"] });
319
+ onSuccess: (e) => {
320
+ n.invalidateQueries({ queryKey: [s, "auditions"] }), n.invalidateQueries({ queryKey: [
321
+ s,
322
+ "audition-by-id",
323
+ e.id
324
+ ] });
316
325
  }
317
326
  });
318
- }, F = () => {
327
+ }, I = () => {
319
328
  let n = r(), { apiGatewayUrl: i } = e();
320
329
  return t({
321
- mutationFn: async (e) => (await a("mutation HokApplyToAudition($input: HokApplyToAuditionInput!) {\n hokApplyToAudition(input: $input) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }", { input: e }, i)).hokApplyToAudition,
330
+ mutationFn: async (e) => (await o("mutation HokApplyToAudition($input: HokApplyToAuditionInput!) {\n hokApplyToAudition(input: $input) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }", { input: e }, i)).hokApplyToAudition,
322
331
  onSuccess: (e) => {
323
332
  n.invalidateQueries({ queryKey: [
324
- o,
333
+ s,
325
334
  "applications",
326
335
  e.auditionId
327
336
  ] });
328
337
  }
329
338
  });
330
- }, I = () => {
339
+ }, L = () => {
331
340
  let n = r(), { apiGatewayUrl: i } = e();
332
341
  return t({
333
- mutationFn: async ({ id: e, score: t }) => (await a("mutation HokScoreApplication($id: ID!, $score: Int!) {\n hokScoreApplication(id: $id, score: $score) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }", {
342
+ mutationFn: async ({ id: e, score: t }) => (await o("mutation HokScoreApplication($id: ID!, $score: Int!) {\n hokScoreApplication(id: $id, score: $score) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }", {
334
343
  id: e,
335
344
  score: t
336
345
  }, i)).hokScoreApplication,
337
346
  onSuccess: (e) => {
338
347
  n.invalidateQueries({ queryKey: [
339
- o,
348
+ s,
340
349
  "applications",
341
350
  e.auditionId
342
351
  ] });
343
352
  }
344
353
  });
345
- }, L = (t = {}, r = {
354
+ }, R = (t = {}, r = {
346
355
  limit: 50,
347
356
  offset: 0
348
357
  }) => {
349
358
  let { apiGatewayUrl: i } = e();
350
359
  return n({
351
360
  queryKey: [
352
- o,
361
+ s,
353
362
  "reviews",
354
363
  t,
355
364
  r
356
365
  ],
357
- queryFn: async () => (await a(`query HokReviews($pagination: PaginationInput, $status: HokReviewStatus, $titleId: ID) {
366
+ queryFn: async () => (await o(`query HokReviews($pagination: PaginationInput, $status: HokReviewStatus, $titleId: ID) {
358
367
  hokListReviews(pagination: $pagination, status: $status, titleId: $titleId) {
359
368
  items {
360
- ${f}
369
+ ${p}
361
370
  title { id title }
362
371
  }
363
- ${h}
372
+ ${g}
364
373
  }
365
374
  }`, {
366
375
  pagination: r,
@@ -368,43 +377,43 @@ var a = async (e, t, n) => {
368
377
  titleId: t.titleId
369
378
  }, i)).hokListReviews
370
379
  });
371
- }, R = () => {
380
+ }, z = () => {
372
381
  let n = r(), { apiGatewayUrl: i } = e();
373
382
  return t({
374
- mutationFn: async (e) => (await a(`mutation HokCreateReview($input: HokCreateReviewInput!) {
375
- hokCreateReview(input: $input) { ${f} }
383
+ mutationFn: async (e) => (await o(`mutation HokCreateReview($input: HokCreateReviewInput!) {
384
+ hokCreateReview(input: $input) { ${p} }
376
385
  }`, { input: e }, i)).hokCreateReview,
377
386
  onSuccess: () => {
378
- n.invalidateQueries({ queryKey: [o, "reviews"] });
387
+ n.invalidateQueries({ queryKey: [s, "reviews"] });
379
388
  }
380
389
  });
381
- }, z = () => {
390
+ }, B = () => {
382
391
  let n = r(), { apiGatewayUrl: i } = e();
383
392
  return t({
384
- mutationFn: async (e) => (await a("mutation HokDeleteReview($id: ID!) { hokDeleteReview(id: $id) }", { id: e }, i)).hokDeleteReview,
393
+ mutationFn: async (e) => (await o("mutation HokDeleteReview($id: ID!) { hokDeleteReview(id: $id) }", { id: e }, i)).hokDeleteReview,
385
394
  onSuccess: () => {
386
- n.invalidateQueries({ queryKey: [o, "reviews"] });
395
+ n.invalidateQueries({ queryKey: [s, "reviews"] });
387
396
  }
388
397
  });
389
- }, B = (t = {}, r = {
398
+ }, V = (t = {}, r = {
390
399
  limit: 50,
391
400
  offset: 0
392
401
  }) => {
393
402
  let { apiGatewayUrl: i } = e();
394
403
  return n({
395
404
  queryKey: [
396
- o,
405
+ s,
397
406
  "rights",
398
407
  t,
399
408
  r
400
409
  ],
401
- queryFn: async () => (await a(`query HokRightsWindows($pagination: PaginationInput, $status: HokRightsWindowStatus, $titleId: ID) {
410
+ queryFn: async () => (await o(`query HokRightsWindows($pagination: PaginationInput, $status: HokRightsWindowStatus, $titleId: ID) {
402
411
  hokListRightsWindows(pagination: $pagination, status: $status, titleId: $titleId) {
403
412
  items {
404
- ${p}
413
+ ${m}
405
414
  title { id title }
406
415
  }
407
- ${h}
416
+ ${g}
408
417
  }
409
418
  }`, {
410
419
  pagination: r,
@@ -412,106 +421,106 @@ var a = async (e, t, n) => {
412
421
  titleId: t.titleId
413
422
  }, i)).hokListRightsWindows
414
423
  });
415
- }, V = () => {
424
+ }, H = () => {
416
425
  let n = r(), { apiGatewayUrl: i } = e();
417
426
  return t({
418
- mutationFn: async (e) => (await a(`mutation HokCreateRightsWindow($input: HokCreateRightsWindowInput!) {
419
- hokCreateRightsWindow(input: $input) { ${p} }
427
+ mutationFn: async (e) => (await o(`mutation HokCreateRightsWindow($input: HokCreateRightsWindowInput!) {
428
+ hokCreateRightsWindow(input: $input) { ${m} }
420
429
  }`, { input: e }, i)).hokCreateRightsWindow,
421
430
  onSuccess: () => {
422
- n.invalidateQueries({ queryKey: [o, "rights"] });
431
+ n.invalidateQueries({ queryKey: [s, "rights"] });
423
432
  }
424
433
  });
425
- }, H = () => {
434
+ }, U = () => {
426
435
  let n = r(), { apiGatewayUrl: i } = e();
427
436
  return t({
428
- mutationFn: async ({ id: e, status: t }) => (await a(`mutation HokTransitionRightsWindow($id: ID!, $status: HokRightsWindowStatus!) {
429
- hokTransitionRightsWindow(id: $id, status: $status) { ${p} }
437
+ mutationFn: async ({ id: e, status: t }) => (await o(`mutation HokTransitionRightsWindow($id: ID!, $status: HokRightsWindowStatus!) {
438
+ hokTransitionRightsWindow(id: $id, status: $status) { ${m} }
430
439
  }`, {
431
440
  id: e,
432
441
  status: t
433
442
  }, i)).hokTransitionRightsWindow,
434
443
  onSuccess: () => {
435
- n.invalidateQueries({ queryKey: [o, "rights"] });
444
+ n.invalidateQueries({ queryKey: [s, "rights"] });
436
445
  }
437
446
  });
438
- }, U = () => {
447
+ }, W = () => {
439
448
  let n = r(), { apiGatewayUrl: i } = e();
440
449
  return t({
441
- mutationFn: async (e) => (await a("mutation HokRevokeEntitlement($id: ID!) { hokRevokeEntitlement(id: $id) }", { id: e }, i)).hokRevokeEntitlement,
450
+ mutationFn: async (e) => (await o("mutation HokRevokeEntitlement($id: ID!) { hokRevokeEntitlement(id: $id) }", { id: e }, i)).hokRevokeEntitlement,
442
451
  onSuccess: () => {
443
- n.invalidateQueries({ queryKey: [o, "my-entitlements"] });
452
+ n.invalidateQueries({ queryKey: [s, "my-entitlements"] });
444
453
  }
445
454
  });
446
- }, W = (t) => {
455
+ }, G = (t) => {
447
456
  let { apiGatewayUrl: r } = e();
448
457
  return n({
449
458
  queryKey: [
450
- o,
459
+ s,
451
460
  "my-entitlements",
452
461
  t
453
462
  ],
454
- queryFn: async () => (await a("query HokMyEntitlements($titleId: ID) {\n hokMyEntitlements(titleId: $titleId) {\n id titleId userId mode source status territory expiresAt createdAt updatedAt\n title { id title }\n }\n }", { titleId: t }, r)).hokMyEntitlements
463
+ queryFn: async () => (await o("query HokMyEntitlements($titleId: ID) {\n hokMyEntitlements(titleId: $titleId) {\n id titleId userId mode source status territory expiresAt createdAt updatedAt\n title { id title }\n }\n }", { titleId: t }, r)).hokMyEntitlements
455
464
  });
456
- }, G = (t, r = {
465
+ }, K = (t, r = {
457
466
  limit: 50,
458
467
  offset: 0
459
468
  }) => {
460
469
  let { apiGatewayUrl: i } = e();
461
470
  return n({
462
471
  queryKey: [
463
- o,
472
+ s,
464
473
  "my-lists",
465
474
  t,
466
475
  r
467
476
  ],
468
- queryFn: async () => (await a(`query HokMyLists($kind: HokListKind, $pagination: PaginationInput) {
477
+ queryFn: async () => (await o(`query HokMyLists($kind: HokListKind, $pagination: PaginationInput) {
469
478
  hokMyLists(kind: $kind, pagination: $pagination) {
470
- items { ${m} }
471
- ${h}
479
+ items { ${h} }
480
+ ${g}
472
481
  }
473
482
  }`, {
474
483
  kind: t,
475
484
  pagination: r
476
485
  }, i)).hokMyLists
477
486
  });
478
- }, K = () => {
487
+ }, q = () => {
479
488
  let n = r(), { apiGatewayUrl: i } = e();
480
489
  return t({
481
- mutationFn: async (e) => (await a(`mutation HokCreateList($input: HokCreateListInput!) {
482
- hokCreateList(input: $input) { ${m} }
490
+ mutationFn: async (e) => (await o(`mutation HokCreateList($input: HokCreateListInput!) {
491
+ hokCreateList(input: $input) { ${h} }
483
492
  }`, { input: e }, i)).hokCreateList,
484
493
  onSuccess: () => {
485
- n.invalidateQueries({ queryKey: [o, "my-lists"] });
494
+ n.invalidateQueries({ queryKey: [s, "my-lists"] });
486
495
  }
487
496
  });
488
- }, q = () => {
497
+ }, J = () => {
489
498
  let n = r(), { apiGatewayUrl: i } = e();
490
499
  return t({
491
- mutationFn: async (e) => (await a("mutation HokDeleteList($id: ID!) { hokDeleteList(id: $id) }", { id: e }, i)).hokDeleteList,
500
+ mutationFn: async (e) => (await o("mutation HokDeleteList($id: ID!) { hokDeleteList(id: $id) }", { id: e }, i)).hokDeleteList,
492
501
  onSuccess: () => {
493
- n.invalidateQueries({ queryKey: [o, "my-lists"] });
502
+ n.invalidateQueries({ queryKey: [s, "my-lists"] });
494
503
  }
495
504
  });
496
- }, J = (t) => {
505
+ }, Y = (t) => {
497
506
  let { apiGatewayUrl: r } = e();
498
507
  return n({
499
508
  queryKey: [
500
- o,
509
+ s,
501
510
  "my-watch-progress",
502
511
  t
503
512
  ],
504
- queryFn: async () => (await a("query HokMyWatchProgress($titleId: ID) {\n hokMyWatchProgress(titleId: $titleId) {\n id titleId episodeId positionSeconds completed lastDevice updatedAt\n title { id title type }\n }\n }", { titleId: t }, r)).hokMyWatchProgress
513
+ queryFn: async () => (await o("query HokMyWatchProgress($titleId: ID) {\n hokMyWatchProgress(titleId: $titleId) {\n id titleId episodeId positionSeconds completed lastDevice updatedAt\n title { id title type }\n }\n }", { titleId: t }, r)).hokMyWatchProgress
505
514
  });
506
- }, Y = () => {
515
+ }, X = () => {
507
516
  let { apiGatewayUrl: t } = e();
508
517
  return n({
509
- queryKey: [o, "health"],
510
- queryFn: async () => (await a("query HokHealth { hokHealth }", {}, t)).hokHealth,
518
+ queryKey: [s, "health"],
519
+ queryFn: async () => (await o("query HokHealth { hokHealth }", {}, t)).hokHealth,
511
520
  staleTime: 60 * 1e3
512
521
  });
513
522
  };
514
523
  //#endregion
515
- export { F as useApplyToAudition, x as useArchiveTitle, M as useAuditionApplications, j as useAuditionById, A as useAuditions, P as useCloseAudition, N as useCreateAudition, K as useCreateList, T as useCreatePerson, O as useCreateProduction, R as useCreateReview, V as useCreateRightsWindow, C as useCreateStudio, v as useCreateTitle, q as useDeleteList, z as useDeleteReview, Y as useHealth, W as useMyEntitlements, G as useMyLists, J as useMyWatchProgress, w as usePeople, D as useProduction, E as useProductions, L as useReviews, U as useRevokeEntitlement, B as useRightsWindows, I as useScoreApplication, S as useStudios, _ as useTitle, g as useTitles, k as useTransitionProduction, H as useTransitionRightsWindow, b as useTransitionTitle, y as useUpdateTitle };
524
+ export { I as useApplyToAudition, S as useArchiveTitle, N as useAuditionApplications, M as useAuditionById, j as useAuditions, F as useCloseAudition, P as useCreateAudition, q as useCreateList, E as useCreatePerson, k as useCreateProduction, z as useCreateReview, H as useCreateRightsWindow, w as useCreateStudio, y as useCreateTitle, J as useDeleteList, B as useDeleteReview, X as useHealth, G as useMyEntitlements, K as useMyLists, Y as useMyWatchProgress, T as usePeople, O as useProduction, D as useProductions, R as useReviews, W as useRevokeEntitlement, V as useRightsWindows, L as useScoreApplication, C as useStudios, v as useTitle, _ as useTitles, A as useTransitionProduction, U as useTransitionRightsWindow, x as useTransitionTitle, b as useUpdateTitle };
516
525
 
517
526
  //# sourceMappingURL=useHookMoviesApi.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useHookMoviesApi.js","names":[],"sources":["../../../src/hookmovies/hooks/useHookMoviesApi.ts"],"sourcesContent":["/**\n * HookMovies API hooks\n * @module hookmovies/hooks\n *\n * Real data layer for the HookMovies workspace subgraph (`hookmovies` Hive\n * service / `wspace-hookmovies-svc`). Every hook talks to the live workspace\n * GraphQL gateway via {@link graphqlFetch} with inline operations whose fields\n * mirror `.hive-schema.graphql` exactly. No mocks.\n *\n * Conventions (mirrors microfe-kadaikodi):\n * - `hookmoviesQuery` wraps graphqlFetch({ gateway: 'workspace', workspaceToken: true })\n * and throws on GraphQL errors / missing data.\n * - One react-query `useQuery` per read op and `useMutation` per write op.\n * - Strict hand-written result interfaces — no `any`.\n * - Pagination uses the subgraph's `PaginationInput` (limit/offset/cursor) and\n * `Hok*Connection { items, pageInfo { cursor hasMore } }` shapes verbatim.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\n\nimport { useHookMovies } from '../context';\n\n// ============================================================================\n// Low-level query runner\n// ============================================================================\n\nconst hookmoviesQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n\n return response.data;\n};\n\nconst QK = 'hookmovies' as const;\n\n// ============================================================================\n// Shared scalar / enum types (mirror .hive-schema.graphql)\n// ============================================================================\n\nexport interface HokPaginationInput {\n cursor?: string | null;\n limit?: number | null;\n offset?: number | null;\n}\n\nexport interface HokPageInfo {\n cursor: string | null;\n hasMore: boolean;\n}\n\nexport type HokTitleType =\n | 'MOVIE'\n | 'SERIES'\n | 'SHORT_FILM'\n | 'DOCUMENTARY'\n | 'ANIME'\n | 'SHORT_FORM'\n | 'LONG_FORM'\n | 'LIVE_EVENT'\n | 'TRAILER'\n | 'COLLECTION'\n | 'FAST_CHANNEL';\n\nexport type HokTitleStatus =\n | 'DRAFT'\n | 'IN_REVIEW'\n | 'SCHEDULED'\n | 'PUBLISHED'\n | 'UNPUBLISHED'\n | 'ARCHIVED';\n\nexport type HokProductionStatus =\n | 'DEVELOPMENT'\n | 'GREENLIT'\n | 'IN_PRODUCTION'\n | 'POST_PRODUCTION'\n | 'RELEASED'\n | 'SHELVED';\n\nexport type HokAuditionStatus = 'OPEN' | 'REVIEWING' | 'CALLBACKS' | 'CLOSED' | 'CANCELLED';\n\nexport type HokApplicationStatus =\n | 'SUBMITTED'\n | 'SHORTLISTED'\n | 'CALLBACK'\n | 'OFFERED'\n | 'REJECTED'\n | 'WITHDRAWN';\n\nexport type HokCreditRole =\n | 'ACTOR'\n | 'DIRECTOR'\n | 'WRITER'\n | 'PRODUCER'\n | 'CINEMATOGRAPHER'\n | 'EDITOR'\n | 'COMPOSER'\n | 'VOICE_ACTOR'\n | 'CREW';\n\nexport type HokReviewStatus = 'PENDING' | 'PUBLISHED' | 'HIDDEN' | 'REMOVED';\n\nexport type HokRightsWindowStatus = 'DRAFT' | 'PENDING' | 'ACTIVE' | 'EXPIRED' | 'REVOKED';\n\nexport type HokMonetizationMode = 'FREE_AVOD' | 'SVOD' | 'TVOD_RENT' | 'TVOD_BUY' | 'PPV' | 'FAST';\n\nexport type HokEntitlementSource = 'SUBSCRIPTION' | 'PURCHASE' | 'RENTAL' | 'PROMO' | 'FREE';\n\nexport type HokEntitlementStatus = 'ACTIVE' | 'EXPIRED' | 'REVOKED';\n\nexport type HokListKind = 'WATCHLIST' | 'PLAYLIST';\n\nexport type HokListVisibility = 'PRIVATE' | 'UNLISTED' | 'PUBLIC';\n\n// ============================================================================\n// Domain object types\n// ============================================================================\n\nexport interface HokStudio {\n id: string;\n name: string;\n slug: string | null;\n description: string | null;\n country: string | null;\n websiteUrl: string | null;\n isVerified: boolean;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokPerson {\n id: string;\n name: string;\n biography: string | null;\n knownFor: string | null;\n primaryLanguage: string | null;\n portfolioRef: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokCredit {\n id: string;\n personId: string;\n titleId: string;\n role: HokCreditRole;\n characterName: string | null;\n billingOrder: number;\n person: Pick<HokPerson, 'id' | 'name' | 'knownFor'> | null;\n}\n\nexport interface HokEpisodeSummary {\n id: string;\n name: string;\n number: number;\n seasonId: string | null;\n synopsis: string | null;\n runtimeMinutes: number | null;\n airDate: string | null;\n}\n\nexport interface HokSeasonSummary {\n id: string;\n name: string | null;\n number: number;\n synopsis: string | null;\n}\n\nexport interface HokTitle {\n id: string;\n title: string;\n slug: string | null;\n type: HokTitleType;\n status: HokTitleStatus;\n synopsis: string | null;\n genres: string[];\n tags: string[];\n originalLanguage: string | null;\n originCountry: string | null;\n releaseYear: number | null;\n releaseDate: string | null;\n runtimeMinutes: number | null;\n certification: string | null;\n aiDisclosure: boolean;\n studioId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokTitleDetail extends HokTitle {\n studio: Pick<HokStudio, 'id' | 'name'> | null;\n credits: HokCredit[];\n seasons: HokSeasonSummary[];\n episodes: HokEpisodeSummary[];\n}\n\nexport interface HokProduction {\n id: string;\n title: string;\n logline: string | null;\n synopsis: string | null;\n status: HokProductionStatus;\n currency: string;\n budgetMinorUnits: string;\n studioId: string | null;\n producerId: string | null;\n resultingTitleId: string | null;\n artistrybaseProjectRef: string | null;\n tags: string[];\n startDate: string | null;\n endDate: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokAuditionSummary {\n id: string;\n roleName: string;\n status: HokAuditionStatus;\n isMinorRole: boolean;\n payMinorUnits: string;\n currency: string;\n location: string | null;\n language: string | null;\n submissionDeadline: string | null;\n}\n\nexport interface HokProductionDetail extends HokProduction {\n auditions: HokAuditionSummary[];\n}\n\nexport interface HokAudition {\n id: string;\n productionId: string;\n roleName: string;\n description: string | null;\n status: HokAuditionStatus;\n isMinorRole: boolean;\n payMinorUnits: string;\n currency: string;\n location: string | null;\n language: string | null;\n submissionDeadline: string | null;\n createdAt: string;\n updatedAt: string;\n production: Pick<HokProduction, 'id' | 'title'> | null;\n}\n\nexport interface HokApplication {\n id: string;\n auditionId: string;\n applicantId: string;\n coverNote: string | null;\n score: number | null;\n status: HokApplicationStatus;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokReview {\n id: string;\n titleId: string;\n authorId: string;\n score: number;\n body: string | null;\n hasSpoilers: boolean;\n helpfulCount: number;\n verifiedWatch: boolean;\n status: HokReviewStatus;\n createdAt: string;\n updatedAt: string;\n title: Pick<HokTitle, 'id' | 'title'> | null;\n}\n\nexport interface HokRightsWindow {\n id: string;\n titleId: string;\n status: HokRightsWindowStatus;\n modes: HokMonetizationMode[];\n territories: string[];\n exclusive: boolean;\n currency: string;\n licenseeId: string | null;\n startsAt: string | null;\n endsAt: string | null;\n createdAt: string;\n updatedAt: string;\n title: Pick<HokTitle, 'id' | 'title'> | null;\n}\n\nexport interface HokEntitlement {\n id: string;\n titleId: string;\n userId: string;\n mode: HokMonetizationMode;\n source: HokEntitlementSource;\n status: HokEntitlementStatus;\n territory: string | null;\n expiresAt: string | null;\n createdAt: string;\n updatedAt: string;\n title: Pick<HokTitle, 'id' | 'title'> | null;\n}\n\nexport interface HokList {\n id: string;\n name: string;\n description: string | null;\n kind: HokListKind;\n visibility: HokListVisibility;\n ownerId: string;\n itemCount: number;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokWatchProgress {\n id: string;\n titleId: string;\n episodeId: string | null;\n positionSeconds: number;\n completed: boolean;\n lastDevice: string | null;\n updatedAt: string;\n title: Pick<HokTitle, 'id' | 'title' | 'type'> | null;\n}\n\n// ============================================================================\n// Connection wrappers\n// ============================================================================\n\ninterface HokConnection<TItem> {\n items: TItem[];\n pageInfo: HokPageInfo;\n}\n\n// ============================================================================\n// Inline field selections (reused across ops)\n// ============================================================================\n\nconst TITLE_FIELDS = `\n id title slug type status synopsis genres tags originalLanguage originCountry\n releaseYear releaseDate runtimeMinutes certification aiDisclosure studioId\n createdAt updatedAt\n`;\n\nconst STUDIO_FIELDS = `\n id name slug description country websiteUrl isVerified tags createdAt updatedAt\n`;\n\nconst PERSON_FIELDS = `\n id name biography knownFor primaryLanguage portfolioRef tags createdAt updatedAt\n`;\n\nconst PRODUCTION_FIELDS = `\n id title logline synopsis status currency budgetMinorUnits studioId producerId\n resultingTitleId artistrybaseProjectRef tags startDate endDate createdAt updatedAt\n`;\n\nconst AUDITION_FIELDS = `\n id productionId roleName description status isMinorRole payMinorUnits currency\n location language submissionDeadline createdAt updatedAt\n`;\n\nconst REVIEW_FIELDS = `\n id titleId authorId score body hasSpoilers helpfulCount verifiedWatch status\n createdAt updatedAt\n`;\n\nconst RIGHTS_FIELDS = `\n id titleId status modes territories exclusive currency licenseeId startsAt endsAt\n createdAt updatedAt\n`;\n\nconst LIST_FIELDS = `\n id name description kind visibility ownerId itemCount createdAt updatedAt\n`;\n\nconst PAGE_INFO = `pageInfo { cursor hasMore }`;\n\n// ============================================================================\n// Titles\n// ============================================================================\n\nexport interface HokTitleFilters {\n status?: HokTitleStatus;\n type?: HokTitleType;\n studioId?: string;\n}\n\nexport const useTitles = (\n filters: HokTitleFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'titles', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListTitles: HokConnection<HokTitle> }>(\n `query HokTitles($pagination: PaginationInput, $status: HokTitleStatus, $type: HokTitleType, $studioId: ID) {\n hokListTitles(pagination: $pagination, status: $status, type: $type, studioId: $studioId) {\n items { ${TITLE_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n {\n pagination,\n status: filters.status,\n type: filters.type,\n studioId: filters.studioId,\n },\n apiGatewayUrl\n );\n return result.hokListTitles;\n },\n });\n};\n\nexport const useTitle = (id: string | undefined) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'title', id],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokTitle: HokTitleDetail | null }>(\n `query HokTitle($id: ID!) {\n hokTitle(id: $id) {\n ${TITLE_FIELDS}\n studio { id name }\n credits {\n id personId titleId role characterName billingOrder\n person { id name knownFor }\n }\n seasons { id name number synopsis }\n episodes { id name number seasonId synopsis runtimeMinutes airDate }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.hokTitle;\n },\n enabled: Boolean(id),\n });\n};\n\nexport interface CreateTitleInput {\n title: string;\n type?: HokTitleType;\n synopsis?: string;\n genres?: string[];\n tags?: string[];\n originalLanguage?: string;\n originCountry?: string;\n releaseYear?: number;\n runtimeMinutes?: number;\n certification?: string;\n slug?: string;\n studioId?: string;\n aiDisclosure?: boolean;\n}\n\nexport const useCreateTitle = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateTitleInput) => {\n const result = await hookmoviesQuery<{ hokCreateTitle: HokTitle }>(\n `mutation HokCreateTitle($input: HokCreateTitleInput!) {\n hokCreateTitle(input: $input) { ${TITLE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateTitle;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'titles'] });\n },\n });\n};\n\nexport interface UpdateTitleInput {\n title?: string;\n type?: HokTitleType;\n synopsis?: string;\n genres?: string[];\n tags?: string[];\n originalLanguage?: string;\n originCountry?: string;\n releaseYear?: number;\n runtimeMinutes?: number;\n certification?: string;\n slug?: string;\n studioId?: string;\n aiDisclosure?: boolean;\n}\n\nexport const useUpdateTitle = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, input }: { id: string; input: UpdateTitleInput }) => {\n const result = await hookmoviesQuery<{ hokUpdateTitle: HokTitle }>(\n `mutation HokUpdateTitle($id: ID!, $input: HokUpdateTitleInput!) {\n hokUpdateTitle(id: $id, input: $input) { ${TITLE_FIELDS} }\n }`,\n { id, input },\n apiGatewayUrl\n );\n return result.hokUpdateTitle;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'titles'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'title', data.id] });\n },\n });\n};\n\nexport const useTransitionTitle = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, status }: { id: string; status: HokTitleStatus }) => {\n const result = await hookmoviesQuery<{ hokTransitionTitle: HokTitle }>(\n `mutation HokTransitionTitle($id: ID!, $status: HokTitleStatus!) {\n hokTransitionTitle(id: $id, status: $status) { ${TITLE_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.hokTransitionTitle;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'titles'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'title', data.id] });\n },\n });\n};\n\nexport const useArchiveTitle = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokArchiveTitle: boolean }>(\n `mutation HokArchiveTitle($id: ID!) { hokArchiveTitle(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.hokArchiveTitle;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'titles'] });\n },\n });\n};\n\n// ============================================================================\n// Studios\n// ============================================================================\n\nexport const useStudios = (pagination: HokPaginationInput = { limit: 50, offset: 0 }) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'studios', pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListStudios: HokConnection<HokStudio> }>(\n `query HokStudios($pagination: PaginationInput) {\n hokListStudios(pagination: $pagination) {\n items { ${STUDIO_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n { pagination },\n apiGatewayUrl\n );\n return result.hokListStudios;\n },\n });\n};\n\nexport interface CreateStudioInput {\n name: string;\n slug?: string;\n description?: string;\n country?: string;\n websiteUrl?: string;\n tags?: string[];\n}\n\nexport const useCreateStudio = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateStudioInput) => {\n const result = await hookmoviesQuery<{ hokCreateStudio: HokStudio }>(\n `mutation HokCreateStudio($input: HokCreateStudioInput!) {\n hokCreateStudio(input: $input) { ${STUDIO_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateStudio;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'studios'] });\n },\n });\n};\n\n// ============================================================================\n// People\n// ============================================================================\n\nexport const usePeople = (pagination: HokPaginationInput = { limit: 50, offset: 0 }) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'people', pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListPeople: HokConnection<HokPerson> }>(\n `query HokPeople($pagination: PaginationInput) {\n hokListPeople(pagination: $pagination) {\n items { ${PERSON_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n { pagination },\n apiGatewayUrl\n );\n return result.hokListPeople;\n },\n });\n};\n\nexport interface CreatePersonInput {\n name: string;\n biography?: string;\n knownFor?: string;\n primaryLanguage?: string;\n portfolioRef?: string;\n tags?: string[];\n}\n\nexport const useCreatePerson = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreatePersonInput) => {\n const result = await hookmoviesQuery<{ hokCreatePerson: HokPerson }>(\n `mutation HokCreatePerson($input: HokCreatePersonInput!) {\n hokCreatePerson(input: $input) { ${PERSON_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreatePerson;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'people'] });\n },\n });\n};\n\n// ============================================================================\n// Productions\n// ============================================================================\n\nexport interface HokProductionFilters {\n status?: HokProductionStatus;\n studioId?: string;\n}\n\nexport const useProductions = (\n filters: HokProductionFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'productions', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListProductions: HokConnection<HokProduction> }>(\n `query HokProductions($pagination: PaginationInput, $status: HokProductionStatus, $studioId: ID) {\n hokListProductions(pagination: $pagination, status: $status, studioId: $studioId) {\n items { ${PRODUCTION_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n { pagination, status: filters.status, studioId: filters.studioId },\n apiGatewayUrl\n );\n return result.hokListProductions;\n },\n });\n};\n\nexport const useProduction = (id: string | undefined) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'production', id],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokProduction: HokProductionDetail | null }>(\n `query HokProduction($id: ID!) {\n hokProduction(id: $id) {\n ${PRODUCTION_FIELDS}\n auditions {\n id roleName status isMinorRole payMinorUnits currency location language submissionDeadline\n }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.hokProduction;\n },\n enabled: Boolean(id),\n });\n};\n\nexport interface CreateProductionInput {\n title: string;\n logline?: string;\n synopsis?: string;\n currency?: string;\n budgetMinorUnits?: string;\n studioId?: string;\n producerId?: string;\n artistrybaseProjectRef?: string;\n tags?: string[];\n startDate?: string;\n endDate?: string;\n}\n\nexport const useCreateProduction = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateProductionInput) => {\n const result = await hookmoviesQuery<{ hokCreateProduction: HokProduction }>(\n `mutation HokCreateProduction($input: HokCreateProductionInput!) {\n hokCreateProduction(input: $input) { ${PRODUCTION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateProduction;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'productions'] });\n },\n });\n};\n\nexport const useTransitionProduction = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, status }: { id: string; status: HokProductionStatus }) => {\n const result = await hookmoviesQuery<{ hokTransitionProduction: HokProduction }>(\n `mutation HokTransitionProduction($id: ID!, $status: HokProductionStatus!) {\n hokTransitionProduction(id: $id, status: $status) { ${PRODUCTION_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.hokTransitionProduction;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'productions'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'production', data.id] });\n },\n });\n};\n\n// ============================================================================\n// Auditions & Applications\n// ============================================================================\n\nexport interface HokAuditionFilters {\n status?: HokAuditionStatus;\n productionId?: string;\n}\n\nexport const useAuditions = (\n filters: HokAuditionFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'auditions', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListAuditions: HokConnection<HokAudition> }>(\n `query HokAuditions($pagination: PaginationInput, $status: HokAuditionStatus, $productionId: ID) {\n hokListAuditions(pagination: $pagination, status: $status, productionId: $productionId) {\n items {\n ${AUDITION_FIELDS}\n production { id title }\n }\n ${PAGE_INFO}\n }\n }`,\n { pagination, status: filters.status, productionId: filters.productionId },\n apiGatewayUrl\n );\n return result.hokListAuditions;\n },\n });\n};\n\n/**\n * Resolve a single audition by id. The subgraph exposes no `hokAudition(id)`\n * root field, so we read the (workspace-scoped) audition list and pick the row.\n * Fetched with a generous page size since auditions are workspace-bounded.\n */\nexport const useAuditionById = (id: string | undefined) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'audition-by-id', id],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListAuditions: HokConnection<HokAudition> }>(\n `query HokAuditionLookup($pagination: PaginationInput) {\n hokListAuditions(pagination: $pagination) {\n items {\n ${AUDITION_FIELDS}\n production { id title }\n }\n ${PAGE_INFO}\n }\n }`,\n { pagination: { limit: 200, offset: 0 } },\n apiGatewayUrl\n );\n return result.hokListAuditions.items.find((a) => a.id === id) ?? null;\n },\n enabled: Boolean(id),\n });\n};\n\nexport const useAuditionApplications = (auditionId: string | undefined) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'applications', auditionId],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListApplications: HokApplication[] }>(\n `query HokApplications($auditionId: ID!) {\n hokListApplications(auditionId: $auditionId) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }`,\n { auditionId },\n apiGatewayUrl\n );\n return result.hokListApplications;\n },\n enabled: Boolean(auditionId),\n });\n};\n\nexport interface CreateAuditionInput {\n productionId: string;\n roleName: string;\n description?: string;\n payMinorUnits?: string;\n currency?: string;\n location?: string;\n language?: string;\n isMinorRole?: boolean;\n submissionDeadline?: string;\n}\n\nexport const useCreateAudition = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateAuditionInput) => {\n const result = await hookmoviesQuery<{ hokCreateAudition: HokAudition }>(\n `mutation HokCreateAudition($input: HokCreateAuditionInput!) {\n hokCreateAudition(input: $input) { ${AUDITION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateAudition;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'auditions'] });\n },\n });\n};\n\nexport const useCloseAudition = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokCloseAudition: HokAudition }>(\n `mutation HokCloseAudition($id: ID!) {\n hokCloseAudition(id: $id) { ${AUDITION_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.hokCloseAudition;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'auditions'] });\n },\n });\n};\n\nexport interface ApplyToAuditionInput {\n auditionId: string;\n coverNote?: string;\n selfTapeFileId?: string;\n}\n\nexport const useApplyToAudition = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: ApplyToAuditionInput) => {\n const result = await hookmoviesQuery<{ hokApplyToAudition: HokApplication }>(\n `mutation HokApplyToAudition($input: HokApplyToAuditionInput!) {\n hokApplyToAudition(input: $input) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokApplyToAudition;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'applications', data.auditionId] });\n },\n });\n};\n\nexport const useScoreApplication = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, score }: { id: string; score: number }) => {\n const result = await hookmoviesQuery<{ hokScoreApplication: HokApplication }>(\n `mutation HokScoreApplication($id: ID!, $score: Int!) {\n hokScoreApplication(id: $id, score: $score) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }`,\n { id, score },\n apiGatewayUrl\n );\n return result.hokScoreApplication;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'applications', data.auditionId] });\n },\n });\n};\n\n// ============================================================================\n// Reviews\n// ============================================================================\n\nexport interface HokReviewFilters {\n status?: HokReviewStatus;\n titleId?: string;\n}\n\nexport const useReviews = (\n filters: HokReviewFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'reviews', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListReviews: HokConnection<HokReview> }>(\n `query HokReviews($pagination: PaginationInput, $status: HokReviewStatus, $titleId: ID) {\n hokListReviews(pagination: $pagination, status: $status, titleId: $titleId) {\n items {\n ${REVIEW_FIELDS}\n title { id title }\n }\n ${PAGE_INFO}\n }\n }`,\n { pagination, status: filters.status, titleId: filters.titleId },\n apiGatewayUrl\n );\n return result.hokListReviews;\n },\n });\n};\n\nexport interface CreateReviewInput {\n titleId: string;\n score: number;\n body?: string;\n hasSpoilers?: boolean;\n aspectScores?: Record<string, unknown>;\n}\n\nexport const useCreateReview = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateReviewInput) => {\n const result = await hookmoviesQuery<{ hokCreateReview: HokReview }>(\n `mutation HokCreateReview($input: HokCreateReviewInput!) {\n hokCreateReview(input: $input) { ${REVIEW_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateReview;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'reviews'] });\n },\n });\n};\n\nexport const useDeleteReview = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokDeleteReview: boolean }>(\n `mutation HokDeleteReview($id: ID!) { hokDeleteReview(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.hokDeleteReview;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'reviews'] });\n },\n });\n};\n\n// ============================================================================\n// Rights Windows\n// ============================================================================\n\nexport interface HokRightsFilters {\n status?: HokRightsWindowStatus;\n titleId?: string;\n}\n\nexport const useRightsWindows = (\n filters: HokRightsFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'rights', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{\n hokListRightsWindows: HokConnection<HokRightsWindow>;\n }>(\n `query HokRightsWindows($pagination: PaginationInput, $status: HokRightsWindowStatus, $titleId: ID) {\n hokListRightsWindows(pagination: $pagination, status: $status, titleId: $titleId) {\n items {\n ${RIGHTS_FIELDS}\n title { id title }\n }\n ${PAGE_INFO}\n }\n }`,\n { pagination, status: filters.status, titleId: filters.titleId },\n apiGatewayUrl\n );\n return result.hokListRightsWindows;\n },\n });\n};\n\nexport interface CreateRightsWindowInput {\n titleId: string;\n modes: HokMonetizationMode[];\n territories?: string[];\n exclusive?: boolean;\n currency?: string;\n licenseeId?: string;\n startsAt?: string;\n endsAt?: string;\n contractFileId?: string;\n priceMinorUnits?: Record<string, unknown>;\n}\n\nexport const useCreateRightsWindow = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateRightsWindowInput) => {\n const result = await hookmoviesQuery<{ hokCreateRightsWindow: HokRightsWindow }>(\n `mutation HokCreateRightsWindow($input: HokCreateRightsWindowInput!) {\n hokCreateRightsWindow(input: $input) { ${RIGHTS_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateRightsWindow;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'rights'] });\n },\n });\n};\n\nexport const useTransitionRightsWindow = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, status }: { id: string; status: HokRightsWindowStatus }) => {\n const result = await hookmoviesQuery<{ hokTransitionRightsWindow: HokRightsWindow }>(\n `mutation HokTransitionRightsWindow($id: ID!, $status: HokRightsWindowStatus!) {\n hokTransitionRightsWindow(id: $id, status: $status) { ${RIGHTS_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.hokTransitionRightsWindow;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'rights'] });\n },\n });\n};\n\nexport const useRevokeEntitlement = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokRevokeEntitlement: boolean }>(\n `mutation HokRevokeEntitlement($id: ID!) { hokRevokeEntitlement(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.hokRevokeEntitlement;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'my-entitlements'] });\n },\n });\n};\n\n// ============================================================================\n// Entitlements (self-scoped)\n// ============================================================================\n\nexport const useMyEntitlements = (titleId?: string) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'my-entitlements', titleId],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokMyEntitlements: HokEntitlement[] }>(\n `query HokMyEntitlements($titleId: ID) {\n hokMyEntitlements(titleId: $titleId) {\n id titleId userId mode source status territory expiresAt createdAt updatedAt\n title { id title }\n }\n }`,\n { titleId },\n apiGatewayUrl\n );\n return result.hokMyEntitlements;\n },\n });\n};\n\n// ============================================================================\n// Lists / Watchlists (self-scoped)\n// ============================================================================\n\nexport const useMyLists = (\n kind?: HokListKind,\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'my-lists', kind, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokMyLists: HokConnection<HokList> }>(\n `query HokMyLists($kind: HokListKind, $pagination: PaginationInput) {\n hokMyLists(kind: $kind, pagination: $pagination) {\n items { ${LIST_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n { kind, pagination },\n apiGatewayUrl\n );\n return result.hokMyLists;\n },\n });\n};\n\nexport interface CreateListInput {\n name: string;\n description?: string;\n kind?: HokListKind;\n visibility?: HokListVisibility;\n items?: Record<string, unknown>;\n}\n\nexport const useCreateList = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateListInput) => {\n const result = await hookmoviesQuery<{ hokCreateList: HokList }>(\n `mutation HokCreateList($input: HokCreateListInput!) {\n hokCreateList(input: $input) { ${LIST_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateList;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'my-lists'] });\n },\n });\n};\n\nexport const useDeleteList = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokDeleteList: boolean }>(\n `mutation HokDeleteList($id: ID!) { hokDeleteList(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.hokDeleteList;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'my-lists'] });\n },\n });\n};\n\n// ============================================================================\n// Watch progress / Continue Watching (self-scoped)\n// ============================================================================\n\nexport const useMyWatchProgress = (titleId?: string) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'my-watch-progress', titleId],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokMyWatchProgress: HokWatchProgress[] }>(\n `query HokMyWatchProgress($titleId: ID) {\n hokMyWatchProgress(titleId: $titleId) {\n id titleId episodeId positionSeconds completed lastDevice updatedAt\n title { id title type }\n }\n }`,\n { titleId },\n apiGatewayUrl\n );\n return result.hokMyWatchProgress;\n },\n });\n};\n\n// ============================================================================\n// Health probe (used by the dashboard service-status card)\n// ============================================================================\n\nexport const useHealth = () => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'health'],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokHealth: string }>(\n `query HokHealth { hokHealth }`,\n {},\n apiGatewayUrl\n );\n return result.hokHealth;\n },\n staleTime: 60 * 1000,\n });\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"useHookMoviesApi.js","names":[],"sources":["../../../src/hookmovies/hooks/useHookMoviesApi.ts"],"sourcesContent":["/**\n * HookMovies API hooks\n * @module hookmovies/hooks\n *\n * Real data layer for the HookMovies workspace subgraph (`hookmovies` Hive\n * service / `wspace-hookmovies-svc`). Every hook talks to the live workspace\n * GraphQL gateway via {@link graphqlFetch} with inline operations whose fields\n * mirror `.hive-schema.graphql` exactly. No mocks.\n *\n * Conventions (mirrors microfe-kadaikodi):\n * - `hookmoviesQuery` wraps graphqlFetch({ gateway: 'workspace', workspaceToken: true })\n * and throws on GraphQL errors / missing data.\n * - One react-query `useQuery` per read op and `useMutation` per write op.\n * - Strict hand-written result interfaces — no `any`.\n * - Pagination uses the subgraph's `PaginationInput` (limit/offset/cursor) and\n * `Hok*Connection { items, pageInfo { cursor hasMore } }` shapes verbatim.\n */\n\nimport { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';\n\nimport { graphqlFetch } from '@burdenoff/fe-libs/shared/graphql';\nimport { clearGraphqlFetchResponseCache } from '@burdenoff/fe-libs/shared/graphql/fetch';\n\nimport { useHookMovies } from '../context';\n\n// ============================================================================\n// Low-level query runner\n// ============================================================================\n\nconst hookmoviesQuery = async <TData>(\n query: string,\n variables: Record<string, unknown>,\n baseUrl?: string\n): Promise<TData> => {\n const response = await graphqlFetch<TData>({\n gateway: 'workspace',\n baseUrl,\n query,\n variables,\n workspaceToken: true,\n });\n\n if (response.errors?.length) {\n throw new Error(response.errors[0]?.message ?? 'GraphQL request failed');\n }\n\n if (!response.data) {\n throw new Error('GraphQL response did not include data');\n }\n\n // This MFE bypasses Apollo, so fe-libs' short-lived graphqlFetch read cache\n // (~15s) would otherwise serve pre-write data to the very next refetch issued\n // by a mutation's onSuccess invalidation. Clear it after any successful\n // mutation so every downstream read is fresh (fleet-wide stale-read-after-\n // write fix).\n if (query.trimStart().startsWith('mutation')) {\n clearGraphqlFetchResponseCache();\n }\n\n return response.data;\n};\n\nconst QK = 'hookmovies' as const;\n\n// ============================================================================\n// Shared scalar / enum types (mirror .hive-schema.graphql)\n// ============================================================================\n\nexport interface HokPaginationInput {\n cursor?: string | null;\n limit?: number | null;\n offset?: number | null;\n}\n\nexport interface HokPageInfo {\n cursor: string | null;\n hasMore: boolean;\n}\n\nexport type HokTitleType =\n | 'MOVIE'\n | 'SERIES'\n | 'SHORT_FILM'\n | 'DOCUMENTARY'\n | 'ANIME'\n | 'SHORT_FORM'\n | 'LONG_FORM'\n | 'LIVE_EVENT'\n | 'TRAILER'\n | 'COLLECTION'\n | 'FAST_CHANNEL';\n\nexport type HokTitleStatus =\n | 'DRAFT'\n | 'IN_REVIEW'\n | 'SCHEDULED'\n | 'PUBLISHED'\n | 'UNPUBLISHED'\n | 'ARCHIVED';\n\nexport type HokProductionStatus =\n | 'DEVELOPMENT'\n | 'GREENLIT'\n | 'IN_PRODUCTION'\n | 'POST_PRODUCTION'\n | 'RELEASED'\n | 'SHELVED';\n\nexport type HokAuditionStatus = 'OPEN' | 'REVIEWING' | 'CALLBACKS' | 'CLOSED' | 'CANCELLED';\n\nexport type HokApplicationStatus =\n | 'SUBMITTED'\n | 'SHORTLISTED'\n | 'CALLBACK'\n | 'OFFERED'\n | 'REJECTED'\n | 'WITHDRAWN';\n\nexport type HokCreditRole =\n | 'ACTOR'\n | 'DIRECTOR'\n | 'WRITER'\n | 'PRODUCER'\n | 'CINEMATOGRAPHER'\n | 'EDITOR'\n | 'COMPOSER'\n | 'VOICE_ACTOR'\n | 'CREW';\n\nexport type HokReviewStatus = 'PENDING' | 'PUBLISHED' | 'HIDDEN' | 'REMOVED';\n\nexport type HokRightsWindowStatus = 'DRAFT' | 'PENDING' | 'ACTIVE' | 'EXPIRED' | 'REVOKED';\n\nexport type HokMonetizationMode = 'FREE_AVOD' | 'SVOD' | 'TVOD_RENT' | 'TVOD_BUY' | 'PPV' | 'FAST';\n\nexport type HokEntitlementSource = 'SUBSCRIPTION' | 'PURCHASE' | 'RENTAL' | 'PROMO' | 'FREE';\n\nexport type HokEntitlementStatus = 'ACTIVE' | 'EXPIRED' | 'REVOKED';\n\nexport type HokListKind = 'WATCHLIST' | 'PLAYLIST';\n\nexport type HokListVisibility = 'PRIVATE' | 'UNLISTED' | 'PUBLIC';\n\n// ============================================================================\n// Domain object types\n// ============================================================================\n\nexport interface HokStudio {\n id: string;\n name: string;\n slug: string | null;\n description: string | null;\n country: string | null;\n websiteUrl: string | null;\n isVerified: boolean;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokPerson {\n id: string;\n name: string;\n biography: string | null;\n knownFor: string | null;\n primaryLanguage: string | null;\n portfolioRef: string | null;\n tags: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokCredit {\n id: string;\n personId: string;\n titleId: string;\n role: HokCreditRole;\n characterName: string | null;\n billingOrder: number;\n person: Pick<HokPerson, 'id' | 'name' | 'knownFor'> | null;\n}\n\nexport interface HokEpisodeSummary {\n id: string;\n name: string;\n number: number;\n seasonId: string | null;\n synopsis: string | null;\n runtimeMinutes: number | null;\n airDate: string | null;\n}\n\nexport interface HokSeasonSummary {\n id: string;\n name: string | null;\n number: number;\n synopsis: string | null;\n}\n\nexport interface HokTitle {\n id: string;\n title: string;\n slug: string | null;\n type: HokTitleType;\n status: HokTitleStatus;\n synopsis: string | null;\n genres: string[];\n tags: string[];\n originalLanguage: string | null;\n originCountry: string | null;\n releaseYear: number | null;\n releaseDate: string | null;\n runtimeMinutes: number | null;\n certification: string | null;\n aiDisclosure: boolean;\n studioId: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokTitleDetail extends HokTitle {\n studio: Pick<HokStudio, 'id' | 'name'> | null;\n credits: HokCredit[];\n seasons: HokSeasonSummary[];\n episodes: HokEpisodeSummary[];\n}\n\nexport interface HokProduction {\n id: string;\n title: string;\n logline: string | null;\n synopsis: string | null;\n status: HokProductionStatus;\n currency: string;\n budgetMinorUnits: string;\n studioId: string | null;\n producerId: string | null;\n resultingTitleId: string | null;\n artistrybaseProjectRef: string | null;\n tags: string[];\n startDate: string | null;\n endDate: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokAuditionSummary {\n id: string;\n roleName: string;\n status: HokAuditionStatus;\n isMinorRole: boolean;\n payMinorUnits: string;\n currency: string;\n location: string | null;\n language: string | null;\n submissionDeadline: string | null;\n}\n\nexport interface HokProductionDetail extends HokProduction {\n auditions: HokAuditionSummary[];\n}\n\nexport interface HokAudition {\n id: string;\n productionId: string;\n roleName: string;\n description: string | null;\n status: HokAuditionStatus;\n isMinorRole: boolean;\n payMinorUnits: string;\n currency: string;\n location: string | null;\n language: string | null;\n submissionDeadline: string | null;\n createdAt: string;\n updatedAt: string;\n production: Pick<HokProduction, 'id' | 'title'> | null;\n}\n\nexport interface HokApplication {\n id: string;\n auditionId: string;\n applicantId: string;\n coverNote: string | null;\n score: number | null;\n status: HokApplicationStatus;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokReview {\n id: string;\n titleId: string;\n authorId: string;\n score: number;\n body: string | null;\n hasSpoilers: boolean;\n helpfulCount: number;\n verifiedWatch: boolean;\n status: HokReviewStatus;\n createdAt: string;\n updatedAt: string;\n title: Pick<HokTitle, 'id' | 'title'> | null;\n}\n\nexport interface HokRightsWindow {\n id: string;\n titleId: string;\n status: HokRightsWindowStatus;\n modes: HokMonetizationMode[];\n territories: string[];\n exclusive: boolean;\n currency: string;\n licenseeId: string | null;\n startsAt: string | null;\n endsAt: string | null;\n createdAt: string;\n updatedAt: string;\n title: Pick<HokTitle, 'id' | 'title'> | null;\n}\n\nexport interface HokEntitlement {\n id: string;\n titleId: string;\n userId: string;\n mode: HokMonetizationMode;\n source: HokEntitlementSource;\n status: HokEntitlementStatus;\n territory: string | null;\n expiresAt: string | null;\n createdAt: string;\n updatedAt: string;\n title: Pick<HokTitle, 'id' | 'title'> | null;\n}\n\nexport interface HokList {\n id: string;\n name: string;\n description: string | null;\n kind: HokListKind;\n visibility: HokListVisibility;\n ownerId: string;\n itemCount: number;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface HokWatchProgress {\n id: string;\n titleId: string;\n episodeId: string | null;\n positionSeconds: number;\n completed: boolean;\n lastDevice: string | null;\n updatedAt: string;\n title: Pick<HokTitle, 'id' | 'title' | 'type'> | null;\n}\n\n// ============================================================================\n// Connection wrappers\n// ============================================================================\n\ninterface HokConnection<TItem> {\n items: TItem[];\n pageInfo: HokPageInfo;\n}\n\n// ============================================================================\n// Inline field selections (reused across ops)\n// ============================================================================\n\nconst TITLE_FIELDS = `\n id title slug type status synopsis genres tags originalLanguage originCountry\n releaseYear releaseDate runtimeMinutes certification aiDisclosure studioId\n createdAt updatedAt\n`;\n\nconst STUDIO_FIELDS = `\n id name slug description country websiteUrl isVerified tags createdAt updatedAt\n`;\n\nconst PERSON_FIELDS = `\n id name biography knownFor primaryLanguage portfolioRef tags createdAt updatedAt\n`;\n\nconst PRODUCTION_FIELDS = `\n id title logline synopsis status currency budgetMinorUnits studioId producerId\n resultingTitleId artistrybaseProjectRef tags startDate endDate createdAt updatedAt\n`;\n\nconst AUDITION_FIELDS = `\n id productionId roleName description status isMinorRole payMinorUnits currency\n location language submissionDeadline createdAt updatedAt\n`;\n\nconst REVIEW_FIELDS = `\n id titleId authorId score body hasSpoilers helpfulCount verifiedWatch status\n createdAt updatedAt\n`;\n\nconst RIGHTS_FIELDS = `\n id titleId status modes territories exclusive currency licenseeId startsAt endsAt\n createdAt updatedAt\n`;\n\nconst LIST_FIELDS = `\n id name description kind visibility ownerId itemCount createdAt updatedAt\n`;\n\nconst PAGE_INFO = `pageInfo { cursor hasMore }`;\n\n// ============================================================================\n// Titles\n// ============================================================================\n\nexport interface HokTitleFilters {\n status?: HokTitleStatus;\n type?: HokTitleType;\n studioId?: string;\n}\n\nexport const useTitles = (\n filters: HokTitleFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'titles', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListTitles: HokConnection<HokTitle> }>(\n `query HokTitles($pagination: PaginationInput, $status: HokTitleStatus, $type: HokTitleType, $studioId: ID) {\n hokListTitles(pagination: $pagination, status: $status, type: $type, studioId: $studioId) {\n items { ${TITLE_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n {\n pagination,\n status: filters.status,\n type: filters.type,\n studioId: filters.studioId,\n },\n apiGatewayUrl\n );\n return result.hokListTitles;\n },\n });\n};\n\nexport const useTitle = (id: string | undefined) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'title', id],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokTitle: HokTitleDetail | null }>(\n `query HokTitle($id: ID!) {\n hokTitle(id: $id) {\n ${TITLE_FIELDS}\n studio { id name }\n credits {\n id personId titleId role characterName billingOrder\n person { id name knownFor }\n }\n seasons { id name number synopsis }\n episodes { id name number seasonId synopsis runtimeMinutes airDate }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.hokTitle;\n },\n enabled: Boolean(id),\n });\n};\n\nexport interface CreateTitleInput {\n title: string;\n type?: HokTitleType;\n synopsis?: string;\n genres?: string[];\n tags?: string[];\n originalLanguage?: string;\n originCountry?: string;\n releaseYear?: number;\n runtimeMinutes?: number;\n certification?: string;\n slug?: string;\n studioId?: string;\n aiDisclosure?: boolean;\n}\n\nexport const useCreateTitle = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateTitleInput) => {\n const result = await hookmoviesQuery<{ hokCreateTitle: HokTitle }>(\n `mutation HokCreateTitle($input: HokCreateTitleInput!) {\n hokCreateTitle(input: $input) { ${TITLE_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateTitle;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'titles'] });\n },\n });\n};\n\nexport interface UpdateTitleInput {\n title?: string;\n type?: HokTitleType;\n synopsis?: string;\n genres?: string[];\n tags?: string[];\n originalLanguage?: string;\n originCountry?: string;\n releaseYear?: number;\n runtimeMinutes?: number;\n certification?: string;\n slug?: string;\n studioId?: string;\n aiDisclosure?: boolean;\n}\n\nexport const useUpdateTitle = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, input }: { id: string; input: UpdateTitleInput }) => {\n const result = await hookmoviesQuery<{ hokUpdateTitle: HokTitle }>(\n `mutation HokUpdateTitle($id: ID!, $input: HokUpdateTitleInput!) {\n hokUpdateTitle(id: $id, input: $input) { ${TITLE_FIELDS} }\n }`,\n { id, input },\n apiGatewayUrl\n );\n return result.hokUpdateTitle;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'titles'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'title', data.id] });\n },\n });\n};\n\nexport const useTransitionTitle = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, status }: { id: string; status: HokTitleStatus }) => {\n const result = await hookmoviesQuery<{ hokTransitionTitle: HokTitle }>(\n `mutation HokTransitionTitle($id: ID!, $status: HokTitleStatus!) {\n hokTransitionTitle(id: $id, status: $status) { ${TITLE_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.hokTransitionTitle;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'titles'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'title', data.id] });\n },\n });\n};\n\nexport const useArchiveTitle = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokArchiveTitle: boolean }>(\n `mutation HokArchiveTitle($id: ID!) { hokArchiveTitle(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.hokArchiveTitle;\n },\n onSuccess: (_data, id) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'titles'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'title', id] });\n },\n });\n};\n\n// ============================================================================\n// Studios\n// ============================================================================\n\nexport const useStudios = (pagination: HokPaginationInput = { limit: 50, offset: 0 }) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'studios', pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListStudios: HokConnection<HokStudio> }>(\n `query HokStudios($pagination: PaginationInput) {\n hokListStudios(pagination: $pagination) {\n items { ${STUDIO_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n { pagination },\n apiGatewayUrl\n );\n return result.hokListStudios;\n },\n });\n};\n\nexport interface CreateStudioInput {\n name: string;\n slug?: string;\n description?: string;\n country?: string;\n websiteUrl?: string;\n tags?: string[];\n}\n\nexport const useCreateStudio = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateStudioInput) => {\n const result = await hookmoviesQuery<{ hokCreateStudio: HokStudio }>(\n `mutation HokCreateStudio($input: HokCreateStudioInput!) {\n hokCreateStudio(input: $input) { ${STUDIO_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateStudio;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'studios'] });\n },\n });\n};\n\n// ============================================================================\n// People\n// ============================================================================\n\nexport const usePeople = (pagination: HokPaginationInput = { limit: 50, offset: 0 }) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'people', pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListPeople: HokConnection<HokPerson> }>(\n `query HokPeople($pagination: PaginationInput) {\n hokListPeople(pagination: $pagination) {\n items { ${PERSON_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n { pagination },\n apiGatewayUrl\n );\n return result.hokListPeople;\n },\n });\n};\n\nexport interface CreatePersonInput {\n name: string;\n biography?: string;\n knownFor?: string;\n primaryLanguage?: string;\n portfolioRef?: string;\n tags?: string[];\n}\n\nexport const useCreatePerson = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreatePersonInput) => {\n const result = await hookmoviesQuery<{ hokCreatePerson: HokPerson }>(\n `mutation HokCreatePerson($input: HokCreatePersonInput!) {\n hokCreatePerson(input: $input) { ${PERSON_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreatePerson;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'people'] });\n },\n });\n};\n\n// ============================================================================\n// Productions\n// ============================================================================\n\nexport interface HokProductionFilters {\n status?: HokProductionStatus;\n studioId?: string;\n}\n\nexport const useProductions = (\n filters: HokProductionFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'productions', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListProductions: HokConnection<HokProduction> }>(\n `query HokProductions($pagination: PaginationInput, $status: HokProductionStatus, $studioId: ID) {\n hokListProductions(pagination: $pagination, status: $status, studioId: $studioId) {\n items { ${PRODUCTION_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n { pagination, status: filters.status, studioId: filters.studioId },\n apiGatewayUrl\n );\n return result.hokListProductions;\n },\n });\n};\n\nexport const useProduction = (id: string | undefined) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'production', id],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokProduction: HokProductionDetail | null }>(\n `query HokProduction($id: ID!) {\n hokProduction(id: $id) {\n ${PRODUCTION_FIELDS}\n auditions {\n id roleName status isMinorRole payMinorUnits currency location language submissionDeadline\n }\n }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.hokProduction;\n },\n enabled: Boolean(id),\n });\n};\n\nexport interface CreateProductionInput {\n title: string;\n logline?: string;\n synopsis?: string;\n currency?: string;\n budgetMinorUnits?: string;\n studioId?: string;\n producerId?: string;\n artistrybaseProjectRef?: string;\n tags?: string[];\n startDate?: string;\n endDate?: string;\n}\n\nexport const useCreateProduction = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateProductionInput) => {\n const result = await hookmoviesQuery<{ hokCreateProduction: HokProduction }>(\n `mutation HokCreateProduction($input: HokCreateProductionInput!) {\n hokCreateProduction(input: $input) { ${PRODUCTION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateProduction;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'productions'] });\n },\n });\n};\n\nexport const useTransitionProduction = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, status }: { id: string; status: HokProductionStatus }) => {\n const result = await hookmoviesQuery<{ hokTransitionProduction: HokProduction }>(\n `mutation HokTransitionProduction($id: ID!, $status: HokProductionStatus!) {\n hokTransitionProduction(id: $id, status: $status) { ${PRODUCTION_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.hokTransitionProduction;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'productions'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'production', data.id] });\n },\n });\n};\n\n// ============================================================================\n// Auditions & Applications\n// ============================================================================\n\nexport interface HokAuditionFilters {\n status?: HokAuditionStatus;\n productionId?: string;\n}\n\nexport const useAuditions = (\n filters: HokAuditionFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'auditions', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListAuditions: HokConnection<HokAudition> }>(\n `query HokAuditions($pagination: PaginationInput, $status: HokAuditionStatus, $productionId: ID) {\n hokListAuditions(pagination: $pagination, status: $status, productionId: $productionId) {\n items {\n ${AUDITION_FIELDS}\n production { id title }\n }\n ${PAGE_INFO}\n }\n }`,\n { pagination, status: filters.status, productionId: filters.productionId },\n apiGatewayUrl\n );\n return result.hokListAuditions;\n },\n });\n};\n\n/**\n * Resolve a single audition by id. The subgraph exposes no `hokAudition(id)`\n * root field, so we read the (workspace-scoped) audition list and pick the row.\n * Fetched with a generous page size since auditions are workspace-bounded.\n */\nexport const useAuditionById = (id: string | undefined) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'audition-by-id', id],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListAuditions: HokConnection<HokAudition> }>(\n `query HokAuditionLookup($pagination: PaginationInput) {\n hokListAuditions(pagination: $pagination) {\n items {\n ${AUDITION_FIELDS}\n production { id title }\n }\n ${PAGE_INFO}\n }\n }`,\n { pagination: { limit: 200, offset: 0 } },\n apiGatewayUrl\n );\n return result.hokListAuditions.items.find((a) => a.id === id) ?? null;\n },\n enabled: Boolean(id),\n });\n};\n\nexport const useAuditionApplications = (auditionId: string | undefined) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'applications', auditionId],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListApplications: HokApplication[] }>(\n `query HokApplications($auditionId: ID!) {\n hokListApplications(auditionId: $auditionId) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }`,\n { auditionId },\n apiGatewayUrl\n );\n return result.hokListApplications;\n },\n enabled: Boolean(auditionId),\n });\n};\n\nexport interface CreateAuditionInput {\n productionId: string;\n roleName: string;\n description?: string;\n payMinorUnits?: string;\n currency?: string;\n location?: string;\n language?: string;\n isMinorRole?: boolean;\n submissionDeadline?: string;\n}\n\nexport const useCreateAudition = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateAuditionInput) => {\n const result = await hookmoviesQuery<{ hokCreateAudition: HokAudition }>(\n `mutation HokCreateAudition($input: HokCreateAuditionInput!) {\n hokCreateAudition(input: $input) { ${AUDITION_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateAudition;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'auditions'] });\n },\n });\n};\n\nexport const useCloseAudition = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokCloseAudition: HokAudition }>(\n `mutation HokCloseAudition($id: ID!) {\n hokCloseAudition(id: $id) { ${AUDITION_FIELDS} }\n }`,\n { id },\n apiGatewayUrl\n );\n return result.hokCloseAudition;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'auditions'] });\n void queryClient.invalidateQueries({ queryKey: [QK, 'audition-by-id', data.id] });\n },\n });\n};\n\nexport interface ApplyToAuditionInput {\n auditionId: string;\n coverNote?: string;\n selfTapeFileId?: string;\n}\n\nexport const useApplyToAudition = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: ApplyToAuditionInput) => {\n const result = await hookmoviesQuery<{ hokApplyToAudition: HokApplication }>(\n `mutation HokApplyToAudition($input: HokApplyToAuditionInput!) {\n hokApplyToAudition(input: $input) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokApplyToAudition;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'applications', data.auditionId] });\n },\n });\n};\n\nexport const useScoreApplication = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, score }: { id: string; score: number }) => {\n const result = await hookmoviesQuery<{ hokScoreApplication: HokApplication }>(\n `mutation HokScoreApplication($id: ID!, $score: Int!) {\n hokScoreApplication(id: $id, score: $score) {\n id auditionId applicantId coverNote score status createdAt updatedAt\n }\n }`,\n { id, score },\n apiGatewayUrl\n );\n return result.hokScoreApplication;\n },\n onSuccess: (data) => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'applications', data.auditionId] });\n },\n });\n};\n\n// ============================================================================\n// Reviews\n// ============================================================================\n\nexport interface HokReviewFilters {\n status?: HokReviewStatus;\n titleId?: string;\n}\n\nexport const useReviews = (\n filters: HokReviewFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'reviews', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokListReviews: HokConnection<HokReview> }>(\n `query HokReviews($pagination: PaginationInput, $status: HokReviewStatus, $titleId: ID) {\n hokListReviews(pagination: $pagination, status: $status, titleId: $titleId) {\n items {\n ${REVIEW_FIELDS}\n title { id title }\n }\n ${PAGE_INFO}\n }\n }`,\n { pagination, status: filters.status, titleId: filters.titleId },\n apiGatewayUrl\n );\n return result.hokListReviews;\n },\n });\n};\n\nexport interface CreateReviewInput {\n titleId: string;\n score: number;\n body?: string;\n hasSpoilers?: boolean;\n aspectScores?: Record<string, unknown>;\n}\n\nexport const useCreateReview = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateReviewInput) => {\n const result = await hookmoviesQuery<{ hokCreateReview: HokReview }>(\n `mutation HokCreateReview($input: HokCreateReviewInput!) {\n hokCreateReview(input: $input) { ${REVIEW_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateReview;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'reviews'] });\n },\n });\n};\n\nexport const useDeleteReview = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokDeleteReview: boolean }>(\n `mutation HokDeleteReview($id: ID!) { hokDeleteReview(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.hokDeleteReview;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'reviews'] });\n },\n });\n};\n\n// ============================================================================\n// Rights Windows\n// ============================================================================\n\nexport interface HokRightsFilters {\n status?: HokRightsWindowStatus;\n titleId?: string;\n}\n\nexport const useRightsWindows = (\n filters: HokRightsFilters = {},\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'rights', filters, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{\n hokListRightsWindows: HokConnection<HokRightsWindow>;\n }>(\n `query HokRightsWindows($pagination: PaginationInput, $status: HokRightsWindowStatus, $titleId: ID) {\n hokListRightsWindows(pagination: $pagination, status: $status, titleId: $titleId) {\n items {\n ${RIGHTS_FIELDS}\n title { id title }\n }\n ${PAGE_INFO}\n }\n }`,\n { pagination, status: filters.status, titleId: filters.titleId },\n apiGatewayUrl\n );\n return result.hokListRightsWindows;\n },\n });\n};\n\nexport interface CreateRightsWindowInput {\n titleId: string;\n modes: HokMonetizationMode[];\n territories?: string[];\n exclusive?: boolean;\n currency?: string;\n licenseeId?: string;\n startsAt?: string;\n endsAt?: string;\n contractFileId?: string;\n priceMinorUnits?: Record<string, unknown>;\n}\n\nexport const useCreateRightsWindow = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateRightsWindowInput) => {\n const result = await hookmoviesQuery<{ hokCreateRightsWindow: HokRightsWindow }>(\n `mutation HokCreateRightsWindow($input: HokCreateRightsWindowInput!) {\n hokCreateRightsWindow(input: $input) { ${RIGHTS_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateRightsWindow;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'rights'] });\n },\n });\n};\n\nexport const useTransitionRightsWindow = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async ({ id, status }: { id: string; status: HokRightsWindowStatus }) => {\n const result = await hookmoviesQuery<{ hokTransitionRightsWindow: HokRightsWindow }>(\n `mutation HokTransitionRightsWindow($id: ID!, $status: HokRightsWindowStatus!) {\n hokTransitionRightsWindow(id: $id, status: $status) { ${RIGHTS_FIELDS} }\n }`,\n { id, status },\n apiGatewayUrl\n );\n return result.hokTransitionRightsWindow;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'rights'] });\n },\n });\n};\n\nexport const useRevokeEntitlement = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokRevokeEntitlement: boolean }>(\n `mutation HokRevokeEntitlement($id: ID!) { hokRevokeEntitlement(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.hokRevokeEntitlement;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'my-entitlements'] });\n },\n });\n};\n\n// ============================================================================\n// Entitlements (self-scoped)\n// ============================================================================\n\nexport const useMyEntitlements = (titleId?: string) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'my-entitlements', titleId],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokMyEntitlements: HokEntitlement[] }>(\n `query HokMyEntitlements($titleId: ID) {\n hokMyEntitlements(titleId: $titleId) {\n id titleId userId mode source status territory expiresAt createdAt updatedAt\n title { id title }\n }\n }`,\n { titleId },\n apiGatewayUrl\n );\n return result.hokMyEntitlements;\n },\n });\n};\n\n// ============================================================================\n// Lists / Watchlists (self-scoped)\n// ============================================================================\n\nexport const useMyLists = (\n kind?: HokListKind,\n pagination: HokPaginationInput = { limit: 50, offset: 0 }\n) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'my-lists', kind, pagination],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokMyLists: HokConnection<HokList> }>(\n `query HokMyLists($kind: HokListKind, $pagination: PaginationInput) {\n hokMyLists(kind: $kind, pagination: $pagination) {\n items { ${LIST_FIELDS} }\n ${PAGE_INFO}\n }\n }`,\n { kind, pagination },\n apiGatewayUrl\n );\n return result.hokMyLists;\n },\n });\n};\n\nexport interface CreateListInput {\n name: string;\n description?: string;\n kind?: HokListKind;\n visibility?: HokListVisibility;\n items?: Record<string, unknown>;\n}\n\nexport const useCreateList = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (input: CreateListInput) => {\n const result = await hookmoviesQuery<{ hokCreateList: HokList }>(\n `mutation HokCreateList($input: HokCreateListInput!) {\n hokCreateList(input: $input) { ${LIST_FIELDS} }\n }`,\n { input },\n apiGatewayUrl\n );\n return result.hokCreateList;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'my-lists'] });\n },\n });\n};\n\nexport const useDeleteList = () => {\n const queryClient = useQueryClient();\n const { apiGatewayUrl } = useHookMovies();\n return useMutation({\n mutationFn: async (id: string) => {\n const result = await hookmoviesQuery<{ hokDeleteList: boolean }>(\n `mutation HokDeleteList($id: ID!) { hokDeleteList(id: $id) }`,\n { id },\n apiGatewayUrl\n );\n return result.hokDeleteList;\n },\n onSuccess: () => {\n void queryClient.invalidateQueries({ queryKey: [QK, 'my-lists'] });\n },\n });\n};\n\n// ============================================================================\n// Watch progress / Continue Watching (self-scoped)\n// ============================================================================\n\nexport const useMyWatchProgress = (titleId?: string) => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'my-watch-progress', titleId],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokMyWatchProgress: HokWatchProgress[] }>(\n `query HokMyWatchProgress($titleId: ID) {\n hokMyWatchProgress(titleId: $titleId) {\n id titleId episodeId positionSeconds completed lastDevice updatedAt\n title { id title type }\n }\n }`,\n { titleId },\n apiGatewayUrl\n );\n return result.hokMyWatchProgress;\n },\n });\n};\n\n// ============================================================================\n// Health probe (used by the dashboard service-status card)\n// ============================================================================\n\nexport const useHealth = () => {\n const { apiGatewayUrl } = useHookMovies();\n return useQuery({\n queryKey: [QK, 'health'],\n queryFn: async () => {\n const result = await hookmoviesQuery<{ hokHealth: string }>(\n `query HokHealth { hokHealth }`,\n {},\n apiGatewayUrl\n );\n return result.hokHealth;\n },\n staleTime: 60 * 1000,\n });\n};\n"],"mappings":"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"}
@@ -23,7 +23,14 @@ var x = [
23
23
  }), I = o({}, {
24
24
  limit: 200,
25
25
  offset: 0
26
- }), L = r(), R = i(), [z, B] = f(""), [V, H] = f("8"), [U, W] = f(""), [G, K] = f(!1), [q, J] = f(null), Y = async (e) => {
26
+ }), L = r(), R = i(), [z, B] = f(""), [V, H] = f("8"), [U, W] = f(""), [G, K] = f(!1), [q, J] = f(null), [Y, X] = f(null), Z = async (e) => {
27
+ X(null);
28
+ try {
29
+ await R.mutateAsync(e);
30
+ } catch (e) {
31
+ X(e instanceof Error ? e.message : "Failed to delete review (you can only delete your own)");
32
+ }
33
+ }, Q = async (e) => {
27
34
  if (e.preventDefault(), J(null), !z) {
28
35
  J("Select a title to review.");
29
36
  return;
@@ -44,7 +51,7 @@ var x = [
44
51
  } catch (e) {
45
52
  J(e instanceof Error ? e.message : "Failed to create review");
46
53
  }
47
- }, X = M?.items ?? [];
54
+ }, $ = M?.items ?? [];
48
55
  return /* @__PURE__ */ y(t, {
49
56
  title: "Reviews",
50
57
  description: "Ratings & audience reviews",
@@ -71,7 +78,7 @@ var x = [
71
78
  children: /* @__PURE__ */ v(_, { className: "h-4 w-4" })
72
79
  })]
73
80
  }), /* @__PURE__ */ y("form", {
74
- onSubmit: Y,
81
+ onSubmit: Q,
75
82
  className: "space-y-4",
76
83
  children: [
77
84
  q && /* @__PURE__ */ v("div", {
@@ -159,13 +166,17 @@ var x = [
159
166
  }, e))]
160
167
  })
161
168
  }),
162
- N ? /* @__PURE__ */ v(l, { label: "Loading reviews…" }) : P ? /* @__PURE__ */ v(c, { onRetry: () => void F() }) : X.length === 0 ? /* @__PURE__ */ v(u, {
169
+ Y && /* @__PURE__ */ v("div", {
170
+ className: "mb-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
171
+ children: Y
172
+ }),
173
+ N ? /* @__PURE__ */ v(l, { label: "Loading reviews…" }) : P ? /* @__PURE__ */ v(c, { onRetry: () => void F() }) : $.length === 0 ? /* @__PURE__ */ v(u, {
163
174
  icon: /* @__PURE__ */ v(h, { className: "h-12 w-12" }),
164
175
  title: "No reviews",
165
176
  description: "No reviews match this filter yet."
166
177
  }) : /* @__PURE__ */ v("div", {
167
178
  className: "space-y-3",
168
- children: X.map((e) => /* @__PURE__ */ y(b, {
179
+ children: $.map((e) => /* @__PURE__ */ y(b, {
169
180
  treatment: "metric",
170
181
  className: "border-border-seam p-4",
171
182
  children: [
@@ -204,7 +215,7 @@ var x = [
204
215
  children: [/* @__PURE__ */ v(n, { status: e.status }), /* @__PURE__ */ v("button", {
205
216
  type: "button",
206
217
  disabled: R.isPending,
207
- onClick: () => void R.mutateAsync(e.id),
218
+ onClick: () => void Z(e.id),
208
219
  className: "rounded-md p-1.5 text-text-secondary hover:text-status-error-text disabled:opacity-50 transition-colors",
209
220
  "aria-label": "Delete review",
210
221
  title: "Delete (only your own reviews)",
@@ -231,7 +242,7 @@ var x = [
231
242
  page: O,
232
243
  hasMore: M?.pageInfo.hasMore ?? !1,
233
244
  onPageChange: k,
234
- shownCount: X.length
245
+ shownCount: $.length
235
246
  })
236
247
  ]
237
248
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ReviewsPage.js","names":[],"sources":["../../../../src/hookmovies/pages/engagement/ReviewsPage.tsx"],"sourcesContent":["/**\n * Reviews (Audience engagement)\n * @module hookmovies/pages/engagement\n *\n * Lists reviews via `hokListReviews` (status + title filters), creates them via\n * `hokCreateReview`, and removes the caller's own via `hokDeleteReview`.\n */\n\nimport { type FC, type FormEvent, useState } from 'react';\nimport { Star, Plus, X, Trash2, ShieldCheck } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/StateViews';\nimport { Pagination } from '../../components/Pagination';\nimport { useHookMovies } from '../../context/HookMoviesContext';\nimport {\n useReviews,\n useCreateReview,\n useDeleteReview,\n useTitles,\n type HokReviewStatus,\n type CreateReviewInput,\n} from '../../hooks/useHookMoviesApi';\nimport { formatRelativeTime } from '../../utils/formatters';\n\nconst STATUS_OPTIONS: HokReviewStatus[] = ['PENDING', 'PUBLISHED', 'HIDDEN', 'REMOVED'];\nconst PAGE_LIMIT = 20;\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)]';\nconst labelClass = 'mb-1.5 block text-xs font-medium text-text-secondary';\n\nexport const ReviewsPage: FC = () => {\n const { navigateTo } = useHookMovies();\n const [statusFilter, setStatusFilter] = useState<HokReviewStatus | ''>('');\n const [page, setPage] = useState(0);\n const [showCreate, setShowCreate] = useState(false);\n\n const { data, isLoading, isError, refetch } = useReviews(\n { status: statusFilter || undefined },\n { limit: PAGE_LIMIT, offset: page * PAGE_LIMIT }\n );\n const titles = useTitles({}, { limit: 200, offset: 0 });\n const createReview = useCreateReview();\n const deleteReview = useDeleteReview();\n\n const [titleId, setTitleId] = useState('');\n const [score, setScore] = useState('8');\n const [body, setBody] = useState('');\n const [hasSpoilers, setHasSpoilers] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!titleId) {\n setError('Select a title to review.');\n return;\n }\n const scoreNum = Number(score);\n if (!Number.isInteger(scoreNum) || scoreNum < 1 || scoreNum > 10) {\n setError('Score must be a whole number from 1 to 10.');\n return;\n }\n const input: CreateReviewInput = {\n titleId,\n score: scoreNum,\n body: body.trim() || undefined,\n hasSpoilers,\n };\n try {\n await createReview.mutateAsync(input);\n setTitleId('');\n setScore('8');\n setBody('');\n setHasSpoilers(false);\n setShowCreate(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create review');\n }\n };\n\n const items = data?.items ?? [];\n\n return (\n <PageLayout\n title=\"Reviews\"\n description=\"Ratings & audience reviews\"\n purpose=\"Audience scores and written reviews per title, with verified-watch badges and moderation status. Write a review or moderate the queue.\"\n actions={\n <button\n type=\"button\"\n onClick={() => setShowCreate((v) => !v)}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 transition-opacity\"\n >\n <Plus className=\"h-4 w-4\" />\n Write Review\n </button>\n }\n >\n {showCreate && (\n <GlassCard treatment=\"glass\" className=\"mb-6 border-border-seam p-5\">\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Write a Review</h2>\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {error && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {error}\n </div>\n )}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"review-title\" className={labelClass}>\n Title *\n </label>\n <select\n id=\"review-title\"\n value={titleId}\n onChange={(e) => setTitleId(e.target.value)}\n className={fieldClass}\n required\n >\n <option value=\"\">Select a title…</option>\n {(titles.data?.items ?? []).map((t) => (\n <option key={t.id} value={t.id}>\n {t.title}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"review-score\" className={labelClass}>\n Score (1–10) *\n </label>\n <input\n id=\"review-score\"\n type=\"number\"\n min=\"1\"\n max=\"10\"\n value={score}\n onChange={(e) => setScore(e.target.value)}\n className={fieldClass}\n required\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"review-body\" className={labelClass}>\n Review\n </label>\n <textarea\n id=\"review-body\"\n value={body}\n onChange={(e) => setBody(e.target.value)}\n rows={3}\n placeholder=\"Share your thoughts…\"\n className={fieldClass}\n />\n </div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={hasSpoilers}\n onChange={(e) => setHasSpoilers(e.target.checked)}\n className=\"h-4 w-4 rounded border-border-subtle\"\n />\n This review contains spoilers\n </label>\n <button\n type=\"submit\"\n disabled={createReview.isPending}\n className=\"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 {createReview.isPending ? 'Publishing…' : 'Publish Review'}\n </button>\n </form>\n </GlassCard>\n )}\n\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <select\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as HokReviewStatus | '');\n setPage(0);\n }}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">Any Status</option>\n {STATUS_OPTIONS.map((s) => (\n <option key={s} value={s}>\n {s.charAt(0) + s.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n\n {isLoading ? (\n <LoadingState label=\"Loading reviews…\" />\n ) : isError ? (\n <ErrorState onRetry={() => void refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n icon={<Star className=\"h-12 w-12\" />}\n title=\"No reviews\"\n description=\"No reviews match this filter yet.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {items.map((review) => (\n <GlassCard key={review.id} treatment=\"metric\" className=\"border-border-seam p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`catalog/titles/${review.titleId}`)}\n className=\"truncate text-sm font-semibold text-text-primary hover:text-action-primary-bg transition-colors\"\n >\n {review.title?.title ?? 'Title'}\n </button>\n <div className=\"mt-1 flex items-center gap-2\">\n <span className=\"inline-flex items-center gap-1 text-sm font-semibold text-text-primary\">\n <Star className=\"h-3.5 w-3.5 fill-status-warning-text text-status-warning-text\" />\n {review.score}/10\n </span>\n {review.verifiedWatch && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-[10px] text-status-success-text\">\n <ShieldCheck className=\"h-3 w-3\" />\n Verified watch\n </span>\n )}\n {review.hasSpoilers && (\n <span className=\"rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-[10px] text-status-warning-text\">\n Spoilers\n </span>\n )}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={review.status} />\n <button\n type=\"button\"\n disabled={deleteReview.isPending}\n onClick={() => void deleteReview.mutateAsync(review.id)}\n className=\"rounded-md p-1.5 text-text-secondary hover:text-status-error-text disabled:opacity-50 transition-colors\"\n aria-label=\"Delete review\"\n title=\"Delete (only your own reviews)\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n {review.body && <p className=\"mt-2 text-sm text-text-secondary\">{review.body}</p>}\n <p className=\"mt-2 text-xs text-text-muted\">\n {review.helpfulCount} found this helpful · {formatRelativeTime(review.createdAt)}\n </p>\n </GlassCard>\n ))}\n </div>\n )}\n\n {!isLoading && !isError && (\n <Pagination\n page={page}\n hasMore={data?.pageInfo.hasMore ?? false}\n onPageChange={setPage}\n shownCount={items.length}\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ReviewsPage.js","names":[],"sources":["../../../../src/hookmovies/pages/engagement/ReviewsPage.tsx"],"sourcesContent":["/**\n * Reviews (Audience engagement)\n * @module hookmovies/pages/engagement\n *\n * Lists reviews via `hokListReviews` (status + title filters), creates them via\n * `hokCreateReview`, and removes the caller's own via `hokDeleteReview`.\n */\n\nimport { type FC, type FormEvent, useState } from 'react';\nimport { Star, Plus, X, Trash2, ShieldCheck } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { StatusBadge } from '../../components/StatusBadge';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/StateViews';\nimport { Pagination } from '../../components/Pagination';\nimport { useHookMovies } from '../../context/HookMoviesContext';\nimport {\n useReviews,\n useCreateReview,\n useDeleteReview,\n useTitles,\n type HokReviewStatus,\n type CreateReviewInput,\n} from '../../hooks/useHookMoviesApi';\nimport { formatRelativeTime } from '../../utils/formatters';\n\nconst STATUS_OPTIONS: HokReviewStatus[] = ['PENDING', 'PUBLISHED', 'HIDDEN', 'REMOVED'];\nconst PAGE_LIMIT = 20;\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)]';\nconst labelClass = 'mb-1.5 block text-xs font-medium text-text-secondary';\n\nexport const ReviewsPage: FC = () => {\n const { navigateTo } = useHookMovies();\n const [statusFilter, setStatusFilter] = useState<HokReviewStatus | ''>('');\n const [page, setPage] = useState(0);\n const [showCreate, setShowCreate] = useState(false);\n\n const { data, isLoading, isError, refetch } = useReviews(\n { status: statusFilter || undefined },\n { limit: PAGE_LIMIT, offset: page * PAGE_LIMIT }\n );\n const titles = useTitles({}, { limit: 200, offset: 0 });\n const createReview = useCreateReview();\n const deleteReview = useDeleteReview();\n\n const [titleId, setTitleId] = useState('');\n const [score, setScore] = useState('8');\n const [body, setBody] = useState('');\n const [hasSpoilers, setHasSpoilers] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n\n const handleDelete = async (id: string) => {\n setActionError(null);\n try {\n await deleteReview.mutateAsync(id);\n } catch (err) {\n setActionError(\n err instanceof Error ? err.message : 'Failed to delete review (you can only delete your own)'\n );\n }\n };\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!titleId) {\n setError('Select a title to review.');\n return;\n }\n const scoreNum = Number(score);\n if (!Number.isInteger(scoreNum) || scoreNum < 1 || scoreNum > 10) {\n setError('Score must be a whole number from 1 to 10.');\n return;\n }\n const input: CreateReviewInput = {\n titleId,\n score: scoreNum,\n body: body.trim() || undefined,\n hasSpoilers,\n };\n try {\n await createReview.mutateAsync(input);\n setTitleId('');\n setScore('8');\n setBody('');\n setHasSpoilers(false);\n setShowCreate(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create review');\n }\n };\n\n const items = data?.items ?? [];\n\n return (\n <PageLayout\n title=\"Reviews\"\n description=\"Ratings & audience reviews\"\n purpose=\"Audience scores and written reviews per title, with verified-watch badges and moderation status. Write a review or moderate the queue.\"\n actions={\n <button\n type=\"button\"\n onClick={() => setShowCreate((v) => !v)}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 transition-opacity\"\n >\n <Plus className=\"h-4 w-4\" />\n Write Review\n </button>\n }\n >\n {showCreate && (\n <GlassCard treatment=\"glass\" className=\"mb-6 border-border-seam p-5\">\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Write a Review</h2>\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {error && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {error}\n </div>\n )}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"review-title\" className={labelClass}>\n Title *\n </label>\n <select\n id=\"review-title\"\n value={titleId}\n onChange={(e) => setTitleId(e.target.value)}\n className={fieldClass}\n required\n >\n <option value=\"\">Select a title…</option>\n {(titles.data?.items ?? []).map((t) => (\n <option key={t.id} value={t.id}>\n {t.title}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"review-score\" className={labelClass}>\n Score (1–10) *\n </label>\n <input\n id=\"review-score\"\n type=\"number\"\n min=\"1\"\n max=\"10\"\n value={score}\n onChange={(e) => setScore(e.target.value)}\n className={fieldClass}\n required\n />\n </div>\n </div>\n <div>\n <label htmlFor=\"review-body\" className={labelClass}>\n Review\n </label>\n <textarea\n id=\"review-body\"\n value={body}\n onChange={(e) => setBody(e.target.value)}\n rows={3}\n placeholder=\"Share your thoughts…\"\n className={fieldClass}\n />\n </div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={hasSpoilers}\n onChange={(e) => setHasSpoilers(e.target.checked)}\n className=\"h-4 w-4 rounded border-border-subtle\"\n />\n This review contains spoilers\n </label>\n <button\n type=\"submit\"\n disabled={createReview.isPending}\n className=\"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 {createReview.isPending ? 'Publishing…' : 'Publish Review'}\n </button>\n </form>\n </GlassCard>\n )}\n\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <select\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value as HokReviewStatus | '');\n setPage(0);\n }}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">Any Status</option>\n {STATUS_OPTIONS.map((s) => (\n <option key={s} value={s}>\n {s.charAt(0) + s.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n\n {actionError && (\n <div className=\"mb-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {actionError}\n </div>\n )}\n\n {isLoading ? (\n <LoadingState label=\"Loading reviews…\" />\n ) : isError ? (\n <ErrorState onRetry={() => void refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n icon={<Star className=\"h-12 w-12\" />}\n title=\"No reviews\"\n description=\"No reviews match this filter yet.\"\n />\n ) : (\n <div className=\"space-y-3\">\n {items.map((review) => (\n <GlassCard key={review.id} treatment=\"metric\" className=\"border-border-seam p-4\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <button\n type=\"button\"\n onClick={() => navigateTo(`catalog/titles/${review.titleId}`)}\n className=\"truncate text-sm font-semibold text-text-primary hover:text-action-primary-bg transition-colors\"\n >\n {review.title?.title ?? 'Title'}\n </button>\n <div className=\"mt-1 flex items-center gap-2\">\n <span className=\"inline-flex items-center gap-1 text-sm font-semibold text-text-primary\">\n <Star className=\"h-3.5 w-3.5 fill-status-warning-text text-status-warning-text\" />\n {review.score}/10\n </span>\n {review.verifiedWatch && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-[10px] text-status-success-text\">\n <ShieldCheck className=\"h-3 w-3\" />\n Verified watch\n </span>\n )}\n {review.hasSpoilers && (\n <span className=\"rounded-full bg-status-warning-bg-subtle px-2 py-0.5 text-[10px] text-status-warning-text\">\n Spoilers\n </span>\n )}\n </div>\n </div>\n <div className=\"flex items-center gap-2\">\n <StatusBadge status={review.status} />\n <button\n type=\"button\"\n disabled={deleteReview.isPending}\n onClick={() => void handleDelete(review.id)}\n className=\"rounded-md p-1.5 text-text-secondary hover:text-status-error-text disabled:opacity-50 transition-colors\"\n aria-label=\"Delete review\"\n title=\"Delete (only your own reviews)\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n </div>\n {review.body && <p className=\"mt-2 text-sm text-text-secondary\">{review.body}</p>}\n <p className=\"mt-2 text-xs text-text-muted\">\n {review.helpfulCount} found this helpful · {formatRelativeTime(review.createdAt)}\n </p>\n </GlassCard>\n ))}\n </div>\n )}\n\n {!isLoading && !isError && (\n <Pagination\n page={page}\n hasMore={data?.pageInfo.hasMore ?? false}\n onPageChange={setPage}\n shownCount={items.length}\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -20,7 +20,14 @@ var y = ["WATCHLIST", "PLAYLIST"], b = [
20
20
  let [l, u] = c(""), [f, w] = c(!1), { data: T, isLoading: E, isError: D, refetch: O } = r(l || void 0, {
21
21
  limit: 100,
22
22
  offset: 0
23
- }), k = t(), A = n(), [j, M] = c(""), [N, P] = c(""), [F, I] = c("WATCHLIST"), [L, R] = c("PRIVATE"), [z, B] = c(null), V = async (e) => {
23
+ }), k = t(), A = n(), [j, M] = c(""), [N, P] = c(""), [F, I] = c("WATCHLIST"), [L, R] = c("PRIVATE"), [z, B] = c(null), [V, H] = c(null), U = async (e) => {
24
+ H(null);
25
+ try {
26
+ await A.mutateAsync(e);
27
+ } catch (e) {
28
+ H(e instanceof Error ? e.message : "Failed to delete list (you can only delete your own)");
29
+ }
30
+ }, W = async (e) => {
24
31
  if (e.preventDefault(), B(null), !j.trim()) {
25
32
  B("Name is required.");
26
33
  return;
@@ -36,7 +43,7 @@ var y = ["WATCHLIST", "PLAYLIST"], b = [
36
43
  } catch (e) {
37
44
  B(e instanceof Error ? e.message : "Failed to create list");
38
45
  }
39
- }, H = T?.items ?? [];
46
+ }, G = T?.items ?? [];
40
47
  return /* @__PURE__ */ _(e, {
41
48
  title: "My Library",
42
49
  description: "Watchlists & playlists",
@@ -63,7 +70,7 @@ var y = ["WATCHLIST", "PLAYLIST"], b = [
63
70
  children: /* @__PURE__ */ g(h, { className: "h-4 w-4" })
64
71
  })]
65
72
  }), /* @__PURE__ */ _("form", {
66
- onSubmit: V,
73
+ onSubmit: W,
67
74
  className: "space-y-4",
68
75
  children: [
69
76
  z && /* @__PURE__ */ g("div", {
@@ -148,13 +155,17 @@ var y = ["WATCHLIST", "PLAYLIST"], b = [
148
155
  }, e))]
149
156
  })
150
157
  }),
151
- E ? /* @__PURE__ */ g(o, { label: "Loading your lists…" }) : D ? /* @__PURE__ */ g(a, { onRetry: () => void O() }) : H.length === 0 ? /* @__PURE__ */ g(s, {
158
+ V && /* @__PURE__ */ g("div", {
159
+ className: "mb-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text",
160
+ children: V
161
+ }),
162
+ E ? /* @__PURE__ */ g(o, { label: "Loading your lists…" }) : D ? /* @__PURE__ */ g(a, { onRetry: () => void O() }) : G.length === 0 ? /* @__PURE__ */ g(s, {
152
163
  icon: /* @__PURE__ */ g(d, { className: "h-12 w-12" }),
153
164
  title: "No lists yet",
154
165
  description: "Create a watchlist or playlist to organize what you watch."
155
166
  }) : /* @__PURE__ */ g("div", {
156
167
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3",
157
- children: H.map((e) => {
168
+ children: G.map((e) => {
158
169
  let t = C[e.visibility];
159
170
  return /* @__PURE__ */ _(v, {
160
171
  treatment: "metric",
@@ -168,7 +179,7 @@ var y = ["WATCHLIST", "PLAYLIST"], b = [
168
179
  }), /* @__PURE__ */ g("button", {
169
180
  type: "button",
170
181
  disabled: A.isPending,
171
- onClick: () => void A.mutateAsync(e.id),
182
+ onClick: () => void U(e.id),
172
183
  className: "rounded-md p-1 text-text-secondary hover:text-status-error-text disabled:opacity-50 transition-colors",
173
184
  "aria-label": "Delete list",
174
185
  children: /* @__PURE__ */ g(m, { className: "h-4 w-4" })
@@ -1 +1 @@
1
- {"version":3,"file":"ListsPage.js","names":[],"sources":["../../../../src/hookmovies/pages/library/ListsPage.tsx"],"sourcesContent":["/**\n * My Lists (Library — self-scoped)\n * @module hookmovies/pages/library\n *\n * The caller's own watchlists and playlists via `hokMyLists`, created with\n * `hokCreateList` and removed with `hokDeleteList`. All self-scoped to the\n * calling user by the subgraph.\n */\n\nimport { type FC, type FormEvent, useState } from 'react';\nimport { ListVideo, Plus, X, Trash2, Lock, Globe, Link as LinkIcon } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/StateViews';\nimport {\n useMyLists,\n useCreateList,\n useDeleteList,\n type HokListKind,\n type HokListVisibility,\n type CreateListInput,\n} from '../../hooks/useHookMoviesApi';\nimport { formatRelativeTime } from '../../utils/formatters';\n\nconst KIND_OPTIONS: HokListKind[] = ['WATCHLIST', 'PLAYLIST'];\nconst VISIBILITY_OPTIONS: HokListVisibility[] = ['PRIVATE', 'UNLISTED', 'PUBLIC'];\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)]';\nconst labelClass = 'mb-1.5 block text-xs font-medium text-text-secondary';\n\nconst visibilityIcon: Record<HokListVisibility, typeof Lock> = {\n PRIVATE: Lock,\n UNLISTED: LinkIcon,\n PUBLIC: Globe,\n};\n\nexport const ListsPage: FC = () => {\n const [kindFilter, setKindFilter] = useState<HokListKind | ''>('');\n const [showCreate, setShowCreate] = useState(false);\n\n const { data, isLoading, isError, refetch } = useMyLists(kindFilter || undefined, {\n limit: 100,\n offset: 0,\n });\n const createList = useCreateList();\n const deleteList = useDeleteList();\n\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [kind, setKind] = useState<HokListKind>('WATCHLIST');\n const [visibility, setVisibility] = useState<HokListVisibility>('PRIVATE');\n const [error, setError] = useState<string | null>(null);\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!name.trim()) {\n setError('Name is required.');\n return;\n }\n const input: CreateListInput = {\n name: name.trim(),\n description: description.trim() || undefined,\n kind,\n visibility,\n };\n try {\n await createList.mutateAsync(input);\n setName('');\n setDescription('');\n setKind('WATCHLIST');\n setVisibility('PRIVATE');\n setShowCreate(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create list');\n }\n };\n\n const items = data?.items ?? [];\n\n return (\n <PageLayout\n title=\"My Library\"\n description=\"Watchlists & playlists\"\n purpose=\"Your personal collections — a watchlist of what to watch next and curated playlists you can keep private, unlisted, or public.\"\n actions={\n <button\n type=\"button\"\n onClick={() => setShowCreate((v) => !v)}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 transition-opacity\"\n >\n <Plus className=\"h-4 w-4\" />\n New List\n </button>\n }\n >\n {showCreate && (\n <GlassCard treatment=\"glass\" className=\"mb-6 border-border-seam p-5\">\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Create List</h2>\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {error && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {error}\n </div>\n )}\n <div>\n <label htmlFor=\"list-name\" className={labelClass}>\n Name *\n </label>\n <input\n id=\"list-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Weekend Watch\"\n className={fieldClass}\n required\n />\n </div>\n <div>\n <label htmlFor=\"list-desc\" className={labelClass}>\n Description\n </label>\n <textarea\n id=\"list-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n className={fieldClass}\n />\n </div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"list-kind\" className={labelClass}>\n Kind\n </label>\n <select\n id=\"list-kind\"\n value={kind}\n onChange={(e) => setKind(e.target.value as HokListKind)}\n className={fieldClass}\n >\n {KIND_OPTIONS.map((k) => (\n <option key={k} value={k}>\n {k.charAt(0) + k.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"list-visibility\" className={labelClass}>\n Visibility\n </label>\n <select\n id=\"list-visibility\"\n value={visibility}\n onChange={(e) => setVisibility(e.target.value as HokListVisibility)}\n className={fieldClass}\n >\n {VISIBILITY_OPTIONS.map((v) => (\n <option key={v} value={v}>\n {v.charAt(0) + v.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n </div>\n <button\n type=\"submit\"\n disabled={createList.isPending}\n className=\"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 {createList.isPending ? 'Creating…' : 'Create List'}\n </button>\n </form>\n </GlassCard>\n )}\n\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <select\n value={kindFilter}\n onChange={(e) => setKindFilter(e.target.value as HokListKind | '')}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Lists</option>\n {KIND_OPTIONS.map((k) => (\n <option key={k} value={k}>\n {k.charAt(0) + k.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n\n {isLoading ? (\n <LoadingState label=\"Loading your lists…\" />\n ) : isError ? (\n <ErrorState onRetry={() => void refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n icon={<ListVideo className=\"h-12 w-12\" />}\n title=\"No lists yet\"\n description=\"Create a watchlist or playlist to organize what you watch.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {items.map((list) => {\n const VisibilityIcon = visibilityIcon[list.visibility];\n return (\n <GlassCard\n key={list.id}\n treatment=\"metric\"\n className=\"flex flex-col border-border-seam p-4\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <h3 className=\"line-clamp-1 text-sm font-semibold text-text-primary\">\n {list.name}\n </h3>\n <button\n type=\"button\"\n disabled={deleteList.isPending}\n onClick={() => void deleteList.mutateAsync(list.id)}\n className=\"rounded-md p-1 text-text-secondary hover:text-status-error-text disabled:opacity-50 transition-colors\"\n aria-label=\"Delete list\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n {list.description && (\n <p className=\"mt-1 line-clamp-2 text-xs text-text-secondary\">\n {list.description}\n </p>\n )}\n <div className=\"mt-3 flex items-center gap-3 text-xs text-text-secondary\">\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5\">\n {list.kind.charAt(0) + list.kind.slice(1).toLowerCase()}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <VisibilityIcon className=\"h-3 w-3\" />\n {list.visibility.charAt(0) + list.visibility.slice(1).toLowerCase()}\n </span>\n <span>{list.itemCount} items</span>\n </div>\n <p className=\"mt-2 text-[11px] text-text-muted\">\n Updated {formatRelativeTime(list.updatedAt)}\n </p>\n </GlassCard>\n );\n })}\n </div>\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ListsPage.js","names":[],"sources":["../../../../src/hookmovies/pages/library/ListsPage.tsx"],"sourcesContent":["/**\n * My Lists (Library — self-scoped)\n * @module hookmovies/pages/library\n *\n * The caller's own watchlists and playlists via `hokMyLists`, created with\n * `hokCreateList` and removed with `hokDeleteList`. All self-scoped to the\n * calling user by the subgraph.\n */\n\nimport { type FC, type FormEvent, useState } from 'react';\nimport { ListVideo, Plus, X, Trash2, Lock, Globe, Link as LinkIcon } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components/PageLayout';\nimport { EmptyState } from '../../components/EmptyState';\nimport { LoadingState, ErrorState } from '../../components/StateViews';\nimport {\n useMyLists,\n useCreateList,\n useDeleteList,\n type HokListKind,\n type HokListVisibility,\n type CreateListInput,\n} from '../../hooks/useHookMoviesApi';\nimport { formatRelativeTime } from '../../utils/formatters';\n\nconst KIND_OPTIONS: HokListKind[] = ['WATCHLIST', 'PLAYLIST'];\nconst VISIBILITY_OPTIONS: HokListVisibility[] = ['PRIVATE', 'UNLISTED', 'PUBLIC'];\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)]';\nconst labelClass = 'mb-1.5 block text-xs font-medium text-text-secondary';\n\nconst visibilityIcon: Record<HokListVisibility, typeof Lock> = {\n PRIVATE: Lock,\n UNLISTED: LinkIcon,\n PUBLIC: Globe,\n};\n\nexport const ListsPage: FC = () => {\n const [kindFilter, setKindFilter] = useState<HokListKind | ''>('');\n const [showCreate, setShowCreate] = useState(false);\n\n const { data, isLoading, isError, refetch } = useMyLists(kindFilter || undefined, {\n limit: 100,\n offset: 0,\n });\n const createList = useCreateList();\n const deleteList = useDeleteList();\n\n const [name, setName] = useState('');\n const [description, setDescription] = useState('');\n const [kind, setKind] = useState<HokListKind>('WATCHLIST');\n const [visibility, setVisibility] = useState<HokListVisibility>('PRIVATE');\n const [error, setError] = useState<string | null>(null);\n const [actionError, setActionError] = useState<string | null>(null);\n\n const handleDelete = async (id: string) => {\n setActionError(null);\n try {\n await deleteList.mutateAsync(id);\n } catch (err) {\n setActionError(\n err instanceof Error ? err.message : 'Failed to delete list (you can only delete your own)'\n );\n }\n };\n\n const handleSubmit = async (e: FormEvent) => {\n e.preventDefault();\n setError(null);\n if (!name.trim()) {\n setError('Name is required.');\n return;\n }\n const input: CreateListInput = {\n name: name.trim(),\n description: description.trim() || undefined,\n kind,\n visibility,\n };\n try {\n await createList.mutateAsync(input);\n setName('');\n setDescription('');\n setKind('WATCHLIST');\n setVisibility('PRIVATE');\n setShowCreate(false);\n } catch (err) {\n setError(err instanceof Error ? err.message : 'Failed to create list');\n }\n };\n\n const items = data?.items ?? [];\n\n return (\n <PageLayout\n title=\"My Library\"\n description=\"Watchlists & playlists\"\n purpose=\"Your personal collections — a watchlist of what to watch next and curated playlists you can keep private, unlisted, or public.\"\n actions={\n <button\n type=\"button\"\n onClick={() => setShowCreate((v) => !v)}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 transition-opacity\"\n >\n <Plus className=\"h-4 w-4\" />\n New List\n </button>\n }\n >\n {showCreate && (\n <GlassCard treatment=\"glass\" className=\"mb-6 border-border-seam p-5\">\n <div className=\"mb-3 flex items-center justify-between\">\n <h2 className=\"text-sm font-semibold text-text-primary\">Create List</h2>\n <button\n type=\"button\"\n onClick={() => setShowCreate(false)}\n className=\"rounded-md p-1 text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-4 w-4\" />\n </button>\n </div>\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {error && (\n <div className=\"rounded-lg border border-status-error-border bg-status-error-bg-subtle px-3 py-2 text-sm text-status-error-text\">\n {error}\n </div>\n )}\n <div>\n <label htmlFor=\"list-name\" className={labelClass}>\n Name *\n </label>\n <input\n id=\"list-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Weekend Watch\"\n className={fieldClass}\n required\n />\n </div>\n <div>\n <label htmlFor=\"list-desc\" className={labelClass}>\n Description\n </label>\n <textarea\n id=\"list-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n className={fieldClass}\n />\n </div>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n <div>\n <label htmlFor=\"list-kind\" className={labelClass}>\n Kind\n </label>\n <select\n id=\"list-kind\"\n value={kind}\n onChange={(e) => setKind(e.target.value as HokListKind)}\n className={fieldClass}\n >\n {KIND_OPTIONS.map((k) => (\n <option key={k} value={k}>\n {k.charAt(0) + k.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"list-visibility\" className={labelClass}>\n Visibility\n </label>\n <select\n id=\"list-visibility\"\n value={visibility}\n onChange={(e) => setVisibility(e.target.value as HokListVisibility)}\n className={fieldClass}\n >\n {VISIBILITY_OPTIONS.map((v) => (\n <option key={v} value={v}>\n {v.charAt(0) + v.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n </div>\n <button\n type=\"submit\"\n disabled={createList.isPending}\n className=\"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 {createList.isPending ? 'Creating…' : 'Create List'}\n </button>\n </form>\n </GlassCard>\n )}\n\n <div className=\"mb-4 flex flex-wrap items-center gap-3\">\n <select\n value={kindFilter}\n onChange={(e) => setKindFilter(e.target.value as HokListKind | '')}\n className=\"rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-xs text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n <option value=\"\">All Lists</option>\n {KIND_OPTIONS.map((k) => (\n <option key={k} value={k}>\n {k.charAt(0) + k.slice(1).toLowerCase()}\n </option>\n ))}\n </select>\n </div>\n\n {actionError && (\n <div className=\"mb-4 rounded-lg border border-status-error-border bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {actionError}\n </div>\n )}\n\n {isLoading ? (\n <LoadingState label=\"Loading your lists…\" />\n ) : isError ? (\n <ErrorState onRetry={() => void refetch()} />\n ) : items.length === 0 ? (\n <EmptyState\n icon={<ListVideo className=\"h-12 w-12\" />}\n title=\"No lists yet\"\n description=\"Create a watchlist or playlist to organize what you watch.\"\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {items.map((list) => {\n const VisibilityIcon = visibilityIcon[list.visibility];\n return (\n <GlassCard\n key={list.id}\n treatment=\"metric\"\n className=\"flex flex-col border-border-seam p-4\"\n >\n <div className=\"flex items-start justify-between gap-2\">\n <h3 className=\"line-clamp-1 text-sm font-semibold text-text-primary\">\n {list.name}\n </h3>\n <button\n type=\"button\"\n disabled={deleteList.isPending}\n onClick={() => void handleDelete(list.id)}\n className=\"rounded-md p-1 text-text-secondary hover:text-status-error-text disabled:opacity-50 transition-colors\"\n aria-label=\"Delete list\"\n >\n <Trash2 className=\"h-4 w-4\" />\n </button>\n </div>\n {list.description && (\n <p className=\"mt-1 line-clamp-2 text-xs text-text-secondary\">\n {list.description}\n </p>\n )}\n <div className=\"mt-3 flex items-center gap-3 text-xs text-text-secondary\">\n <span className=\"rounded-full bg-bg-sunken px-2 py-0.5\">\n {list.kind.charAt(0) + list.kind.slice(1).toLowerCase()}\n </span>\n <span className=\"inline-flex items-center gap-1\">\n <VisibilityIcon className=\"h-3 w-3\" />\n {list.visibility.charAt(0) + list.visibility.slice(1).toLowerCase()}\n </span>\n <span>{list.itemCount} items</span>\n </div>\n <p className=\"mt-2 text-[11px] text-text-muted\">\n Updated {formatRelativeTime(list.updatedAt)}\n </p>\n </GlassCard>\n );\n })}\n </div>\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-hookmovies",
3
- "version": "2026.629.1",
3
+ "version": "2026.705.1",
4
4
  "description": "Burdenoff HookMovies Microfrontend - Mobile services marketplace platform for connecting service providers with customers",
5
5
  "type": "module",
6
6
  "files": [