Skip to content

Commit 5c0b278

Browse files
authored
[CFD-205] Event Calendar (#546)
1 parent 87af5e8 commit 5c0b278

File tree

10 files changed

+211
-64
lines changed

10 files changed

+211
-64
lines changed

.github/workflows/ci.yml

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -62,28 +62,6 @@ jobs:
6262

6363
- name: Check formatting
6464
run: pnpm turbo format
65-
build:
66-
runs-on: ubuntu-latest
67-
68-
steps:
69-
- name: Checkout repo
70-
uses: actions/checkout@v4
71-
72-
- name: Setup pnpm
73-
uses: pnpm/action-setup@v3.0.0
74-
75-
- name: Setup Node
76-
uses: actions/setup-node@v4
77-
with:
78-
node-version-file: '.nvmrc'
79-
cache: 'pnpm'
80-
cache-dependency-path: 'pnpm-lock.yaml'
81-
82-
- name: Install deps
83-
run: pnpm install
84-
85-
- name: Build
86-
run: pnpm turbo typecheck build
8765

8866
android:
8967
runs-on: ubuntu-latest

apps/nextjs/src/components/absenteestable.tsx

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,18 @@ import { format } from "date-fns";
33

44
import { cn } from "~/lib/utils";
55
import { api } from "~/utils/api";
6+
import DropdownIcon from "./icons/dropdownicon";
67
import { Button } from "./ui/button";
78
import { Calendar } from "./ui/calendar";
89
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
910

10-
const selectedDateStyle = {
11+
export const selectedDateStyle = {
1112
backgroundColor: "#2E4D90",
1213
color: "#FFFFFF",
1314
borderRadius: "24px",
1415
};
1516

16-
const noSelectedDateStyle = {
17+
export const noSelectedDateStyle = {
1718
borderWidth: "1px",
1819
borderColor: "#2E4D90",
1920
borderRadius: "24px",
@@ -155,28 +156,7 @@ function AbsencesTable(absences: number[]) {
155156
);
156157
}
157158

158-
function DropdownIcon(isSelected: boolean) {
159-
return (
160-
<svg
161-
className="ml-auto h-4 w-4"
162-
width="16"
163-
height="9"
164-
viewBox="0 0 16 9"
165-
fill="none"
166-
xmlns="http://www.w3.org/2000/svg"
167-
>
168-
<path
169-
d="M15 0.999999L8 8L1 1"
170-
stroke={isSelected ? "white" : "black"}
171-
strokeWidth="2"
172-
strokeLinecap="round"
173-
strokeLinejoin="round"
174-
/>
175-
</svg>
176-
);
177-
}
178-
179-
function areDatesEqual(date1: Date, date2: Date) {
159+
export function areDatesEqual(date1: Date, date2: Date) {
180160
return (
181161
date1.getDate() === date2.getDate() &&
182162
date1.getMonth() === date2.getMonth() &&

apps/nextjs/src/components/activity/activitycreatemodal.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { useForm } from "react-hook-form";
88
import { cn } from "~/lib/utils";
99
import { api } from "~/utils/api";
1010
import type { RouterInputs } from "~/utils/api";
11+
import PlusIcon from "../icons/plusicon";
1112
import { Button } from "../ui/button";
1213
import { Calendar } from "../ui/calendar";
1314
import {
@@ -70,7 +71,10 @@ export default function ActivityCreateModal() {
7071
return (
7172
<Dialog open={open} onOpenChange={setOpen}>
7273
<DialogTrigger asChild>
73-
<Button variant="outline">Create Activity</Button>
74+
<Button variant="default" className="rounded-[24px] bg-[#2E4D90]">
75+
<PlusIcon />
76+
Create
77+
</Button>
7478
</DialogTrigger>
7579

7680
<DialogContent className="p-8 font-semibold">

apps/nextjs/src/components/activity/activityupdatemodal.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useForm } from "react-hook-form";
66
import { cn } from "~/lib/utils";
77
import { api } from "~/utils/api";
88
import type { RouterInputs } from "~/utils/api";
9+
import PencilIcon from "../icons/pencilicon";
910
import { Button } from "../ui/button";
1011
import { Calendar } from "../ui/calendar";
1112
import {
@@ -84,7 +85,9 @@ export default function ActivityUpdateModal({ id }: { id: number }) {
8485
activity.data && (
8586
<Dialog open={open} onOpenChange={setOpen}>
8687
<DialogTrigger asChild>
87-
<Button variant="outline">Update Activity</Button>
88+
<Button variant={"ghost"} size={"icon"}>
89+
{<PencilIcon />}
90+
</Button>
8891
</DialogTrigger>
8992

9093
<DialogContent className="p-8 font-semibold">
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import React from "react";
2+
import { format } from "date-fns";
3+
4+
import { cn } from "~/lib/utils";
5+
import { noSelectedDateStyle, selectedDateStyle } from "./absenteestable";
6+
import ActivityCreateModal from "./activity/activitycreatemodal";
7+
import DropdownIcon from "./icons/dropdownicon";
8+
import Schedule from "./schedule";
9+
import { Button } from "./ui/button";
10+
import { Calendar } from "./ui/calendar";
11+
import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover";
12+
13+
export default function EventsCalendar() {
14+
const [selectedDate, setSelectedDate] = React.useState<Date>();
15+
16+
return (
17+
<div className="p-8">
18+
<div className="flex flex-row justify-between">
19+
<div className="flex flex-row items-center">
20+
<h3 className="pr-3 text-[20px]">Events for</h3>
21+
<Popover>
22+
<PopoverTrigger
23+
asChild
24+
style={selectedDate ? selectedDateStyle : noSelectedDateStyle}
25+
>
26+
<Button
27+
variant={"outline"}
28+
className={cn(
29+
"justify-start text-left font-normal",
30+
!selectedDate && "text-muted-foreground",
31+
)}
32+
style={{ minWidth: "170px" }}
33+
>
34+
{selectedDate ? (
35+
format(selectedDate, "PPP")
36+
) : (
37+
<span>Select Date</span>
38+
)}
39+
{DropdownIcon(!!selectedDate)}
40+
</Button>
41+
</PopoverTrigger>
42+
<PopoverContent className="w-auto p-0">
43+
<Calendar
44+
mode="single"
45+
selected={selectedDate}
46+
onSelect={setSelectedDate}
47+
initialFocus
48+
/>
49+
</PopoverContent>
50+
</Popover>
51+
</div>
52+
<ActivityCreateModal />
53+
</div>
54+
<Schedule selectedDate={selectedDate} />
55+
</div>
56+
);
57+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import React from "react";
2+
3+
export default function DropdownIcon(isSelected: boolean) {
4+
return (
5+
<svg
6+
className="ml-auto h-4 w-4"
7+
width="16"
8+
height="9"
9+
viewBox="0 0 16 9"
10+
fill="none"
11+
xmlns="http://www.w3.org/2000/svg"
12+
>
13+
<path
14+
d="M15 0.999999L8 8L1 1"
15+
stroke={isSelected ? "white" : "black"}
16+
strokeWidth="2"
17+
strokeLinecap="round"
18+
strokeLinejoin="round"
19+
/>
20+
</svg>
21+
);
22+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import React from "react";
2+
3+
export default function PencilIcon() {
4+
return (
5+
<svg
6+
width="20"
7+
height="21"
8+
viewBox="0 0 20 21"
9+
fill="none"
10+
xmlns="http://www.w3.org/2000/svg"
11+
>
12+
<path
13+
d="M13.2322 3.23223L16.7677 6.76777M14.7322 1.73223C15.7085 0.755922 17.2914 0.755922 18.2677 1.73223C19.244 2.70854 19.244 4.29146 18.2677 5.26777L4.5 19.0355H1V15.4644L14.7322 1.73223Z"
14+
stroke="#111827"
15+
strokeWidth="2"
16+
strokeLinecap="round"
17+
strokeLinejoin="round"
18+
/>
19+
</svg>
20+
);
21+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import React from "react";
2+
3+
export default function PlusIcon() {
4+
return (
5+
<svg
6+
width="14"
7+
height="14"
8+
viewBox="0 0 14 14"
9+
fill="none"
10+
xmlns="http://www.w3.org/2000/svg"
11+
>
12+
<path
13+
d="M14 7.99805H8V13.998H6V7.99805H0V5.99805H6V-0.00195312H8V5.99805H14V7.99805Z"
14+
fill="white"
15+
/>
16+
</svg>
17+
);
18+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import React from "react";
2+
import { addMinutes, format } from "date-fns";
3+
4+
import { api } from "~/utils/api";
5+
import ActivityUpdateModal from "./activity/activityupdatemodal";
6+
7+
interface Activity {
8+
name: string;
9+
id: number;
10+
day: Date;
11+
startTime: Date;
12+
durationMinutes: number;
13+
leader: string;
14+
location: string;
15+
}
16+
17+
interface ScheduleProps {
18+
selectedDate: Date | undefined;
19+
}
20+
21+
export default function Schedule(props: ScheduleProps) {
22+
let dailySchedule;
23+
const [activities, setActivities] = React.useState<Activity[]>([]);
24+
25+
if (props.selectedDate) {
26+
({ data: dailySchedule } = api.activity.getDailySchedule.useQuery({
27+
day: props.selectedDate.toISOString().split("T")[0] ?? "",
28+
}));
29+
} else {
30+
({ data: dailySchedule } = api.activity.getDailySchedule.useQuery({
31+
day: new Date().toISOString().split("T")[0] ?? "",
32+
}));
33+
}
34+
35+
React.useEffect(() => {
36+
const sortedActivities = [...(dailySchedule ?? [])].sort(
37+
(a, b) => a.startTime.getTime() - b.startTime.getTime(),
38+
);
39+
setActivities(sortedActivities ?? []);
40+
}, [dailySchedule, props.selectedDate]);
41+
42+
return (
43+
<div className="pt-[32px]">
44+
{props.selectedDate && activities.length > 0 ? (
45+
<div>{activities.map((activity: Activity) => Event(activity))}</div>
46+
) : (
47+
<div className="text-[16px]">
48+
{props.selectedDate
49+
? "No events are scheduled for today"
50+
: "Pick a Date to View Events"}
51+
</div>
52+
)}
53+
</div>
54+
);
55+
}
56+
57+
function Event(activity: Activity) {
58+
return (
59+
<div
60+
key={activity.id}
61+
className="mb-5 flex flex-row items-center justify-start"
62+
>
63+
<div className="w-[100px] font-bold">
64+
{`${format(activity.startTime, "h:mm a")} - ${format(addMinutes(activity.startTime, activity.durationMinutes), "h:mm a")}`}
65+
</div>
66+
<div className="ml-5 w-full rounded-[10px] bg-[#EFF2FB] p-4">
67+
<div className="flex flex-row items-center justify-between">
68+
<div className="font-bold">{activity.name}</div>
69+
<ActivityUpdateModal id={activity.id} />
70+
</div>
71+
</div>
72+
</div>
73+
);
74+
}
Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,15 @@
11
import React from "react";
22

3-
import ActivityCreateModal from "~/components/activity/activitycreatemodal";
4-
import ActivityUpdateModal from "~/components/activity/activityupdatemodal";
3+
import EventsCalendar from "~/components/eventscalendar";
54
import NavBar from "~/components/navbar";
6-
import CreateActivity from "../components/activity/activityform";
7-
import ViewActivities from "../components/activity/viewactivites";
85

9-
const Activities = () => {
6+
export default function Activities() {
107
return (
11-
<div className="relative flex">
8+
<div className="absolute bottom-0 top-0 flex w-full">
129
<NavBar />
13-
<div className="flex-col items-center pl-6 pt-6">
14-
<ActivityUpdateModal id={1} />
15-
<ActivityCreateModal />
16-
<div className="font-medium">Create Activity</div>
17-
<CreateActivity />
18-
<div className="font-medium">View Activites</div>
19-
<ViewActivities />
10+
<div className="flex w-full flex-col justify-start">
11+
<EventsCalendar />
2012
</div>
2113
</div>
2214
);
23-
};
24-
25-
export default Activities;
15+
}

0 commit comments

Comments
 (0)