Small UI changes

This commit is contained in:
2025-02-24 21:20:43 -06:00
parent df438ec702
commit 7aff496314
14 changed files with 412 additions and 19 deletions

View File

@ -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
View 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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View 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>