@getmicdrop/svelte-components 2.0.6 → 2.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/pages/performers/AvailabilityCalendarModal.svelte +4 -4
- package/dist/components/pages/performers/ModalShowInfo.svelte +1 -1
- package/dist/components/pages/performers/ShowItemCard.svelte +3 -3
- package/dist/components/pages/performers/VenueInfo.svelte +1 -1
- package/dist/components/pages/performers/VenueItemCard.svelte +4 -4
- package/dist/components/pages/settings/tabs/CustomImageDropzone.svelte +3 -3
- package/dist/services/EventService.d.ts +5 -0
- package/dist/services/EventService.d.ts.map +1 -0
- package/dist/services/EventService.js +75 -0
- package/dist/services/EventService.spec.d.ts +2 -0
- package/dist/services/EventService.spec.d.ts.map +1 -0
- package/dist/services/EventService.spec.js +217 -0
- package/dist/services/ShowService.d.ts +47 -0
- package/dist/services/ShowService.d.ts.map +1 -0
- package/dist/services/ShowService.js +143 -0
- package/dist/services/ShowService.spec.d.ts +2 -0
- package/dist/services/ShowService.spec.d.ts.map +1 -0
- package/dist/services/ShowService.spec.js +342 -0
- package/package.json +1 -1
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
import { writable } from "svelte/store";
|
|
4
4
|
import { jwtDecode } from "jwt-decode";
|
|
5
5
|
import QuarterView from "../../Calendar/QuarterView.svelte";
|
|
6
|
-
import { timeAgo } from "
|
|
7
|
-
import { buildApiUrl, API_ENDPOINTS } from "
|
|
8
|
-
import { auth, initializeAuthState } from "
|
|
9
|
-
import microphonePlaceholder from "
|
|
6
|
+
import { timeAgo } from "../../../utils/utils/utils";
|
|
7
|
+
import { buildApiUrl, API_ENDPOINTS } from "../../../utils/apiConfig.js";
|
|
8
|
+
import { auth, initializeAuthState } from "../../../stores/auth.js";
|
|
9
|
+
import microphonePlaceholder from "../../../assets/images/microphone.png";
|
|
10
10
|
|
|
11
11
|
export let show = false;
|
|
12
12
|
export let venue = null;
|
|
@@ -3,14 +3,14 @@
|
|
|
3
3
|
import Icon from "../../Icons/Icon.svelte";
|
|
4
4
|
import Input from "../../Input/Input.svelte";
|
|
5
5
|
import Modal from "../../Modal/Modal.svelte";
|
|
6
|
-
import { showToast } from "
|
|
7
|
-
import { microphonePlaceholder, getUserDetails } from "
|
|
6
|
+
import { showToast } from "../../../stores/toaster";
|
|
7
|
+
import { microphonePlaceholder, getUserDetails } from "../../../utils/utils";
|
|
8
8
|
import {
|
|
9
9
|
formatHour,
|
|
10
10
|
formattedDate,
|
|
11
11
|
formattedFullDate,
|
|
12
12
|
timeAgo,
|
|
13
|
-
} from "
|
|
13
|
+
} from "../../../utils/utils/utils";
|
|
14
14
|
import {
|
|
15
15
|
acceptInvite,
|
|
16
16
|
declineInvite,
|
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
import Input from "../../Input/Input.svelte";
|
|
3
3
|
import Modal from "../../Modal/Modal.svelte";
|
|
4
4
|
import VenueInfo from "./VenueInfo.svelte";
|
|
5
|
-
import { showToast } from "
|
|
6
|
-
import { getPerformerToken } from "
|
|
7
|
-
import { timeAgo } from "
|
|
8
|
-
import { buildApiUrl, API_ENDPOINTS } from "
|
|
5
|
+
import { showToast } from "../../../stores/toaster";
|
|
6
|
+
import { getPerformerToken } from "../../../utils/utils";
|
|
7
|
+
import { timeAgo } from "../../../utils/utils/utils";
|
|
8
|
+
import { buildApiUrl, API_ENDPOINTS } from "../../../utils/apiConfig";
|
|
9
9
|
import { Dropdown, DropdownItem } from "flowbite-svelte";
|
|
10
10
|
import { DotsHorizontalOutline } from "flowbite-svelte-icons";
|
|
11
11
|
import Button from "../../Button/Button.svelte";
|
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
export let readonly = false;
|
|
5
5
|
export let shape = "default";
|
|
6
6
|
export let label = "";
|
|
7
|
-
import CancelIcon from "
|
|
7
|
+
import CancelIcon from "../../../../assets/svg/cancel.svg";
|
|
8
8
|
|
|
9
|
-
import AddMain from "
|
|
10
|
-
import CloudUpload from "
|
|
9
|
+
import AddMain from "../../../../assets/svg/add-main-01.svg";
|
|
10
|
+
import CloudUpload from "../../../../assets/svg/cloud-upload.svg";
|
|
11
11
|
|
|
12
12
|
let images = [];
|
|
13
13
|
let error = "";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export function fetchEventsFromAPI(): Promise<any>;
|
|
2
|
+
export function fetchEventsForMonth(year: any, month: any): Promise<any>;
|
|
3
|
+
export function fetchEventsForWeek(date: any): Promise<any>;
|
|
4
|
+
export function fetchEventsForDay(date: any): Promise<any>;
|
|
5
|
+
//# sourceMappingURL=EventService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventService.d.ts","sourceRoot":"","sources":["../../src/lib/services/EventService.js"],"names":[],"mappings":"AAIA,mDAkBC;AAED,yEAYC;AAED,4DAkBC;AAED,2DAgBC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { addDays, startOfWeek } from "date-fns";
|
|
2
|
+
|
|
3
|
+
let mockEvents = [];
|
|
4
|
+
|
|
5
|
+
export async function fetchEventsFromAPI() {
|
|
6
|
+
try {
|
|
7
|
+
const response = await fetch("https://get-micdrop.com/api/public/getEventsForVenue");
|
|
8
|
+
if (response.ok) {
|
|
9
|
+
const events = await response.json();
|
|
10
|
+
return events.map((event) => ({
|
|
11
|
+
id: event.ID,
|
|
12
|
+
date: event.startDateTime,
|
|
13
|
+
title: event.title,
|
|
14
|
+
}));
|
|
15
|
+
} else {
|
|
16
|
+
console.error("Failed to load events:", response.status);
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
19
|
+
} catch (error) {
|
|
20
|
+
console.error("Error fetching events:", error);
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function fetchEventsForMonth(year, month) {
|
|
26
|
+
mockEvents = await fetchEventsFromAPI();
|
|
27
|
+
|
|
28
|
+
return new Promise((resolve) => {
|
|
29
|
+
setTimeout(() => {
|
|
30
|
+
resolve(
|
|
31
|
+
mockEvents.filter((event) =>
|
|
32
|
+
event.date.startsWith(`${year}-${String(month).padStart(2, "0")}`)
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
}, 500);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function fetchEventsForWeek(date) {
|
|
40
|
+
mockEvents = await fetchEventsFromAPI();
|
|
41
|
+
|
|
42
|
+
const startOfWeekDate = startOfWeek(date, { weekStartsOn: 1 });
|
|
43
|
+
const endOfWeekDate = addDays(startOfWeekDate, 6);
|
|
44
|
+
|
|
45
|
+
return new Promise((resolve) => {
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
const filteredEvents = mockEvents.filter((event) => {
|
|
48
|
+
const eventDate = new Date(event.date).getTime();
|
|
49
|
+
return (
|
|
50
|
+
eventDate >= startOfWeekDate.getTime() &&
|
|
51
|
+
eventDate <= endOfWeekDate.getTime()
|
|
52
|
+
);
|
|
53
|
+
});
|
|
54
|
+
resolve(filteredEvents);
|
|
55
|
+
}, 500);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export async function fetchEventsForDay(date) {
|
|
60
|
+
mockEvents = await fetchEventsFromAPI();
|
|
61
|
+
|
|
62
|
+
return new Promise((resolve) => {
|
|
63
|
+
setTimeout(() => {
|
|
64
|
+
const filteredEvents = mockEvents.filter((event) => {
|
|
65
|
+
const eventDate = new Date(event.date);
|
|
66
|
+
return (
|
|
67
|
+
eventDate.getUTCDate() === date.getUTCDate() &&
|
|
68
|
+
eventDate.getUTCMonth() === date.getUTCMonth() &&
|
|
69
|
+
eventDate.getUTCFullYear() === date.getUTCFullYear()
|
|
70
|
+
);
|
|
71
|
+
});
|
|
72
|
+
resolve(filteredEvents);
|
|
73
|
+
}, 500);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EventService.spec.d.ts","sourceRoot":"","sources":["../../src/lib/services/EventService.spec.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Create mock functions we'll spy on
|
|
4
|
+
const mockEvents = [
|
|
5
|
+
{ ID: 1, startDateTime: '2025-01-15T20:00:00', title: 'Comedy Night' },
|
|
6
|
+
{ ID: 2, startDateTime: '2025-01-15T21:00:00', title: 'Open Mic' },
|
|
7
|
+
{ ID: 3, startDateTime: '2025-02-10T19:00:00', title: 'Improv Show' },
|
|
8
|
+
];
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
fetchEventsFromAPI,
|
|
12
|
+
fetchEventsForMonth,
|
|
13
|
+
fetchEventsForWeek,
|
|
14
|
+
fetchEventsForDay,
|
|
15
|
+
} from './EventService';
|
|
16
|
+
|
|
17
|
+
describe('EventService', () => {
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
vi.clearAllMocks();
|
|
20
|
+
global.fetch = vi.fn();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
describe('fetchEventsFromAPI', () => {
|
|
24
|
+
it('fetches events from the API', async () => {
|
|
25
|
+
global.fetch.mockResolvedValue({
|
|
26
|
+
ok: true,
|
|
27
|
+
json: () => Promise.resolve(mockEvents),
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
const events = await fetchEventsFromAPI();
|
|
31
|
+
|
|
32
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
33
|
+
'https://get-micdrop.com/api/public/getEventsForVenue'
|
|
34
|
+
);
|
|
35
|
+
expect(events).toHaveLength(3);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('transforms event data correctly', async () => {
|
|
39
|
+
global.fetch.mockResolvedValue({
|
|
40
|
+
ok: true,
|
|
41
|
+
json: () => Promise.resolve([mockEvents[0]]),
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const events = await fetchEventsFromAPI();
|
|
45
|
+
|
|
46
|
+
expect(events[0]).toEqual({
|
|
47
|
+
id: 1,
|
|
48
|
+
date: '2025-01-15T20:00:00',
|
|
49
|
+
title: 'Comedy Night',
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('returns empty array on failed response', async () => {
|
|
54
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
55
|
+
global.fetch.mockResolvedValue({
|
|
56
|
+
ok: false,
|
|
57
|
+
status: 500,
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const events = await fetchEventsFromAPI();
|
|
61
|
+
|
|
62
|
+
expect(events).toEqual([]);
|
|
63
|
+
consoleSpy.mockRestore();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('returns empty array on network error', async () => {
|
|
67
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
68
|
+
global.fetch.mockRejectedValue(new Error('Network error'));
|
|
69
|
+
|
|
70
|
+
const events = await fetchEventsFromAPI();
|
|
71
|
+
|
|
72
|
+
expect(events).toEqual([]);
|
|
73
|
+
consoleSpy.mockRestore();
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe('fetchEventsForMonth', () => {
|
|
78
|
+
it('filters events by year and month', async () => {
|
|
79
|
+
global.fetch.mockResolvedValue({
|
|
80
|
+
ok: true,
|
|
81
|
+
json: () => Promise.resolve(mockEvents),
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const events = await fetchEventsForMonth(2025, 1);
|
|
85
|
+
|
|
86
|
+
expect(events.length).toBe(2);
|
|
87
|
+
expect(events[0].title).toBe('Comedy Night');
|
|
88
|
+
expect(events[1].title).toBe('Open Mic');
|
|
89
|
+
}, 10000);
|
|
90
|
+
|
|
91
|
+
it('returns empty for month with no events', async () => {
|
|
92
|
+
global.fetch.mockResolvedValue({
|
|
93
|
+
ok: true,
|
|
94
|
+
json: () => Promise.resolve(mockEvents),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const events = await fetchEventsForMonth(2025, 3);
|
|
98
|
+
|
|
99
|
+
expect(events).toEqual([]);
|
|
100
|
+
}, 10000);
|
|
101
|
+
|
|
102
|
+
it('pads single digit months correctly', async () => {
|
|
103
|
+
global.fetch.mockResolvedValue({
|
|
104
|
+
ok: true,
|
|
105
|
+
json: () => Promise.resolve(mockEvents),
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
const events = await fetchEventsForMonth(2025, 2);
|
|
109
|
+
|
|
110
|
+
expect(events.length).toBe(1);
|
|
111
|
+
expect(events[0].title).toBe('Improv Show');
|
|
112
|
+
}, 10000);
|
|
113
|
+
|
|
114
|
+
it('handles double digit months', async () => {
|
|
115
|
+
const decemberEvents = [
|
|
116
|
+
{ ID: 4, startDateTime: '2025-12-25T20:00:00', title: 'Holiday Show' },
|
|
117
|
+
];
|
|
118
|
+
global.fetch.mockResolvedValue({
|
|
119
|
+
ok: true,
|
|
120
|
+
json: () => Promise.resolve(decemberEvents),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const events = await fetchEventsForMonth(2025, 12);
|
|
124
|
+
|
|
125
|
+
expect(events.length).toBe(1);
|
|
126
|
+
}, 10000);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
describe('fetchEventsForWeek', () => {
|
|
130
|
+
it('filters events within the week', async () => {
|
|
131
|
+
// Events on Jan 13-14, 2025 (Monday-Tuesday of that week)
|
|
132
|
+
const weekEvents = [
|
|
133
|
+
{ ID: 1, startDateTime: '2025-01-13T20:00:00', title: 'Monday Show' },
|
|
134
|
+
{ ID: 2, startDateTime: '2025-01-14T19:00:00', title: 'Tuesday Show' },
|
|
135
|
+
{ ID: 3, startDateTime: '2025-01-20T20:00:00', title: 'Next Week Show' },
|
|
136
|
+
];
|
|
137
|
+
global.fetch.mockResolvedValue({
|
|
138
|
+
ok: true,
|
|
139
|
+
json: () => Promise.resolve(weekEvents),
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Jan 15, 2025 is a Wednesday
|
|
143
|
+
const date = new Date('2025-01-15');
|
|
144
|
+
const events = await fetchEventsForWeek(date);
|
|
145
|
+
|
|
146
|
+
// Should include Monday and Tuesday shows (same week)
|
|
147
|
+
expect(events.length).toBe(2);
|
|
148
|
+
}, 10000);
|
|
149
|
+
|
|
150
|
+
it('uses Monday as week start', async () => {
|
|
151
|
+
const events = [
|
|
152
|
+
{ ID: 1, startDateTime: '2025-01-12T20:00:00', title: 'Sunday Show' },
|
|
153
|
+
{ ID: 2, startDateTime: '2025-01-13T20:00:00', title: 'Monday Show' },
|
|
154
|
+
];
|
|
155
|
+
global.fetch.mockResolvedValue({
|
|
156
|
+
ok: true,
|
|
157
|
+
json: () => Promise.resolve(events),
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
// Pass a date in the week starting Jan 13
|
|
161
|
+
const date = new Date('2025-01-15');
|
|
162
|
+
const result = await fetchEventsForWeek(date);
|
|
163
|
+
|
|
164
|
+
// Sunday should be excluded, Monday included
|
|
165
|
+
expect(result.some((e) => e.title === 'Monday Show')).toBe(true);
|
|
166
|
+
}, 10000);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('fetchEventsForDay', () => {
|
|
170
|
+
it('filters events for specific day', async () => {
|
|
171
|
+
// Use Z suffix for UTC dates to avoid timezone issues
|
|
172
|
+
const dayEvents = [
|
|
173
|
+
{ ID: 1, startDateTime: '2025-01-15T14:00:00Z', title: 'Afternoon Show' },
|
|
174
|
+
{ ID: 2, startDateTime: '2025-01-15T20:00:00Z', title: 'Evening Show' },
|
|
175
|
+
{ ID: 3, startDateTime: '2025-01-16T20:00:00Z', title: 'Next Day Show' },
|
|
176
|
+
];
|
|
177
|
+
global.fetch.mockResolvedValue({
|
|
178
|
+
ok: true,
|
|
179
|
+
json: () => Promise.resolve(dayEvents),
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
const date = new Date(Date.UTC(2025, 0, 15)); // Jan 15, 2025 UTC
|
|
183
|
+
const events = await fetchEventsForDay(date);
|
|
184
|
+
|
|
185
|
+
expect(events.length).toBe(2);
|
|
186
|
+
expect(events[0].title).toBe('Afternoon Show');
|
|
187
|
+
expect(events[1].title).toBe('Evening Show');
|
|
188
|
+
}, 10000);
|
|
189
|
+
|
|
190
|
+
it('returns empty array for day with no events', async () => {
|
|
191
|
+
global.fetch.mockResolvedValue({
|
|
192
|
+
ok: true,
|
|
193
|
+
json: () => Promise.resolve(mockEvents),
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
const date = new Date(Date.UTC(2025, 0, 20)); // Jan 20, 2025
|
|
197
|
+
const events = await fetchEventsForDay(date);
|
|
198
|
+
|
|
199
|
+
expect(events).toEqual([]);
|
|
200
|
+
}, 10000);
|
|
201
|
+
|
|
202
|
+
it('matches dates using UTC methods', async () => {
|
|
203
|
+
const dayEvents = [
|
|
204
|
+
{ ID: 1, startDateTime: '2025-06-15T23:00:00Z', title: 'Late Show' },
|
|
205
|
+
];
|
|
206
|
+
global.fetch.mockResolvedValue({
|
|
207
|
+
ok: true,
|
|
208
|
+
json: () => Promise.resolve(dayEvents),
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
const date = new Date(Date.UTC(2025, 5, 15)); // June 15, 2025 UTC
|
|
212
|
+
const events = await fetchEventsForDay(date);
|
|
213
|
+
|
|
214
|
+
expect(events.length).toBe(1);
|
|
215
|
+
}, 10000);
|
|
216
|
+
});
|
|
217
|
+
});
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Accept an event performer invitation
|
|
3
|
+
* @param {string|number} inviteId - The invitation ID
|
|
4
|
+
* @param {string} message - Optional message to include
|
|
5
|
+
* @returns {Promise<{ok: boolean, result?: any}>}
|
|
6
|
+
*/
|
|
7
|
+
export function acceptInvite(inviteId: string | number, message?: string): Promise<{
|
|
8
|
+
ok: boolean;
|
|
9
|
+
result?: any;
|
|
10
|
+
}>;
|
|
11
|
+
/**
|
|
12
|
+
* Decline an event performer invitation
|
|
13
|
+
* @param {string|number} inviteId - The invitation ID
|
|
14
|
+
* @param {string} message - Optional message to include
|
|
15
|
+
* @returns {Promise<{ok: boolean, result?: any}>}
|
|
16
|
+
*/
|
|
17
|
+
export function declineInvite(inviteId: string | number, message?: string): Promise<{
|
|
18
|
+
ok: boolean;
|
|
19
|
+
result?: any;
|
|
20
|
+
}>;
|
|
21
|
+
/**
|
|
22
|
+
* Cancel an event performer invitation
|
|
23
|
+
* @param {string|number} inviteId - The invitation ID
|
|
24
|
+
* @param {string} message - Optional message to include
|
|
25
|
+
* @returns {Promise<{ok: boolean, result?: any}>}
|
|
26
|
+
*/
|
|
27
|
+
export function cancelInvite(inviteId: string | number, message?: string): Promise<{
|
|
28
|
+
ok: boolean;
|
|
29
|
+
result?: any;
|
|
30
|
+
}>;
|
|
31
|
+
/**
|
|
32
|
+
* Send a message to a venue
|
|
33
|
+
* @param {string|number} inviteId - The invitation/event ID
|
|
34
|
+
* @param {string} message - The message to send
|
|
35
|
+
* @returns {Promise<{ok: boolean, result?: any}>}
|
|
36
|
+
*/
|
|
37
|
+
export function sendVenueMessage(inviteId: string | number, message: string): Promise<{
|
|
38
|
+
ok: boolean;
|
|
39
|
+
result?: any;
|
|
40
|
+
}>;
|
|
41
|
+
/**
|
|
42
|
+
* Get the ticketing event URL
|
|
43
|
+
* @param {string|number} venueId - The venue/event ID
|
|
44
|
+
* @returns {string}
|
|
45
|
+
*/
|
|
46
|
+
export function getEventUrl(venueId: string | number): string;
|
|
47
|
+
//# sourceMappingURL=ShowService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShowService.d.ts","sourceRoot":"","sources":["ShowService.js"],"names":[],"mappings":"AAGA;;;;;GAKG;AACH,uCAJW,MAAM,GAAC,MAAM,YACb,MAAM,GACJ,OAAO,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAC,CAAC,CAwBhD;AAED;;;;;GAKG;AACH,wCAJW,MAAM,GAAC,MAAM,YACb,MAAM,GACJ,OAAO,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAC,CAAC,CAwBhD;AAED;;;;;GAKG;AACH,uCAJW,MAAM,GAAC,MAAM,YACb,MAAM,GACJ,OAAO,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAC,CAAC,CAwBhD;AAED;;;;;GAKG;AACH,2CAJW,MAAM,GAAC,MAAM,WACb,MAAM,GACJ,OAAO,CAAC;IAAC,EAAE,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,GAAG,CAAA;CAAC,CAAC,CAoChD;AAED;;;;GAIG;AACH,qCAHW,MAAM,GAAC,MAAM,GACX,MAAM,CAIlB"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { API_BASE_URL, API_ENDPOINTS, buildApiUrl } from "../../utils/apiConfig";
|
|
2
|
+
import { getPerformerToken } from "../../utils/utils";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Accept an event performer invitation
|
|
6
|
+
* @param {string|number} inviteId - The invitation ID
|
|
7
|
+
* @param {string} message - Optional message to include
|
|
8
|
+
* @returns {Promise<{ok: boolean, result?: any}>}
|
|
9
|
+
*/
|
|
10
|
+
export async function acceptInvite(inviteId, message = "") {
|
|
11
|
+
try {
|
|
12
|
+
const response = await fetch(
|
|
13
|
+
buildApiUrl(`${API_ENDPOINTS.ACCEPT_EVENT_PERFORMER_INVITE}/${inviteId}`),
|
|
14
|
+
{
|
|
15
|
+
method: "PUT",
|
|
16
|
+
headers: {
|
|
17
|
+
"Content-Type": "application/json",
|
|
18
|
+
},
|
|
19
|
+
body: JSON.stringify({ message }),
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
if (response.ok) {
|
|
24
|
+
const result = await response.json();
|
|
25
|
+
return { ok: true, result };
|
|
26
|
+
}
|
|
27
|
+
return { ok: false };
|
|
28
|
+
} catch (error) {
|
|
29
|
+
console.error("Error accepting invite:", error);
|
|
30
|
+
return { ok: false };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Decline an event performer invitation
|
|
36
|
+
* @param {string|number} inviteId - The invitation ID
|
|
37
|
+
* @param {string} message - Optional message to include
|
|
38
|
+
* @returns {Promise<{ok: boolean, result?: any}>}
|
|
39
|
+
*/
|
|
40
|
+
export async function declineInvite(inviteId, message = "") {
|
|
41
|
+
try {
|
|
42
|
+
const response = await fetch(
|
|
43
|
+
buildApiUrl(`${API_ENDPOINTS.DECLINE_EVENT_PERFORMER_INVITE}/${inviteId}`),
|
|
44
|
+
{
|
|
45
|
+
method: "PUT",
|
|
46
|
+
headers: {
|
|
47
|
+
"Content-Type": "application/json",
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({ message }),
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
if (response.ok) {
|
|
54
|
+
const result = await response.json();
|
|
55
|
+
return { ok: true, result };
|
|
56
|
+
}
|
|
57
|
+
return { ok: false };
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error("Error declining invite:", error);
|
|
60
|
+
return { ok: false };
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Cancel an event performer invitation
|
|
66
|
+
* @param {string|number} inviteId - The invitation ID
|
|
67
|
+
* @param {string} message - Optional message to include
|
|
68
|
+
* @returns {Promise<{ok: boolean, result?: any}>}
|
|
69
|
+
*/
|
|
70
|
+
export async function cancelInvite(inviteId, message = "") {
|
|
71
|
+
try {
|
|
72
|
+
const response = await fetch(
|
|
73
|
+
buildApiUrl(`${API_ENDPOINTS.CANCEL_EVENT_PERFORMER_INVITE}/${inviteId}`),
|
|
74
|
+
{
|
|
75
|
+
method: "PUT",
|
|
76
|
+
headers: {
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
},
|
|
79
|
+
body: JSON.stringify({ message }),
|
|
80
|
+
}
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
if (response.ok) {
|
|
84
|
+
const result = await response.json();
|
|
85
|
+
return { ok: true, result };
|
|
86
|
+
}
|
|
87
|
+
return { ok: false };
|
|
88
|
+
} catch (error) {
|
|
89
|
+
console.error("Error cancelling invite:", error);
|
|
90
|
+
return { ok: false };
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Send a message to a venue
|
|
96
|
+
* @param {string|number} inviteId - The invitation/event ID
|
|
97
|
+
* @param {string} message - The message to send
|
|
98
|
+
* @returns {Promise<{ok: boolean, result?: any}>}
|
|
99
|
+
*/
|
|
100
|
+
export async function sendVenueMessage(inviteId, message) {
|
|
101
|
+
try {
|
|
102
|
+
const token = getPerformerToken();
|
|
103
|
+
|
|
104
|
+
const response = await fetch(
|
|
105
|
+
buildApiUrl(`${API_ENDPOINTS.SEND_VENUE_MESSAGE}/${inviteId}`),
|
|
106
|
+
{
|
|
107
|
+
method: "POST",
|
|
108
|
+
headers: {
|
|
109
|
+
"Content-Type": "application/json",
|
|
110
|
+
Authorization: `Bearer ${token}`,
|
|
111
|
+
},
|
|
112
|
+
credentials: "include",
|
|
113
|
+
body: JSON.stringify({ message }),
|
|
114
|
+
}
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
if (response.ok) {
|
|
118
|
+
const text = await response.text();
|
|
119
|
+
let result = { message: "Email sent successfully" };
|
|
120
|
+
if (text) {
|
|
121
|
+
try {
|
|
122
|
+
result = JSON.parse(text);
|
|
123
|
+
} catch (e) {
|
|
124
|
+
// Empty response is fine
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return { ok: true, result };
|
|
128
|
+
}
|
|
129
|
+
return { ok: false };
|
|
130
|
+
} catch (error) {
|
|
131
|
+
console.error("Error sending venue message:", error);
|
|
132
|
+
return { ok: false };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Get the ticketing event URL
|
|
138
|
+
* @param {string|number} venueId - The venue/event ID
|
|
139
|
+
* @returns {string}
|
|
140
|
+
*/
|
|
141
|
+
export function getEventUrl(venueId) {
|
|
142
|
+
return `${API_BASE_URL}/ticketing/events/${venueId}`;
|
|
143
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ShowService.spec.d.ts","sourceRoot":"","sources":["../../src/lib/services/ShowService.spec.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Mock the utility modules before imports
|
|
4
|
+
vi.mock('@/utils/apiConfig', () => ({
|
|
5
|
+
API_BASE_URL: 'https://api.example.com',
|
|
6
|
+
API_ENDPOINTS: {
|
|
7
|
+
ACCEPT_EVENT_PERFORMER_INVITE: '/accept-invite',
|
|
8
|
+
DECLINE_EVENT_PERFORMER_INVITE: '/decline-invite',
|
|
9
|
+
CANCEL_EVENT_PERFORMER_INVITE: '/cancel-invite',
|
|
10
|
+
SEND_VENUE_MESSAGE: '/send-message',
|
|
11
|
+
},
|
|
12
|
+
buildApiUrl: (path) => `https://api.example.com${path}`,
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
vi.mock('@/utils/utils', () => ({
|
|
16
|
+
getPerformerToken: () => 'test-token',
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
import {
|
|
20
|
+
acceptInvite,
|
|
21
|
+
declineInvite,
|
|
22
|
+
cancelInvite,
|
|
23
|
+
sendVenueMessage,
|
|
24
|
+
getEventUrl,
|
|
25
|
+
} from './ShowService';
|
|
26
|
+
|
|
27
|
+
describe('ShowService', () => {
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
vi.clearAllMocks();
|
|
30
|
+
global.fetch = vi.fn();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('acceptInvite', () => {
|
|
34
|
+
it('makes PUT request to accept invite endpoint', async () => {
|
|
35
|
+
global.fetch.mockResolvedValue({
|
|
36
|
+
ok: true,
|
|
37
|
+
json: () => Promise.resolve({ success: true }),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
await acceptInvite('123');
|
|
41
|
+
|
|
42
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
43
|
+
'https://api.example.com/accept-invite/123',
|
|
44
|
+
expect.objectContaining({
|
|
45
|
+
method: 'PUT',
|
|
46
|
+
headers: { 'Content-Type': 'application/json' },
|
|
47
|
+
})
|
|
48
|
+
);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('returns ok: true on successful response', async () => {
|
|
52
|
+
global.fetch.mockResolvedValue({
|
|
53
|
+
ok: true,
|
|
54
|
+
json: () => Promise.resolve({ id: 123 }),
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const result = await acceptInvite('123');
|
|
58
|
+
|
|
59
|
+
expect(result.ok).toBe(true);
|
|
60
|
+
expect(result.result).toEqual({ id: 123 });
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('returns ok: false on failed response', async () => {
|
|
64
|
+
global.fetch.mockResolvedValue({
|
|
65
|
+
ok: false,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const result = await acceptInvite('123');
|
|
69
|
+
|
|
70
|
+
expect(result.ok).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('returns ok: false on network error', async () => {
|
|
74
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
75
|
+
global.fetch.mockRejectedValue(new Error('Network error'));
|
|
76
|
+
|
|
77
|
+
const result = await acceptInvite('123');
|
|
78
|
+
|
|
79
|
+
expect(result.ok).toBe(false);
|
|
80
|
+
consoleSpy.mockRestore();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('includes message in request body', async () => {
|
|
84
|
+
global.fetch.mockResolvedValue({
|
|
85
|
+
ok: true,
|
|
86
|
+
json: () => Promise.resolve({}),
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
await acceptInvite('123', 'Thanks for the invite!');
|
|
90
|
+
|
|
91
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
92
|
+
expect.any(String),
|
|
93
|
+
expect.objectContaining({
|
|
94
|
+
body: JSON.stringify({ message: 'Thanks for the invite!' }),
|
|
95
|
+
})
|
|
96
|
+
);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('sends empty message by default', async () => {
|
|
100
|
+
global.fetch.mockResolvedValue({
|
|
101
|
+
ok: true,
|
|
102
|
+
json: () => Promise.resolve({}),
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
await acceptInvite('123');
|
|
106
|
+
|
|
107
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
108
|
+
expect.any(String),
|
|
109
|
+
expect.objectContaining({
|
|
110
|
+
body: JSON.stringify({ message: '' }),
|
|
111
|
+
})
|
|
112
|
+
);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
describe('declineInvite', () => {
|
|
117
|
+
it('makes PUT request to decline invite endpoint', async () => {
|
|
118
|
+
global.fetch.mockResolvedValue({
|
|
119
|
+
ok: true,
|
|
120
|
+
json: () => Promise.resolve({}),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
await declineInvite('456');
|
|
124
|
+
|
|
125
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
126
|
+
'https://api.example.com/decline-invite/456',
|
|
127
|
+
expect.objectContaining({
|
|
128
|
+
method: 'PUT',
|
|
129
|
+
})
|
|
130
|
+
);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('returns ok: true on success', async () => {
|
|
134
|
+
global.fetch.mockResolvedValue({
|
|
135
|
+
ok: true,
|
|
136
|
+
json: () => Promise.resolve({ declined: true }),
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
const result = await declineInvite('456');
|
|
140
|
+
|
|
141
|
+
expect(result.ok).toBe(true);
|
|
142
|
+
expect(result.result).toEqual({ declined: true });
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('returns ok: false on failure', async () => {
|
|
146
|
+
global.fetch.mockResolvedValue({
|
|
147
|
+
ok: false,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const result = await declineInvite('456');
|
|
151
|
+
|
|
152
|
+
expect(result.ok).toBe(false);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('returns ok: false on error', async () => {
|
|
156
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
157
|
+
global.fetch.mockRejectedValue(new Error('Error'));
|
|
158
|
+
|
|
159
|
+
const result = await declineInvite('456');
|
|
160
|
+
|
|
161
|
+
expect(result.ok).toBe(false);
|
|
162
|
+
consoleSpy.mockRestore();
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('includes decline message in body', async () => {
|
|
166
|
+
global.fetch.mockResolvedValue({
|
|
167
|
+
ok: true,
|
|
168
|
+
json: () => Promise.resolve({}),
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
await declineInvite('456', 'Schedule conflict');
|
|
172
|
+
|
|
173
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
174
|
+
expect.any(String),
|
|
175
|
+
expect.objectContaining({
|
|
176
|
+
body: JSON.stringify({ message: 'Schedule conflict' }),
|
|
177
|
+
})
|
|
178
|
+
);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe('cancelInvite', () => {
|
|
183
|
+
it('makes PUT request to cancel invite endpoint', async () => {
|
|
184
|
+
global.fetch.mockResolvedValue({
|
|
185
|
+
ok: true,
|
|
186
|
+
json: () => Promise.resolve({}),
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
await cancelInvite('789');
|
|
190
|
+
|
|
191
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
192
|
+
'https://api.example.com/cancel-invite/789',
|
|
193
|
+
expect.objectContaining({
|
|
194
|
+
method: 'PUT',
|
|
195
|
+
})
|
|
196
|
+
);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('returns ok: true on success', async () => {
|
|
200
|
+
global.fetch.mockResolvedValue({
|
|
201
|
+
ok: true,
|
|
202
|
+
json: () => Promise.resolve({ cancelled: true }),
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const result = await cancelInvite('789');
|
|
206
|
+
|
|
207
|
+
expect(result.ok).toBe(true);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
it('returns ok: false on failure', async () => {
|
|
211
|
+
global.fetch.mockResolvedValue({
|
|
212
|
+
ok: false,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const result = await cancelInvite('789');
|
|
216
|
+
|
|
217
|
+
expect(result.ok).toBe(false);
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('returns ok: false on error', async () => {
|
|
221
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
222
|
+
global.fetch.mockRejectedValue(new Error('Error'));
|
|
223
|
+
|
|
224
|
+
const result = await cancelInvite('789');
|
|
225
|
+
|
|
226
|
+
expect(result.ok).toBe(false);
|
|
227
|
+
consoleSpy.mockRestore();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
describe('sendVenueMessage', () => {
|
|
232
|
+
it('makes POST request with auth token', async () => {
|
|
233
|
+
global.fetch.mockResolvedValue({
|
|
234
|
+
ok: true,
|
|
235
|
+
text: () => Promise.resolve(''),
|
|
236
|
+
});
|
|
237
|
+
|
|
238
|
+
await sendVenueMessage('123', 'Hello!');
|
|
239
|
+
|
|
240
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
241
|
+
'https://api.example.com/send-message/123',
|
|
242
|
+
expect.objectContaining({
|
|
243
|
+
method: 'POST',
|
|
244
|
+
headers: {
|
|
245
|
+
'Content-Type': 'application/json',
|
|
246
|
+
Authorization: 'Bearer test-token',
|
|
247
|
+
},
|
|
248
|
+
credentials: 'include',
|
|
249
|
+
})
|
|
250
|
+
);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it('sends message in request body', async () => {
|
|
254
|
+
global.fetch.mockResolvedValue({
|
|
255
|
+
ok: true,
|
|
256
|
+
text: () => Promise.resolve(''),
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
await sendVenueMessage('123', 'Hello venue!');
|
|
260
|
+
|
|
261
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
262
|
+
expect.any(String),
|
|
263
|
+
expect.objectContaining({
|
|
264
|
+
body: JSON.stringify({ message: 'Hello venue!' }),
|
|
265
|
+
})
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it('returns ok: true with default message on empty response', async () => {
|
|
270
|
+
global.fetch.mockResolvedValue({
|
|
271
|
+
ok: true,
|
|
272
|
+
text: () => Promise.resolve(''),
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
const result = await sendVenueMessage('123', 'Hello');
|
|
276
|
+
|
|
277
|
+
expect(result.ok).toBe(true);
|
|
278
|
+
expect(result.result).toEqual({ message: 'Email sent successfully' });
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('parses JSON response when present', async () => {
|
|
282
|
+
global.fetch.mockResolvedValue({
|
|
283
|
+
ok: true,
|
|
284
|
+
text: () => Promise.resolve(JSON.stringify({ sent: true, id: 456 })),
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
const result = await sendVenueMessage('123', 'Hello');
|
|
288
|
+
|
|
289
|
+
expect(result.ok).toBe(true);
|
|
290
|
+
expect(result.result).toEqual({ sent: true, id: 456 });
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
it('handles invalid JSON in response gracefully', async () => {
|
|
294
|
+
global.fetch.mockResolvedValue({
|
|
295
|
+
ok: true,
|
|
296
|
+
text: () => Promise.resolve('not json'),
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
const result = await sendVenueMessage('123', 'Hello');
|
|
300
|
+
|
|
301
|
+
expect(result.ok).toBe(true);
|
|
302
|
+
expect(result.result).toEqual({ message: 'Email sent successfully' });
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it('returns ok: false on failure', async () => {
|
|
306
|
+
global.fetch.mockResolvedValue({
|
|
307
|
+
ok: false,
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
const result = await sendVenueMessage('123', 'Hello');
|
|
311
|
+
|
|
312
|
+
expect(result.ok).toBe(false);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('returns ok: false on error', async () => {
|
|
316
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
317
|
+
global.fetch.mockRejectedValue(new Error('Network error'));
|
|
318
|
+
|
|
319
|
+
const result = await sendVenueMessage('123', 'Hello');
|
|
320
|
+
|
|
321
|
+
expect(result.ok).toBe(false);
|
|
322
|
+
consoleSpy.mockRestore();
|
|
323
|
+
});
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
describe('getEventUrl', () => {
|
|
327
|
+
it('returns ticketing URL for venue', () => {
|
|
328
|
+
const url = getEventUrl('123');
|
|
329
|
+
expect(url).toBe('https://api.example.com/ticketing/events/123');
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('handles numeric venue ID', () => {
|
|
333
|
+
const url = getEventUrl(456);
|
|
334
|
+
expect(url).toBe('https://api.example.com/ticketing/events/456');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
it('handles string venue ID', () => {
|
|
338
|
+
const url = getEventUrl('venue-abc');
|
|
339
|
+
expect(url).toBe('https://api.example.com/ticketing/events/venue-abc');
|
|
340
|
+
});
|
|
341
|
+
});
|
|
342
|
+
});
|