[READ-ONLY] Mirror of https://github.com/danielroe/dwaring87-webdev-wedding. Marissa & David's Wedding Website!
5.6 kB
160 lines
1<script setup>
2 const { updateGuest, getDetails } = useCMS();
3 const { sleep } = useSleep();
4
5 const props = defineProps({
6 invitation: Object
7 });
8 const emit = defineEmits(['cancel']);
9 const guests = ref(JSON.parse(JSON.stringify(props.invitation.guests)));
10
11 const email = await getDetails("contact_email");
12 const DIET = {
13 vegan: "Vegan",
14 vegetarian: "Vegetarian",
15 gluten: "Gluten Free",
16 soy: "Soy Allergy",
17 nut: "Nut Allergy",
18 dairy: "Dairy Allergy",
19 other: "Other"
20 }
21 const updateDietaryRestriction = (guest, key, enabled) => {
22 if ( enabled ) {
23 if ( guest.dietary_restrictions ) {
24 guest.dietary_restrictions.push(key);
25 }
26 else {
27 guest.dietary_restrictions = [key];
28 }
29 }
30 else {
31 guest.dietary_restrictions = guest.dietary_restrictions.filter((item) => item !== key);
32 }
33 }
34
35 const cancel = () => {
36 emit('cancel');
37 }
38
39 const finish = async () => {
40 await navigateTo('/page/wedding-info');
41 }
42
43 const saving = ref(false);
44 const error = ref();
45 const success = ref(false);
46 const attending = ref(false);
47 const save = async () => {
48 saving.value = true;
49 error.value = undefined;
50 success.value = false;
51 attending.value = false;
52 let errors = [];
53
54 window.scrollTo(0, 0);
55
56 for ( let i = 0; i < guests.value.length; i++ ) {
57 const guest = guests.value[i];
58 const original = props.invitation.guests[i];
59 const updated_guest_props = {
60 name: guest.name !== original.name ? guest.name : undefined,
61 email: guest.email !== original.email ? guest.email : undefined,
62 rsvp_welcome: !!guest.rsvp_welcome,
63 rsvp: !!guest.rsvp,
64 dietary_restrictions: JSON.stringify(guest.dietary_restrictions) !== JSON.stringify(original.dietary_restrictions) ? guest.dietary_restrictions : undefined,
65 notes: guest.notes !== original.notes ? guest.notes : undefined
66 }
67 if ( guest.rsvp || guest.rsvp_welcome ) {
68 attending.value = true;
69 }
70
71 useTrackEvent('RSVP Submit', { props: { code: props.invitation.invite_code, guest: guest.name, ...updated_guest_props } });
72 let { success, error } = await updateGuest(guest.id, updated_guest_props);
73 await sleep(500);
74 if ( !success ) {
75 errors.push(`Could not update Guest <strong><em>${guest.name}</em></strong> [${error}].`);
76 useTrackEvent('RSVP Error', { props: { code: props.invitation.invite_code, guest: guest.name, error } });
77 }
78 };
79
80 if ( errors.length > 0 ) {
81 error.value = errors.join(`<br />`);
82 error.value += `<br /><br />Please try again later. If the issue persists, please reach out to us directly or email us at <a style="text-decoration: underline" href="mailto:${email.value}?subject=[Contact] RSVP Errors">${email.value}</a>.`;
83 }
84 else {
85 useTrackEvent('RSVP Success', { props: { code: props.invitation.invite_code, name: props.invitation.name } });
86 success.value = true;
87 }
88 }
89</script>
90
91<template>
92 <div>
93 <h2>{{ invitation.name }}</h2>
94
95 <RSVPLoading v-if="saving"
96 loading="Updating Guest Information..."
97 :error="error"
98 :success="success"
99 :attending="attending"
100 continueLabel="Wedding Information"
101 @continue="finish"
102 @cancel="saving=false"
103 />
104
105 <div v-show="!saving">
106 <div class="mx-1 sm:mx-2 md:mx-4 mt-4 mb-8 px-4 bg-gray-100 border border-gray-400 rounded-md shadow" :id="`guest-container-${guest.id}`" v-for="(guest) in guests" :key="guest.id">
107 <div class="group">
108 <p>Name:</p>
109 <input class="guest-name" v-model="guest.name" @input="onInput" />
110 </div>
111 <div class="group">
112 <p>Email:</p>
113 <input class="guest-email" v-model="guest.email" />
114 <p class="info">Enter your email to receive updates from us about the wedding</p>
115 </div>
116 <div class="group">
117 <p>RSVP (Friday Welcome Dinner):</p>
118 <FormToggle class="guest-rsvp-welcome" :enabled="guest.rsvp_welcome" @toggle="(s) => guest.rsvp_welcome = s" />
119 <p class="info">Will you be attending the welcome dinner (potluck) the Friday evening before the wedding?</p>
120 </div>
121 <div class="group">
122 <p>RSVP (Saturday Ceremony & Reception):</p>
123 <FormToggle class="guest-rsvp" :enabled="guest.rsvp" @toggle="(s) => guest.rsvp = s" />
124 <p class="info">Will you be attending the wedding ceremony and reception on Saturday?</p>
125 </div>
126 <div class="group">
127 <p>Dietary Restrictions:</p>
128 <div class="flex flex-wrap gap-2">
129 <FormCheck class="guest-diet" v-for="(value, key) in DIET" :key="key" :code="key" :label="value"
130 :enabled="guest.dietary_restrictions && guest.dietary_restrictions.includes(key)"
131 @check="(s) => updateDietaryRestriction(guest, key, s)" />
132 </div>
133 </div>
134 <div class="group">
135 <p>Comments:</p>
136 <textarea class="guest-notes" v-model="guest.notes" rows="5"></textarea>
137 <p class="info">Any other information we should know?</p>
138 </div>
139 </div>
140
141 <div class="m-4 flex gap-4 justify-between">
142 <button class="btn" @click="cancel">Cancel</button>
143 <button class="btn-dark" @click="save">Save</button>
144 </div>
145 </div>
146
147 </div>
148</template>
149
150<style scoped>
151 .group {
152 @apply flex flex-col gap-2 py-5;
153 }
154 .group p {
155 @apply font-bold;
156 }
157 .group p.info {
158 @apply text-sm font-normal italic text-gray-500;
159 }
160</style>