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

feat: refactor theme logic & implement AppInfoProvider #216

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
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
8 changes: 5 additions & 3 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 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
20 changes: 3 additions & 17 deletions components/ExportButton/ExportButton.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import { Fragment, useState } from "react";
import { Menu, Transition } from "@headlessui/react";

import CalendarExportModal from "../CalendarExportModal";

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);

return (
<div className="w-full">
Expand All @@ -23,12 +14,7 @@ const ExportButton = ({ isHome, filters }: ExportButtonProps) => {
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
Loading