Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2c54071
fix(frontend): fix landing page responsive design
Oct 23, 2025
9b76994
fix(frontend) fix mobile sidebar layout
Oct 23, 2025
4d708a2
fix(frontend): fix mobile sidebar not closing when navigating
Oct 23, 2025
8a374a7
fix(frontend): fix day cards mobile layout
Oct 23, 2025
c38c719
feat(frontend): add content transition wrapper to transition initial …
Oct 23, 2025
162890d
fix(frontend): fix sidebar not closing when navigating via custom sho…
Oct 23, 2025
8bdaa42
fix(frontend): separate no data ui for fetch failed and fetch success…
Oct 23, 2025
45313bd
fix(frontend): fix responsive design of the student profile layout in…
Oct 23, 2025
ce41fad
refactor(frontend): add reusables folder for organization
Oct 23, 2025
ec8dd1a
fix(frontend): remove unecessary error components and utilize next.js…
Oct 24, 2025
97bbc95
feat(frontend): add global 404 not found page
Oct 24, 2025
0b2d75b
refactor(frontend): add animo-dev-badge component for org gradient br…
Oct 24, 2025
657f519
fix(frontend): fix range page overflowing on mobile screen
Oct 24, 2025
2780e11
feat(frontend): add tabs in date range page instead of scrolling to e…
Oct 24, 2025
ebc4636
fix(frontend): fix header not sticky on top in mobile view
Oct 24, 2025
baaffe2
fix(frontend): fix load data failed on fetch using relative path
Oct 24, 2025
1de122f
fix(frontend): fix page and layout height inconsistency by using dvh
Oct 24, 2025
095c054
fix(frontend): fix overflowing error component styling and add global…
Oct 24, 2025
1d333f5
style(frontend): styling for loading.tsx in pages
Oct 24, 2025
9264398
fix(frontend): fix loading not showing when searching for the same st…
Oct 24, 2025
583c7ac
chore(frontend): remove unecessary loading.tsx files
Oct 24, 2025
071f38e
fix(frontend): add missing styles that cause overflow in main
Oct 24, 2025
5c97a1b
fix(frontend): fix load failed on the new student-on-date.tsx component
Oct 24, 2025
7e962e6
fix(frontend): title for range-attendance-table.tsx overflow on mobil…
Oct 24, 2025
d4c142e
feat(frontend): remove share button feature
Oct 24, 2025
66e19af
feat(frontend): add suspense loading fallback in main layout
Oct 24, 2025
7956435
fix(frontend): fix alert message truncate on mobile view
Oct 24, 2025
d8dc7aa
style(frontend): improve main layout loader styling and refactor into…
Oct 24, 2025
80c0e8e
style(frontend): improve loader styling for range-attendance-table.tsx
Oct 24, 2025
2553d4f
style(frontend): improve student page loader component
Oct 24, 2025
ac8a82a
style(frontend): improve single date page loader component
Oct 24, 2025
ebd67a8
fix(frontend): move the suspense to just the days sidebar to avoid th…
Oct 24, 2025
cabf4b9
fix(frontend): add dates initial null value and cache
Oct 24, 2025
f63b123
fix(frontend): fix day-card layout
Oct 24, 2025
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: 2 additions & 2 deletions app/(main)/account/page.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {
BentoContainer,
BentoContainerHeader,
} from "@/components/bento-container";
import { Title, Description, SubTitle } from "@/components/texts";
} from "@/components/reusables/bento-container";
import { Title, Description, SubTitle } from "@/components/reusables/texts";
import AccountField from "@/components/account/account-field";
import { Button } from "@/components/ui/button";
import { LogOut } from "lucide-react";
Expand Down
13 changes: 9 additions & 4 deletions app/(main)/day/[date]/loading.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
import { Skeleton } from "@/components/ui/skeleton";

const Loading = () => {
return (
<div>
Loading...
<div className="flex flex-col h-full w-full p-4">
<Skeleton className="h-10 w-1/4 mb-4" />
<Skeleton className="h-6 w-1/4 mb-4" />
<Skeleton className="flex-1 w-full" />

</div>
)
);
};

export default Loading;
export default Loading;
16 changes: 2 additions & 14 deletions app/(main)/day/[date]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
import { Suspense } from "react";
import AttendanceTableServer from "@/components/attendance-table/attendance-table-server";
import Loader from "@/components/loader";

interface SingleDayPageProps {
// When a page component is async, Next.js may provide params as a thenable.
Expand All @@ -11,19 +9,9 @@ const SingleDayPage = async ({ params }: SingleDayPageProps) => {

return (
<div className="flex h-full w-full">
<Suspense
fallback={
<Loader
className="w-full bg-background"
mainText="Loading record data..."
subText="Please wait while we fetch the records"
/>
}
>
<AttendanceTableServer className="w-full h-full" date={date} />
</Suspense>
<AttendanceTableServer className="w-full h-full" date={date} />
</div>
);
};

export default SingleDayPage;
export default SingleDayPage;
9 changes: 0 additions & 9 deletions app/(main)/day/range/loading.tsx

This file was deleted.

10 changes: 10 additions & 0 deletions app/(main)/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use client";

import { ErrorBoundaryProps } from "@/lib/error-types";
import FetchFailed from "@/components/error/fetch-failed";

const ErrorPage: React.FC<ErrorBoundaryProps> = ({ error, reset }) => {
return <FetchFailed error={error} reset={reset} />;
};

export default ErrorPage;
9 changes: 0 additions & 9 deletions app/(main)/home/loading.tsx

This file was deleted.

61 changes: 45 additions & 16 deletions app/(main)/home/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
import {
BentoContainer,
BentoContainerHeader,
} from "@/components/bento-container";
import { Description, Title } from "@/components/texts";
} from "@/components/reusables/bento-container";
import { Description, Title } from "@/components/reusables/texts";
import { useDates } from "@/context/dates-context";
import {
DayCards,
Expand All @@ -13,11 +13,15 @@ import {
} from "@/components/days/day-cards";
import { groupDatesByMonth } from "@/lib/utils";
import { ScrollArea } from "@/components/ui/scroll-area";
import AlertMessage from "@/components/alert-message";
import AlertMessage from "@/components/reusables/alert-message";
import { Skeleton } from "@/components/ui/skeleton";

const HomePage = () => {
const { dates } = useDates();
const groupedDates = groupDatesByMonth(dates);
const groupedDates = dates ? groupDatesByMonth(dates) : {};

const isLoading = dates === null;
const isEmpty = dates && dates.length === 0;

return (
<ScrollArea className="flex-1 overflow-auto" type="always">
Expand All @@ -30,20 +34,45 @@ const HomePage = () => {
</Description>
</BentoContainerHeader>

<AlertMessage title="If a date does not appear below, refresh the page or it meansthat there is no report for that day" />

{Object.entries(groupedDates).map(([monthYear, days]) => (
<DayCardsContainer key={monthYear} title={monthYear}>
<DayCards>
{days.map((item) => (
<DayCardItem item={item} key={item.id} />
))}
</DayCards>
</DayCardsContainer>
))}
{isLoading && (
<div className="flex-1 space-y-4">
{Array.from({ length: 2 }).map((_, monthIndex) => (
<div key={monthIndex} className="space-y-2">
<Skeleton className="h-6 w-32 rounded-md" />
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-4">
{Array.from({ length: 4 }).map(
(_, dayIndex) => (
<Skeleton
key={dayIndex}
className="h-32 w-full rounded-md"
/>
)
)}
</div>
</div>
))}
</div>
)}

{isEmpty && (
<AlertMessage title="No reports are available for any day." />
)}

{!isLoading &&
!isEmpty &&
Object.entries(groupedDates).map(([monthYear, days]) => (
<DayCardsContainer key={monthYear} title={monthYear}>
<DayCards>
{days.map((item) => (
<DayCardItem item={item} key={item.id} />
))}
</DayCards>
</DayCardsContainer>
))}
</BentoContainer>
</ScrollArea>
);
};

export default HomePage;

export default HomePage;
42 changes: 25 additions & 17 deletions app/(main)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,41 @@
import { LoadingProvider } from "@/context/loading-context";
import { SidebarOpenProvider } from "@/context/sidebar-open-context";
import { DatesProvider } from "@/context/dates-context";
import Header from "@/components/header";
import { Toaster } from "sonner";
import React from "react";
import DaysSidebarServer from "@/components/days/days-sidebar-server";
import { Toaster } from "sonner";
import NextTopLoader from "nextjs-toploader";
import { DatesProvider } from "@/context/dates-context";
import React, { Suspense } from "react";
import DaysSidebarLoader from "@/components/days/days-sidebar-loader";

export const dynamic = "force-dynamic";

interface MainLayoutProps {
children: React.ReactNode;
}

const MainLayout: React.FC<MainLayoutProps> = ({ children }) => {
return (
<div>
<NextTopLoader />
<LoadingProvider>
<Header />
<main className="w-full h-[calc(100vh-3rem)] lg:p-8 flex flex-col lg:flex-row items-stretch gap-4">
<DatesProvider>
<DaysSidebarServer className="lg:basis-[20%] lg:shrink-0 lg:grow-0" />
<section className="flex-1 flex flex-col ">
{children}
</section>
</DatesProvider>
<LoadingProvider>
<SidebarOpenProvider>
<div className="flex flex-col h-[100dvh] overflow-hidden">
<NextTopLoader />
<Header />

<main className="flex-1 overflow-y-auto flex flex-col lg:flex-row gap-4 lg:p-8">
<DatesProvider>
<Suspense fallback={<DaysSidebarLoader />}>
<DaysSidebarServer className="lg:basis-[20%] shrink-0" />
</Suspense>
<section className="flex-1 flex flex-col">
{children}
</section>
</DatesProvider>
</main>
<Toaster />
</main>
</LoadingProvider>
</div>
</div>
</SidebarOpenProvider>
</LoadingProvider>
);
};

Expand Down
15 changes: 0 additions & 15 deletions app/(main)/student/[studentId]/loading.tsx

This file was deleted.

111 changes: 2 additions & 109 deletions app/(main)/student/[studentId]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,4 @@
import { AttendanceRecordResponse } from "@/lib/types";
import {
fetchJSON,
formatDateForRender,
formatTimeForRender,
} from "@/lib/utils";

import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "@/components/ui/table";
import { BentoContainer } from "@/components/bento-container";
import { Description, SubTitle, Title } from "@/components/texts";
import { ScrollArea } from "@/components/ui/scroll-area";
import NoDataMessage from "@/components/no-data-message";
import StudentOnDate from "@/components/student/student-on-date";

interface StudentOnDatePageProps {
// params of the studentId
Expand All @@ -32,96 +14,7 @@ const StudentOnDatePage: React.FC<StudentOnDatePageProps> = async ({
const studentId = (await params).studentId;
const date = (await searchParams).date;

const route =
process.env.NEXT_PUBLIC_BASE_URL +
`/api/reports/student/${studentId}?date=${date}`;

const data = await fetchJSON<AttendanceRecordResponse>(route);

if (!data.success) return <NoDataMessage />

const student = [
{
label: "Partner Id",
value:
data.data.length > 0 ? data.data[0].partner_id : "Unknown ID",
},
{
label: "Email",
value:
data.data.length > 0
? data.data[0].email_address
: "Unknown Email",
},
{
label: "Section",
value:
data.data.length > 0
? data.data[0].department
: "Unknown Section",
},
];

// Format the data.data to just the checkIn and check_out fields
const formattedData = data.data.map((item) => {
return {
checkIn: item.checkIn,
check_out: item.check_out,
};
});

return (
<div className="flex flex-col h-full w-full space-y-8">
<div>
<Title>
Student Record for {studentId} on{" "}
{formatDateForRender(date)}
</Title>
<Description>
If data is missing, it means the student did not check in or out
on that date. Refresh the page if you believe this is an error.
</Description>
</div>

{/* STUDENT PROFILE */}
<section className="grid grid-cols-3 gap-4">
{student.map(({ value, label }) => (
<BentoContainer
key={label}
className="space-y-12 px-6 bg-gradient-to-tl from-[#f9f5ff] via-[#f0e7ff] to-[#e2d9ff] shadow-md transition h-[10rem] hover:border-2 hover:border-purple-200 flex flex-col justify-between"
>
<SubTitle>{value}</SubTitle>
<Description>{label}</Description>
</BentoContainer>
))}
</section>

<div className="flex-1 min-h-0">
<ScrollArea className="h-full w-full">
<Table>
<TableHeader>
<TableRow>
<TableHead>Check In</TableHead>
<TableHead>Check Out</TableHead>
</TableRow>
</TableHeader>
<TableBody>
{formattedData.map((item, index) => (
<TableRow key={index}>
<TableCell>
{formatTimeForRender(item.checkIn)}
</TableCell>
<TableCell>
{formatTimeForRender(item.check_out)}
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</ScrollArea>
</div>
</div>
);
return <StudentOnDate studentId={studentId} date={date} />;
};

export default StudentOnDatePage;
10 changes: 10 additions & 0 deletions app/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use client";

import { ErrorBoundaryProps } from "@/lib/error-types";
import FetchFailed from "@/components/error/fetch-failed";

const ErrorPage: React.FC<ErrorBoundaryProps> = ({ error, reset }) => {
return <FetchFailed error={error} reset={reset} showMessage={false} />;
};

export default ErrorPage;
Loading