1+ <script setup lang="ts">
2+ import { ref , inject , onMounted } from ' vue' ;
3+ import { useI18n } from ' vue-i18n' ;
4+ import { useRoute } from ' vue-router' ;
5+ import { callKey } from ' @/keys' ;
6+ import { AvailabilitySlotResponse } from ' @/models' ;
7+ import ArtInvalidLink from ' @/elements/arts/ArtInvalidLink.vue' ;
8+ import ArtSuccessfulBooking from ' @/elements/arts/ArtSuccessfulBooking.vue' ;
9+ import LoadingSpinner from ' @/elements/LoadingSpinner.vue' ;
10+ import { usePosthog , posthog } from ' @/composables/posthog' ;
11+ import { MetricEvents } from ' @/definitions' ;
12+
13+ const { t } = useI18n ();
14+ const route = useRoute ();
15+ const call = inject (callKey );
16+
17+ // retrieve all required data from url
18+ const [signedUrl] = window .location .href .split (' /confirm/' );
19+ const slotId = Number (route .params .slot );
20+ const slotToken = route .params .token ;
21+ const confirmed = parseInt (route .params .confirmed as string ) === 1 ;
22+
23+ const isError = ref <boolean | null >(null );
24+ const attendeeEmail = ref <string | null >(null );
25+
26+ // initially load data when component gets remounted
27+ onMounted (async () => {
28+ // build data object for put request
29+ const obj = {
30+ slot_id: slotId ,
31+ slot_token: slotToken ,
32+ owner_url: signedUrl ,
33+ confirmed ,
34+ };
35+ const { error, data }: AvailabilitySlotResponse = await call (' schedule/public/availability/booking' ).put (obj ).json ();
36+ if (error .value ) {
37+ isError .value = true ;
38+
39+ return ;
40+ }
41+
42+ isError .value = false ;
43+ attendeeEmail .value = data .value ?.attendee ?.email ;
44+
45+ if (usePosthog ) {
46+ const event = confirmed ? MetricEvents .ConfirmBooking : MetricEvents .DenyBooking ;
47+ posthog .capture (event );
48+ }
49+ });
50+ </script >
51+
52+ <template >
53+ <div class =" booking-confirmation-view-container" >
54+ <div v-if =" isError === null" >
55+ <loading-spinner />
56+ </div >
57+ <div v-else-if =" isError === true" class =" content" >
58+ <art-invalid-link class =" art" />
59+ <h1 >{{ t('info.bookingLinkIsInvalid') }}</h1 >
60+ <p >{{ t('text.invalidOrAlreadyBooked') }}</p >
61+ </div >
62+ <div v-else class =" content" >
63+ <art-successful-booking class =" art" />
64+ <template v-if =" confirmed " >
65+ <h1 >{{ t('info.bookingSuccessfullyConfirmed') }}</h1 >
66+ <p >
67+ {{ t('info.eventWasCreated') }}<br >
68+ {{ t('text.invitationSentToAddress', { 'address': attendeeEmail }) }}
69+ </p >
70+ </template >
71+ <template v-else >
72+ <h1 >{{ t('info.bookingSuccessfullyDenied') }}</h1 >
73+ <p >
74+ {{ t('text.denialSentToAddress', { 'address': attendeeEmail }) }}<br >
75+ {{ t('info.slotIsAvailableAgain') }}
76+ </p >
77+ </template >
78+ </div >
79+ </div >
80+ </template >
81+
82+ <style scoped>
83+ .booking-confirmation-view-container {
84+ display : flex ;
85+ flex-direction : column ;
86+ gap : 3rem ;
87+ align-items : center ;
88+ justify-content : center ;
89+ height : 100% ;
90+ padding : 1rem ;
91+
92+ .content {
93+ display : flex ;
94+ flex-direction : column ;
95+ gap : 2rem ;
96+ align-items : center ;
97+ justify-content : center ;
98+ padding-inline : 1rem ;
99+
100+ h 1 {
101+ font-size : 1.25rem ;
102+ line-height : 1.75rem ;
103+ font-weight : 600 ;
104+ color : var (--colour-ti-highlight );
105+ }
106+
107+ p {
108+ text-align : center ;
109+ color : var (--colour-ti-secondary );
110+ }
111+
112+ .art {
113+ margin-block : 1.5rem ;
114+ height : auto ;
115+ max-width : 24rem ;
116+ }
117+ }
118+ }
119+ </style >
0 commit comments