Small UI changes
This commit is contained in:
@ -3,7 +3,7 @@ import { getS3Data, putS3Data } from "../../lib/s3";
|
||||
import type { RSVPItem } from "../../lib/types";
|
||||
|
||||
const objectsToCSV = (data: RSVPItem[]): string => {
|
||||
const headers = ["name", "dietaryRestrictions", "timestamp"];
|
||||
const headers = ["name", "dietaryRestrictions", "notes", "timestamp"];
|
||||
const csvRows = [headers.join(",")];
|
||||
|
||||
data.forEach((entry) => {
|
||||
@ -27,7 +27,12 @@ const csvToObjects = (csv: string): RSVPItem[] => {
|
||||
.filter((line) => line.trim())
|
||||
.map((line) => {
|
||||
const values = line.match(/(".*?"|[^",\s]+)(?=\s*,|\s*$)/g) || [];
|
||||
const entry: Partial<RSVPItem> = {};
|
||||
const entry: Partial<RSVPItem> = {
|
||||
name: "",
|
||||
dietaryRestrictions: "",
|
||||
notes: "",
|
||||
timestamp: "",
|
||||
};
|
||||
|
||||
headers.forEach((header, index) => {
|
||||
let value = values[index] || "";
|
||||
@ -39,6 +44,44 @@ const csvToObjects = (csv: string): RSVPItem[] => {
|
||||
});
|
||||
};
|
||||
|
||||
// GET: Retrieve all RSVPs
|
||||
export const GET: APIRoute = async ({ request }) => {
|
||||
const headers = {
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
try {
|
||||
const FILE_KEY = "rsvp.csv";
|
||||
const fileContent = await getS3Data<string>(FILE_KEY);
|
||||
|
||||
if (!fileContent) {
|
||||
return new Response(JSON.stringify([]), {
|
||||
status: 200,
|
||||
headers,
|
||||
});
|
||||
}
|
||||
|
||||
const rsvpList = csvToObjects(fileContent);
|
||||
return new Response(JSON.stringify(rsvpList), {
|
||||
status: 200,
|
||||
headers,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error retrieving RSVPs:", error);
|
||||
return new Response(
|
||||
JSON.stringify({
|
||||
success: false,
|
||||
error: "Failed to retrieve RSVPs",
|
||||
}),
|
||||
{
|
||||
status: 500,
|
||||
headers,
|
||||
}
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// POST: Submit a new RSVP
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
console.log("API endpoint hit - starting request processing");
|
||||
|
||||
@ -65,6 +108,7 @@ export const POST: APIRoute = async ({ request }) => {
|
||||
|
||||
existingRsvps.push({
|
||||
...newRsvp,
|
||||
notes: newRsvp.notes || "",
|
||||
timestamp: new Date().toISOString(),
|
||||
});
|
||||
|
||||
|
118
src/pages/faq.astro
Normal file
118
src/pages/faq.astro
Normal file
@ -0,0 +1,118 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
---
|
||||
|
||||
<Layout title="FAQ">
|
||||
<div class="flex flex-col gap-8 max-w-3xl mx-auto p-6">
|
||||
<div class="text-center">
|
||||
<h1 class="text-4xl mb-8">Frequently Asked Questions</h1>
|
||||
</div>
|
||||
|
||||
<div class="space-y-4">
|
||||
<!-- Dress Code -->
|
||||
<div class="collapse collapse-plus bg-base-200">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
Dress Code?
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<p class="text-lg">
|
||||
Semi-formal, any colour you want. Want to get dressed up? Go for it! Want to wear a shirt with no stains on it? Go for it!
|
||||
There will be dancing, so choose your wardrobe accordingly. Maybe don't wear a white dress...
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Dietary Restrictions -->
|
||||
<div class="collapse collapse-plus bg-base-200">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
Dietary Restrictions?
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<p class="text-lg">
|
||||
We will do our best to accommodate any dietary restrictions you have! Our caterer can cook gluten/dairy/peanut free etc.
|
||||
but may not be able to guarantee that there are no traces of allergens in the food. Please contact us if you have any concerns.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Alcohol -->
|
||||
<div class="collapse collapse-plus bg-base-200">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
Alcohol?
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<p class="text-lg">
|
||||
We will not be serving alcohol.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Childcare -->
|
||||
<div class="collapse collapse-plus bg-base-200">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
Childcare?
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<p class="text-lg">
|
||||
Your young children are adorable and welcome, but we don't have childcare or designated areas for naps etc.
|
||||
If you have any concerns, please contact us.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Gifts -->
|
||||
<div class="collapse collapse-plus bg-base-200">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
Gifts?
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<p class="text-lg">
|
||||
The best gift is you sharing in our joy! Don't feel obligated. If you would like to give a physical gift,
|
||||
cash is preferred, but we do have a registry available on this website as well.
|
||||
Ix would be over the moon if someone found him a
|
||||
<a href="https://www.youtube.com/watch?v=jeT7X3HfXP8" target="_blank" class="link link-primary">hurdy-gurdy</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Help -->
|
||||
<div class="collapse collapse-plus bg-base-200">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
Can I Help With Anything?
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<p class="text-lg">
|
||||
If you're up for staying a bit later, we could definitely use your help cleaning up the venues when the wedding is done!
|
||||
Tony and Gladys will be coordinating that the day-of, please speak with them. If you want to help with wedding preparations,
|
||||
please contact Ix or Natasha. Thank you!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact -->
|
||||
<div class="collapse collapse-plus bg-base-200">
|
||||
<input type="checkbox" />
|
||||
<div class="collapse-title text-xl font-medium">
|
||||
Where Do I Contact You With All of My Concerns?
|
||||
</div>
|
||||
<div class="collapse-content">
|
||||
<div class="text-lg space-y-2">
|
||||
<p>Email us at: <a href="mailto:ixabatasha25@proton.me" class="link link-primary">ixabatasha25@proton.me</a></p>
|
||||
<p>Call/text Natasha: <a href="tel:13062929000" class="link link-primary">1 (306) 292-9000</a></p>
|
||||
<p>Call/text Ix: <a href="tel:13067179403" class="link link-primary">1 (306) 717-9403</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="text-center mt-8">
|
||||
<a href="/" class="btn btn-primary">Back to Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
@ -1,16 +1,63 @@
|
||||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import SignOut from "../components/SignOut.tsx";
|
||||
---
|
||||
|
||||
<Layout title="Welcome">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="text-center">❤️ Natasha + Ixabat ❤️</div>
|
||||
<div class="flex flex-col gap-8 max-w-5xl mx-auto p-6">
|
||||
<!-- Header -->
|
||||
<div class="text-center space-y-4">
|
||||
<div class="text-5xl font-normal" style="font-family: 'Great Vibes', cursive;">❤️ Natasha + Ixabat ❤️</div>
|
||||
<p class="text-xl text-gray-600">We hope you can join us in celebration on</p>
|
||||
<p class="text-2xl font-semibold">Saturday, June 7, 2025</p>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-2 justify-center items-center">
|
||||
<a class="btn btn-primary" href="/rsvp">RSVP</a>
|
||||
<a class="btn btn-primary" href="/registry">View Registry</a>
|
||||
<SignOut client:load />
|
||||
<!-- Event Details Cards -->
|
||||
<div class="flex flex-col md:flex-row gap-6">
|
||||
<!-- Ceremony Card -->
|
||||
<div class="card bg-base-100 shadow-xl flex-1">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-2xl justify-center">Ceremony</h2>
|
||||
<div class="text-center space-y-2">
|
||||
<p class="text-xl">1:00 PM</p>
|
||||
<p>Preston Avenue Community Church</p>
|
||||
<p class="text-gray-600">2216 Preston Avenue, Saskatoon, SK</p>
|
||||
<a
|
||||
href="https://maps.google.com/?q=2216+Preston+Avenue+Saskatoon+SK"
|
||||
target="_blank"
|
||||
class="btn btn-outline btn-sm mt-2"
|
||||
>
|
||||
View on Map
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reception Card -->
|
||||
<div class="card bg-base-100 shadow-xl flex-1">
|
||||
<div class="card-body">
|
||||
<h2 class="card-title text-2xl justify-center">Reception</h2>
|
||||
<div class="text-center space-y-2">
|
||||
<p class="text-xl">5:00 PM</p>
|
||||
<p>Saskatoon Christian School</p>
|
||||
<p class="text-gray-600">55 Glazier Road, Corman Park, SK</p>
|
||||
<a
|
||||
href="https://maps.google.com/?q=55+Glazier+Road+Corman+Park+SK"
|
||||
target="_blank"
|
||||
class="btn btn-outline btn-sm mt-2"
|
||||
>
|
||||
View on Map
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RSVP Section -->
|
||||
<div class="text-center space-y-4">
|
||||
<p class="text-lg">Please RSVP whether you're able to come or not by <span class="font-semibold">April 1</span></p>
|
||||
<a href="/rsvp" class="btn btn-primary btn-lg">
|
||||
RSVP Now
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
@ -18,8 +18,7 @@ import SignOut from "../../components/SignOut.tsx";
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-2 justify-center items-center">
|
||||
<a class="btn btn-primary" href="/">Home</a>
|
||||
<SignOut client:load />
|
||||
<a class="btn btn-primary" href="/">Back to Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
|
@ -13,8 +13,7 @@ import SignOut from "../../components/SignOut.tsx";
|
||||
<RegistryList client:load />
|
||||
|
||||
<div class="flex flex-row gap-2 justify-center items-center">
|
||||
<a class="btn btn-primary" href="/">Home</a>
|
||||
<SignOut client:load />
|
||||
<a class="btn btn-primary" href="/">Back to Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
@ -13,8 +13,7 @@ import SignOut from "../components/SignOut.tsx";
|
||||
<RSVP client:load />
|
||||
|
||||
<div class="flex flex-row gap-2 justify-center items-center">
|
||||
<a class="btn btn-primary" href="/">Home</a>
|
||||
<SignOut client:load />
|
||||
<a class="btn btn-primary" href="/">Back to Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
54
src/pages/rsvp/admin.astro
Normal file
54
src/pages/rsvp/admin.astro
Normal file
@ -0,0 +1,54 @@
|
||||
---
|
||||
import AdminLayout from "../../layouts/AdminLayout.astro";
|
||||
import RSVPManager from "../../components/RSVPManager.tsx";
|
||||
import SignIn from "../../components/SignIn.tsx";
|
||||
import SignOut from "../../components/SignOut.tsx";
|
||||
---
|
||||
|
||||
<AdminLayout title="RSVP Manager">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="text-center text-4xl">RSVP Manager</div>
|
||||
|
||||
<div id="auth-container">
|
||||
<SignIn client:load onSuccess={() => {}} requiredRole="admin" />
|
||||
</div>
|
||||
|
||||
<div id="manager-container" class="hidden">
|
||||
<RSVPManager client:load />
|
||||
</div>
|
||||
|
||||
<div class="flex flex-row gap-2 justify-center items-center">
|
||||
<a class="btn btn-primary" href="/">Back to Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</AdminLayout>
|
||||
|
||||
<script>
|
||||
const checkAndUpdateVisibility = (role: string | null) => {
|
||||
if (role === "admin") {
|
||||
document.getElementById("auth-container")?.classList.add("hidden");
|
||||
document
|
||||
.getElementById("manager-container")
|
||||
?.classList.remove("hidden");
|
||||
} else {
|
||||
document
|
||||
.getElementById("auth-container")
|
||||
?.classList.remove("hidden");
|
||||
document
|
||||
.getElementById("manager-container")
|
||||
?.classList.add("hidden");
|
||||
}
|
||||
};
|
||||
|
||||
// Check auth state on page load
|
||||
const isAuthenticated =
|
||||
sessionStorage.getItem("isAuthenticated") === "true";
|
||||
const role = sessionStorage.getItem("role");
|
||||
checkAndUpdateVisibility(role);
|
||||
|
||||
// Add event listener for custom event from SignIn component
|
||||
document.addEventListener("auth-success", ((event: CustomEvent) => {
|
||||
const newRole = event.detail?.role || sessionStorage.getItem("role");
|
||||
checkAndUpdateVisibility(newRole);
|
||||
}) as EventListener);
|
||||
</script>
|
Reference in New Issue
Block a user