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

Feature: Button that allows the user to switch the side where the sidebar is displayed #340

Open
wants to merge 6 commits into
base: develop
Choose a base branch
from
57 changes: 30 additions & 27 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -60,33 +61,35 @@ const App = () => {
const SentryRoutes = Sentry.withSentryReactRouterV6Routing(Routes);

return (
<BrowserRouter>
<CombinedProvider>
<SentryRoutes>
{pages.map((page, pageIdx) => (
<Route
path={page.path}
key={`page-${pageIdx}`}
element={
<Layout location={page.location} title={page.location} liquid={page.liquid}>
<div>
<page.element />
<Toaster />
</div>
</Layout>
}
/>
))}
{redirects.map((redirect, redirectIdx) => (
<Route
path={redirect.from}
key={`redirect-${redirectIdx}`}
element={<Navigate replace to={redirect.to} />}
/>
))}
</SentryRoutes>
</CombinedProvider>
</BrowserRouter>
<SidebarProvider>
Copy link
Member

@tomaspalma tomaspalma Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the same light as the previous comment, since the sidebar button to change sides should not be global, it does not really make sense to render the SidebarProvider here.

It should be inside the TimeTableScheduler.tsx page

<BrowserRouter>
<CombinedProvider>
<SentryRoutes>
{pages.map((page, pageIdx) => (
<Route
path={page.path}
key={`page-${pageIdx}`}
element={
<Layout location={page.location} title={page.location} liquid={page.liquid}>
<div>
<page.element />
<Toaster/>
</div>
</Layout>
}
/>
))}
{redirects.map((redirect, redirectIdx) => (
<Route
path={redirect.from}
key={`redirect-${redirectIdx}`}
element={<Navigate replace to={redirect.to} />}
/>
))}
</SentryRoutes>
</CombinedProvider>
</BrowserRouter>
</SidebarProvider>
)
}

Expand Down
37 changes: 37 additions & 0 deletions src/components/layout/SidebarPosition.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { createContext, useContext, useState, useEffect } from "react";

Check failure on line 1 in src/components/layout/SidebarPosition.tsx

View workflow job for this annotation

GitHub Actions / Lint (21.x)

'useEffect' is defined but never used

type SidebarContextType = {
sidebarPosition: 'left' | 'right';
toggleSidebarPosition: () => void;
};

const SidebarContext = createContext<SidebarContextType | undefined>(undefined);

export const SidebarProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {

Check failure on line 10 in src/components/layout/SidebarPosition.tsx

View workflow job for this annotation

GitHub Actions / Lint (21.x)

'children' is missing in props validation
const [sidebarPosition, setSidebarPosition] = useState<'left' | 'right'>(() => {
const storedPosition = window.localStorage.getItem("sidebar-position");
return storedPosition === "left" || storedPosition === "right" ? storedPosition : "right";
});

const toggleSidebarPosition = () => {
setSidebarPosition((prev) => {
const newPosition = prev === "right" ? "left" : "right";
window.localStorage.setItem("sidebar-position", newPosition);
return newPosition;
});
};

return (
<SidebarContext.Provider value={{ sidebarPosition, toggleSidebarPosition }}>
{children}
</SidebarContext.Provider>
);
};

export const useSidebarContext = () => {
const context = useContext(SidebarContext);
if (!context) {
throw new Error('useSidebarContext must be used within a SidebarProvider')
}
return context
}
14 changes: 13 additions & 1 deletion src/components/planner/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,19 @@ 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 { toggleSidebarPosition } = useSidebarContext();

return (
<div className="lg:min-h-adjusted order-2 col-span-12 flex min-h-min flex-col justify-between rounded-md bg-lightest px-3 py-3 dark:bg-dark lg:col-span-3 2xl:px-4 2xl:py-4">
<div className="space-y-2">
<div className="flex-grow space-y-2">
<div className="relative flex flex-row flex-wrap items-center justify-center gap-x-2 gap-y-2 lg:justify-start">
<SessionController />
<OptionsController />
Expand All @@ -23,6 +26,15 @@ const Sidebar = () => {
<CoursesController />
</div>
</div>
<footer className="mt-4 border-white-300 pt-3 text-center flex items-end justify-end min-h-[100px]">
<button title='Mudar o lado da Sidebar'
onClick={toggleSidebarPosition}
className="flex items-center justify-center gap-2 w-[48px] h-[40px] bg-primary hover:opacity-80 dark:text-white rounded-md p-1 text-gray text-sm"
style={{order: 2}}
>
<ArrowsRightLeftIcon className="h-5 w-5 text-white dark:text-white" />
</button>
</footer>
</div>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,4 @@ const ClassItem = ({ course_id, classInfo, onSelect, onMouseEnter, onMouseLeave
)
}

export default ClassItem
export default ClassItem
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ import { ClearAllCoursesButton } from './course-picker/ClearAllCoursesButton'

//TODO: absolute imports with @


const CoursePicker = () => {
const { pickedCourses, setPickedCourses, checkboxedCourses, setChoosingNewCourse, setCoursesInfo, ucsModalOpen, setUcsModalOpen } = useContext(CourseContext)

const [selectedMajor, setSelectedMajor] = useState<Major>(StorageAPI.getSelectedMajorStorage());
const { courseUnits, loading: loadingCourseUnits } = useCourseUnits(selectedMajor ? selectedMajor.id : null);
const showContent = selectedMajor || pickedCourses.length > 0
Expand Down
36 changes: 26 additions & 10 deletions src/pages/TimeTableSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@ 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<Major[]>([])
const [coursesInfo, setCoursesInfo] = useState([]);
const [pickedCourses, setPickedCourses] = useState<CourseInfo[]>(StorageAPI.getPickedCoursesStorage());
const [checkboxedCourses, setCheckboxedCourses] = useState<CourseInfo[]>(StorageAPI.getPickedCoursesStorage());
const [ucsModalOpen, setUcsModalOpen] = useState<boolean>(false);
const { sidebarPosition } = useSidebarContext();

//TODO: Looks suspicious
const [choosingNewCourse, setChoosingNewCourse] = useState<boolean>(false);
Expand All @@ -21,6 +23,8 @@ const TimeTableSelectorPage = () => {
setMajors(majors)
})
}, [])


return (
<MajorContext.Provider value={{ majors, setMajors }}>
<CourseContext.Provider value={
Expand All @@ -33,18 +37,30 @@ const TimeTableSelectorPage = () => {
}
}>
<div className="grid w-full grid-cols-12 gap-x-4 gap-y-4 px-4 py-4">
{/* Schedule Preview */}
<div className="lg:min-h-adjusted order-1 col-span-12 min-h-min rounded-md bg-lightest px-3 py-3 dark:bg-dark lg:col-span-9 2xl:px-5 2xl:py-5">
<div className="h-full w-full">
{sidebarPosition === 'left' ?(
<>
<div className='col-span-12 lg:col-span-3 min-h'>
<Sidebar />
</div>
<div className='col-span-12 lg:col-span-9 min-h rounded-md bg-lightest px-3 py-3 dark:bg-dark 2xl:px-5 2xl:py-5'>
<Schedule />
</div>
</>
) : (
<>
<div className='col-span-12 lg:col-span-9 min-h rounded-md bg-lightest px-3 py-3 dark:bg-dark 2xl:px-5 2xl:py-5'>
<Schedule />
</div>
</div>

<Sidebar />
</div>
<div className='col-span-12 lg:col-span-3 min-h'>
<Sidebar />
</div>
</>
)}
</div>
</CourseContext.Provider>
</MajorContext.Provider>
)
}
);
};


export default TimeTableSelectorPage;
export default TimeTableSelectorPage;
Loading