Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .vscode/settings.json

This file was deleted.

8 changes: 5 additions & 3 deletions src/app/api/eventSignup/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,9 @@ export interface AdminUser {
lastName: string;
emailAddress: string;
phoneNumber: string;
guestOf?: string;
isGuest?: boolean;
speaksSpanish: boolean;
guestOf?: string; // For displaying "Guest of X"
isGuest?: boolean; // To mark if this row is a guest
}

function adminUserWithGuests(s: {
Expand All @@ -65,6 +66,7 @@ function adminUserWithGuests(s: {
lastName: s.user.lastName,
emailAddress: s.user.emailAddress,
phoneNumber: s.user.phoneNumber,
speaksSpanish: s.user.speaksSpanish ?? false,
};

const guestUsers: AdminUser[] = s.guests.map((guest) => ({
Expand Down Expand Up @@ -151,4 +153,4 @@ export const createWaitlistSignup = async (
userId,
},
});
};
};
2 changes: 1 addition & 1 deletion src/app/api/eventSignup/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ export async function POST(req: NextRequest) {
const { positionId, userId, guests = [] } = data;

// Get position and count current signups
const [position, signupCount] = await Promise.all([
const [position] = await Promise.all([
prisma.eventPosition.findUnique({
where: { id: positionId },
}),
Expand Down
2 changes: 1 addition & 1 deletion src/app/api/users/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export async function createUser(data: User) {
state: data.state,
zipCode: data.zipCode,
role: (data.role as UserRole) || "VOLUNTEER",
profileImage: data.profileImage,
speaksSpanish: data.speaksSpanish ?? null,
},
});
return newUser;
Expand Down
4 changes: 2 additions & 2 deletions src/app/api/users/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,15 @@ export async function GET(req: NextRequest) {
try {
const currentUser = await getCurrentUser();

if (currentUser && currentUser.role === UserRole.ADMIN) {
if (currentUser && currentUser.role !== UserRole.ADMIN) {
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
}

const users = await getUsers();
if (!users) {
return NextResponse.json({ error: "Users not found" }, { status: 404 });
}

return NextResponse.json(users, { status: 200 });
} catch (error) {
console.error("Error:", error);
Expand Down
17 changes: 15 additions & 2 deletions src/app/event/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default async function EventDetailsPage(props: {
<h1 className="text-bcp-blue text-[40px] leading-[44px]">
{event.name ? event.name : "Event Name"}
</h1>
{/* Time / Date */}
{/* Date */}
<p className="mt-[8px] text-bcp-blue text-[28px] leading-[40px]">
{(() => {
if (!event.startTime) return "Date unavailable";
Expand All @@ -66,7 +66,20 @@ export default async function EventDetailsPage(props: {
return `${month} ${start.getDate()}-${end.getDate()}, ${year}`;
})()}
</p>

{/* Time */}
<p className="mt-[4px] text-bcp-blue text-[28px] leading-[40px]">
{event.startTime && event.endTime
? `${new Date(event.startTime).toLocaleTimeString("en-US", {
timeZone: "America/New_York",
hour: "numeric",
minute: "2-digit",
})} – ${new Date(event.endTime).toLocaleTimeString("en-US", {
timeZone: "America/New_York",
hour: "numeric",
minute: "2-digit",
})}`
: "Time unavailable"}
</p>
{/* Address */}
<p className="mt-[4px] text-bcp-blue text-[20px] leading-[32px]">
{[
Expand Down
55 changes: 20 additions & 35 deletions src/app/event/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { getEvents } from "@/app/api/events/controller";
import { Event, UserRole } from "@prisma/client";
import { getCurrentUser } from "@/lib/auth";
import Link from "next/link";
import Button from "@/components/common/buttons/Button";
import { getPublicURL } from "@/lib/r2";

export default async function EventsPage() {
Expand Down Expand Up @@ -76,15 +77,25 @@ export default async function EventsPage() {
</div>

<div className="w-full max-w-[1200px] px-6 py-12">
<h1 className="text-[16px] font-semibold mb-6 text-[#234254]">
<Link href="/" className="hover:underline">
Home
</Link>
{" / "}
<Link href="/event" className="hover:underline">
Events
</Link>
</h1>
<div className="flex">
<h1 className="text-[16px] font-semibold mb-6 text-[#234254]">
<Link href="/" className="hover:underline">
Home
</Link>
{" / "}
<Link href="/event" className="hover:underline">
Events
</Link>
</h1>
{user?.role === UserRole.ADMIN && (
<Link
href="/admin/createEvent"
className="ml-auto rounded-lg bg-bcp-blue text-white mx-4 mt-1"
>
<Button label="Create New Event" />
</Link>
)}
</div>
{/* Featured Opportunities */}
<h2 className="text-[32px] font-semibold mb-6 color: #234254">
Featured Opportunities
Expand All @@ -94,17 +105,6 @@ export default async function EventsPage() {
<p className="text-red-600 font-medium">{error}</p>
) : featuredEvents.length > 0 ? (
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-4 gap-6 mb-12">
{/* Add Event Card (Admin only) */}
{user && user.role === UserRole.ADMIN && (
<Link href="/event/createEvent">
<div className="w-[283px] h-[348px] border-2 border-dashed border-gray-300 rounded-xl bg-white flex items-center justify-center cursor-pointer transition hover:border-gray-400 hover:bg-gray-50 hover:shadow-md">
<div className="w-12 h-12 rounded-full border border-gray-400 flex items-center justify-center">
<span className="text-2xl text-gray-500">+</span>
</div>
</div>
</Link>
)}

{featuredEvents.map((event) => {
return (
<EventCard
Expand All @@ -121,21 +121,6 @@ export default async function EventsPage() {
);
})}
</div>
) : user && user.role === UserRole.ADMIN ? (
<div className="mb-12">
<Link href="/event/createEvent">
<div className="w-[283px] h-[318px] border-2 border-dashed border-gray-300 rounded-xl bg-white flex items-center justify-center cursor-pointer transition hover:border-gray-400 hover:bg-gray-50 hover:shadow-md">
<div className="w-12 h-12 rounded-full border border-gray-400 flex items-center justify-center">
<span className="text-2xl text-gray-500">+</span>
</div>
</div>
</Link>

<p className="text-gray-500 mt-8">
There are currently no pinned events. Pin an event to display it
on the home page.
</p>
</div>
) : (
<p className="text-gray-500 mb-12">
There are no featured events at this time.
Expand Down
46 changes: 37 additions & 9 deletions src/app/onboarding/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ function OnboardingPage() {
// User inputs these now
phoneNumber: formData.get("phone"),
dateOfBirth: formData.get("dob"), // "YYYY-MM-DD"
languages: formData.get("languages"),
speaksSpanish: formData.get("speaksSpanish") === "true",
streetAddress: formData.get("street"),
city: formData.get("city"),
state: formData.get("state"),
Expand Down Expand Up @@ -182,18 +182,46 @@ function OnboardingPage() {
</div>

{/* Languages (Optional) */}
<div className="flex flex-col items-start">
<div className="flex flex-row items-start justify-between">
<label
htmlFor="languages"
htmlFor="speakSpanish"
className="text-base font-normal text-medium-gray mb-1"
>
Languages Spoken
Do you speak Spanish?
</label>
<input
name="languages"
id="languages"
className="w-full h-[43px] rounded-lg border border-medium-gray p-3 text-base text-medium-gray focus:outline-none focus:ring-2 focus:ring-bcp-blue/30 focus:border-bcp-blue"
/>
<div className="flex flex-row items-center justify-between gap-[48px]">
<div className="flex flex-row items-center gap-[14px]">
<input
// type="checkbox"
type="radio"
name="speaksSpanish"
value="true"
required
className="accent-bcp-blue rounded-md"
/>
<label
htmlFor="speaksSpanish"
className="flex flex-row text-base font-normal text-medium-gray mb-1"
>
Yes
</label>
</div>
<div className="flex flex-row items-center gap-[14px]">
<input
type="radio"
// type="checkbox"
className="accent-bcp-blue rounded-md"
name="speaksSpanish"
value="false"
/>
<label
htmlFor="speaksSpanish"
className="text-base font-normal text-medium-gray mb-1 gap-14"
>
No
</label>
</div>
</div>
</div>

{/* City/State/Zip (Optional) */}
Expand Down
5 changes: 1 addition & 4 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,12 @@ const Home: React.FC = () => {
try {
const res = await fetch("/api/events/pinned");
const data = await res.json();

console.log(data);

const now = new Date();

data.forEach((event: Event) => {
if (new Date(event.endTime) < now) {
fetch(`/api/events/${event.id}/unpin`, { method: "POST" }).catch(
(err) => console.error(`Failed to unpin event ${event.id}:`, err)
() => console.error(`Failed to unpin event ${event.id}:`)
);
}
});
Expand Down
7 changes: 3 additions & 4 deletions src/app/profile/edit/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import Image from "next/image";
import Link from "next/link";
import { useUser } from "@clerk/nextjs";
import { useRouter } from "next/navigation";
import ProfilePlaceholder from "@/assets/icons/pfp-placeholder.svg"; // Ensure this path is correct

export default function EditProfilePage() {
const { user, isLoaded } = useUser();
Expand Down Expand Up @@ -106,7 +105,6 @@ export default function EditProfilePage() {
setForm((prev) => ({ ...prev, profileImageKey: "" })); // Mark for deletion
}

// --- SUBMIT ---
// --- SUBMIT ---
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
Expand Down Expand Up @@ -136,7 +134,6 @@ export default function EditProfilePage() {
}

// 2. Update Database
// WE CHANGED THE STRUCTURE HERE 👇
const res = await fetch("/api/users", {
method: "PUT",
headers: { "Content-Type": "application/json" },
Expand Down Expand Up @@ -343,9 +340,11 @@ export default function EditProfilePage() {
className="w-[160px] h-[160px] border-2 border-dashed border-gray-500 rounded flex items-center justify-center bg-[#f9f9f9] cursor-pointer hover:bg-gray-100 transition-colors shrink-0 overflow-hidden relative"
>
{previewUrl ? (
<img
<Image
src={previewUrl}
alt="Preview"
width={48}
height={48}
className="w-full h-full object-cover"
/>
) : (
Expand Down
4 changes: 2 additions & 2 deletions src/app/profile/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export default function ProfilePage() {
},
]);
}
} catch (error) {
} catch {
setModalTitle("Error");
setModalMessage("An error occurred. Please try again.");
setModalButtons([
Expand Down Expand Up @@ -311,7 +311,7 @@ export default function ProfilePage() {
id={event.id}
image={reg.imageUrl || "/event1.jpg"}
title={event.name}
startTime={new Date(event.startTime)}
startTime={new Date(reg.position.startTime)}
endTime={new Date(reg.position.endTime)}
location={event.addressLine1}
date={firstDate}
Expand Down
16 changes: 15 additions & 1 deletion src/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,21 @@ import React from "react";
const Footer: React.FC = () => {
return (
<footer className="bg-bcp-blue bg-opacity-100 w-full flex items-center justify-between p-6 mt-auto">
<p className="text-xs text-white">© 2025 Boston Community Pediatrics</p>
<div>
<a
href="https://www.bostoncommunitypediatrics.org/donate"
className="bg-light-bcp-blue text-white text-sm px-4 py-3 rounded text-center"
>
Donate to BCP
</a>
</div>
<div className="text-xs text-white text-right">
<p>
Boston Community Pediatrics (BCP) is a nonprofit organization, Tax ID
84-3091463.
</p>
<p>© 2025 Boston Community Pediatrics</p>
</div>
</footer>
);
};
Expand Down
1 change: 1 addition & 0 deletions src/components/auth/SignupForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ const SignupForm = () => {
type="radio"
name="speaksSpanish"
value="true"
required
className="accent-bcp-blue rounded-md"
/>
<label
Expand Down
Loading
Loading