[READ-ONLY] Mirror of https://github.com/danielroe/dwaring87-webdev-wedding. Marissa & David's Wedding Website!
0

Configure Feed

Select the types of activity you want to include in your feed.

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 &amp; 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>