Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WEB-15: Implement Announcement Preview Popup #29

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
Binary file added public/user-placeholder-icons/lauren.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 23 additions & 5 deletions src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,31 +78,49 @@ const ann4: Announcement = {
};

const ann5: Announcement = {
id: "4",
id: "5",
apps: [AppName.RESELL],
body: "Starting at the same time as ...",
endDate: new Date("2025-08-09T18:57:00Z"),
imageUrl:
"https://kidszoo.org/wp-content/uploads/2017/06/IMG_2034-2-scaled.jpg",
link: "https://www.instagram.com/p/C4ft4SyOaUj/",
startDate: new Date("2024-08-08T19:24:20Z"),
title: "Yet Another Announcement",
};

const ann6: Announcement = {
id: "6",
apps: [AppName.RESELL, AppName.EATERY, AppName.UPLIFT],
body: "Starting at the same time as ...",
endDate: new Date("2025-08-09T18:57:00Z"),
imageUrl:
"https://kidszoo.org/wp-content/uploads/2017/06/IMG_2034-2-scaled.jpg",
link: "https://www.instagram.com/p/C4ft4SyOaUj/",
startDate: new Date("2025-08-08T19:24:20Z"),
title: "Announcement",
title: "Courses Start Soon!",
};

export default function Landing() {
const name = "Vin";
const announcements = [ann0, ann1, ann2, ann3, ann4, ann5];
const announcements = [ann0, ann1, ann2, ann3, ann4, ann5, ann6];
return (
<div className="flex flex-col gap-16 md:gap-20 lg:w-[1128px] lg:mx-auto">
<div className="flex flex-col gap-8 px-4 md:px-8 lg:hidden">
<PageHeader title={`Welcome, ${name}!`} subtitle={"Send announcements to our applications"}/>
<PageHeader
title={`Welcome, ${name}!`}
subtitle={"Send announcements to our applications"}
/>
<CreateAnnouncementEntry />
<UpcomingAnnouncements announcements={announcements} />
<ActiveAnnouncements announcements={announcements} />
<PastAnnouncements announcements={announcements} />
</div>
<div className="max-lg:hidden flex flex-col gap-8">
<PageHeader title={`Welcome, ${name}!`} subtitle={"Send announcements to our applications"} />
<PageHeader
title={`Welcome, ${name}!`}
subtitle={"Send announcements to our applications"}
/>
<div className="flex flex-row gap-8">
<div className="flex flex-col gap-8">
<CreateAnnouncementEntry />
Expand Down
22 changes: 21 additions & 1 deletion src/components/landing/ActiveAnnouncements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
sortAnnouncementsByStartDate,
} from "@/utils/utils";
import ActiveCell from "./AnnouncementCell";
import AnnouncementModal from "./AnnouncementModal";
import { useState, useEffect } from "react";

interface Props {
Expand All @@ -27,6 +28,17 @@ export default function ActiveAnnouncements({ announcements }: Props) {
seconds: 0,
});

const [selectedAnnouncement, setSelectedAnnouncement] =
useState<Announcement | null>(null);

const openModal = (announcement: Announcement) => {
setSelectedAnnouncement(announcement);
};

const closeModal = () => {
setSelectedAnnouncement(null);
};

useEffect(() => {
if (activeAnnouncements.length === 0) return;

Expand Down Expand Up @@ -59,14 +71,22 @@ export default function ActiveAnnouncements({ announcements }: Props) {
{activeAnnouncements.length > 0 ? (
<div className="flex flex-col items-start self-stretch bg-neutral-white rounded-lg gap-3">
{activeAnnouncements.map((announcement) => (
<ActiveCell key={announcement.id} announcement={announcement} />
<ActiveCell
key={announcement.id}
announcement={announcement}
onClick={() => openModal(announcement)}
/>
))}
</div>
) : (
<p className="b1 self-stretch text-neutral-400 text-center">
{NO_ANNOUNCEMENTS_MESSAGE}
</p>
)}
<AnnouncementModal
onClose={closeModal}
announcement={selectedAnnouncement}
/>
</div>
);
}
14 changes: 9 additions & 5 deletions src/components/landing/AnnouncementCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ import LiveIndicator from "../shared/LiveIndicator";

interface Props {
announcement: Announcement;
onClick: () => void;
}

export default function AnnouncementCell({ announcement }: Props) {
export default function AnnouncementCell({ announcement, onClick }: Props) {
const [currentDate, setCurrentDate] = useState(new Date());
const isActive = filterActiveAnnouncements([announcement]).length > 0;

Expand All @@ -28,7 +29,10 @@ export default function AnnouncementCell({ announcement }: Props) {
}, []);

return (
<div className="flex flex-col p-6 items-start md:items-end md:flex-row justify-center gap-6 md:gap-8 self-stretch bg-neutral-white rounded-lg border border-other-stroke relative">
<div
className="flex flex-col p-6 cursor-pointer items-start md:items-end md:flex-row justify-center gap-6 md:gap-8 self-stretch bg-neutral-white rounded-lg border border-other-stroke relative"
onClick={onClick}
>
<img
src={announcement.imageUrl}
className="h-[265px] md:w-[108px] md:h-[108px] self-stretch rounded-lg object-cover bg-center"
Expand All @@ -48,7 +52,7 @@ export default function AnnouncementCell({ announcement }: Props) {
{isActive ? (
<TertiaryButton
text="Edit"
action={() => console.log("Button clicked")}
action={() => console.log("Edit Button clicked")}
className="max-md:hidden"
/>
) : null}
Expand All @@ -67,9 +71,9 @@ export default function AnnouncementCell({ announcement }: Props) {
) : null}
</div>
{dateInRange(
currentDate,
announcement.startDate,
announcement.endDate
announcement.endDate,
currentDate
) ? (
<LiveIndicator />
) : null}
Expand Down
101 changes: 101 additions & 0 deletions src/components/landing/AnnouncementModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { Announcement } from "@/models/Announcement";
import AnnouncementBanner from "../shared/AnnouncementBanner";
import AppIcon from "@/icons/AppIcon";
import ButtonPrimary2 from "../shared/ButtonPrimary2";
import ButtonPrimary3 from "../shared/ButtonPrimary3";
import CrossThinIcon from "@/icons/CrossThinIcon";
import { dateInRange, formatDate } from "@/utils/utils";
import ModalLiveIndicator from "../shared/ModalLiveIndicator";
import ModalPastIndicator from "../shared/ModalPastIndicator";
import ModalUpcomingIndicator from "../shared/ModalUpcomingIndicator";
import { useEffect, useState } from "react";

interface AnnouncementModalProps {
onClose: () => void;
announcement: Announcement | null;
}

export default function AnnouncementModal({
onClose,
announcement,
}: AnnouncementModalProps) {
if (!announcement) return null;

return (
<div className="fixed inset-0 bg-neutral-black bg-opacity-60 flex justify-center items-center z-50">
<div className="bg-neutral-white rounded-lg p-8 max-md:w-full m-4 md:m-8 lg:max-w-[1128px]">
<div className="flex flex-col gap-4 md:gap-6">
<div className="flex flex-col gap-2">
<div className="flex flex-col gap-1">
<div className="flex flex-row items-center justify-between gap-1">
<h4 className="text-neutral-800 break-all">
{announcement.title}
</h4>
<button
className="h-[24px] w-[24px] fill-neutral-400"
onClick={onClose}
>
<CrossThinIcon />
</button>
</div>
<p className="b1 text-neutral-600">
{`${formatDate(announcement.startDate)} - ${formatDate(
announcement.endDate
)}`}
</p>
</div>
<div className="flex flex-row items-center gap-2">
<img
src="https://runningscaredsite.wordpress.com/wp-content/uploads/2016/01/running-scared-chicken.jpeg?w=640"
className="w-6 h-6 rounded-full"
/>
<p className="b2 text-neutral-400">Scheduled by Lauren Jun</p>
</div>
</div>

belle-hu marked this conversation as resolved.
Show resolved Hide resolved
<div className="flex flex-col md:flex-row md:justify-between gap-4 items-left">
<div className="flex flex-row items-center gap-2">
{announcement.apps.map((app) => (
<AppIcon
appName={app}
className="rounded-sm w-[32px] h-[32px]"
/>
))}
</div>
{dateInRange(
announcement.startDate,
announcement.endDate,
new Date()
) ? (
<ModalLiveIndicator className="w-fit" />
) : new Date() > announcement.endDate ? (
<ModalPastIndicator className="w-fit" />
) : new Date() < announcement.startDate ? (
<ModalUpcomingIndicator className="w-fit" />
) : null}
</div>

<div className="flex flex-col p-4 justify-center items-center rounded-md border border-other-stroke bg-other-offWhite">
<AnnouncementBanner announcement={announcement} />
</div>

{dateInRange(
announcement.startDate,
announcement.endDate,
new Date()
) ? (
<ButtonPrimary3
text="End Live Announcement"
action={() => console.log("End Live Announcement button tapped")}
/>
) : (
<ButtonPrimary2
text="Delete Announcement"
action={() => console.log("Delete button tapped")}
/>
)}
</div>
</div>
</div>
);
}
24 changes: 23 additions & 1 deletion src/components/landing/PastAnnouncements.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
sortAnnouncementsByStartDate,
} from "@/utils/utils";
import ActiveCell from "./AnnouncementCell";
import AnnouncementModal from "./AnnouncementModal";
import { useState, useEffect } from "react";
import ButtonSecondary1 from "../shared/ButtonSecondary1";

Expand All @@ -20,6 +21,17 @@ export default function PastAnnouncements({ announcements }: Props) {
filterPastAnnouncements(announcements)
);

const [selectedAnnouncement, setSelectedAnnouncement] =
useState<Announcement | null>(null);

const openModal = (announcement: Announcement) => {
setSelectedAnnouncement(announcement);
};

const closeModal = () => {
setSelectedAnnouncement(null);
};

return (
<div className="flex flex-col p-6 items-start gap-6 rounded-lg bg-neutral-white">
<div className="flex items-center gap-4 self-stretch">
Expand All @@ -37,6 +49,7 @@ export default function PastAnnouncements({ announcements }: Props) {
<ActiveCell
key={pastAnnouncements[0].id}
announcement={pastAnnouncements[0]}
onClick={() => openModal(pastAnnouncements[0])}
/>
{pastAnnouncements.length > 1 && (
<ButtonSecondary1
Expand All @@ -53,6 +66,7 @@ export default function PastAnnouncements({ announcements }: Props) {
<ActiveCell
key={announcement.id}
announcement={announcement}
onClick={() => openModal(announcement)}
/>
))}
<ButtonSecondary1
Expand All @@ -62,7 +76,11 @@ export default function PastAnnouncements({ announcements }: Props) {
</>
) : (
pastAnnouncements.map((announcement) => (
<ActiveCell key={announcement.id} announcement={announcement} />
<ActiveCell
key={announcement.id}
announcement={announcement}
onClick={() => openModal(announcement)}
/>
))
)}
</div>
Expand All @@ -72,6 +90,10 @@ export default function PastAnnouncements({ announcements }: Props) {
{NO_ANNOUNCEMENTS_MESSAGE}
</p>
)}
<AnnouncementModal
onClose={closeModal}
announcement={selectedAnnouncement}
/>
</div>
);
}
17 changes: 17 additions & 0 deletions src/components/shared/ButtonPrimary2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use client";

interface Props {
text: string;
action: () => void;
}

export default function ButtonPrimary2({ text, action }: Props) {
return (
<button
className="flex p-4 justify-center items-center gap-1 self-stretch bg-red-100 rounded-md"
onClick={action}
>
<p className="text-red-600 text-center">{text}</p>
</button>
);
}
17 changes: 17 additions & 0 deletions src/components/shared/ButtonPrimary3.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
"use client";

interface Props {
text: string;
action: () => void;
}

export default function ButtonPrimary3({ text, action }: Props) {
return (
<button
className="flex p-4 justify-center items-center gap-1 self-stretch bg-red-600 rounded-md"
onClick={action}
>
<p className="s2 text-neutral-white text-center">{text}</p>
</button>
);
}
16 changes: 16 additions & 0 deletions src/components/shared/ModalLiveIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
interface ModalLiveIndicatorProps {
className?: string;
}

export default function ModalLiveIndicator({
className,
}: ModalLiveIndicatorProps) {
return (
<div
className={`flex h-[32px] py-2 px-3 items-center gap-1 bg-green-100 rounded-xl ${className}`}
>
<div className="w-[10px] h-[10px] bg-green-600 border-2 border-green-300 rounded-xl" />
<div className="label text-green-600 text-center">LIVE</div>
</div>
);
}
15 changes: 15 additions & 0 deletions src/components/shared/ModalPastIndicator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
interface ModalPastIndicatorProps {
className?: string;
}

export default function ModalPastIndicator({
className,
}: ModalPastIndicatorProps) {
return (
<div
className={`flex h-[32px] py-2 px-3 items-center gap-1 bg-red-100 rounded-xl ${className}`}
>
<div className="label text-red-600 text-center">PAST</div>
</div>
);
}
Loading