@frigear-nu/events 0.0.7 → 0.0.9
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/README.md +1 -1
- package/dist/module.d.mts +45 -7
- package/dist/module.json +1 -1
- package/dist/module.mjs +59 -41
- package/dist/runtime/app/components/EventAdminAddonDialog.d.vue.ts +11 -0
- package/dist/runtime/app/components/EventAdminAddonDialog.vue +113 -0
- package/dist/runtime/app/components/EventAdminAddonDialog.vue.d.ts +11 -0
- package/dist/runtime/app/components/EventAdminAddonGroupDialog.d.vue.ts +11 -0
- package/dist/runtime/app/components/EventAdminAddonGroupDialog.vue +79 -0
- package/dist/runtime/app/components/EventAdminAddonGroupDialog.vue.d.ts +11 -0
- package/dist/runtime/app/components/EventAdminAddonGroups.d.vue.ts +19 -0
- package/dist/runtime/app/components/EventAdminAddonGroups.vue +123 -0
- package/dist/runtime/app/components/EventAdminAddonGroups.vue.d.ts +19 -0
- package/dist/runtime/app/components/EventAdminTicketTypeDialog.d.vue.ts +20 -0
- package/dist/runtime/app/components/EventAdminTicketTypeDialog.vue +175 -0
- package/dist/runtime/app/components/EventAdminTicketTypeDialog.vue.d.ts +20 -0
- package/dist/runtime/app/components/EventCard.vue +39 -27
- package/dist/runtime/app/components/EventTicketCard.vue +5 -4
- package/dist/runtime/app/components/EventTicketPicker.vue +40 -21
- package/dist/runtime/app/composables/index.d.ts +1 -1
- package/dist/runtime/app/composables/index.js +1 -1
- package/dist/runtime/app/composables/useEvents.d.ts +10 -4
- package/dist/runtime/app/composables/useEvents.js +21 -10
- package/dist/runtime/app/pages/admin-event.d.vue.ts +3 -0
- package/dist/runtime/app/pages/admin-event.vue +151 -0
- package/dist/runtime/app/pages/admin-event.vue.d.ts +3 -0
- package/dist/runtime/app/pages/admin.d.vue.ts +3 -0
- package/dist/runtime/app/pages/admin.vue +154 -0
- package/dist/runtime/app/pages/admin.vue.d.ts +3 -0
- package/dist/runtime/app/pages/event.d.vue.ts +14 -1
- package/dist/runtime/app/pages/event.vue +160 -45
- package/dist/runtime/app/pages/event.vue.d.ts +14 -1
- package/dist/runtime/app/pages/events.vue +12 -10
- package/dist/runtime/app/pages/tickets.vue +26 -19
- package/dist/runtime/app/tabs/Attendees.d.vue.ts +7 -0
- package/dist/runtime/app/tabs/Attendees.vue +88 -0
- package/dist/runtime/app/tabs/Attendees.vue.d.ts +7 -0
- package/dist/runtime/app/tabs/Details.d.vue.ts +11 -0
- package/dist/runtime/app/tabs/Details.vue +74 -0
- package/dist/runtime/app/tabs/Details.vue.d.ts +11 -0
- package/dist/runtime/app/tabs/Tickets.d.vue.ts +11 -0
- package/dist/runtime/app/tabs/Tickets.vue +164 -0
- package/dist/runtime/app/tabs/Tickets.vue.d.ts +11 -0
- package/dist/runtime/app/utils/admin-event.d.ts +48 -0
- package/dist/runtime/app/utils/admin-event.js +22 -0
- package/dist/runtime/app/widgets/UpcomingEvents.d.vue.ts +3 -0
- package/dist/runtime/app/widgets/UpcomingEvents.vue +39 -0
- package/dist/runtime/app/widgets/UpcomingEvents.vue.d.ts +3 -0
- package/dist/runtime/app/widgets/UpcomingEventsStat.d.vue.ts +3 -0
- package/dist/runtime/app/widgets/UpcomingEventsStat.vue +17 -0
- package/dist/runtime/app/widgets/UpcomingEventsStat.vue.d.ts +3 -0
- package/dist/runtime/i18n/lang/da.json +33 -0
- package/dist/runtime/i18n/lang/en.json +33 -0
- package/dist/runtime/menus.js +15 -1
- package/dist/runtime/server/db/schema.sqlite.d.ts +62 -5
- package/dist/runtime/server/db/schema.sqlite.js +27 -2
- package/dist/runtime/server/mcp/money.d.ts +24 -0
- package/dist/runtime/server/mcp/money.js +42 -0
- package/dist/runtime/server/mcp/schemas.d.ts +119 -0
- package/dist/runtime/server/mcp/schemas.js +59 -0
- package/dist/runtime/server/mcp/tools/admin/create-event.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/create-event.js +12 -0
- package/dist/runtime/server/mcp/tools/admin/get-event-definition.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/get-event-definition.js +11 -0
- package/dist/runtime/server/mcp/tools/admin/list-all-events.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/list-all-events.js +9 -0
- package/dist/runtime/server/mcp/tools/admin/list-attendees.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/list-attendees.js +26 -0
- package/dist/runtime/server/mcp/tools/admin/update-event.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/update-event.js +10 -0
- package/dist/runtime/server/mcp/tools/admin/update-ticket-type.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/admin/update-ticket-type.js +17 -0
- package/dist/runtime/server/mcp/tools/get-event.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/get-event.js +13 -0
- package/dist/runtime/server/mcp/tools/list-events.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/list-events.js +6 -0
- package/dist/runtime/server/mcp/tools/my-tickets.d.ts +2 -0
- package/dist/runtime/server/mcp/tools/my-tickets.js +7 -0
- package/dist/runtime/server/plugins/staff-scopes.d.ts +2 -0
- package/dist/runtime/server/plugins/staff-scopes.js +1 -0
- package/dist/runtime/server/plugins/subscriptions-membership.d.ts +2 -0
- package/dist/runtime/server/plugins/subscriptions-membership.js +11 -0
- package/dist/runtime/server/routes/admin/event-clone.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/event-clone.post.js +31 -0
- package/dist/runtime/server/routes/admin/event.get.d.ts +2 -0
- package/dist/runtime/server/routes/admin/event.get.js +5 -0
- package/dist/runtime/server/routes/admin/event.patch.js +3 -8
- package/dist/runtime/server/routes/admin/events.post.js +3 -13
- package/dist/runtime/server/routes/admin/membership-options.get.d.ts +2 -0
- package/dist/runtime/server/routes/admin/membership-options.get.js +4 -0
- package/dist/runtime/server/routes/admin/ticket-type.patch.js +3 -8
- package/dist/runtime/server/routes/admin/ticket-types.post.js +2 -1
- package/dist/runtime/server/routes/admin/upcoming.get.d.ts +2 -0
- package/dist/runtime/server/routes/admin/upcoming.get.js +17 -0
- package/dist/runtime/server/routes/public/event.get.js +2 -2
- package/dist/runtime/server/routes/public/purchase.post.js +3 -2
- package/dist/runtime/server/routes/public/ticket-pay.post.js +1 -1
- package/dist/runtime/server/routes/public/ticket.get.js +1 -1
- package/dist/runtime/server/routes/public/tickets-me.get.js +1 -1
- package/dist/runtime/server/utils/admin-schemas.d.ts +102 -20
- package/dist/runtime/server/utils/admin-schemas.js +8 -2
- package/dist/runtime/server/utils/admin.d.ts +82 -1
- package/dist/runtime/server/utils/admin.js +51 -1
- package/dist/runtime/server/utils/auth.d.ts +7 -6
- package/dist/runtime/server/utils/auth.js +4 -4
- package/dist/runtime/server/utils/catalog.d.ts +14 -0
- package/dist/runtime/server/utils/catalog.js +20 -4
- package/dist/runtime/server/utils/membership.d.ts +6 -2
- package/dist/runtime/server/utils/membership.js +15 -2
- package/dist/runtime/server/utils/tickets.js +15 -12
- package/dist/runtime/utils/index.d.ts +17 -7
- package/dist/runtime/utils/index.js +16 -19
- package/dist/types.d.mts +3 -1
- package/package.json +20 -7
package/README.md
CHANGED
package/dist/module.d.mts
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import * as _nuxt_schema from '@nuxt/schema';
|
|
2
2
|
import { H3Event } from 'h3';
|
|
3
|
+
import { Translated } from '@frigear-nu/ui/translated';
|
|
4
|
+
export { Translated } from '@frigear-nu/ui/translated';
|
|
3
5
|
|
|
4
|
-
/** A text that is either one string or a map of locale -> string. */
|
|
5
|
-
type Translated = string | Record<string, string>;
|
|
6
6
|
/** `null` = open to everyone, `'any'` = any active subscription, or a list of plan keys. */
|
|
7
7
|
type MembershipRequirement = 'any' | string[] | null;
|
|
8
8
|
type EventStatus = 'draft' | 'published' | 'archived';
|
|
9
9
|
type TicketStatus = 'pending' | 'paid' | 'cancelled' | 'refunded' | 'expired';
|
|
10
10
|
type ModuleOptions = {
|
|
11
11
|
settings?: {
|
|
12
|
+
mcp?: boolean;
|
|
12
13
|
pages?: {
|
|
13
14
|
/** Event list. `true` = `/events`. */
|
|
14
15
|
events?: string | boolean;
|
|
@@ -16,6 +17,10 @@ type ModuleOptions = {
|
|
|
16
17
|
event?: string | boolean;
|
|
17
18
|
/** The signed-in user's tickets. `true` = `/account/tickets`. */
|
|
18
19
|
tickets?: string | boolean;
|
|
20
|
+
/** Staff event list (needs the `events:authorize` hook to allow staff). `true` = `/admin/events`. Off by default. */
|
|
21
|
+
admin?: string | boolean;
|
|
22
|
+
/** Staff event page (details, ticket types, attendees); must contain an `:id` param. `true` = `/admin/events/:id`. Off by default. */
|
|
23
|
+
adminEvent?: string | boolean;
|
|
19
24
|
};
|
|
20
25
|
/** Minutes an unpaid ticket keeps its seat (the Stripe session expires then). Defaults to `30`. */
|
|
21
26
|
reservationMinutes?: number;
|
|
@@ -23,14 +28,14 @@ type ModuleOptions = {
|
|
|
23
28
|
};
|
|
24
29
|
type EventsRuntimeConfig = {
|
|
25
30
|
reservationMinutes: number;
|
|
26
|
-
/** Whether `@frigear-nu/subscriptions` is installed (membership requirements can be evaluated). */
|
|
27
|
-
membershipEnabled: boolean;
|
|
28
31
|
};
|
|
29
32
|
type PublicModuleOptions = {
|
|
30
33
|
pages: {
|
|
31
34
|
events?: string;
|
|
32
35
|
event?: string;
|
|
33
36
|
tickets?: string;
|
|
37
|
+
admin?: string;
|
|
38
|
+
adminEvent?: string;
|
|
34
39
|
};
|
|
35
40
|
};
|
|
36
41
|
type AddonDto = {
|
|
@@ -57,6 +62,8 @@ type TicketTypeDto = {
|
|
|
57
62
|
hidePrice: boolean;
|
|
58
63
|
isDefault: boolean;
|
|
59
64
|
requiresMembership: MembershipRequirement;
|
|
65
|
+
/** Holders of these plans cannot buy this ticket (`'any'` = any active subscription). */
|
|
66
|
+
excludesMembership: MembershipRequirement;
|
|
60
67
|
/** Seats left, or null when unlimited. */
|
|
61
68
|
remaining: number | null;
|
|
62
69
|
saleStartsAt: string | null;
|
|
@@ -64,7 +71,7 @@ type TicketTypeDto = {
|
|
|
64
71
|
/** `open | not_started | ended | sold_out`. */
|
|
65
72
|
saleState: 'open' | 'not_started' | 'ended' | 'sold_out';
|
|
66
73
|
/** Only set for signed-in users: `null` when allowed, otherwise why not. */
|
|
67
|
-
blocked: 'membership_required' | 'limit_reached' | null;
|
|
74
|
+
blocked: 'membership_required' | 'membership_excluded' | 'limit_reached' | null;
|
|
68
75
|
addonGroups: AddonGroupDto[];
|
|
69
76
|
};
|
|
70
77
|
type EventSummaryDto = {
|
|
@@ -73,7 +80,7 @@ type EventSummaryDto = {
|
|
|
73
80
|
name: Translated;
|
|
74
81
|
description: Translated | null;
|
|
75
82
|
image: string | null;
|
|
76
|
-
location:
|
|
83
|
+
location: Translated | null;
|
|
77
84
|
startsAt: string;
|
|
78
85
|
endsAt: string | null;
|
|
79
86
|
requiresMembership: MembershipRequirement;
|
|
@@ -88,6 +95,8 @@ type PurchaseBody = {
|
|
|
88
95
|
addonIds?: string[];
|
|
89
96
|
successUrl?: string;
|
|
90
97
|
cancelUrl?: string;
|
|
98
|
+
/** The buyer's site language (e.g. `da`), kept on the ticket so later mails and Stripe texts use it. */
|
|
99
|
+
locale?: string;
|
|
91
100
|
};
|
|
92
101
|
type PurchaseResponse = {
|
|
93
102
|
ticket: TicketDto;
|
|
@@ -115,6 +124,8 @@ type TicketDto = {
|
|
|
115
124
|
code: string | null;
|
|
116
125
|
checkedInAt: string | null;
|
|
117
126
|
createdAt: string;
|
|
127
|
+
/** Language the buyer was browsing in when buying, for localised mails; `null` for tickets bought before it was kept. */
|
|
128
|
+
locale: string | null;
|
|
118
129
|
};
|
|
119
130
|
type CheckInResponse = {
|
|
120
131
|
ok: boolean;
|
|
@@ -135,6 +146,26 @@ type AuthorizeContext = {
|
|
|
135
146
|
/** Set `ctx.allowed = true` to let the user manage events / check tickets in. Denied by default. */
|
|
136
147
|
allowed: boolean;
|
|
137
148
|
};
|
|
149
|
+
/** A selectable membership (plan) offered by a membership provider. */
|
|
150
|
+
type MembershipOption = {
|
|
151
|
+
value: string;
|
|
152
|
+
label: string;
|
|
153
|
+
};
|
|
154
|
+
/** Context of the `events:membership:check` hook. */
|
|
155
|
+
type MembershipCheckContext = {
|
|
156
|
+
userId: number;
|
|
157
|
+
/** `'any'` = any active membership, or the plan keys of which the user must hold one. */
|
|
158
|
+
requirement: 'any' | string[];
|
|
159
|
+
/** A provider sets this to `true` when the user holds a matching membership. Defaults to `false`. */
|
|
160
|
+
satisfied: boolean;
|
|
161
|
+
};
|
|
162
|
+
/** Context of the `events:membership:options` hook. */
|
|
163
|
+
type MembershipOptionsContext = {
|
|
164
|
+
/** A provider sets this to `true`: membership rules can then be used on events and tickets. */
|
|
165
|
+
available: boolean;
|
|
166
|
+
/** The memberships staff can pick from. */
|
|
167
|
+
options: MembershipOption[];
|
|
168
|
+
};
|
|
138
169
|
type TicketHookContext = {
|
|
139
170
|
ticket: TicketDto;
|
|
140
171
|
};
|
|
@@ -154,6 +185,13 @@ declare module 'nitropack' {
|
|
|
154
185
|
interface NitroRuntimeHooks {
|
|
155
186
|
/** Staff gate (event management, check-in): set `ctx.allowed = true` to let the user in. Denied by default. */
|
|
156
187
|
'events:authorize': (ctx: AuthorizeContext) => void | Promise<void>;
|
|
188
|
+
/**
|
|
189
|
+
* Membership provider (e.g. `@frigear-nu/subscriptions`): set `ctx.satisfied = true` when the user holds a
|
|
190
|
+
* membership matching `ctx.requirement`. With no provider a requirement can never be met, so it fails closed.
|
|
191
|
+
*/
|
|
192
|
+
'events:membership:check': (ctx: MembershipCheckContext) => void | Promise<void>;
|
|
193
|
+
/** Membership provider: set `ctx.available = true` and add the selectable memberships to `ctx.options`. */
|
|
194
|
+
'events:membership:options': (ctx: MembershipOptionsContext) => void | Promise<void>;
|
|
157
195
|
/** Policy hook: throw to deny a purchase. */
|
|
158
196
|
'events:purchase:before': (ctx: PurchaseBeforeContext) => void | Promise<void>;
|
|
159
197
|
/** A ticket became `paid` (free tickets immediately, paid ones after the Stripe event). Send confirmations here. */
|
|
@@ -165,4 +203,4 @@ declare module 'nitropack' {
|
|
|
165
203
|
declare const _default: _nuxt_schema.NuxtModule<ModuleOptions, ModuleOptions, false>;
|
|
166
204
|
|
|
167
205
|
export { _default as default };
|
|
168
|
-
export type { AddonDto, AddonGroupDto, AuthorizeContext, CheckInResponse, EventDetailDto, EventStatus, EventSummaryDto, EventsRuntimeConfig, MembershipRequirement, ModuleOptions, PublicModuleOptions, PurchaseBeforeContext, PurchaseBody, PurchaseResponse, TicketDto, TicketHookContext, TicketStatus, TicketTypeDto
|
|
206
|
+
export type { AddonDto, AddonGroupDto, AuthorizeContext, CheckInResponse, EventDetailDto, EventStatus, EventSummaryDto, EventsRuntimeConfig, MembershipCheckContext, MembershipOption, MembershipOptionsContext, MembershipRequirement, ModuleOptions, PublicModuleOptions, PurchaseBeforeContext, PurchaseBody, PurchaseResponse, TicketDto, TicketHookContext, TicketStatus, TicketTypeDto };
|
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
import { defineNuxtModule, createResolver, hasNuxtModule,
|
|
2
|
-
import { registerModule, registerLocales, registerDatabaseTable,
|
|
1
|
+
import { defineNuxtModule, createResolver, hasNuxtModule, addServerImportsDir, addServerPlugin, addImports, addComponentsDir, addServerHandler } from '@nuxt/kit';
|
|
2
|
+
import { registerModule, registerTailwindSource, registerLocales, resolvePagePath, registerDatabaseTable, inlineModuleRuntime, addModulePages, addOptionalMenuSource } from '@frigear-nu/module-kit/utils';
|
|
3
|
+
import { adminRoute } from '@frigear-nu/admin/utils';
|
|
4
|
+
import { addAuthScope } from '@frigear-nu/auth/utils';
|
|
5
|
+
import { addMcpDefinitions } from '@frigear-nu/mcp/utils';
|
|
3
6
|
|
|
4
7
|
const MODULE_NAME = "@frigear-nu/events";
|
|
5
|
-
function resolvePagePath(setting, defaultPath) {
|
|
6
|
-
if (typeof setting === "string") return setting;
|
|
7
|
-
if (setting === true) return defaultPath;
|
|
8
|
-
return void 0;
|
|
9
|
-
}
|
|
10
8
|
const module$1 = defineNuxtModule({
|
|
11
9
|
meta: { name: MODULE_NAME, configKey: "events" },
|
|
12
10
|
defaults: {
|
|
@@ -18,44 +16,47 @@ const module$1 = defineNuxtModule({
|
|
|
18
16
|
defaults: { kv: true }
|
|
19
17
|
},
|
|
20
18
|
"@frigear-nu/module-kit": { version: ">=0.0.1" },
|
|
19
|
+
"@frigear-nu/auth": { version: ">=0.0.1" },
|
|
20
|
+
"@frigear-nu/mcp": { version: ">=0.0.1" },
|
|
21
21
|
"@frigear-nu/users": { version: ">=0.0.1" },
|
|
22
|
+
"@frigear-nu/ui": { version: ">=0.0.1" },
|
|
22
23
|
"@frigear-nu/stripe": { version: ">=0.0.1" },
|
|
23
24
|
"@frigear-nu/payments": { version: ">=0.0.1" },
|
|
24
25
|
"@frigear-nu/subscriptions": { version: ">=0.0.1", optional: true },
|
|
25
|
-
"@frigear-nu/menu": { version: ">=0.0.1", optional: true }
|
|
26
|
+
"@frigear-nu/menu": { version: ">=0.0.1", optional: true },
|
|
27
|
+
"@frigear-nu/widget": { version: ">=0.0.0", optional: true },
|
|
28
|
+
// Provides the shared page components of the admin pages (`AdminPage`, `AdminTable`, ...).
|
|
29
|
+
"@frigear-nu/admin": { version: ">=0.0.0", optional: true }
|
|
26
30
|
},
|
|
27
31
|
async setup(options, nuxt) {
|
|
28
32
|
registerModule(MODULE_NAME, nuxt);
|
|
33
|
+
addAuthScope(
|
|
34
|
+
nuxt,
|
|
35
|
+
{ name: "events:manage", description: "Manage events, tickets and check-in (staff)" },
|
|
36
|
+
{ name: "tickets:read", description: "Read your tickets and event details" },
|
|
37
|
+
{ name: "tickets:write", description: "Buy tickets and pay for them" },
|
|
38
|
+
{ name: "events:pii", description: "See attendee names and emails through MCP tools (also needs events:manage)" }
|
|
39
|
+
);
|
|
29
40
|
const resolver = createResolver(import.meta.url);
|
|
41
|
+
registerTailwindSource(nuxt, resolver.resolve("./runtime/app"));
|
|
30
42
|
registerLocales(nuxt, resolver.resolve("./runtime/i18n/lang"));
|
|
31
43
|
const settings = options.settings ?? {};
|
|
32
|
-
const withMenus = hasNuxtModule("@frigear-nu/menu");
|
|
33
|
-
const withMembership = hasNuxtModule("@frigear-nu/subscriptions");
|
|
34
44
|
const eventsPath = resolvePagePath(settings.pages?.events, "/events");
|
|
35
45
|
const eventPath = resolvePagePath(settings.pages?.event, "/events/:slug");
|
|
36
46
|
const ticketsPath = resolvePagePath(settings.pages?.tickets, "/account/tickets");
|
|
47
|
+
const withAdmin = hasNuxtModule("@frigear-nu/admin");
|
|
48
|
+
const adminPath = withAdmin ? resolvePagePath(settings.pages?.admin, adminRoute(nuxt, "events")) : void 0;
|
|
49
|
+
const adminEventPath = withAdmin ? resolvePagePath(settings.pages?.adminEvent, adminRoute(nuxt, "events", ":id")) : void 0;
|
|
37
50
|
nuxt.options.runtimeConfig.events = {
|
|
38
|
-
reservationMinutes: settings.reservationMinutes ?? 30
|
|
39
|
-
membershipEnabled: withMembership
|
|
51
|
+
reservationMinutes: settings.reservationMinutes ?? 30
|
|
40
52
|
};
|
|
41
53
|
nuxt.options.runtimeConfig.public.events = {
|
|
42
|
-
pages: { events: eventsPath, event: eventPath, tickets: ticketsPath }
|
|
54
|
+
pages: { events: eventsPath, event: eventPath, tickets: ticketsPath, admin: adminPath, adminEvent: adminEventPath }
|
|
43
55
|
};
|
|
44
56
|
await registerDatabaseTable(nuxt, {
|
|
45
57
|
resolver,
|
|
46
58
|
schema: (dialect) => `./runtime/server/db/schema.${dialect}`
|
|
47
59
|
});
|
|
48
|
-
addServerTemplate({
|
|
49
|
-
filename: "#events/membership",
|
|
50
|
-
getContents: () => withMembership ? `export { hasActiveSubscription } from '@frigear-nu/subscriptions/utils'` : `export const hasActiveSubscription = async () => false`
|
|
51
|
-
});
|
|
52
|
-
addTypeTemplate({
|
|
53
|
-
filename: "types/events-membership.d.ts",
|
|
54
|
-
getContents: () => `declare module '#events/membership' {
|
|
55
|
-
export function hasActiveSubscription(userId: number, options?: { plans?: string[], statuses?: string[] }): Promise<boolean>
|
|
56
|
-
}
|
|
57
|
-
`
|
|
58
|
-
});
|
|
59
60
|
const route = (method, path, file) => addServerHandler({ route: `/api/events${path}`, method, handler: resolver.resolve(`./runtime/server/routes/${file}`) });
|
|
60
61
|
route("get", "", "public/events.get");
|
|
61
62
|
route("get", "/tickets/me", "public/tickets-me.get");
|
|
@@ -64,10 +65,14 @@ const module$1 = defineNuxtModule({
|
|
|
64
65
|
route("post", "/check-in", "public/check-in.post");
|
|
65
66
|
route("get", "/:slug", "public/event.get");
|
|
66
67
|
route("post", "/:slug/purchase", "public/purchase.post");
|
|
68
|
+
route("get", "/admin/membership-options", "admin/membership-options.get");
|
|
69
|
+
route("get", "/admin/upcoming", "admin/upcoming.get");
|
|
67
70
|
route("get", "/admin/events", "admin/events.get");
|
|
71
|
+
route("get", "/admin/events/:id", "admin/event.get");
|
|
68
72
|
route("post", "/admin/events", "admin/events.post");
|
|
69
73
|
route("patch", "/admin/events/:id", "admin/event.patch");
|
|
70
74
|
route("delete", "/admin/events/:id", "admin/event.delete");
|
|
75
|
+
route("post", "/admin/events/:id/clone", "admin/event-clone.post");
|
|
71
76
|
route("get", "/admin/events/:id/tickets", "admin/attendees.get");
|
|
72
77
|
route("post", "/admin/events/:id/ticket-types", "admin/ticket-types.post");
|
|
73
78
|
route("patch", "/admin/ticket-types/:id", "admin/ticket-type.patch");
|
|
@@ -81,32 +86,45 @@ const module$1 = defineNuxtModule({
|
|
|
81
86
|
route("post", "/admin/tickets/:id/cancel", "admin/ticket-cancel.post");
|
|
82
87
|
route("post", "/admin/tickets/:id/refund", "admin/ticket-refund.post");
|
|
83
88
|
addServerImportsDir(resolver.resolve("./runtime/server/utils"));
|
|
89
|
+
inlineModuleRuntime(nuxt, resolver);
|
|
90
|
+
if (settings.mcp === true) addMcpDefinitions(nuxt, resolver.resolve("./runtime/server/mcp"));
|
|
84
91
|
addServerPlugin(resolver.resolve("./runtime/server/plugins/payment-hooks"));
|
|
92
|
+
addServerPlugin(resolver.resolve("./runtime/server/plugins/staff-scopes"));
|
|
93
|
+
nuxt.hook("modules:done", () => {
|
|
94
|
+
if (hasNuxtModule("@frigear-nu/subscriptions", nuxt)) {
|
|
95
|
+
addServerPlugin(resolver.resolve("./runtime/server/plugins/subscriptions-membership"));
|
|
96
|
+
}
|
|
97
|
+
});
|
|
85
98
|
addImports([
|
|
86
99
|
{ name: "useEvents", from: resolver.resolve("./runtime/app/composables/useEvents") },
|
|
87
100
|
{ name: "useEvent", from: resolver.resolve("./runtime/app/composables/useEvents") },
|
|
88
101
|
{ name: "useMyTickets", from: resolver.resolve("./runtime/app/composables/useEvents") },
|
|
89
|
-
{ name: "useEventsLocale", from: resolver.resolve("./runtime/app/composables/useEvents") }
|
|
102
|
+
{ name: "useEventsLocale", from: resolver.resolve("./runtime/app/composables/useEvents") },
|
|
103
|
+
{ name: "useEventsFallbackLocale", from: resolver.resolve("./runtime/app/composables/useEvents") },
|
|
104
|
+
{ name: "useEventsTranslate", from: resolver.resolve("./runtime/app/composables/useEvents") }
|
|
90
105
|
]);
|
|
91
106
|
addComponentsDir({ path: resolver.resolve("./runtime/app/components") });
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
|
|
107
|
+
addModulePages(MODULE_NAME, resolver, [
|
|
108
|
+
{ name: "events-list", path: eventsPath, file: "./runtime/app/pages/events.vue" },
|
|
109
|
+
{ name: "events-detail", path: eventPath, file: "./runtime/app/pages/event.vue" },
|
|
110
|
+
{ name: "events-admin", path: adminPath, file: "./runtime/app/pages/admin.vue" },
|
|
111
|
+
{ name: "events-admin-event", path: adminEventPath, file: "./runtime/app/pages/admin-event.vue" },
|
|
112
|
+
{ name: "events-tickets", path: ticketsPath, file: "./runtime/app/pages/tickets.vue" }
|
|
113
|
+
]);
|
|
114
|
+
if (adminEventPath && hasNuxtModule("@frigear-nu/widget")) {
|
|
115
|
+
const { extendTabs } = await import('@frigear-nu/widget/utils');
|
|
116
|
+
extendTabs(nuxt, "admin.events", [
|
|
117
|
+
{ id: "details", component: resolver.resolve("./runtime/app/tabs/Details.vue"), order: 0, label: "Details", labelKey: "events.admin.tabs.details", icon: "i-lucide-file-text" },
|
|
118
|
+
{ id: "tickets", component: resolver.resolve("./runtime/app/tabs/Tickets.vue"), order: 10, label: "Tickets", labelKey: "events.admin.tabs.tickets", icon: "i-lucide-ticket" },
|
|
119
|
+
{ id: "attendees", component: resolver.resolve("./runtime/app/tabs/Attendees.vue"), order: 20, label: "Attendees", labelKey: "events.admin.tabs.attendees", icon: "i-lucide-users" }
|
|
120
|
+
]);
|
|
105
121
|
}
|
|
106
|
-
if (
|
|
107
|
-
const {
|
|
108
|
-
|
|
122
|
+
if (adminPath && hasNuxtModule("@frigear-nu/widget")) {
|
|
123
|
+
const { extendWidgets } = await import('@frigear-nu/widget/utils');
|
|
124
|
+
extendWidgets(nuxt, "admin.dashboard.top", { id: "events-upcoming-stat", component: resolver.resolve("./runtime/app/widgets/UpcomingEventsStat.vue"), order: 20 });
|
|
125
|
+
extendWidgets(nuxt, "admin.dashboard.side", { id: "events-upcoming", component: resolver.resolve("./runtime/app/widgets/UpcomingEvents.vue"), order: 10 });
|
|
109
126
|
}
|
|
127
|
+
addOptionalMenuSource(nuxt, { file: resolver.resolve("./runtime/menus"), menu: "dashboard.account" });
|
|
110
128
|
}
|
|
111
129
|
});
|
|
112
130
|
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AdminAddon, type AdminAddonGroup } from '../utils/admin-event.js';
|
|
2
|
+
declare function open(addonGroup: AdminAddonGroup, currency: string, existing?: AdminAddon): void;
|
|
3
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {
|
|
4
|
+
open: typeof open;
|
|
5
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
refresh: () => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onRefresh?: (() => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: typeof __VLS_export;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { fromCents, toCents } from "@frigear-nu/ui/money";
|
|
3
|
+
import { DEFAULT_CURRENCY } from "../../utils";
|
|
4
|
+
import { useAdminAction } from "../utils/admin-event";
|
|
5
|
+
defineOptions({ name: "EventAdminAddonDialog" });
|
|
6
|
+
const emit = defineEmits(["refresh"]);
|
|
7
|
+
const t = useModuleT("events");
|
|
8
|
+
const tr = useEventsTranslate();
|
|
9
|
+
const { busy, run } = useAdminAction();
|
|
10
|
+
const dialog = ref(false);
|
|
11
|
+
const groupId = ref("");
|
|
12
|
+
const editingAddon = ref(null);
|
|
13
|
+
const addon = reactive({ label: void 0, description: void 0, price: 0, capacity: "" });
|
|
14
|
+
const addonCurrency = ref(DEFAULT_CURRENCY);
|
|
15
|
+
function open(addonGroup, currency, existing) {
|
|
16
|
+
groupId.value = addonGroup.id;
|
|
17
|
+
addonCurrency.value = currency;
|
|
18
|
+
editingAddon.value = existing ?? null;
|
|
19
|
+
Object.assign(addon, {
|
|
20
|
+
label: existing?.label,
|
|
21
|
+
description: existing?.description ?? void 0,
|
|
22
|
+
price: existing ? fromCents(existing.price, currency) : 0,
|
|
23
|
+
capacity: existing?.capacity ?? ""
|
|
24
|
+
});
|
|
25
|
+
dialog.value = true;
|
|
26
|
+
}
|
|
27
|
+
defineExpose({ open });
|
|
28
|
+
const save = () => run(async () => {
|
|
29
|
+
const body = {
|
|
30
|
+
label: addon.label,
|
|
31
|
+
description: addon.description ?? null,
|
|
32
|
+
// Prices are stored in minor units (øre/cents).
|
|
33
|
+
price: toCents(Number(addon.price), addonCurrency.value),
|
|
34
|
+
capacity: addon.capacity === "" ? null : Number(addon.capacity)
|
|
35
|
+
};
|
|
36
|
+
if (editingAddon.value) {
|
|
37
|
+
await $fetch(`/api/events/admin/addons/${editingAddon.value.id}`, { method: "PATCH", body });
|
|
38
|
+
} else {
|
|
39
|
+
await $fetch(`/api/events/admin/addon-groups/${groupId.value}/addons`, { method: "POST", body });
|
|
40
|
+
}
|
|
41
|
+
dialog.value = false;
|
|
42
|
+
emit("refresh");
|
|
43
|
+
}, t("admin.addonSaved", "Add-on saved."));
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<UModal
|
|
48
|
+
v-model:open="dialog"
|
|
49
|
+
:title="editingAddon ? t('admin.editAddon', 'Edit choice') : t('admin.addAddon', 'Add choice')"
|
|
50
|
+
>
|
|
51
|
+
<template #body>
|
|
52
|
+
<form
|
|
53
|
+
id="admin-addon-form"
|
|
54
|
+
class="flex flex-col gap-4"
|
|
55
|
+
@submit.prevent="save"
|
|
56
|
+
>
|
|
57
|
+
<UFormField :label="t('admin.name', 'Name')">
|
|
58
|
+
<TranslatedInput
|
|
59
|
+
v-model="addon.label"
|
|
60
|
+
required
|
|
61
|
+
/>
|
|
62
|
+
</UFormField>
|
|
63
|
+
<UFormField :label="t('admin.description', 'Description')">
|
|
64
|
+
<TranslatedInput
|
|
65
|
+
v-model="addon.description"
|
|
66
|
+
multiline
|
|
67
|
+
:rows="2"
|
|
68
|
+
/>
|
|
69
|
+
</UFormField>
|
|
70
|
+
<UFormField
|
|
71
|
+
:label="t('admin.price', 'Price')"
|
|
72
|
+
:description="t('admin.addonPriceHelp', 'Added to the ticket price. 0 means included.')"
|
|
73
|
+
>
|
|
74
|
+
<UInput
|
|
75
|
+
v-model="addon.price"
|
|
76
|
+
type="number"
|
|
77
|
+
min="0"
|
|
78
|
+
step="0.01"
|
|
79
|
+
class="w-full"
|
|
80
|
+
/>
|
|
81
|
+
</UFormField>
|
|
82
|
+
<UFormField
|
|
83
|
+
:label="t('admin.capacity', 'Capacity')"
|
|
84
|
+
:description="t('admin.capacityHelp', 'Leave empty for unlimited.')"
|
|
85
|
+
>
|
|
86
|
+
<UInput
|
|
87
|
+
v-model="addon.capacity"
|
|
88
|
+
type="number"
|
|
89
|
+
min="0"
|
|
90
|
+
class="w-full"
|
|
91
|
+
/>
|
|
92
|
+
</UFormField>
|
|
93
|
+
</form>
|
|
94
|
+
</template>
|
|
95
|
+
<template #footer>
|
|
96
|
+
<div class="flex w-full justify-end gap-2">
|
|
97
|
+
<UButton
|
|
98
|
+
variant="subtle"
|
|
99
|
+
color="neutral"
|
|
100
|
+
:label="t('admin.cancel', 'Cancel')"
|
|
101
|
+
@click="dialog = false"
|
|
102
|
+
/>
|
|
103
|
+
<UButton
|
|
104
|
+
type="submit"
|
|
105
|
+
form="admin-addon-form"
|
|
106
|
+
:loading="busy"
|
|
107
|
+
:disabled="!tr(addon.label)"
|
|
108
|
+
:label="t('admin.save', 'Save')"
|
|
109
|
+
/>
|
|
110
|
+
</div>
|
|
111
|
+
</template>
|
|
112
|
+
</UModal>
|
|
113
|
+
</template>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AdminAddon, type AdminAddonGroup } from '../utils/admin-event.js';
|
|
2
|
+
declare function open(addonGroup: AdminAddonGroup, currency: string, existing?: AdminAddon): void;
|
|
3
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {
|
|
4
|
+
open: typeof open;
|
|
5
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
refresh: () => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onRefresh?: (() => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: typeof __VLS_export;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AdminAddonGroup, type AdminTicketType } from '../utils/admin-event.js';
|
|
2
|
+
declare function open(ticketType: AdminTicketType, existing?: AdminAddonGroup): void;
|
|
3
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {
|
|
4
|
+
open: typeof open;
|
|
5
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
refresh: () => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onRefresh?: (() => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: typeof __VLS_export;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { useAdminAction } from "../utils/admin-event";
|
|
3
|
+
defineOptions({ name: "EventAdminAddonGroupDialog" });
|
|
4
|
+
const emit = defineEmits(["refresh"]);
|
|
5
|
+
const t = useModuleT("events");
|
|
6
|
+
const tr = useEventsTranslate();
|
|
7
|
+
const { busy, run } = useAdminAction();
|
|
8
|
+
const dialog = ref(false);
|
|
9
|
+
const ticketTypeId = ref("");
|
|
10
|
+
const editingGroup = ref(null);
|
|
11
|
+
const group = reactive({ title: void 0, required: false, multiple: false });
|
|
12
|
+
function open(ticketType, existing) {
|
|
13
|
+
ticketTypeId.value = ticketType.id;
|
|
14
|
+
editingGroup.value = existing ?? null;
|
|
15
|
+
Object.assign(group, { title: existing?.title, required: existing?.required ?? false, multiple: existing?.multiple ?? false });
|
|
16
|
+
dialog.value = true;
|
|
17
|
+
}
|
|
18
|
+
defineExpose({ open });
|
|
19
|
+
const save = () => run(async () => {
|
|
20
|
+
const body = { title: group.title, required: group.required, multiple: group.multiple };
|
|
21
|
+
if (editingGroup.value) {
|
|
22
|
+
await $fetch(`/api/events/admin/addon-groups/${editingGroup.value.id}`, { method: "PATCH", body });
|
|
23
|
+
} else {
|
|
24
|
+
await $fetch(`/api/events/admin/ticket-types/${ticketTypeId.value}/addon-groups`, { method: "POST", body });
|
|
25
|
+
}
|
|
26
|
+
dialog.value = false;
|
|
27
|
+
emit("refresh");
|
|
28
|
+
}, t("admin.groupSaved", "Add-on group saved."));
|
|
29
|
+
</script>
|
|
30
|
+
|
|
31
|
+
<template>
|
|
32
|
+
<UModal
|
|
33
|
+
v-model:open="dialog"
|
|
34
|
+
:title="editingGroup ? t('admin.editGroup', 'Edit add-on group') : t('admin.addGroup', 'Add add-on group')"
|
|
35
|
+
>
|
|
36
|
+
<template #body>
|
|
37
|
+
<form
|
|
38
|
+
id="admin-addon-group-form"
|
|
39
|
+
class="flex flex-col gap-4"
|
|
40
|
+
@submit.prevent="save"
|
|
41
|
+
>
|
|
42
|
+
<UFormField
|
|
43
|
+
:label="t('admin.groupTitle', 'Title')"
|
|
44
|
+
:description="t('admin.groupTitleHelp', 'Shown above the choices, e.g. Food.')"
|
|
45
|
+
>
|
|
46
|
+
<TranslatedInput
|
|
47
|
+
v-model="group.title"
|
|
48
|
+
required
|
|
49
|
+
/>
|
|
50
|
+
</UFormField>
|
|
51
|
+
<UCheckbox
|
|
52
|
+
v-model="group.required"
|
|
53
|
+
:label="t('admin.groupRequiredLabel', 'Buyers must choose at least one')"
|
|
54
|
+
/>
|
|
55
|
+
<UCheckbox
|
|
56
|
+
v-model="group.multiple"
|
|
57
|
+
:label="t('admin.groupMultipleLabel', 'Buyers can choose several')"
|
|
58
|
+
/>
|
|
59
|
+
</form>
|
|
60
|
+
</template>
|
|
61
|
+
<template #footer>
|
|
62
|
+
<div class="flex w-full justify-end gap-2">
|
|
63
|
+
<UButton
|
|
64
|
+
variant="subtle"
|
|
65
|
+
color="neutral"
|
|
66
|
+
:label="t('admin.cancel', 'Cancel')"
|
|
67
|
+
@click="dialog = false"
|
|
68
|
+
/>
|
|
69
|
+
<UButton
|
|
70
|
+
type="submit"
|
|
71
|
+
form="admin-addon-group-form"
|
|
72
|
+
:loading="busy"
|
|
73
|
+
:disabled="!tr(group.title)"
|
|
74
|
+
:label="t('admin.save', 'Save')"
|
|
75
|
+
/>
|
|
76
|
+
</div>
|
|
77
|
+
</template>
|
|
78
|
+
</UModal>
|
|
79
|
+
</template>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type AdminAddonGroup, type AdminTicketType } from '../utils/admin-event.js';
|
|
2
|
+
declare function open(ticketType: AdminTicketType, existing?: AdminAddonGroup): void;
|
|
3
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {
|
|
4
|
+
open: typeof open;
|
|
5
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
refresh: () => any;
|
|
7
|
+
}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{
|
|
8
|
+
onRefresh?: (() => any) | undefined;
|
|
9
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
10
|
+
declare const _default: typeof __VLS_export;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type AdminAddon, type AdminAddonGroup, type AdminTicketType } from '../utils/admin-event.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
ticketType: AdminTicketType;
|
|
4
|
+
};
|
|
5
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
6
|
+
refresh: () => any;
|
|
7
|
+
addGroup: () => any;
|
|
8
|
+
editGroup: (group: AdminAddonGroup) => any;
|
|
9
|
+
addAddon: (group: AdminAddonGroup) => any;
|
|
10
|
+
editAddon: (group: AdminAddonGroup, addon: AdminAddon) => any;
|
|
11
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
12
|
+
onRefresh?: (() => any) | undefined;
|
|
13
|
+
onAddGroup?: (() => any) | undefined;
|
|
14
|
+
onEditGroup?: ((group: AdminAddonGroup) => any) | undefined;
|
|
15
|
+
onAddAddon?: ((group: AdminAddonGroup) => any) | undefined;
|
|
16
|
+
onEditAddon?: ((group: AdminAddonGroup, addon: AdminAddon) => any) | undefined;
|
|
17
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
18
|
+
declare const _default: typeof __VLS_export;
|
|
19
|
+
export default _default;
|