@frigear-nu/events 0.0.0-stage → 0.0.3
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 +35 -2
- package/dist/module.d.mts +168 -0
- package/dist/module.json +9 -0
- package/dist/module.mjs +113 -0
- package/dist/runtime/app/components/EventCard.d.vue.ts +8 -0
- package/dist/runtime/app/components/EventCard.vue +52 -0
- package/dist/runtime/app/components/EventCard.vue.d.ts +8 -0
- package/dist/runtime/app/components/EventTicketCard.d.vue.ts +12 -0
- package/dist/runtime/app/components/EventTicketCard.vue +82 -0
- package/dist/runtime/app/components/EventTicketCard.vue.d.ts +12 -0
- package/dist/runtime/app/components/EventTicketPicker.d.vue.ts +13 -0
- package/dist/runtime/app/components/EventTicketPicker.vue +133 -0
- package/dist/runtime/app/components/EventTicketPicker.vue.d.ts +13 -0
- package/dist/runtime/app/composables/index.d.ts +1 -0
- package/dist/runtime/app/composables/index.js +1 -0
- package/dist/runtime/app/composables/useEvents.d.ts +21 -0
- package/dist/runtime/app/composables/useEvents.js +50 -0
- package/dist/runtime/app/pages/event.d.vue.ts +3 -0
- package/dist/runtime/app/pages/event.vue +135 -0
- package/dist/runtime/app/pages/event.vue.d.ts +3 -0
- package/dist/runtime/app/pages/events.d.vue.ts +3 -0
- package/dist/runtime/app/pages/events.vue +43 -0
- package/dist/runtime/app/pages/events.vue.d.ts +3 -0
- package/dist/runtime/app/pages/tickets.d.vue.ts +3 -0
- package/dist/runtime/app/pages/tickets.vue +30 -0
- package/dist/runtime/app/pages/tickets.vue.d.ts +3 -0
- package/dist/runtime/i18n/lang/da.json +87 -0
- package/dist/runtime/i18n/lang/en.json +87 -0
- package/dist/runtime/menus.d.ts +2 -0
- package/dist/runtime/menus.js +14 -0
- package/dist/runtime/server/db/schema.sqlite.d.ts +1095 -0
- package/dist/runtime/server/db/schema.sqlite.js +100 -0
- package/dist/runtime/server/plugins/payment-hooks.d.ts +2 -0
- package/dist/runtime/server/plugins/payment-hooks.js +34 -0
- package/dist/runtime/server/routes/admin/addon-group.delete.d.ts +2 -0
- package/dist/runtime/server/routes/admin/addon-group.delete.js +7 -0
- package/dist/runtime/server/routes/admin/addon-group.patch.d.ts +2 -0
- package/dist/runtime/server/routes/admin/addon-group.patch.js +11 -0
- package/dist/runtime/server/routes/admin/addon-groups.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/addon-groups.post.js +11 -0
- package/dist/runtime/server/routes/admin/addon.delete.d.ts +2 -0
- package/dist/runtime/server/routes/admin/addon.delete.js +7 -0
- package/dist/runtime/server/routes/admin/addon.patch.d.ts +2 -0
- package/dist/runtime/server/routes/admin/addon.patch.js +10 -0
- package/dist/runtime/server/routes/admin/addons.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/addons.post.js +12 -0
- package/dist/runtime/server/routes/admin/attendees.get.d.ts +2 -0
- package/dist/runtime/server/routes/admin/attendees.get.js +11 -0
- package/dist/runtime/server/routes/admin/event.delete.d.ts +2 -0
- package/dist/runtime/server/routes/admin/event.delete.js +10 -0
- package/dist/runtime/server/routes/admin/event.patch.d.ts +2 -0
- package/dist/runtime/server/routes/admin/event.patch.js +11 -0
- package/dist/runtime/server/routes/admin/events.get.d.ts +2 -0
- package/dist/runtime/server/routes/admin/events.get.js +6 -0
- package/dist/runtime/server/routes/admin/events.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/events.post.js +19 -0
- package/dist/runtime/server/routes/admin/ticket-cancel.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/ticket-cancel.post.js +14 -0
- package/dist/runtime/server/routes/admin/ticket-refund.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/ticket-refund.post.js +10 -0
- package/dist/runtime/server/routes/admin/ticket-type.delete.d.ts +2 -0
- package/dist/runtime/server/routes/admin/ticket-type.delete.js +10 -0
- package/dist/runtime/server/routes/admin/ticket-type.patch.d.ts +2 -0
- package/dist/runtime/server/routes/admin/ticket-type.patch.js +11 -0
- package/dist/runtime/server/routes/admin/ticket-types.post.d.ts +2 -0
- package/dist/runtime/server/routes/admin/ticket-types.post.js +11 -0
- package/dist/runtime/server/routes/public/check-in.post.d.ts +2 -0
- package/dist/runtime/server/routes/public/check-in.post.js +15 -0
- package/dist/runtime/server/routes/public/event.get.d.ts +2 -0
- package/dist/runtime/server/routes/public/event.get.js +7 -0
- package/dist/runtime/server/routes/public/events.get.d.ts +2 -0
- package/dist/runtime/server/routes/public/events.get.js +1 -0
- package/dist/runtime/server/routes/public/purchase.post.d.ts +2 -0
- package/dist/runtime/server/routes/public/purchase.post.js +12 -0
- package/dist/runtime/server/routes/public/ticket-pay.post.d.ts +2 -0
- package/dist/runtime/server/routes/public/ticket-pay.post.js +10 -0
- package/dist/runtime/server/routes/public/ticket.get.d.ts +2 -0
- package/dist/runtime/server/routes/public/ticket.get.js +4 -0
- package/dist/runtime/server/routes/public/tickets-me.get.d.ts +2 -0
- package/dist/runtime/server/routes/public/tickets-me.get.js +4 -0
- package/dist/runtime/server/utils/admin-schemas.d.ts +96 -0
- package/dist/runtime/server/utils/admin-schemas.js +48 -0
- package/dist/runtime/server/utils/admin.d.ts +7 -0
- package/dist/runtime/server/utils/admin.js +24 -0
- package/dist/runtime/server/utils/auth.d.ts +10 -0
- package/dist/runtime/server/utils/auth.js +7 -0
- package/dist/runtime/server/utils/catalog.d.ts +25 -0
- package/dist/runtime/server/utils/catalog.js +129 -0
- package/dist/runtime/server/utils/membership.d.ts +3 -0
- package/dist/runtime/server/utils/membership.js +5 -0
- package/dist/runtime/server/utils/tickets.d.ts +10 -0
- package/dist/runtime/server/utils/tickets.js +122 -0
- package/dist/runtime/utils/index.d.ts +14 -0
- package/dist/runtime/utils/index.js +30 -0
- package/dist/types.d.mts +3 -0
- package/package.json +91 -3
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { TicketTypeDto } from '../../../types.js';
|
|
2
|
+
type __VLS_Props = {
|
|
3
|
+
ticketTypes: TicketTypeDto[];
|
|
4
|
+
loggedIn: boolean;
|
|
5
|
+
loading?: boolean;
|
|
6
|
+
};
|
|
7
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
8
|
+
purchase: (ticketTypeId: string, addonIds: string[]) => any;
|
|
9
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
+
onPurchase?: ((ticketTypeId: string, addonIds: string[]) => any) | undefined;
|
|
11
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
12
|
+
declare const _default: typeof __VLS_export;
|
|
13
|
+
export default _default;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useEvents, useEvent, useMyTickets, useEventsLocale } from './useEvents.js';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useEvents, useEvent, useMyTickets, useEventsLocale } from "./useEvents.js";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare function useEvents(): {
|
|
2
|
+
events: any;
|
|
3
|
+
grouped: any;
|
|
4
|
+
status: any;
|
|
5
|
+
refresh: any;
|
|
6
|
+
};
|
|
7
|
+
export declare function useEvent(slug: MaybeRefOrGetter<string>): {
|
|
8
|
+
event: any;
|
|
9
|
+
status: any;
|
|
10
|
+
error: any;
|
|
11
|
+
refresh: any;
|
|
12
|
+
purchase: (ticketTypeId: string, addonIds?: string[]) => Promise<any>;
|
|
13
|
+
};
|
|
14
|
+
export declare function useMyTickets(): {
|
|
15
|
+
tickets: any;
|
|
16
|
+
status: any;
|
|
17
|
+
refresh: any;
|
|
18
|
+
pay: (ticketId: string) => Promise<void>;
|
|
19
|
+
};
|
|
20
|
+
/** Locale for translated texts: `@nuxtjs/i18n`'s when installed, otherwise `en`. */
|
|
21
|
+
export declare function useEventsLocale(): any;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
export function useEvents() {
|
|
2
|
+
const { data, status, refresh } = useFetch("/api/events", { key: "events:list", default: () => [] });
|
|
3
|
+
const grouped = computed(() => {
|
|
4
|
+
const now = Date.now();
|
|
5
|
+
const start = (e) => new Date(e.startsAt).getTime();
|
|
6
|
+
const end = (e) => e.endsAt ? new Date(e.endsAt).getTime() : start(e) + 24 * 36e5;
|
|
7
|
+
return {
|
|
8
|
+
ongoing: data.value.filter((e) => start(e) <= now && now < end(e)),
|
|
9
|
+
upcoming: data.value.filter((e) => start(e) > now),
|
|
10
|
+
past: data.value.filter((e) => end(e) <= now).reverse()
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
return { events: data, grouped, status, refresh };
|
|
14
|
+
}
|
|
15
|
+
export function useEvent(slug) {
|
|
16
|
+
const { loggedIn } = useUserSession();
|
|
17
|
+
const { data, status, error, refresh } = useFetch(() => `/api/events/${toValue(slug)}`, {
|
|
18
|
+
key: `events:detail:${toValue(slug)}`,
|
|
19
|
+
// Eligibility (membership, limits) depends on the session.
|
|
20
|
+
watch: [loggedIn]
|
|
21
|
+
});
|
|
22
|
+
async function purchase(ticketTypeId, addonIds = []) {
|
|
23
|
+
const result = await $fetch(`/api/events/${toValue(slug)}/purchase`, {
|
|
24
|
+
method: "POST",
|
|
25
|
+
body: { ticketTypeId, addonIds }
|
|
26
|
+
});
|
|
27
|
+
if (result.url) await navigateTo(result.url, { external: true });
|
|
28
|
+
else await refresh();
|
|
29
|
+
return result;
|
|
30
|
+
}
|
|
31
|
+
return { event: data, status, error, refresh, purchase };
|
|
32
|
+
}
|
|
33
|
+
export function useMyTickets() {
|
|
34
|
+
const { loggedIn } = useUserSession();
|
|
35
|
+
const { data, status, refresh } = useFetch("/api/events/tickets/me", {
|
|
36
|
+
key: "events:tickets:mine",
|
|
37
|
+
immediate: loggedIn.value,
|
|
38
|
+
watch: false,
|
|
39
|
+
default: () => []
|
|
40
|
+
});
|
|
41
|
+
async function pay(ticketId) {
|
|
42
|
+
const { url } = await $fetch(`/api/events/tickets/${ticketId}/pay`, { method: "POST" });
|
|
43
|
+
await navigateTo(url, { external: true });
|
|
44
|
+
}
|
|
45
|
+
return { tickets: data, status, refresh, pay };
|
|
46
|
+
}
|
|
47
|
+
export function useEventsLocale() {
|
|
48
|
+
const nuxtApp = useNuxtApp();
|
|
49
|
+
return computed(() => nuxtApp.$i18n?.locale?.value ?? "en");
|
|
50
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { translate } from "../../utils";
|
|
3
|
+
const t = useModuleT("events");
|
|
4
|
+
const route = useRoute();
|
|
5
|
+
const slug = computed(() => String(route.params.slug));
|
|
6
|
+
const { loggedIn } = useUserSession();
|
|
7
|
+
const { event, status, error, purchase, refresh } = useEvent(slug);
|
|
8
|
+
const locale = useEventsLocale();
|
|
9
|
+
const toast = useToast();
|
|
10
|
+
if (error.value?.statusCode === 404) {
|
|
11
|
+
throw createError({ statusCode: 404, statusMessage: t("notFound", "Event not found"), fatal: true });
|
|
12
|
+
}
|
|
13
|
+
const buying = ref(false);
|
|
14
|
+
async function onPurchase(ticketTypeId, addonIds) {
|
|
15
|
+
buying.value = true;
|
|
16
|
+
try {
|
|
17
|
+
const result = await purchase(ticketTypeId, addonIds);
|
|
18
|
+
if (!result.url) toast.add({ title: t("ticketReady", "Your ticket is ready"), color: "success" });
|
|
19
|
+
} catch (e) {
|
|
20
|
+
toast.add({ title: e.statusMessage ?? t("purchaseFailed", "Could not buy the ticket"), color: "error" });
|
|
21
|
+
} finally {
|
|
22
|
+
buying.value = false;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
const payment = computed(() => route.query.payment);
|
|
26
|
+
const returnedTicket = computed(() => route.query.ticket);
|
|
27
|
+
const paidState = ref(null);
|
|
28
|
+
onMounted(async () => {
|
|
29
|
+
if (payment.value !== "success" || !returnedTicket.value) return;
|
|
30
|
+
paidState.value = "waiting";
|
|
31
|
+
for (let attempt = 0; attempt < 20; attempt++) {
|
|
32
|
+
const ticket = await $fetch(`/api/events/tickets/${returnedTicket.value}`).catch(() => null);
|
|
33
|
+
if (ticket?.status === "paid") {
|
|
34
|
+
paidState.value = "paid";
|
|
35
|
+
await refresh();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
await new Promise((resolve) => setTimeout(resolve, 1500));
|
|
39
|
+
}
|
|
40
|
+
paidState.value = "timeout";
|
|
41
|
+
});
|
|
42
|
+
const ticketsPath = useRuntimeConfig().public.events?.pages?.tickets;
|
|
43
|
+
useSeoMeta({ title: () => event.value ? translate(event.value.name, locale.value) : "Event" });
|
|
44
|
+
defineOptions({ name: "EventDetailPage" });
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<template>
|
|
48
|
+
<UContainer class="py-10">
|
|
49
|
+
<template v-if="event">
|
|
50
|
+
<UAlert
|
|
51
|
+
v-if="paidState === 'waiting'"
|
|
52
|
+
class="mb-6"
|
|
53
|
+
color="info"
|
|
54
|
+
variant="subtle"
|
|
55
|
+
:title="t('detail.tickets.payment.verifying.description', 'Confirming your payment\u2026')"
|
|
56
|
+
/>
|
|
57
|
+
<UAlert
|
|
58
|
+
v-else-if="paidState === 'paid'"
|
|
59
|
+
class="mb-6"
|
|
60
|
+
color="success"
|
|
61
|
+
variant="subtle"
|
|
62
|
+
:title="t('paymentReceived', 'Payment received - your ticket is ready.')"
|
|
63
|
+
>
|
|
64
|
+
<template
|
|
65
|
+
v-if="ticketsPath"
|
|
66
|
+
#actions
|
|
67
|
+
>
|
|
68
|
+
<UButton
|
|
69
|
+
:to="ticketsPath"
|
|
70
|
+
size="xs"
|
|
71
|
+
>
|
|
72
|
+
{{ t("detail.tickets.view", "View ticket") }}
|
|
73
|
+
</UButton>
|
|
74
|
+
</template>
|
|
75
|
+
</UAlert>
|
|
76
|
+
<UAlert
|
|
77
|
+
v-else-if="paidState === 'timeout'"
|
|
78
|
+
class="mb-6"
|
|
79
|
+
color="warning"
|
|
80
|
+
variant="subtle"
|
|
81
|
+
:title="t('paymentTimeout', 'We have not received the payment confirmation yet. It will show up under your tickets shortly.')"
|
|
82
|
+
/>
|
|
83
|
+
<UAlert
|
|
84
|
+
v-else-if="payment === 'cancel'"
|
|
85
|
+
class="mb-6"
|
|
86
|
+
color="neutral"
|
|
87
|
+
variant="subtle"
|
|
88
|
+
:title="t('paymentCancelled', 'Payment cancelled. Your reservation is held for a short while; you can pay from your tickets.')"
|
|
89
|
+
/>
|
|
90
|
+
|
|
91
|
+
<img
|
|
92
|
+
v-if="event.image"
|
|
93
|
+
:src="event.image"
|
|
94
|
+
:alt="translate(event.name, locale)"
|
|
95
|
+
class="mb-6 aspect-[3/1] w-full rounded-lg object-cover"
|
|
96
|
+
>
|
|
97
|
+
<h1 class="text-3xl font-semibold">
|
|
98
|
+
{{ translate(event.name, locale) }}
|
|
99
|
+
</h1>
|
|
100
|
+
<p class="mt-2 text-muted">
|
|
101
|
+
{{ new Intl.DateTimeFormat(locale, { dateStyle: "full", timeStyle: "short" }).format(new Date(event.startsAt)) }}
|
|
102
|
+
<template v-if="event.location">
|
|
103
|
+
· <a
|
|
104
|
+
v-if="event.locationUrl"
|
|
105
|
+
:href="event.locationUrl"
|
|
106
|
+
target="_blank"
|
|
107
|
+
rel="noopener"
|
|
108
|
+
class="underline"
|
|
109
|
+
>{{ event.location }}</a><template v-else>
|
|
110
|
+
{{ event.location }}
|
|
111
|
+
</template>
|
|
112
|
+
</template>
|
|
113
|
+
</p>
|
|
114
|
+
|
|
115
|
+
<div class="mt-8 grid gap-8 md:grid-cols-[1fr_24rem]">
|
|
116
|
+
<!-- Plain text body: markdown rendering is left to the host (e.g. via a typography module). -->
|
|
117
|
+
<div class="whitespace-pre-line">
|
|
118
|
+
{{ translate(event.body ?? event.description, locale) }}
|
|
119
|
+
</div>
|
|
120
|
+
<EventTicketPicker
|
|
121
|
+
:ticket-types="event.ticketTypes"
|
|
122
|
+
:logged-in="loggedIn"
|
|
123
|
+
:loading="buying"
|
|
124
|
+
@purchase="onPurchase"
|
|
125
|
+
/>
|
|
126
|
+
</div>
|
|
127
|
+
</template>
|
|
128
|
+
<p
|
|
129
|
+
v-else-if="status === 'pending'"
|
|
130
|
+
class="text-muted"
|
|
131
|
+
>
|
|
132
|
+
{{ t("loading", "Loading\u2026") }}
|
|
133
|
+
</p>
|
|
134
|
+
</UContainer>
|
|
135
|
+
</template>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const t = useModuleT("events");
|
|
3
|
+
const { grouped, status } = useEvents();
|
|
4
|
+
const pages = useRuntimeConfig().public.events?.pages;
|
|
5
|
+
const eventTo = (slug) => (pages?.event || "/events/:slug").replace(":slug", encodeURIComponent(slug));
|
|
6
|
+
const sections = computed(() => [
|
|
7
|
+
{ title: t("ongoing.title", "Happening now"), events: grouped.value.ongoing },
|
|
8
|
+
{ title: t("upcoming.title", "Upcoming"), events: grouped.value.upcoming },
|
|
9
|
+
{ title: t("past.title", "Past events"), events: grouped.value.past }
|
|
10
|
+
].filter((section) => section.events.length));
|
|
11
|
+
defineOptions({ name: "EventsListPage" });
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<template>
|
|
15
|
+
<UContainer class="py-10">
|
|
16
|
+
<h1 class="mb-6 text-2xl font-semibold">
|
|
17
|
+
{{ t("title", "Events") }}
|
|
18
|
+
</h1>
|
|
19
|
+
<p
|
|
20
|
+
v-if="status === 'success' && !sections.length"
|
|
21
|
+
class="text-muted"
|
|
22
|
+
>
|
|
23
|
+
{{ t("empty", "There are no events right now.") }}
|
|
24
|
+
</p>
|
|
25
|
+
<section
|
|
26
|
+
v-for="section in sections"
|
|
27
|
+
:key="section.title"
|
|
28
|
+
class="mb-10"
|
|
29
|
+
>
|
|
30
|
+
<h2 class="mb-3 text-lg font-medium">
|
|
31
|
+
{{ section.title }}
|
|
32
|
+
</h2>
|
|
33
|
+
<div class="grid gap-4 md:grid-cols-2">
|
|
34
|
+
<EventCard
|
|
35
|
+
v-for="item in section.events"
|
|
36
|
+
:key="item.id"
|
|
37
|
+
:event="item"
|
|
38
|
+
:to="eventTo(item.slug)"
|
|
39
|
+
/>
|
|
40
|
+
</div>
|
|
41
|
+
</section>
|
|
42
|
+
</UContainer>
|
|
43
|
+
</template>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const t = useModuleT("events");
|
|
3
|
+
const { tickets, pay } = useMyTickets();
|
|
4
|
+
const pages = useRuntimeConfig().public.events?.pages;
|
|
5
|
+
const eventTo = (slug) => (pages?.event || "/events/:slug").replace(":slug", encodeURIComponent(slug));
|
|
6
|
+
defineOptions({ name: "EventTicketsPage" });
|
|
7
|
+
</script>
|
|
8
|
+
|
|
9
|
+
<template>
|
|
10
|
+
<UContainer class="py-10">
|
|
11
|
+
<h1 class="mb-6 text-2xl font-semibold">
|
|
12
|
+
{{ t("myTickets", "My tickets") }}
|
|
13
|
+
</h1>
|
|
14
|
+
<p
|
|
15
|
+
v-if="!tickets.length"
|
|
16
|
+
class="text-muted"
|
|
17
|
+
>
|
|
18
|
+
{{ t("noTickets", "You do not have any tickets yet.") }}
|
|
19
|
+
</p>
|
|
20
|
+
<div class="grid gap-4 md:grid-cols-2">
|
|
21
|
+
<EventTicketCard
|
|
22
|
+
v-for="ticket in tickets"
|
|
23
|
+
:key="ticket.id"
|
|
24
|
+
:ticket="ticket"
|
|
25
|
+
:to="eventTo(ticket.eventSlug)"
|
|
26
|
+
@pay="pay"
|
|
27
|
+
/>
|
|
28
|
+
</div>
|
|
29
|
+
</UContainer>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
declare const __VLS_export: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
2
|
+
declare const _default: typeof __VLS_export;
|
|
3
|
+
export default _default;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"events": {
|
|
3
|
+
"upcoming": {
|
|
4
|
+
"empty": {
|
|
5
|
+
"title": "Der er sku ik' lige nogen kommende events pt. -men tjek tilbage soon ..."
|
|
6
|
+
},
|
|
7
|
+
"title": "Kommende events",
|
|
8
|
+
"description": "Følg med her om future events i Frigear og Frigear Kulturværksted ..."
|
|
9
|
+
},
|
|
10
|
+
"ongoing": {
|
|
11
|
+
"title": "Igangværende events"
|
|
12
|
+
},
|
|
13
|
+
"past": {
|
|
14
|
+
"title": "Tidligere arrangementer",
|
|
15
|
+
"description": "Se tidligere Frigear events du gik glip ..."
|
|
16
|
+
},
|
|
17
|
+
"detail": {
|
|
18
|
+
"when": "Hvornår?",
|
|
19
|
+
"where": "Hvor?",
|
|
20
|
+
"tickets": {
|
|
21
|
+
"title": "Billetter",
|
|
22
|
+
"view": "Se billetter",
|
|
23
|
+
"free": "Gratis",
|
|
24
|
+
"goToCheckout": "Til betaling",
|
|
25
|
+
"signInToPurchase": "Log ind for at deltage",
|
|
26
|
+
"atLeastOneProductRequired": "{addonTitle}valg kræves.",
|
|
27
|
+
"ticket": {
|
|
28
|
+
"label": "Billet"
|
|
29
|
+
},
|
|
30
|
+
"products": {
|
|
31
|
+
"label": "Produkt",
|
|
32
|
+
"required": "Påkrævet"
|
|
33
|
+
},
|
|
34
|
+
"payment": {
|
|
35
|
+
"view": "Se betaling",
|
|
36
|
+
"verifying": {
|
|
37
|
+
"title": "Verificerer...",
|
|
38
|
+
"description": "Tjekker din betaling..."
|
|
39
|
+
},
|
|
40
|
+
"success": {
|
|
41
|
+
"title": "Betalingen er godkendt",
|
|
42
|
+
"description": "Din betaling blev godkendt. Billetterne er klar til brug."
|
|
43
|
+
},
|
|
44
|
+
"cancel": {
|
|
45
|
+
"title": "Betalingen er annulleret",
|
|
46
|
+
"description": "Betalingen blev annuleret, men prøv lige igen, eller kontakt support."
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"tickets": {
|
|
52
|
+
"title": "Billetter",
|
|
53
|
+
"description": "Se dine billetter og betalinger.",
|
|
54
|
+
"ticket": "Billet",
|
|
55
|
+
"payNow": "Betal nu",
|
|
56
|
+
"viewQrCode": "Se QR-kode",
|
|
57
|
+
"goToEvent": "Til event",
|
|
58
|
+
"status": {
|
|
59
|
+
"paid": "Betalt",
|
|
60
|
+
"cancelled": "Annulleret",
|
|
61
|
+
"pending": "Afventer",
|
|
62
|
+
"abandoned": "Opgivet"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"cart": {
|
|
66
|
+
"title": "Kurv",
|
|
67
|
+
"addedToCart": "{title} stuff lagt i kurven.",
|
|
68
|
+
"removedFromCart": "{title} stuff fjernet fra kurven.",
|
|
69
|
+
"continueToPayment": "Til betaling"
|
|
70
|
+
},
|
|
71
|
+
"title": "Events",
|
|
72
|
+
"empty": "Der er ingen events lige nu.",
|
|
73
|
+
"loading": "Henter…",
|
|
74
|
+
"members": "Medlemmer",
|
|
75
|
+
"viewEvent": "Se event",
|
|
76
|
+
"hideQr": "Skjul QR-kode",
|
|
77
|
+
"checkedIn": "Tjekket ind",
|
|
78
|
+
"myTickets": "Mine billetter",
|
|
79
|
+
"noTickets": "Du har ingen billetter endnu.",
|
|
80
|
+
"paymentReceived": "Betaling modtaget - din billet er klar.",
|
|
81
|
+
"paymentTimeout": "Vi har ikke modtaget betalingsbekræftelsen endnu. Den dukker snart op under dine billetter.",
|
|
82
|
+
"paymentCancelled": "Betaling annulleret. Din reservation holdes et kort stykke tid; du kan betale fra dine billetter.",
|
|
83
|
+
"ticketReady": "Din billet er klar",
|
|
84
|
+
"purchaseFailed": "Kunne ikke købe billetten",
|
|
85
|
+
"notFound": "Event ikke fundet"
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
{
|
|
2
|
+
"events": {
|
|
3
|
+
"upcoming": {
|
|
4
|
+
"title": "Upcoming events",
|
|
5
|
+
"description": "Follow along here for upcoming events at Frigear and Frigear Kulturværksted ...",
|
|
6
|
+
"empty": {
|
|
7
|
+
"title": "There are no upcoming events right now - check back soon ..."
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"ongoing": {
|
|
11
|
+
"title": "Ongoing events"
|
|
12
|
+
},
|
|
13
|
+
"detail": {
|
|
14
|
+
"when": "When?",
|
|
15
|
+
"where": "Where?",
|
|
16
|
+
"tickets": {
|
|
17
|
+
"title": "Tickets",
|
|
18
|
+
"free": "Free",
|
|
19
|
+
"view": "Show tickets",
|
|
20
|
+
"goToCheckout": "Go to checkout",
|
|
21
|
+
"signInToPurchase": "Sign in to purchase tickets",
|
|
22
|
+
"atLeastOneProductRequired": "{addonTitle} is required.",
|
|
23
|
+
"ticket": {
|
|
24
|
+
"label": "Ticket"
|
|
25
|
+
},
|
|
26
|
+
"products": {
|
|
27
|
+
"label": "Product",
|
|
28
|
+
"required": "Required"
|
|
29
|
+
},
|
|
30
|
+
"payment": {
|
|
31
|
+
"view": "View payment",
|
|
32
|
+
"verifying": {
|
|
33
|
+
"title": "Verifying...",
|
|
34
|
+
"description": "Checking your payment..."
|
|
35
|
+
},
|
|
36
|
+
"success": {
|
|
37
|
+
"title": "Payment successful!",
|
|
38
|
+
"description": "Your payment was successful. You can now purchase tickets."
|
|
39
|
+
},
|
|
40
|
+
"cancel": {
|
|
41
|
+
"title": "Payment canceled!",
|
|
42
|
+
"description": "Your payment was canceled. You can try again."
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"tickets": {
|
|
48
|
+
"title": "Tickets",
|
|
49
|
+
"description": "See your event tickets and payments.",
|
|
50
|
+
"ticket": "Ticket",
|
|
51
|
+
"payNow": "Pay now",
|
|
52
|
+
"viewQrCode": "View QR code",
|
|
53
|
+
"goToEvent": "Go to event",
|
|
54
|
+
"status": {
|
|
55
|
+
"paid": "Paid",
|
|
56
|
+
"cancelled": "Cancelled",
|
|
57
|
+
"pending": "Pending",
|
|
58
|
+
"abandoned": "Abandoned"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"cart": {
|
|
62
|
+
"title": "Cart",
|
|
63
|
+
"addedToCart": "{title} was added to your cart.",
|
|
64
|
+
"removedFromCart": "{title} stuff was removed.",
|
|
65
|
+
"continueToPayment": "Continue to payment"
|
|
66
|
+
},
|
|
67
|
+
"title": "Events",
|
|
68
|
+
"empty": "There are no events right now.",
|
|
69
|
+
"loading": "Loading…",
|
|
70
|
+
"members": "Members",
|
|
71
|
+
"viewEvent": "View event",
|
|
72
|
+
"hideQr": "Hide QR code",
|
|
73
|
+
"checkedIn": "Checked in",
|
|
74
|
+
"myTickets": "My tickets",
|
|
75
|
+
"noTickets": "You do not have any tickets yet.",
|
|
76
|
+
"paymentReceived": "Payment received - your ticket is ready.",
|
|
77
|
+
"paymentTimeout": "We have not received the payment confirmation yet. It will show up under your tickets shortly.",
|
|
78
|
+
"paymentCancelled": "Payment cancelled. Your reservation is held for a short while; you can pay from your tickets.",
|
|
79
|
+
"ticketReady": "Your ticket is ready",
|
|
80
|
+
"purchaseFailed": "Could not buy the ticket",
|
|
81
|
+
"notFound": "Event not found",
|
|
82
|
+
"past": {
|
|
83
|
+
"title": "Past events",
|
|
84
|
+
"description": "See past Frigear events you missed ..."
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { defineMenuItem, defineMenuSource, extendMenuItem } from "@frigear-nu/menu/utils";
|
|
2
|
+
export default defineMenuSource(() => {
|
|
3
|
+
const config = useRuntimeConfig().public.events;
|
|
4
|
+
if (config?.pages?.tickets) {
|
|
5
|
+
extendMenuItem("dashboard.account", defineMenuItem({
|
|
6
|
+
id: "event-tickets",
|
|
7
|
+
label: "Tickets",
|
|
8
|
+
description: "Your event tickets.",
|
|
9
|
+
icon: "i-lucide-ticket",
|
|
10
|
+
to: config.pages.tickets,
|
|
11
|
+
order: 40
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
});
|