From 74aac3cfa839a6e7d30bb8d3a1bc7bbb40f346b9 Mon Sep 17 00:00:00 2001 From: Rodrigo Nunes Date: Thu, 14 Nov 2024 17:30:24 +0000 Subject: [PATCH 1/4] Feature: Button that allows the user to switch the side where the sidebar is displayed --- src/App.tsx | 57 ++++++++++++----------- src/components/layout/Header.tsx | 18 ++++++- src/components/layout/SidebarPosition.tsx | 31 ++++++++++++ src/pages/TimeTableSelector.tsx | 36 ++++++++++---- 4 files changed, 103 insertions(+), 39 deletions(-) create mode 100644 src/components/layout/SidebarPosition.tsx diff --git a/src/App.tsx b/src/App.tsx index 8c511a0b..23d4118c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,6 +7,7 @@ import { AboutPage, TimeTableSelectorPage, FaqsPage, NotFoundPage } from './page import { getPath, config, dev_config, plausible } from './utils' import Layout from './components/layout' import * as Sentry from "@sentry/react"; +import { SidebarProvider } from "./components/layout/SidebarPosition"; const configToUse = Number(import.meta.env.VITE_APP_PROD) ? config : dev_config @@ -60,33 +61,35 @@ const App = () => { const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes); return ( - - - - {pages.map((page, pageIdx) => ( - -
- - -
- - } - /> - ))} - {redirects.map((redirect, redirectIdx) => ( - } - /> - ))} -
-
-
+ + + + + {pages.map((page, pageIdx) => ( + +
+ + +
+ + } + /> + ))} + {redirects.map((redirect, redirectIdx) => ( + } + /> + ))} +
+
+
+
) } diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 98702132..678bb955 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -8,9 +8,11 @@ import { AtSymbolIcon, RectangleStackIcon, QuestionMarkCircleIcon, + ArrowsRightLeftIcon, } from '@heroicons/react/24/outline' import { LogoNIAEFEUPImage } from '../../images' import { getPath, config } from '../../utils' +import { useSidebarContext } from './SidebarPosition' const navigation = [ { @@ -34,6 +36,8 @@ type Props = { } const Header = ({ siteTitle, location }: Props) => { + const { toggleSidebarPosition } = useSidebarContext(); + return ( { ))} -
+
+ + +
- + + +
diff --git a/src/components/layout/SidebarPosition.tsx b/src/components/layout/SidebarPosition.tsx new file mode 100644 index 00000000..82365956 --- /dev/null +++ b/src/components/layout/SidebarPosition.tsx @@ -0,0 +1,31 @@ +import { createCheckboxScope } from "@radix-ui/react-checkbox"; +import { Children, createContext, useContext, useState } from "react"; + +type SidebarContextType = { + sidebarPosition: 'left' | 'right'; + toggleSidebarPosition: () => void; +}; + +const SidebarContext = createContext(undefined); + +export const SidebarProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [sidebarPosition, setSidebarPosition] = useState<'left' | 'right'>('right'); + + const toggleSidebarPosition = () => { + setSidebarPosition((prev) => (prev === 'right' ? 'left' : 'right')); + }; + + return ( + + {children} + + ); +}; + +export const useSidebarContext = () => { + const context = useContext(SidebarContext); + if (!context) { + throw new Error('useSidebarContext must be used within a SidebarProvider') + } + return context +} \ No newline at end of file diff --git a/src/pages/TimeTableSelector.tsx b/src/pages/TimeTableSelector.tsx index 9eb6f343..4e140c27 100644 --- a/src/pages/TimeTableSelector.tsx +++ b/src/pages/TimeTableSelector.tsx @@ -5,6 +5,7 @@ import { Schedule, Sidebar } from '../components/planner' import { CourseInfo, Major } from '../@types' import MajorContext from '../contexts/MajorContext' import CourseContext from '../contexts/CourseContext' +import { useSidebarContext } from '../components/layout/SidebarPosition' const TimeTableSelectorPage = () => { const [majors, setMajors] = useState([]) @@ -12,6 +13,7 @@ const TimeTableSelectorPage = () => { const [pickedCourses, setPickedCourses] = useState(StorageAPI.getPickedCoursesStorage()); const [checkboxedCourses, setCheckboxedCourses] = useState(StorageAPI.getPickedCoursesStorage()); const [ucsModalOpen, setUcsModalOpen] = useState(false); + const { sidebarPosition } = useSidebarContext(); //TODO: Looks suspicious const [choosingNewCourse, setChoosingNewCourse] = useState(false); @@ -21,6 +23,8 @@ const TimeTableSelectorPage = () => { setMajors(majors) }) }, []) + + return ( { } }>
- {/* Schedule Preview */} -
-
+ {sidebarPosition === 'left' ?( + <> +
+ +
+
+ +
+ + ) : ( + <> +
-
-
- - +
+
+ +
+ + )}
- ) -} + ); +}; + -export default TimeTableSelectorPage; +export default TimeTableSelectorPage; \ No newline at end of file From c13c804767159f3cb6aa88d9e5d37011e6f0eeb7 Mon Sep 17 00:00:00 2001 From: Rodrigo Nunes Date: Wed, 20 Nov 2024 18:28:56 +0000 Subject: [PATCH 2/4] Changed the position of the button and changed the location of the code to the desired location --- src/components/layout/Header.tsx | 18 +-- .../sidebar/CoursesController/ClassItem.tsx | 2 +- .../sessionController/CoursePicker.tsx | 109 ++++++++++-------- 3 files changed, 63 insertions(+), 66 deletions(-) diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 678bb955..98702132 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -8,11 +8,9 @@ import { AtSymbolIcon, RectangleStackIcon, QuestionMarkCircleIcon, - ArrowsRightLeftIcon, } from '@heroicons/react/24/outline' import { LogoNIAEFEUPImage } from '../../images' import { getPath, config } from '../../utils' -import { useSidebarContext } from './SidebarPosition' const navigation = [ { @@ -36,8 +34,6 @@ type Props = { } const Header = ({ siteTitle, location }: Props) => { - const { toggleSidebarPosition } = useSidebarContext(); - return ( { ))} -
- - +
-
- - -
+
diff --git a/src/components/planner/sidebar/CoursesController/ClassItem.tsx b/src/components/planner/sidebar/CoursesController/ClassItem.tsx index b8bc0332..538ca658 100644 --- a/src/components/planner/sidebar/CoursesController/ClassItem.tsx +++ b/src/components/planner/sidebar/CoursesController/ClassItem.tsx @@ -74,4 +74,4 @@ const ClassItem = ({ course_id, classInfo, onSelect, onMouseEnter, onMouseLeave ) } -export default ClassItem +export default ClassItem \ No newline at end of file diff --git a/src/components/planner/sidebar/sessionController/CoursePicker.tsx b/src/components/planner/sidebar/sessionController/CoursePicker.tsx index 6aa5116b..279ee98f 100644 --- a/src/components/planner/sidebar/sessionController/CoursePicker.tsx +++ b/src/components/planner/sidebar/sessionController/CoursePicker.tsx @@ -1,5 +1,5 @@ import { MajorSearchCombobox, CourseYearTabs, PickedCoursesList, Ects } from './course-picker' -import { PencilSquareIcon } from '@heroicons//react/24/solid' +import { PencilSquareIcon, ArrowsRightLeftIcon } from '@heroicons//react/24/solid' import { useContext, useEffect, useState } from 'react' import StorageAPI from '../../../../api/storage' import CourseContext from '../../../../contexts/CourseContext' @@ -12,13 +12,15 @@ import useCourseUnits from '../../../../hooks/useCourseUnits' import { Major } from '../../../../@types' import { Skeleton } from '../../../ui/skeleton' import { ClearAllCoursesButton } from './course-picker/ClearAllCoursesButton' +import { useSidebarContext } from '../../../layout/SidebarPosition' //TODO: absolute imports with @ + const CoursePicker = () => { const { pickedCourses, setPickedCourses, checkboxedCourses, setChoosingNewCourse, setCoursesInfo, ucsModalOpen, setUcsModalOpen } = useContext(CourseContext) - const [selectedMajor, setSelectedMajor] = useState(StorageAPI.getSelectedMajorStorage()); + const { sidebarPosition, toggleSidebarPosition } = useSidebarContext(); const { courseUnits, loading: loadingCourseUnits } = useCourseUnits(selectedMajor ? selectedMajor.id : null); const showContent = selectedMajor || pickedCourses.length > 0 @@ -46,62 +48,71 @@ const CoursePicker = () => { } return ( +
+ - - - - Seleciona as tuas unidades curriculares - - Pesquisa pelas tuas unidades curriculares. As disciplinas selecionadas aparecem no lado direito. - - - - - {showContent ? ( - <> -
-
- {!loadingCourseUnits - ? - :
- -
- - - - - + + + + Seleciona as tuas unidades curriculares + + Pesquisa pelas tuas unidades curriculares. As disciplinas selecionadas aparecem no lado direito. + + + + + {showContent ? ( + <> +
+
+ {!loadingCourseUnits + ? + :
+ +
+ + + + + +
-
- } -
-
- - -
-
- -
- -
- + } +
+
+ +
-
- - ) : ( -
- -

Seleciona um curso primeiro.

-
- )} - -
+ +
+ +
+ +
+
+
+ + ) : ( +
+ +

Seleciona um curso primeiro.

+
+ )} + + +
) } From 4fb60953854956ea38927d234411c8698253a172 Mon Sep 17 00:00:00 2001 From: Rodrigo Nunes Date: Tue, 3 Dec 2024 17:05:57 +0000 Subject: [PATCH 3/4] changed the position of the button to the bottom of the sidebar --- src/components/layout/SidebarPosition.tsx | 3 +- src/components/planner/Sidebar.tsx | 12 ++ .../sessionController/CoursePicker.tsx | 107 ++++++++---------- 3 files changed, 61 insertions(+), 61 deletions(-) diff --git a/src/components/layout/SidebarPosition.tsx b/src/components/layout/SidebarPosition.tsx index 82365956..57c0fce1 100644 --- a/src/components/layout/SidebarPosition.tsx +++ b/src/components/layout/SidebarPosition.tsx @@ -1,5 +1,4 @@ -import { createCheckboxScope } from "@radix-ui/react-checkbox"; -import { Children, createContext, useContext, useState } from "react"; +import { createContext, useContext, useState } from "react"; type SidebarContextType = { sidebarPosition: 'left' | 'right'; diff --git a/src/components/planner/Sidebar.tsx b/src/components/planner/Sidebar.tsx index 9d6f9481..f8d101ad 100644 --- a/src/components/planner/Sidebar.tsx +++ b/src/components/planner/Sidebar.tsx @@ -4,12 +4,15 @@ import OptionsController from './sidebar/OptionsController' import SelectedOptionController from './sidebar/SelectedOptionController' import CoursesController from './sidebar/CoursesController' import MultipleOptionsContext from '../../contexts/MultipleOptionsContext' +import { useSidebarContext } from '../layout/SidebarPosition' +import { ArrowsRightLeftIcon } from '@heroicons/react/24/outline' /** * Sidebar with all the main schedule interactions */ const Sidebar = () => { const { multipleOptions, selectedOption } = useContext(MultipleOptionsContext); + const { sidebarPosition, toggleSidebarPosition } = useSidebarContext(); return (
@@ -23,6 +26,15 @@ const Sidebar = () => {
+
+ +
) } diff --git a/src/components/planner/sidebar/sessionController/CoursePicker.tsx b/src/components/planner/sidebar/sessionController/CoursePicker.tsx index 279ee98f..9a2b2622 100644 --- a/src/components/planner/sidebar/sessionController/CoursePicker.tsx +++ b/src/components/planner/sidebar/sessionController/CoursePicker.tsx @@ -1,5 +1,5 @@ import { MajorSearchCombobox, CourseYearTabs, PickedCoursesList, Ects } from './course-picker' -import { PencilSquareIcon, ArrowsRightLeftIcon } from '@heroicons//react/24/solid' +import { PencilSquareIcon } from '@heroicons//react/24/solid' import { useContext, useEffect, useState } from 'react' import StorageAPI from '../../../../api/storage' import CourseContext from '../../../../contexts/CourseContext' @@ -12,7 +12,6 @@ import useCourseUnits from '../../../../hooks/useCourseUnits' import { Major } from '../../../../@types' import { Skeleton } from '../../../ui/skeleton' import { ClearAllCoursesButton } from './course-picker/ClearAllCoursesButton' -import { useSidebarContext } from '../../../layout/SidebarPosition' //TODO: absolute imports with @ @@ -20,7 +19,6 @@ import { useSidebarContext } from '../../../layout/SidebarPosition' const CoursePicker = () => { const { pickedCourses, setPickedCourses, checkboxedCourses, setChoosingNewCourse, setCoursesInfo, ucsModalOpen, setUcsModalOpen } = useContext(CourseContext) const [selectedMajor, setSelectedMajor] = useState(StorageAPI.getSelectedMajorStorage()); - const { sidebarPosition, toggleSidebarPosition } = useSidebarContext(); const { courseUnits, loading: loadingCourseUnits } = useCourseUnits(selectedMajor ? selectedMajor.id : null); const showContent = selectedMajor || pickedCourses.length > 0 @@ -48,71 +46,62 @@ const CoursePicker = () => { } return ( -
- - - - - Seleciona as tuas unidades curriculares - - Pesquisa pelas tuas unidades curriculares. As disciplinas selecionadas aparecem no lado direito. - - - - - {showContent ? ( - <> -
-
- {!loadingCourseUnits - ? - :
- -
- - - - - -
+ + + + Seleciona as tuas unidades curriculares + + Pesquisa pelas tuas unidades curriculares. As disciplinas selecionadas aparecem no lado direito. + + + + + {showContent ? ( + <> +
+
+ {!loadingCourseUnits + ? + :
+ +
+ + + + +
- } -
-
- - -
-
- -
- -
-
-
-
- - ) : ( -
- -

Seleciona um curso primeiro.

+ } +
+
+ + +
- )} -
-
-
+ +
+ +
+ +
+
+
+ + ) : ( +
+ +

Seleciona um curso primeiro.

+
+ )} + + ) } From b9eaf46d8c36a204fe8e0ad5ad5155186fd9ab03 Mon Sep 17 00:00:00 2001 From: Rodrigo Nunes Date: Tue, 10 Dec 2024 17:04:30 +0000 Subject: [PATCH 4/4] Made it so the position of the sidebar is kept in localStorage --- src/components/layout/SidebarPosition.tsx | 13 ++++++++++--- src/components/planner/Sidebar.tsx | 8 ++++---- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/components/layout/SidebarPosition.tsx b/src/components/layout/SidebarPosition.tsx index 57c0fce1..bbf663dd 100644 --- a/src/components/layout/SidebarPosition.tsx +++ b/src/components/layout/SidebarPosition.tsx @@ -1,4 +1,4 @@ -import { createContext, useContext, useState } from "react"; +import { createContext, useContext, useState, useEffect } from "react"; type SidebarContextType = { sidebarPosition: 'left' | 'right'; @@ -8,10 +8,17 @@ type SidebarContextType = { const SidebarContext = createContext(undefined); export const SidebarProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { - const [sidebarPosition, setSidebarPosition] = useState<'left' | 'right'>('right'); + const [sidebarPosition, setSidebarPosition] = useState<'left' | 'right'>(() => { + const storedPosition = window.localStorage.getItem("sidebar-position"); + return storedPosition === "left" || storedPosition === "right" ? storedPosition : "right"; + }); const toggleSidebarPosition = () => { - setSidebarPosition((prev) => (prev === 'right' ? 'left' : 'right')); + setSidebarPosition((prev) => { + const newPosition = prev === "right" ? "left" : "right"; + window.localStorage.setItem("sidebar-position", newPosition); + return newPosition; + }); }; return ( diff --git a/src/components/planner/Sidebar.tsx b/src/components/planner/Sidebar.tsx index f8d101ad..b78042e9 100644 --- a/src/components/planner/Sidebar.tsx +++ b/src/components/planner/Sidebar.tsx @@ -12,11 +12,11 @@ import { ArrowsRightLeftIcon } from '@heroicons/react/24/outline' */ const Sidebar = () => { const { multipleOptions, selectedOption } = useContext(MultipleOptionsContext); - const { sidebarPosition, toggleSidebarPosition } = useSidebarContext(); + const { toggleSidebarPosition } = useSidebarContext(); return (
-
+
@@ -26,13 +26,13 @@ const Sidebar = () => {
-