From 50ed30cfbeb0ec551674a1bc642aaa3b2cc56c00 Mon Sep 17 00:00:00 2001 From: nguyenpham18 Date: Sat, 28 Mar 2026 11:00:50 -0500 Subject: [PATCH 1/8] fetch event in homepage and notification, change seed for notification and event --- app/pages/inbox.vue | 53 +- app/pages/index.vue | 68 +-- package.json | 6 +- pnpm-lock.yaml | 798 +++++++++++++++++----------- prisma.config.ts | 2 +- prisma/schema/user.prisma | 2 + prisma/seed/events.json | 4 +- prisma/seed/notifications.json | 8 +- server/api/events/index.get.ts | 4 +- server/api/notification/[id].get.ts | 54 ++ server/utils/prisma.ts | 4 +- server/utils/seed.ts | 72 +-- 12 files changed, 650 insertions(+), 425 deletions(-) create mode 100644 server/api/notification/[id].get.ts diff --git a/app/pages/inbox.vue b/app/pages/inbox.vue index 9c44e99..0deb8ce 100644 --- a/app/pages/inbox.vue +++ b/app/pages/inbox.vue @@ -14,31 +14,38 @@ type Notification = { isRead: boolean } -// notifications -const notifications = ref([ - { - id: '1', - title: 'Notification 1', - content: 'Thank you for choosing Abide Women’s Health. This message contains several important reminders and helpful instructions to ensure your upcoming visit goes as smoothly as possible. Please plan to arrive 10–15 minutes early to allow time for check-in and any necessary paperwork. If you have recently experienced changes in your medical history, medications, or insurance coverage, bring any updated documents with you so our team can review them before your appointment begins.', - createdAt: '2025-10-27T10:30:00Z', - isRead: false - }, - { - id: '2', - title: 'Notification 2', - content: 'Message 2', - createdAt: '2025-10-26T14:15:00Z', - isRead:false - }, - { - id: '3', - title: 'Notification 3', - content: 'Message 3', - createdAt: '2025-10-25T09:00:00Z', - isRead: false + +const { data: sessionData } = await useFetch('/api/auth/get-session') +const userId = computed(() => (sessionData.value as any)?.user?.id ?? '24f667b1-c09f-4b9e-a57f-96b87d94327d') + + +const notifications = ref([]) +const loading = ref(false) +const error = ref(null) + +const fetchNotification = async () => { + if (!userId.value) return + loading.value=true + error.value = null + + try { + const data = await $fetch<{ notifications: Notification[] }>( + `/api/notification/${userId.value}` + ) + notifications.value = data.notifications + } catch (err) { + console.error("Failed to fetch notifications", err) + error.value = "Failed to load notifications" + } finally { + loading.value = false } -]) +} +watch(userId, (id) => { + if (id) fetchNotification() +}, { immediate: true }) +console.log('sessionData:', sessionData.value) +console.log('userId:', userId.value) // map to uaccordion items const accordionItems = computed(() => diff --git a/app/pages/index.vue b/app/pages/index.vue index 8a0138a..d56cded 100644 --- a/app/pages/index.vue +++ b/app/pages/index.vue @@ -1,6 +1,7 @@ From f5b2dd13f166c51db7ef60534c5c92e95dd8d55a Mon Sep 17 00:00:00 2001 From: nguyenpham18 Date: Thu, 16 Apr 2026 16:20:45 -0500 Subject: [PATCH 4/8] updated the event API --- app/pages/events/index.vue | 9 +++++++-- server/api/events/index.get.ts | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/app/pages/events/index.vue b/app/pages/events/index.vue index dc574d6..36b51b4 100644 --- a/app/pages/events/index.vue +++ b/app/pages/events/index.vue @@ -15,7 +15,12 @@ type Event = { id: string title: string startTime: string - location: string + location: { + id: string + address: string + latitude: number + longitude: number + } eventAssets: any[] } @@ -36,7 +41,7 @@ const events = computed(() => day: '2-digit', year: 'numeric' }), - location: e.location, + location: e.location?.address, image: e.eventAssets?.[0]?.url ?? '/images/image1.jpeg', })) ) diff --git a/server/api/events/index.get.ts b/server/api/events/index.get.ts index 9f1c7ca..8248901 100644 --- a/server/api/events/index.get.ts +++ b/server/api/events/index.get.ts @@ -4,6 +4,7 @@ export default defineEventHandler(async (_event) => { try { const allEvents = await prisma.event.findMany({ include: { + location: true, eventAssets: true, volunteerHours: true, participants: true From f9b38c64fea5b50bed70f754133a934274af1c33 Mon Sep 17 00:00:00 2001 From: nguyenpham18 Date: Thu, 23 Apr 2026 16:24:14 -0500 Subject: [PATCH 5/8] fetch upcoming on event page --- app/pages/events/[id].vue | 4 +++- app/pages/events/index.vue | 12 +++++++----- app/pages/index.vue | 12 ++++++++---- prisma/seed/events.json | 12 ++++++------ 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/app/pages/events/[id].vue b/app/pages/events/[id].vue index 6d98cae..2317e9d 100644 --- a/app/pages/events/[id].vue +++ b/app/pages/events/[id].vue @@ -1,8 +1,10 @@ \ No newline at end of file + diff --git a/app/components/event/Modal.vue b/app/components/event/Modal.vue index 0cd88d2..b658734 100644 --- a/app/components/event/Modal.vue +++ b/app/components/event/Modal.vue @@ -1,57 +1,40 @@ \ No newline at end of file + diff --git a/app/components/event/Tile.vue b/app/components/event/Tile.vue index 576600e..33b365f 100644 --- a/app/components/event/Tile.vue +++ b/app/components/event/Tile.vue @@ -5,22 +5,23 @@ defineProps<{ subtitle?: string }>() + \ No newline at end of file + diff --git a/app/components/map/Interactive.client.vue b/app/components/map/Interactive.client.vue index 7b1dbca..f2ae87d 100644 --- a/app/components/map/Interactive.client.vue +++ b/app/components/map/Interactive.client.vue @@ -4,19 +4,19 @@ :center="center" :zoom="zoom" :attribution-control="false" - > - + > + + /> diff --git a/app/components/nav/Bottom.vue b/app/components/nav/Bottom.vue index e4dab35..9cb1226 100644 --- a/app/components/nav/Bottom.vue +++ b/app/components/nav/Bottom.vue @@ -1,41 +1,42 @@ + diff --git a/app/components/nav/SecondaryTop.vue b/app/components/nav/SecondaryTop.vue index f36e207..fd60c29 100644 --- a/app/components/nav/SecondaryTop.vue +++ b/app/components/nav/SecondaryTop.vue @@ -3,21 +3,26 @@ const router = useRouter() diff --git a/app/layouts/default.vue b/app/layouts/default.vue index 3e9af13..d3f49d0 100644 --- a/app/layouts/default.vue +++ b/app/layouts/default.vue @@ -2,9 +2,9 @@ diff --git a/app/layouts/secondary.vue b/app/layouts/secondary.vue index 62c390b..eae5c8c 100644 --- a/app/layouts/secondary.vue +++ b/app/layouts/secondary.vue @@ -1,7 +1,7 @@ \ No newline at end of file +
+ + + +
+ diff --git a/app/lib/relativeFetch.ts b/app/lib/relativeFetch.ts index b6e556b..6eb5dfb 100644 --- a/app/lib/relativeFetch.ts +++ b/app/lib/relativeFetch.ts @@ -4,8 +4,9 @@ import { useFetch } from '#app' export const relativeFetch = ((url: string, opts?: any) => { try { if (url.startsWith('http')) url = new URL(url).pathname - } catch { + } + catch { // ignore invalid URLs } return useFetch(url, opts) -}) as any \ No newline at end of file +}) as any diff --git a/app/middleware/auth.ts b/app/middleware/auth.ts index 2997b5d..4aff9c2 100644 --- a/app/middleware/auth.ts +++ b/app/middleware/auth.ts @@ -4,16 +4,17 @@ export default defineNuxtRouteMiddleware(async (to) => { try { const data = await $fetch('/api/auth/get-session', { - cache: 'no-store', // ← forces fresh request every time + cache: 'no-store', // ← forces fresh request every time headers: { - 'Cache-Control': 'no-cache' - } + 'Cache-Control': 'no-cache', + }, }) - + if (!data?.session) { return navigateTo('/auth/login') } - } catch { + } + catch { return navigateTo('/auth/login') } -}) \ No newline at end of file +}) diff --git a/app/pages/admin/donations.vue b/app/pages/admin/donations.vue index 4a85211..fac075c 100644 --- a/app/pages/admin/donations.vue +++ b/app/pages/admin/donations.vue @@ -5,7 +5,7 @@ definePageMeta({ layout: 'secondary', }) -//Backend +// Backend interface DonationFund { id: string name: string @@ -17,30 +17,30 @@ interface DonationFund { } const { data: fundsData, refresh } = await useAsyncData( 'donations', - () => $fetch('/api/admin/donations') + () => $fetch('/api/admin/donations'), ) const funds = computed(() => fundsData.value ?? []) -//Make dates pretty +// Make dates pretty function formatShort(dateStr: string) { if (!dateStr) return '' const d = new Date(dateStr) if (isNaN(d.getTime())) return dateStr const mm = String(d.getMonth() + 1).padStart(2, '0') - const dd = String(d.getDate()+1).padStart(2, '0') + const dd = String(d.getDate() + 1).padStart(2, '0') const yy = String(d.getFullYear()).slice(-2) return `${mm}/${dd}/${yy}` } -//New Fund Modal States +// New Fund Modal States const open = ref(false) const fundName = ref('') const startDate = ref('') -const endDate = ref('') +const endDate = ref('') const image = ref(null) const link = ref('') -//Editing Fund Modal States +// Editing Fund Modal States const editOpen = ref(false) const editFundName = ref('') const editStartDate = ref('') @@ -50,39 +50,37 @@ const editLink = ref('') const editingFund = ref(null) const editImagePrevies = ref('') - -//New Fund Save +// New Fund Save async function saveFund(close: () => void) { - //create the new fund on the backend + // create the new fund on the backend const newDonation = await $fetch<{ id: string }>('/api/admin/donations', { - method: 'POST', - body: { - name: fundName.value, - link: link.value, - startDate: startDate.value, - endDate: endDate.value, - }, -}) - //add the image if it has one - if (image.value) { - const formData = new FormData() - formData.append('file', image.value) - await $fetch(`/api/admin/donations/${newDonation.id}/image`, { - method: 'POST', - body: formData, - }) - } - await refresh() - fundName.value = '' - startDate.value = '' - endDate.value = '' - image.value = null - link.value = '' - close() + method: 'POST', + body: { + name: fundName.value, + link: link.value, + startDate: startDate.value, + endDate: endDate.value, + }, + }) + // add the image if it has one + if (image.value) { + const formData = new FormData() + formData.append('file', image.value) + await $fetch(`/api/admin/donations/${newDonation.id}/image`, { + method: 'POST', + body: formData, + }) + } + await refresh() + fundName.value = '' + startDate.value = '' + endDate.value = '' + image.value = null + link.value = '' + close() } - -//Editing Fund Modal +// Editing Fund Modal async function openEdit(fund: DonationFund) { editingFund.value = fund editFundName.value = fund.name @@ -92,9 +90,8 @@ async function openEdit(fund: DonationFund) { editImagePrevies.value = fund.imageUrl ?? '' editImage.value = null editOpen.value = true - } -//Editing Fund Save +// Editing Fund Save async function saveEdit(close: () => void) { if (!editingFund.value) return await $fetch(`/api/admin/donations/${editingFund.value.id}`, { @@ -107,7 +104,7 @@ async function saveEdit(close: () => void) { imageUrl: editingFund.value?.imageUrl, }, }) - //add the image if it has one + // add the image if it has one if (editImage.value) { const formData = new FormData() formData.append('file', editImage.value) @@ -122,7 +119,7 @@ async function saveEdit(close: () => void) { close() } -//delete Fund +// delete Fund async function deleteFund(id: string) { await $fetch(`/api/admin/donations/${id}`, { method: 'DELETE', @@ -130,117 +127,218 @@ async function deleteFund(id: string) { await refresh() editOpen.value = false } - - + \ No newline at end of file + + + + + + + diff --git a/app/pages/admin/index.vue b/app/pages/admin/index.vue index df65126..5c63229 100644 --- a/app/pages/admin/index.vue +++ b/app/pages/admin/index.vue @@ -1,130 +1,143 @@ \ No newline at end of file +
+

+ {{ kpi.label }} +

+

+ {{ kpi.value }} +

+
+
+
+ + + +
+ +
+ +
+ + {{ feature.label }} + + + + {{ feature.description }} + +
+ + Manage β†’ + +
+
+
+ + diff --git a/app/pages/admin/volunteer-logs/index.vue b/app/pages/admin/volunteer-logs/index.vue index 6b64035..16a1587 100644 --- a/app/pages/admin/volunteer-logs/index.vue +++ b/app/pages/admin/volunteer-logs/index.vue @@ -1,74 +1,72 @@ -