Skip to content

Commit

Permalink
Merge pull request #53 from Genio2003/feat/classroomFullScreen
Browse files Browse the repository at this point in the history
Feat/classroom full screen
  • Loading branch information
Genio2003 authored Feb 23, 2024
2 parents 4bd9919 + 3bbd484 commit 9789c9d
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 9 deletions.
22 changes: 20 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { Home } from "./routes/Home";
import { LoginForm } from "./routes/LoginForm";
import { NotFound } from "./routes/NotFound";
import { UserContext } from "./context/UserContext";
import { ClassroomViewer } from "./routes/ClassroomViewer";

const useStyles = makeStyles({
root: {
Expand Down Expand Up @@ -93,6 +94,10 @@ function App() {
path="/login"
element={<LoginForm />}
/>
<Route
path="/viewer"
element={<ClassroomViewer />}
/>
{token && <Route
path="/"
element={<Wrapper />}
Expand Down
35 changes: 29 additions & 6 deletions src/components/EventDetails.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Body1, Body2, Card, Subtitle2, makeStyles, mergeClasses, tokens } from "@fluentui/react-components";
import { Body1, Body2, Card, Subtitle1, Subtitle2, Title1, Title2, Title3, makeStyles, mergeClasses, tokens } from "@fluentui/react-components";
import { FunctionComponent, useContext, useEffect, useState } from "react";
import { TimekeeperContext } from "../context/TimekeeperContext";
import { EventDto } from "../dto/EventDto";
Expand All @@ -19,6 +19,10 @@ export type EventDetailsProps = {
* The title to be displayed if the `title` property is set to `custom`.
*/
customTitle?: string;
/**
* The size of the title.
*/
titleSize?: "small" | "medium" | "large" | "huge";
/**
* The background color of the card. If not provided, the default background color will be used.
*/
Expand All @@ -27,6 +31,10 @@ export type EventDetailsProps = {
* Whether to make the course label a link to see the calendar of the course. Defaults to `false`.
*/
linkToCalendar?: boolean;
/**
* The subtitle to be displayed.
*/
subtitle?: string;
/**
* The properties to hide. If not provided, all properties will be displayed.
*/
Expand Down Expand Up @@ -55,7 +63,13 @@ const useStyles = makeStyles({
":hover": {
color: "inherit",
},
}
},
text: {
display: "block",
overflowX: "hidden",
whiteSpace: "nowrap",
textOverflow: "ellipsis",
},
});

/**
Expand All @@ -66,6 +80,7 @@ const EventDetails: FunctionComponent<EventDetailsProps> = (props: EventDetailsP
const styles = useStyles();
const globalStyles = useGlobalStyles();

const titleSize = props.titleSize ?? "small";
const time = `${getClockEmoji(props.event.start)} ${props.event.start.toLocaleString([], { timeStyle: "short" })} - ${props.event.end.toLocaleString([], { timeStyle: "short" })}`;
const subject = `\u{1F4BC} ${props.event.subject}`;
const classroom = `\u{1F4CD} Aula ${props.event.classroom.name}`;
Expand All @@ -81,10 +96,10 @@ const EventDetails: FunctionComponent<EventDetailsProps> = (props: EventDetailsP
title = classroom;
break;
case "custom":
title = props.customTitle || "eventDetails";
title = props.customTitle || "Missing custom title";
break;
default:
title = "eventDetails";
title = "Missing title type";
}

const [now, setNow] = useState(() => new Date());
Expand All @@ -98,7 +113,15 @@ const EventDetails: FunctionComponent<EventDetailsProps> = (props: EventDetailsP

const content = (
<div className={styles.root}>
<Subtitle2>{title}</Subtitle2>
{titleSize === "huge" && <Title1 className={styles.text}>{title}</Title1>}
{props.subtitle && titleSize === "huge" && <Title3 className={styles.text}>{props.subtitle}</Title3>}
{titleSize === "large" && <Title2 className={styles.text}>{title}</Title2>}
{props.subtitle && titleSize === "large" && <Subtitle1 className={styles.text}>{props.subtitle}</Subtitle1>}
{titleSize === "medium" && <Subtitle1 className={styles.text}>{title}</Subtitle1>}
{props.subtitle && titleSize === "medium" && <Body1 className={styles.text}>{props.subtitle}</Body1>}
{titleSize === "small" && <Subtitle2 className={styles.text}>{title}</Subtitle2>}
{props.subtitle && titleSize === "small" && <Body1 className={styles.text}>{props.subtitle}</Body1>}

{now && props.event.start <= now && props.event.end > now && <Body2 className={globalStyles.blink}>{"\u{1F534}"} In corso</Body2>}
<div className={styles.body}>
{props.title !== "time" && !props.hide?.includes("time") && <Body1>{time}</Body1>}
Expand All @@ -123,4 +146,4 @@ const EventDetails: FunctionComponent<EventDetailsProps> = (props: EventDetailsP
) : content;
};

export default EventDetails;
export default EventDetails;
1 change: 1 addition & 0 deletions src/globalStyles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const useGlobalStyles = makeStyles({
grid: {
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(16rem, 1fr))",
gridAutoRows: "1fr",
...shorthands.gap("1rem"),
...shorthands.margin("1rem"),
"@media screen and (max-width: 578px)": {
Expand Down
6 changes: 6 additions & 0 deletions src/main.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,10 @@ h4,
h5,
h6 {
margin-top: 0;
}

@keyframes marqueeScroll {
to {
transform: translate3d(0, 0, 0);
}
}
9 changes: 8 additions & 1 deletion src/routes/Classroom.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ import { ClassroomDto } from "../dto/ClassroomDto";
import { ClassroomStatus } from "../dto/ClassroomStatus";
import { EventDto } from "../dto/EventDto";
import { useGlobalStyles } from "../globalStyles";
import { FullScreenMaximizeFilled } from "@fluentui/react-icons";
import getClockEmoji from "../libraries/clockEmoji/clockEmoji";
import useRequests from "../libraries/requests/requests";
import { RouterButton } from "../components/router/RouterButton";

const useLightStyles = makeStyles({
cardFree: {
Expand Down Expand Up @@ -162,7 +164,12 @@ export function Classroom() {
<Card className={globalStyles.titleBar}>
<CardHeader
header={<Title2>🏫 Stato Aule</Title2>}
action={showSideSpinner ? <Spinner size="small" /> : undefined}
action={
<>
{showSideSpinner ? <Spinner size="small" /> : undefined}
{<RouterButton as="a" icon={<FullScreenMaximizeFilled />} href="/viewer" />}
</>
}
/>
<CardFooter className={styles.toolbar}>
<DateSelector autoUpdate={true} inputType="hour" dateTime={dateTime} setDateTime={(newDateTime, autoUpdated) => {
Expand Down
144 changes: 144 additions & 0 deletions src/routes/ClassroomViewer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { Body1, Card, CardHeader, Divider, Spinner, Subtitle2, Title1, makeStyles, mergeClasses, tokens, webLightTheme } from "@fluentui/react-components";
import { useContext, useEffect, useState } from "react";
import { ClassroomStatus } from "../dto/ClassroomStatus";
import { useGlobalStyles } from "../globalStyles";
import { EventDto } from "../dto/EventDto";
import EventDetails from "../components/EventDetails";
import { ThemeContext } from "../context/ThemeContext";
import useRequests from "../libraries/requests/requests";

const useLightStyles = makeStyles({
cardFree: {
backgroundColor: tokens.colorPaletteLightGreenBackground2,
},
cardAboutToBeBusy: {
backgroundColor: tokens.colorStatusWarningBackground2,
},
cardBusy: {
backgroundColor: tokens.colorPaletteRedBackground2,
},
});

const useDarkStyles = makeStyles({
cardFree: {
backgroundColor: tokens.colorPaletteLightGreenBackground2,
},
cardAboutToBeBusy: {
backgroundColor: tokens.colorStatusWarningBackground2,
},
cardBusy: {
backgroundColor: tokens.colorPaletteRedBackground2,
}
});

export function ClassroomViewer() {
const theme = useContext(ThemeContext).themeValue;
const globalStyles = useGlobalStyles();
const themeStyles = theme === webLightTheme ? useLightStyles() : useDarkStyles();

const requests = useRequests();

const [now, setNow] = useState(new Date());
const [classrooms, setClassrooms] = useState<ClassroomStatus[] | null>(null);
const [currentFloor, setCurrentFloor] = useState(1);

useEffect(() => {
// First data fetch
getClassroomsStatus();

// Fetch classrooms status every 10 seconds
const interval = setInterval(() => {
setCurrentFloor((oldValue) => {
if (oldValue === 3) {
getClassroomsStatus(); // Refresh when all data has been shown
setNow(new Date());
}
return oldValue === 3 ? 1 : oldValue + 1;
});
}, 15000);

return () => clearInterval(interval);
}, []);

const getClassroomsStatus = () => {
requests.classroom.status(now)
.then(setClassrooms)
.catch(console.error);
};

const renderFloor = (floor: number, classrooms: ClassroomStatus[]) => {
const filtered = classrooms.filter((item) => item.classroom.name[0] === floor.toString());

return (
<>
<Card className={globalStyles.card}>
<CardHeader
header={<Title1>🏢 {floor}° Piano</Title1>}
/>
</Card>
<div className={globalStyles.grid}>
{renderClassrooms(filtered)}
</div>
</>
);
};

const renderClassrooms = (filtered: ClassroomStatus[]) => {
const getBackgroundColor = (item: ClassroomStatus) => {
if (!item.status.isFree) {
return themeStyles.cardBusy;
}
else if (item.status.currentOrNextEvent &&
item.status.currentOrNextEvent.start.getDate() === now.getDate() &&
(now.getTime() >= (item.status.currentOrNextEvent.start.getTime() - 10 * 60 * 1000)) &&
(now.getTime() <= item.status.currentOrNextEvent.start.getTime())) {
return themeStyles.cardAboutToBeBusy;
} else {
return themeStyles.cardFree;
}
};

return filtered.map((item) => {
const getDividerText = () => {
if (item.status.statusChangeAt && item.status.statusChangeAt.getDate() === now.getDate())
return `${item.status.isFree ? "Libera" : "Occupata"} fino alle ${item.status.statusChangeAt.toLocaleTimeString([], { timeStyle: "short" })}`;
else
return "Libera";
};

return (
<Card key={item.classroom.id} className={mergeClasses(globalStyles.card, getBackgroundColor(item))}>
<CardHeader
header={<Title1>Aula {item.classroom.name.split(" ")[0]}</Title1>}
/>
<div>
<Divider><Body1>{getDividerText()}</Body1></Divider>
{renderEvent(item.status.currentOrNextEvent)}
</div>
</Card>
);
});
};

const renderEvent = (event: EventDto | null) => {
if (event && event.start.getDate() === now.getDate() && event.end > now) {
return <EventDetails
event={event}
titleSize="large"
subtitle={event.course.name}
hide={["classroom", "course"]}
title="custom"
customTitle={event.course.code}
/>;
}
else {
return <Subtitle2>Nessuna lezione</Subtitle2>;
}
};

return (
<div className={globalStyles.container}>
{classrooms ? renderFloor(currentFloor, classrooms) : <Spinner label="Caricamento..." />}
</div>
);
}

0 comments on commit 9789c9d

Please sign in to comment.