@mundogamernetwork/shared-ui 1.1.96 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/playtest/PlaytestBrief.vue +152 -0
- package/components/playtest/PlaytestPendingConfirmation.vue +84 -0
- package/components/playtest/PlaytestResponseFlow.vue +371 -0
- package/components/playtest/StarRatingInput.vue +105 -0
- package/components/playtest/accessibility/CriterionRow.vue +167 -0
- package/components/playtest/baseline/BaselineSectionStep.vue +106 -0
- package/components/playtest/compliance/ChecklistItemRow.vue +200 -0
- package/components/playtest/concept-poll/EmojiReactionVote.vue +145 -0
- package/components/playtest/concept-poll/FiveSecondTestVote.vue +197 -0
- package/components/playtest/concept-poll/HeadToHeadVote.vue +98 -0
- package/components/playtest/concept-poll/MultiSelectVote.vue +104 -0
- package/components/playtest/concept-poll/RankedChoiceVote.vue +169 -0
- package/components/playtest/concept-poll/SingleSelectVote.vue +98 -0
- package/components/playtest/concept-poll/StarRatingVote.vue +110 -0
- package/components/playtest/concept-poll/VoteReasonField.vue +74 -0
- package/components/playtest/lqa/FileIssueForm.vue +181 -0
- package/components/playtest/lqa/IssueList.vue +99 -0
- package/components/playtest/lqa/LocaleSelector.vue +73 -0
- package/components/playtest/moderated/JoinCallPanel.vue +135 -0
- package/components/playtest/moderated/SessionCard.vue +146 -0
- package/composables/usePlaytestResponse.ts +446 -0
- package/package.json +10 -3
- package/services/playtestTesterService.ts +416 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
import { ref, reactive, computed } from "vue";
|
|
2
|
+
import {
|
|
3
|
+
fetchPlaytestCatalog,
|
|
4
|
+
fetchAvailablePlaytestCampaigns,
|
|
5
|
+
submitPlaytestResponse,
|
|
6
|
+
fetchConceptPoll,
|
|
7
|
+
voteConceptPoll,
|
|
8
|
+
fetchCampaignLocales,
|
|
9
|
+
storeLocalizationIssue,
|
|
10
|
+
fetchAccessibilityCriteriaCatalog,
|
|
11
|
+
submitAccessibilityEvaluations,
|
|
12
|
+
fetchComplianceChecklists,
|
|
13
|
+
submitComplianceResult,
|
|
14
|
+
fetchAvailableModeratedSlots,
|
|
15
|
+
claimModeratedSlot,
|
|
16
|
+
fetchMyModeratedSessions,
|
|
17
|
+
fetchModeratedSession,
|
|
18
|
+
confirmModeratedSession,
|
|
19
|
+
markModeratedSessionNoShow,
|
|
20
|
+
cancelModeratedSession,
|
|
21
|
+
uploadPlaytestMedia,
|
|
22
|
+
fetchMyPlaytestResponses,
|
|
23
|
+
type PlaytestCampaign,
|
|
24
|
+
type PlaytestCatalog,
|
|
25
|
+
type PlaytestAnswerEntry,
|
|
26
|
+
type SubmitBaselineResponsePayload,
|
|
27
|
+
type PlaytestConceptPoll,
|
|
28
|
+
type ConceptPollAnswer,
|
|
29
|
+
type PlaytestCampaignLocale,
|
|
30
|
+
type StoreLocalizationIssuePayload,
|
|
31
|
+
type PlaytestLocalizationIssue,
|
|
32
|
+
type AccessibilityCriteriaCatalog,
|
|
33
|
+
type AccessibilityEvaluationEntry,
|
|
34
|
+
type PlaytestComplianceChecklist,
|
|
35
|
+
type ComplianceResultEntry,
|
|
36
|
+
type PlaytestModeratedSlot,
|
|
37
|
+
type PlaytestModeratedSession,
|
|
38
|
+
} from "../services/playtestTesterService";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Accumulates client-side answer/vote/issue/evaluation/result state for a
|
|
42
|
+
* single campaign visit, and centralizes the "you no longer qualify" (422)
|
|
43
|
+
* handling every submit endpoint can independently throw — every submit path
|
|
44
|
+
* re-checks PlaytestService::assertEligible() server-side, even when a prior
|
|
45
|
+
* screen already confirmed eligibility (a campaign's audience rules, or the
|
|
46
|
+
* tester's own certifications, can change between page-load and submit).
|
|
47
|
+
*
|
|
48
|
+
* One instance per campaign visit — instantiate fresh per mount
|
|
49
|
+
* (PlaytestResponseFlow.vue owns the instance), not as a global singleton.
|
|
50
|
+
*/
|
|
51
|
+
export function usePlaytestResponse(campaignId: number) {
|
|
52
|
+
// ── Shared/global state ────────────────────────────────────────────────
|
|
53
|
+
const loading = ref(false);
|
|
54
|
+
const submitting = ref(false);
|
|
55
|
+
|
|
56
|
+
// Structured ineligibility state — distinct from generic errors so the UI
|
|
57
|
+
// can render a dedicated "you no longer qualify" panel instead of a toast.
|
|
58
|
+
const ineligible = ref(false);
|
|
59
|
+
const ineligibilityReason = ref<string | null>(null);
|
|
60
|
+
const genericError = ref<string | null>(null);
|
|
61
|
+
|
|
62
|
+
function resetErrors() {
|
|
63
|
+
ineligible.value = false;
|
|
64
|
+
ineligibilityReason.value = null;
|
|
65
|
+
genericError.value = null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Every submit endpoint returns a 422 (via each controller's guarded()
|
|
70
|
+
* wrapper around PlaytestService::assertEligible()) when the tester no
|
|
71
|
+
* longer qualifies — must be handled gracefully on every call site, not
|
|
72
|
+
* just assumed-passed because a previous screen displayed `eligible: true`.
|
|
73
|
+
*/
|
|
74
|
+
function handleError(e: any): never {
|
|
75
|
+
const status = e?.response?.status;
|
|
76
|
+
const message: string = e?.response?.data?.message ?? "";
|
|
77
|
+
|
|
78
|
+
if (status === 422) {
|
|
79
|
+
ineligible.value = true;
|
|
80
|
+
ineligibilityReason.value = message || null;
|
|
81
|
+
} else {
|
|
82
|
+
genericError.value = message || e?.message || "Something went wrong. Please try again.";
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
throw e;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
async function withGuard<T>(fn: () => Promise<T>): Promise<T | null> {
|
|
89
|
+
resetErrors();
|
|
90
|
+
submitting.value = true;
|
|
91
|
+
try {
|
|
92
|
+
return await fn();
|
|
93
|
+
} catch (e) {
|
|
94
|
+
try {
|
|
95
|
+
handleError(e);
|
|
96
|
+
} catch {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
return null;
|
|
100
|
+
} finally {
|
|
101
|
+
submitting.value = false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// ── Catalog (baseline sections) ────────────────────────────────────────
|
|
106
|
+
const catalog = ref<PlaytestCatalog | null>(null);
|
|
107
|
+
|
|
108
|
+
async function loadCatalog() {
|
|
109
|
+
loading.value = true;
|
|
110
|
+
try {
|
|
111
|
+
const res = await fetchPlaytestCatalog();
|
|
112
|
+
catalog.value = res.data;
|
|
113
|
+
} finally {
|
|
114
|
+
loading.value = false;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// ── Campaign (available() list entry, carries eligibility) ────────────
|
|
119
|
+
const campaign = ref<PlaytestCampaign | null>(null);
|
|
120
|
+
|
|
121
|
+
async function loadCampaignEligibility() {
|
|
122
|
+
loading.value = true;
|
|
123
|
+
try {
|
|
124
|
+
const res = await fetchAvailablePlaytestCampaigns();
|
|
125
|
+
const found = res.data.find((c) => c.id === campaignId) ?? null;
|
|
126
|
+
campaign.value = found;
|
|
127
|
+
if (found && found.eligible === false) {
|
|
128
|
+
ineligible.value = true;
|
|
129
|
+
ineligibilityReason.value = found.ineligibility_reason ?? null;
|
|
130
|
+
}
|
|
131
|
+
return found;
|
|
132
|
+
} finally {
|
|
133
|
+
loading.value = false;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ── Baseline answers accumulator ───────────────────────────────────────
|
|
138
|
+
const baselineAnswers = reactive<Record<string, PlaytestAnswerEntry>>({});
|
|
139
|
+
|
|
140
|
+
function setBaselineAnswer(sectionKey: string, entry: PlaytestAnswerEntry) {
|
|
141
|
+
baselineAnswers[sectionKey] = { ...baselineAnswers[sectionKey], ...entry };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function submitBaseline(meta: Omit<SubmitBaselineResponsePayload, "answers"> = {}) {
|
|
145
|
+
return withGuard(async () => {
|
|
146
|
+
const res = await submitPlaytestResponse(campaignId, {
|
|
147
|
+
answers: { ...baselineAnswers },
|
|
148
|
+
...meta,
|
|
149
|
+
});
|
|
150
|
+
return res.data;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// ── Concept poll ────────────────────────────────────────────────────────
|
|
155
|
+
const poll = ref<PlaytestConceptPoll | null>(null);
|
|
156
|
+
|
|
157
|
+
async function loadConceptPoll(pollId: number) {
|
|
158
|
+
loading.value = true;
|
|
159
|
+
try {
|
|
160
|
+
const res = await fetchConceptPoll(pollId);
|
|
161
|
+
poll.value = res.data;
|
|
162
|
+
} finally {
|
|
163
|
+
loading.value = false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
async function submitConceptPollVote(pollId: number, answer: ConceptPollAnswer, reason: string) {
|
|
168
|
+
return withGuard(async () => {
|
|
169
|
+
const res = await voteConceptPoll(pollId, { answer, reason });
|
|
170
|
+
return res.data;
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ── Localization QA ────────────────────────────────────────────────────
|
|
175
|
+
const locales = ref<PlaytestCampaignLocale[]>([]);
|
|
176
|
+
const filedIssues = ref<PlaytestLocalizationIssue[]>([]);
|
|
177
|
+
|
|
178
|
+
async function loadCampaignLocales() {
|
|
179
|
+
loading.value = true;
|
|
180
|
+
try {
|
|
181
|
+
const res = await fetchCampaignLocales(campaignId);
|
|
182
|
+
locales.value = res.data;
|
|
183
|
+
} finally {
|
|
184
|
+
loading.value = false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async function fileLocalizationIssue(payload: StoreLocalizationIssuePayload) {
|
|
189
|
+
return withGuard(async () => {
|
|
190
|
+
const res = await storeLocalizationIssue(campaignId, payload);
|
|
191
|
+
filedIssues.value.push(res.data);
|
|
192
|
+
return res.data;
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ── Accessibility ───────────────────────────────────────────────────────
|
|
197
|
+
const accessibilityCriteria = ref<AccessibilityCriteriaCatalog>({});
|
|
198
|
+
// criterion key -> completed evaluation entry, so the UI can auto-save
|
|
199
|
+
// each criterion independently (server upserts per-criterion — safe).
|
|
200
|
+
const accessibilityEvaluations = reactive<Record<string, AccessibilityEvaluationEntry>>({});
|
|
201
|
+
|
|
202
|
+
async function loadAccessibilityCriteria() {
|
|
203
|
+
loading.value = true;
|
|
204
|
+
try {
|
|
205
|
+
const res = await fetchAccessibilityCriteriaCatalog();
|
|
206
|
+
accessibilityCriteria.value = res.data;
|
|
207
|
+
} finally {
|
|
208
|
+
loading.value = false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function setAccessibilityEvaluation(entry: AccessibilityEvaluationEntry) {
|
|
213
|
+
accessibilityEvaluations[entry.criterion] = entry;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Submits one (or more) criterion evaluations. Safe to call per-criterion
|
|
218
|
+
* as the tester completes each one (upsert semantics server-side) — pass
|
|
219
|
+
* just the newly-completed entry, or omit `entries` to flush everything
|
|
220
|
+
* accumulated so far.
|
|
221
|
+
*/
|
|
222
|
+
async function submitAccessibilityBatch(entries?: AccessibilityEvaluationEntry[]) {
|
|
223
|
+
return withGuard(async () => {
|
|
224
|
+
const payload = entries ?? Object.values(accessibilityEvaluations);
|
|
225
|
+
const res = await submitAccessibilityEvaluations(campaignId, { evaluations: payload });
|
|
226
|
+
return res.data;
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ── Compliance checklists ──────────────────────────────────────────────
|
|
231
|
+
const complianceChecklists = ref<PlaytestComplianceChecklist[]>([]);
|
|
232
|
+
// checklistId -> (key -> result entry). Kept per-checklist because the
|
|
233
|
+
// submit endpoint fully REPLACES the whole `results` array per checklist —
|
|
234
|
+
// callers must always send the complete accumulated set for that
|
|
235
|
+
// checklist, never a diff.
|
|
236
|
+
const complianceResults = reactive<Record<number, Record<string, ComplianceResultEntry>>>({});
|
|
237
|
+
|
|
238
|
+
async function loadComplianceChecklists() {
|
|
239
|
+
loading.value = true;
|
|
240
|
+
try {
|
|
241
|
+
const res = await fetchComplianceChecklists(campaignId);
|
|
242
|
+
complianceChecklists.value = res.data;
|
|
243
|
+
res.data.forEach((c) => {
|
|
244
|
+
if (!complianceResults[c.id]) complianceResults[c.id] = {};
|
|
245
|
+
});
|
|
246
|
+
} finally {
|
|
247
|
+
loading.value = false;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function setComplianceResult(checklistId: number, entry: ComplianceResultEntry) {
|
|
252
|
+
if (!complianceResults[checklistId]) complianceResults[checklistId] = {};
|
|
253
|
+
complianceResults[checklistId][entry.key] = entry;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Always sends the FULL accumulated results array for this checklist —
|
|
258
|
+
* never a diff — since the backend replaces the whole array on every call.
|
|
259
|
+
*/
|
|
260
|
+
async function submitComplianceChecklist(checklistId: number) {
|
|
261
|
+
return withGuard(async () => {
|
|
262
|
+
const results = Object.values(complianceResults[checklistId] ?? {});
|
|
263
|
+
const res = await submitComplianceResult(checklistId, { results });
|
|
264
|
+
return res.data;
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// ── Moderated sessions ──────────────────────────────────────────────────
|
|
269
|
+
const moderatedSlots = ref<PlaytestModeratedSlot[]>([]);
|
|
270
|
+
const mySessions = ref<PlaytestModeratedSession[]>([]);
|
|
271
|
+
const currentSession = ref<PlaytestModeratedSession | null>(null);
|
|
272
|
+
|
|
273
|
+
async function loadAvailableModeratedSlots() {
|
|
274
|
+
loading.value = true;
|
|
275
|
+
try {
|
|
276
|
+
const res = await fetchAvailableModeratedSlots(campaignId);
|
|
277
|
+
// availableSlots() has no server-side eligibility pre-filtering
|
|
278
|
+
// (documented gap) — the client is expected to work around it by
|
|
279
|
+
// still attempting the claim, which re-checks eligibility server-
|
|
280
|
+
// side and surfaces a 422 gracefully via withGuard() if it fails.
|
|
281
|
+
moderatedSlots.value = res.data;
|
|
282
|
+
} finally {
|
|
283
|
+
loading.value = false;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
async function claimSlot(slotId: number) {
|
|
288
|
+
return withGuard(async () => {
|
|
289
|
+
const res = await claimModeratedSlot(slotId);
|
|
290
|
+
currentSession.value = res.data;
|
|
291
|
+
return res.data;
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async function loadMySessions() {
|
|
296
|
+
loading.value = true;
|
|
297
|
+
try {
|
|
298
|
+
const res = await fetchMyModeratedSessions();
|
|
299
|
+
mySessions.value = res.data;
|
|
300
|
+
} finally {
|
|
301
|
+
loading.value = false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
async function loadSession(sessionId: number) {
|
|
306
|
+
loading.value = true;
|
|
307
|
+
try {
|
|
308
|
+
const res = await fetchModeratedSession(sessionId);
|
|
309
|
+
currentSession.value = res.data;
|
|
310
|
+
return res.data;
|
|
311
|
+
} finally {
|
|
312
|
+
loading.value = false;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
async function confirmSession(sessionId: number) {
|
|
317
|
+
return withGuard(async () => {
|
|
318
|
+
const res = await confirmModeratedSession(sessionId);
|
|
319
|
+
currentSession.value = res.data;
|
|
320
|
+
return res.data;
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
async function noShowSession(sessionId: number) {
|
|
325
|
+
return withGuard(async () => {
|
|
326
|
+
const res = await markModeratedSessionNoShow(sessionId);
|
|
327
|
+
currentSession.value = res.data;
|
|
328
|
+
return res.data;
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
async function cancelSession(sessionId: number, reason?: string) {
|
|
333
|
+
return withGuard(async () => {
|
|
334
|
+
const res = await cancelModeratedSession(sessionId, reason);
|
|
335
|
+
currentSession.value = res.data;
|
|
336
|
+
return res.data;
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
// ── Media upload ────────────────────────────────────────────────────────
|
|
341
|
+
const uploading = ref(false);
|
|
342
|
+
|
|
343
|
+
async function uploadMedia(file: File): Promise<string | null> {
|
|
344
|
+
uploading.value = true;
|
|
345
|
+
try {
|
|
346
|
+
const res = await uploadPlaytestMedia(file);
|
|
347
|
+
return res.data?.data?.url ?? null;
|
|
348
|
+
} catch (e) {
|
|
349
|
+
try {
|
|
350
|
+
handleError(e);
|
|
351
|
+
} catch {
|
|
352
|
+
return null;
|
|
353
|
+
}
|
|
354
|
+
return null;
|
|
355
|
+
} finally {
|
|
356
|
+
uploading.value = false;
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ── My responses (fetch exposed for consuming-app dashboards) ─────────
|
|
361
|
+
const myResponses = ref<any[]>([]);
|
|
362
|
+
|
|
363
|
+
async function loadMyResponses(status?: "submitted" | "accepted" | "rejected") {
|
|
364
|
+
loading.value = true;
|
|
365
|
+
try {
|
|
366
|
+
const res = await fetchMyPlaytestResponses(status);
|
|
367
|
+
myResponses.value = res.data?.data ?? [];
|
|
368
|
+
return res.data;
|
|
369
|
+
} finally {
|
|
370
|
+
loading.value = false;
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const hasError = computed(() => ineligible.value || !!genericError.value);
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
// state
|
|
378
|
+
loading,
|
|
379
|
+
submitting,
|
|
380
|
+
uploading,
|
|
381
|
+
ineligible,
|
|
382
|
+
ineligibilityReason,
|
|
383
|
+
genericError,
|
|
384
|
+
hasError,
|
|
385
|
+
|
|
386
|
+
// catalog / discovery
|
|
387
|
+
catalog,
|
|
388
|
+
campaign,
|
|
389
|
+
loadCatalog,
|
|
390
|
+
loadCampaignEligibility,
|
|
391
|
+
|
|
392
|
+
// baseline
|
|
393
|
+
baselineAnswers,
|
|
394
|
+
setBaselineAnswer,
|
|
395
|
+
submitBaseline,
|
|
396
|
+
|
|
397
|
+
// concept poll
|
|
398
|
+
poll,
|
|
399
|
+
loadConceptPoll,
|
|
400
|
+
submitConceptPollVote,
|
|
401
|
+
|
|
402
|
+
// localization QA
|
|
403
|
+
locales,
|
|
404
|
+
filedIssues,
|
|
405
|
+
loadCampaignLocales,
|
|
406
|
+
fileLocalizationIssue,
|
|
407
|
+
|
|
408
|
+
// accessibility
|
|
409
|
+
accessibilityCriteria,
|
|
410
|
+
accessibilityEvaluations,
|
|
411
|
+
loadAccessibilityCriteria,
|
|
412
|
+
setAccessibilityEvaluation,
|
|
413
|
+
submitAccessibilityBatch,
|
|
414
|
+
|
|
415
|
+
// compliance
|
|
416
|
+
complianceChecklists,
|
|
417
|
+
complianceResults,
|
|
418
|
+
loadComplianceChecklists,
|
|
419
|
+
setComplianceResult,
|
|
420
|
+
submitComplianceChecklist,
|
|
421
|
+
|
|
422
|
+
// moderated sessions
|
|
423
|
+
moderatedSlots,
|
|
424
|
+
mySessions,
|
|
425
|
+
currentSession,
|
|
426
|
+
loadAvailableModeratedSlots,
|
|
427
|
+
claimSlot,
|
|
428
|
+
loadMySessions,
|
|
429
|
+
loadSession,
|
|
430
|
+
confirmSession,
|
|
431
|
+
noShowSession,
|
|
432
|
+
cancelSession,
|
|
433
|
+
|
|
434
|
+
// media
|
|
435
|
+
uploadMedia,
|
|
436
|
+
|
|
437
|
+
// my responses
|
|
438
|
+
myResponses,
|
|
439
|
+
loadMyResponses,
|
|
440
|
+
|
|
441
|
+
// helpers
|
|
442
|
+
resetErrors,
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
export type PlaytestResponseComposable = ReturnType<typeof usePlaytestResponse>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mundogamernetwork/shared-ui",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"description": "Mundo Gamer Network - Shared UI Layer (Nuxt 3)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./nuxt.config.ts",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
"build": "nuxi build .playground"
|
|
29
29
|
},
|
|
30
30
|
"peerDependencies": {
|
|
31
|
-
"@pinia/nuxt": ">=0.5.0",
|
|
32
31
|
"@pinia-plugin-persistedstate/nuxt": ">=1.0.0",
|
|
32
|
+
"@pinia/nuxt": ">=0.5.0",
|
|
33
33
|
"axios": ">=1.0.0",
|
|
34
34
|
"laravel-echo": ">=1.15.0",
|
|
35
35
|
"nuxt": ">=3.13.0",
|
|
@@ -38,7 +38,14 @@
|
|
|
38
38
|
"vue": ">=3.5.0"
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
+
"@pinia-plugin-persistedstate/nuxt": "^1.2.1",
|
|
42
|
+
"@pinia/nuxt": "^0.5.5",
|
|
43
|
+
"axios": "^1.18.1",
|
|
44
|
+
"laravel-echo": "^2.3.7",
|
|
41
45
|
"nuxt": "^3.15.4",
|
|
42
|
-
"
|
|
46
|
+
"pinia": "^2.3.1",
|
|
47
|
+
"pusher-js": "^8.5.0",
|
|
48
|
+
"typescript": "^5.0.0",
|
|
49
|
+
"vue-tsc": "^2.2.0"
|
|
43
50
|
}
|
|
44
51
|
}
|