Skip to content

Commit

Permalink
feat: refactor theme logic & implement AppInfoProvider (#216)
Browse files Browse the repository at this point in the history
  • Loading branch information
diogogmatos authored Jan 7, 2025
1 parent afe452e commit 595f563
Show file tree
Hide file tree
Showing 22 changed files with 579 additions and 814 deletions.
34 changes: 17 additions & 17 deletions components/CalendarExportModal/CalendarExportModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,21 @@ import { useState, useEffect, useCallback } from "react";
import { Collapse } from "antd";

import { IFilterDTO } from "../../dtos";
import { useAppInfo } from "../../contexts/AppInfoProvider";

type CalendarExportModalProps = {
isOpen: boolean;
setIsOpen: (isOpen: boolean) => void;
isHome: boolean;
filters: IFilterDTO[];
};

const CalendarExportModal = ({
isOpen,
setIsOpen,
isHome,
filters,
}: CalendarExportModalProps) => {
const [isCopied, setIsCopied] = useState<boolean>(false);
const [URL, setURL] = useState<string>("");
const info = useAppInfo();
const filters = info.filters as IFilterDTO[];

const generateURL = useCallback((): string => {
// checks if a filter exists for each filterId in checkedEvents
Expand Down Expand Up @@ -49,10 +48,10 @@ const CalendarExportModal = ({

const domain = process.env.NEXT_PUBLIC_DOMAIN;
const baseURL: string =
domain + "/api/export/" + (isHome ? "events" : "schedule") + "?";
domain + "/api/export/" + (info.isEvents ? "events" : "schedule") + "?";

var query: string = "";
if (isHome) {
if (info.isEvents) {
// fecth checked events from localStorage
const checkedEvents: number[] = JSON.parse(
localStorage.getItem("checked")
Expand Down Expand Up @@ -115,7 +114,7 @@ const CalendarExportModal = ({
// still, in an edge case of an empty 'query' string, return empty string (empty URL => warning message on modal)
if (query !== "") return baseURL + query;
else return "";
}, [isHome, filters]);
}, [info.isEvents, filters]);

useEffect(() => {
setURL(generateURL());
Expand Down Expand Up @@ -154,7 +153,7 @@ const CalendarExportModal = ({
{URL === "" ? (
<div id="modal-modal-description" className="text-center">
<i className="bi bi-exclamation-circle-fill text-error"></i>{" "}
{isHome
{info.isEvents
? "Select at least one subject."
: "Select at least one shift."}
</div>
Expand Down Expand Up @@ -196,33 +195,34 @@ const CalendarExportModal = ({
<a className="font-medium">subscribe</a> to your
active{" "}
<a className="font-medium">
{isHome ? "events" : "schedule"}
{info.isEvents ? "events" : "schedule"}
</a>{" "}
in Calendarium, using your favorite calendar app.
</p>
<p>
This means that you will be able to see your{" "}
{isHome ? "events" : "schedule"} in your calendar app,
and add event notifications, change colors and make
other customizations.
{info.isEvents ? "events" : "schedule"} in your
calendar app, and add event notifications, change
colors and make other customizations.
</p>
<p>
Your {isHome ? "events" : "schedule"} will be
Your {info.isEvents ? "events" : "schedule"} will be
automatically synced with Calendarium.
</p>
<p className="rounded-lg bg-blue-500/20 p-3">
<i className="bi bi-info-circle-fill text-blue-500"></i>{" "}
To export your{" "}
<a className="font-medium">
{isHome ? "schedule" : "events"}
{info.isEvents ? "schedule" : "events"}
</a>{" "}
please navigate to{" "}
{isHome ? "/schedule" : "the main page"}.
{info.isEvents ? "/schedule" : "the main page"}.
</p>
<div className="rounded-lg bg-warning/20 p-3">
<i className="bi bi-exclamation-triangle-fill text-warning"></i>{" "}
If you make any changes to your{" "}
{isHome ? "events" : "schedule"} in Calendarium, you
{info.isEvents ? "events" : "schedule"} in
Calendarium, you
{"'"}ll need to{" "}
<a className="font-medium">
re-export and re-subscribe to the calendar
Expand Down Expand Up @@ -342,7 +342,7 @@ const CalendarExportModal = ({
</Collapse.Panel>
</Collapse>
<div className="cursor-pointer select-none text-sm text-neutral-500 dark:text-neutral-400">
{isHome ? (
{info.isEvents ? (
<div title="To export your schedule please go to /schedule.">
<i className="bi bi-info-circle-fill"></i> Currently
exporting your visible{" "}
Expand Down
10 changes: 6 additions & 4 deletions components/ClearSelectionButton/ClearSelectionButton.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { useAppInfo } from "../../contexts/AppInfoProvider";
import ConfirmPopUpButton from "../ConfirmPopUpButton";

const ClearSelectionButton = ({
isHome,
isSettings,
clearSelection,
}: {
isHome: boolean;
isSettings: boolean;
clearSelection: () => void;
}) => {
Expand All @@ -14,11 +13,14 @@ const ClearSelectionButton = ({
"cursor-not-allowed hover:text-error/50 dark:hover:text-red-400/60"
}`;

const info = useAppInfo();

return (
<ConfirmPopUpButton
title={"Are you sure?"}
description={
"This will remove all your selected " + (isHome ? "events." : "shifts.")
"This will remove all your selected " +
(info.isEvents ? "events." : "shifts.")
}
onConfirm={() => clearSelection()}
onCancel={() => {}}
Expand All @@ -31,7 +33,7 @@ const ClearSelectionButton = ({
title: "Clear",
className: classNameData,
"data-umami-event": "clear-selection-button",
"data-umami-event-type": isHome ? "events" : "shifts",
"data-umami-event-type": info.isEvents ? "events" : "shifts",
}}
>
<i className="bi bi-trash-fill"></i>
Expand Down
2 changes: 1 addition & 1 deletion components/CustomToolbar/CustomToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Navigate, ToolbarProps } from "react-big-calendar";
import { Fragment } from "react";
import { Menu, Transition } from "@headlessui/react";

import { useWindowSize } from "../../utils";
import useWindowSize from "../../hooks/useWindowSize";

const MobileToolbar = ({ view, onView }) => {
return (
Expand Down
32 changes: 12 additions & 20 deletions components/EventFilters/EventFilters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,32 @@ import "antd/dist/reset.css";

import FilterBlock from "../FilterBlock";

import { CheckBoxProps, SelectedShift } from "../../types";

import { IFilterDTO } from "../../dtos";
import { CheckBoxProps } from "../../types";
import { IFilterDTO, ISelectedFilterDTO } from "../../dtos";
import { useAppInfo } from "../../contexts/AppInfoProvider";

type EventFiltersProps = {
filters: any;
handleFilters: (selectedFilter: number[]) => void;
clearEvents: boolean;
checked: number[] | SelectedShift[];
setChecked: (obj: number[] | SelectedShift[]) => void;
checked: number[] | ISelectedFilterDTO[];
setChecked: (obj: number[] | ISelectedFilterDTO[]) => void;
};

const EventFilters = ({
filters,
handleFilters,
clearEvents,
checked,
setChecked,
}: EventFiltersProps) => {
const info = useAppInfo();
const filters = info.filters as IFilterDTO[];
const handleFilters = info.handleFilters;

useEffect(() => {
const stored: number[] = JSON.parse(localStorage.getItem("checked")) ?? [];
setChecked(stored);
handleFilters(stored);
}, [setChecked, handleFilters]);

let event: {
map: any;
id: number;
name: string;
groupId: number;
semester: number;
}[][] = [];
let event: IFilterDTO[][] = [];

const mei = ["4ᵗʰ year", "5ᵗʰ year"];

Expand Down Expand Up @@ -74,9 +68,9 @@ const EventFilters = ({

const clearSelection = useCallback(() => {
setChecked([]);
handleFilters([]);
info.handleFilters([]);
localStorage.setItem("checked", JSON.stringify([]));
}, [handleFilters, setChecked]);
}, [info, setChecked]);

useEffect(() => {
clearEvents && clearSelection();
Expand All @@ -91,7 +85,6 @@ const EventFilters = ({
checkBoxes={getCheckBoxes().slice(0, 6)}
checked={checked}
setChecked={setChecked as (v: number[]) => void}
handleFilters={handleFilters}
isShifts={false}
/>
{/* MEI */}
Expand All @@ -102,7 +95,6 @@ const EventFilters = ({
checked={checked}
setChecked={setChecked as (v: number[]) => void}
exception={1}
handleFilters={handleFilters}
isShifts={false}
/>
</>
Expand Down
26 changes: 7 additions & 19 deletions components/ExportButton/ExportButton.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
import { Fragment, useState } from "react";
import { Menu, Transition } from "@headlessui/react";

import { useState } from "react";
import CalendarExportModal from "../CalendarExportModal";
import { useAppInfo } from "../../contexts/AppInfoProvider";

import { IFilterDTO } from "../../dtos";

type ExportButtonProps = {
isHome: boolean;
filters: IFilterDTO[];
};

const ExportButton = ({ isHome, filters }: ExportButtonProps) => {
const [isModalOpen, setIsModalOpen] = useState(false);
const ExportButton = () => {
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);
const info = useAppInfo();

return (
<div className="w-full">
Expand All @@ -20,17 +13,12 @@ const ExportButton = ({ isHome, filters }: ExportButtonProps) => {
title="Export"
className="h-10 w-full rounded-xl p-2 font-medium leading-3 text-neutral-300 shadow-md ring-1 ring-neutral-200/50 transition-all duration-300 hover:text-neutral-900 hover:shadow-lg dark:bg-neutral-800/70 dark:text-neutral-500 dark:ring-neutral-400/20 dark:hover:text-neutral-200"
data-umami-event="export-button"
data-umami-event-type={isHome ? "events" : "shifts"}
data-umami-event-type={info.isEvents ? "events" : "shifts"}
>
Export <i className="bi bi-box-arrow-up"></i>
</button>

<CalendarExportModal
isOpen={isModalOpen}
setIsOpen={setIsModalOpen}
isHome={isHome}
filters={filters}
/>
<CalendarExportModal isOpen={isModalOpen} setIsOpen={setIsModalOpen} />
</div>
);
};
Expand Down
32 changes: 18 additions & 14 deletions components/FilterBlock/FilterBlock.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import "antd/dist/reset.css";

import { Fragment } from "react";

import { CheckBoxProps, SelectedShift } from "../../types";
import { CheckBoxProps } from "../../types";
import { ISelectedFilterDTO } from "../../dtos";
import { useAppInfo } from "../../contexts/AppInfoProvider";

type FilterBlockProps = {
layer1: string[]; // contains the titles for the collapses of the 1st layer
layer2?: string[]; // contains the titles for the collapses of the 2nd layer
checkBoxes: CheckBoxProps[][]; // contains the checkboxes information in a universal format
exception?: number; // indicates the index of an element from layer1 where the layer2 should be ignored, for example "5th year"
checked: number[] | SelectedShift[]; // assumes different types when called from ScheduleFilters.tsx and EventFilters.tsx
setChecked: (obj: number[] | SelectedShift[]) => void; // assumes different types when called from ScheduleFilters.tsx and EventFilters.tsx
handleFilters: any; // assumes different types when called from ScheduleFilters.tsx and EventFilters.tsx
checked: number[] | ISelectedFilterDTO[]; // assumes different types when called from ScheduleFilters.tsx and EventFilters.tsx
setChecked: (obj: number[] | ISelectedFilterDTO[]) => void; // assumes different types when called from ScheduleFilters.tsx and EventFilters.tsx
isShifts: boolean; // used to know if FilterBlock is being called from ScheduleFilters.tsx or EventFilters.tsx
};

Expand All @@ -23,9 +24,10 @@ const FilterBlock = ({
exception,
checked,
setChecked,
handleFilters,
isShifts,
}: FilterBlockProps) => {
const info = useAppInfo();

// "Select All" checkbox
const SelectAll = ({
index1,
Expand Down Expand Up @@ -103,7 +105,7 @@ const FilterBlock = ({
else newCheck.splice(currentIdIndex, 1);

setChecked(newCheck);
handleFilters(newCheck);
info.handleFilters(newCheck);
localStorage.setItem("checked", JSON.stringify(newCheck));
}

Expand All @@ -120,7 +122,7 @@ const FilterBlock = ({
}

setChecked(newChecked);
handleFilters(newChecked);
info.handleFilters(newChecked);
localStorage.setItem("checked", JSON.stringify(newChecked));
}

Expand Down Expand Up @@ -226,31 +228,33 @@ const FilterBlock = ({

// Handles the toggle of a checkbox containing a shift (only used for Schedule)
function handleShiftToggle(id: number, shift: string) {
const currentIdIndex = (checked as SelectedShift[]).findIndex(
(selectedShift: SelectedShift) =>
const currentIdIndex = (checked as ISelectedFilterDTO[]).findIndex(
(selectedShift: ISelectedFilterDTO) =>
selectedShift.id === id && selectedShift.shift === shift
);
const newChecked: SelectedShift[] = [...checked] as SelectedShift[];
const newChecked: ISelectedFilterDTO[] = [
...checked,
] as ISelectedFilterDTO[];

const shiftObj: SelectedShift = { id: id, shift: shift };
const shiftObj: ISelectedFilterDTO = { id: id, shift: shift };
if (currentIdIndex === -1) newChecked.push(shiftObj);
else newChecked.splice(currentIdIndex, 1);

setChecked(newChecked);
handleFilters(newChecked);
info.handleFilters(newChecked);
localStorage.setItem("shifts", JSON.stringify(newChecked));
}

// Checks if a specific shift is selected (checked) (only used for Schedule)
const isShiftChecked = (id: number, shift: string): boolean => {
return (checked as SelectedShift[]).some((shiftObj) => {
return (checked as ISelectedFilterDTO[]).some((shiftObj) => {
return id === shiftObj.id && shift === shiftObj.shift;
});
};

// Checks if some shift under a certain subject is selected (checked) (only used for Schedule)
const isSomeSubjectShiftChecked = (id: number): boolean => {
return (checked as SelectedShift[]).some((s) => s.id === id);
return (checked as ISelectedFilterDTO[]).some((s) => s.id === id);
};

// Checks if a shift that falls under a Collapse from the 2nd layer is selected (checked) (only used for Schedule)
Expand Down
Loading

0 comments on commit 595f563

Please sign in to comment.