Skip to content

Commit

Permalink
Merge pull request #220 from kpi-ua/KB-41-DEV-Day-selection-doesn-t-w…
Browse files Browse the repository at this point in the history
…ork-right-on-mobile

KB-41 fix day toggler and day selection on window resize
  • Loading branch information
ernado-x authored Aug 29, 2024
2 parents 757220b + 2e966c4 commit 0764d44
Show file tree
Hide file tree
Showing 15 changed files with 210 additions and 162 deletions.
2 changes: 1 addition & 1 deletion src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { GroupContextProvider } from "../common/context/groupContext";
import { LecturerContextProvider } from "../common/context/lecturerContext";
import { PreloadedListsContextProvider } from "../common/context/preloadedListsContext";
import { WeekContextProvider } from "../common/context/weekContext";
import { useCurrentDateParams } from "../common/utils/useCurrentDateParams";
import { useCurrentDateParams } from "../common/hooks/useCurrentDateParams";
import ThemeContextProvider from "../common/context/themeContext";
import Navbar from "../containers/navbar";
import ScheduleRouter from "../containers/router";
Expand Down
26 changes: 14 additions & 12 deletions src/common/constants/dayOptions.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
import { ListOption } from '../../types/ListOption';
import { ScreenSize } from '../../types/ScreenSize';

export const DAY_OPTIONS: Partial<Record<ScreenSize, ListOption<string>[]>> = {
export type DaysRange = `${number}-${number}`;

export const DAY_OPTIONS: Partial<Record<ScreenSize, ListOption<DaysRange>[]>> = {
[ScreenSize.ExtraSmall]: [
{label: 'ПН', value: '0-1'},
{label: 'ВТ', value: '1-2'},
{label: 'СР', value: '2-3'},
{label: 'ЧТ', value: '3-4'},
{label: 'ПТ', value: '4-5'},
{label: 'СБ', value: '5-6'},
{label: 'ПН', value: '1-1'},
{label: 'ВТ', value: '2-2'},
{label: 'СР', value: '3-3'},
{label: 'ЧТ', value: '4-4'},
{label: 'ПТ', value: '5-5'},
{label: 'СБ', value: '6-6'},
],
[ScreenSize.Small]: [
{label: 'ПН-ВТ', value: '0-2'},
{label: 'СР-ЧТ', value: '2-4'},
{label: 'ПТ-СБ', value: '4-6'},
{label: 'ПН-ВТ', value: '1-2'},
{label: 'СР-ЧТ', value: '3-4'},
{label: 'ПТ-СБ', value: '5-6'},
],
[ScreenSize.Medium]: [
{label: 'ПН-СР', value: '0-3'},
{label: 'ЧТ-СБ', value: '3-6'},
{label: 'ПН-СР', value: '1-3'},
{label: 'ЧТ-СБ', value: '4-6'},
],
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,8 @@
import { ScreenSize } from '../../types/ScreenSize';

const SCRREN_SIZES: Record<ScreenSize, string> = {
export const SCREEN_SIZES: Record<ScreenSize, string> = {
[ScreenSize.Big]: '1441px',
[ScreenSize.Medium]: '1440px',
[ScreenSize.Small]: '988px',
[ScreenSize.ExtraSmall]: '639px',
};

export const getScreenSize = (mode: ScreenSize) => {
return SCRREN_SIZES[mode];
}
};
73 changes: 68 additions & 5 deletions src/common/context/sliceOptionsContext.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,75 @@
import { createContext, useContext } from 'react';
import { createContext, useContext, useEffect, useState } from 'react';
import { ScreenSize } from '../../types/ScreenSize';
import { useScreenSize } from '../hooks/useScreenSize';
import { clamp, inRange, range } from 'lodash-es';

export interface Slice {
start?: number;
end?: number;
export type Slice = [number, number];

export interface SliceContext {
slice: Slice;
setSlice: (slice: Slice) => void;
setCurrentDay: (currentDay: number) => void;
}

const SliceOptionsContext = createContext<Slice>({});
const defaultValue: Slice = [0, 0];

const SliceOptionsContext = createContext<SliceContext>({
slice: defaultValue,
setSlice: () => ({}),
setCurrentDay: () => ({}),
});

export const useSliceOptionsContext = () => useContext(SliceOptionsContext);

interface SliceContextProviderProps {
children: React.ReactNode | React.ReactNode[];
initialDay: number;
}

const DAYS_COUNT = 6;

const ScreenSizeSlicesCount: Record<ScreenSize, number> = {
[ScreenSize.Big]: 1,
[ScreenSize.Medium]: 2,
[ScreenSize.Small]: 3,
[ScreenSize.ExtraSmall]: 6
};

const generateSlices = (screenSize: ScreenSize): Slice[] => {
const numberOfSlices = ScreenSizeSlicesCount[screenSize];
const sliceRange = DAYS_COUNT / numberOfSlices;

return range(0, numberOfSlices).map(
(index) => ([sliceRange * index + 1, sliceRange * index + sliceRange])
);
};

const getCurrentSlice = (screenSize: ScreenSize, currendDay: number): Slice => {
const slices = generateSlices(screenSize);

return slices.find(([start, end]) => inRange(clamp(currendDay, 1, DAYS_COUNT) , start, end + 1)) || defaultValue;
};

export const SliceContextProvider = ({ children, initialDay }: SliceContextProviderProps) => {
const { screenSize } = useScreenSize();
const [slice, setSlice] = useState<Slice>(defaultValue);
const [currentDay, setCurrentDay] = useState(initialDay);

useEffect(() => {
setSlice(getCurrentSlice(screenSize, currentDay));
}, [screenSize, currentDay]);

const value: SliceContext = {
slice,
setSlice,
setCurrentDay,
};

return (
<SliceOptionsContext.Provider value={value}>
{children}
</SliceOptionsContext.Provider>
);
};

export default SliceOptionsContext.Provider;
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ import { CurrentTime } from '../../models/CurrentTime';

export const useCurrentDateParams = () => {
const [dateParams, setDateParams] = useState<CurrentTime>({
currentDay: -1,
currentLesson: -1,
currentWeek: -1,
currentDay: 0,
currentLesson: 0,
currentWeek: 0,
});

useEffect(() => {
Expand Down
28 changes: 28 additions & 0 deletions src/common/hooks/useScreenSize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { ScreenSize } from '../../types/ScreenSize';
import { useCallback, useEffect, useState } from "react";
import { SCREEN_SIZES } from '../constants/screenSize';

export const useScreenSize = () => {
const detectScreenSize = () => {
for (let key in ScreenSize) {
if (window.innerWidth <= parseInt(SCREEN_SIZES[ScreenSize[key]])) {
return ScreenSize[key];
}
}

return ScreenSize.Big;
};

const [screenSize, setScreenSize] = useState<ScreenSize>(detectScreenSize());

const updateScreenSize = useCallback(() => setScreenSize(detectScreenSize()), []);

useEffect(() => {
window.addEventListener("resize", updateScreenSize);

return () => window.removeEventListener("resize", updateScreenSize);
}, [updateScreenSize]);


return { screenSize };
};
10 changes: 5 additions & 5 deletions src/common/styles/styles.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import styled, { css } from 'styled-components';
import { flexbox, space } from 'styled-system';
import { getScreenSize } from '../utils/getScreenSize';
import { SCREEN_SIZES } from '../constants/screenSize';
import { getValueFromTheme } from '../../common/utils/getValueFromTheme';
import { Link } from 'react-router-dom';
import { ScreenSize } from '../../types/ScreenSize';
Expand All @@ -19,10 +19,10 @@ export const Pictogram = styled.img`
`;

export const media = {
[ScreenSize.ExtraSmall]: `@media(max-width: ${getScreenSize(ScreenSize.ExtraSmall)})`,
[ScreenSize.Small]: `@media(max-width: ${getScreenSize(ScreenSize.Small)})`,
[ScreenSize.Medium]: `@media(max-width: ${getScreenSize(ScreenSize.Medium)})`,
[ScreenSize.Big]: `@media(min-width: ${getScreenSize(ScreenSize.Big)})`,
[ScreenSize.ExtraSmall]: `@media(max-width: ${SCREEN_SIZES[ScreenSize.ExtraSmall]})`,
[ScreenSize.Small]: `@media(max-width: ${SCREEN_SIZES[ScreenSize.Small]})`,
[ScreenSize.Medium]: `@media(max-width: ${SCREEN_SIZES[ScreenSize.Medium]})`,
[ScreenSize.Big]: `@media(min-width: ${SCREEN_SIZES[ScreenSize.Big]})`,
};

export const Logo = styled(Pictogram)`
Expand Down
27 changes: 0 additions & 27 deletions src/common/utils/useCurrentMode.ts

This file was deleted.

38 changes: 38 additions & 0 deletions src/containers/ScheduleTable/ScheduleTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import ScheduleRow from "../scheduleRow";
import { ScheduleMatrix, ScheduleMatrixRow, generateScheduleMatrix } from "../../common/utils/generateScheduleMatrix";
import { useWeekContext } from "../../common/context/weekContext";
import { useSliceOptionsContext } from '../../common/context/sliceOptionsContext';

interface ScheduleWrapperProps<T> {
data: T[];
}

const weekValue: Record<string, string> = {
firstWeek: "scheduleFirstWeek",
secondWeek: "scheduleSecondWeek",
};

const ScheduleTable = <T,>({ data }: ScheduleWrapperProps<T>) => {
const { slice } = useSliceOptionsContext();
const { currentWeek } = useWeekContext();

const generateScheduleRows = (scheduleMatrix: ScheduleMatrix) => {
return scheduleMatrix.map((item: ScheduleMatrixRow, i: number) => {
const [start, end] = slice;
const slicedDataset = item.slice(start - 1, end);
return <ScheduleRow key={i} scheduleMatrixCell={slicedDataset} />;
});
};

if (!data) {
return null;
}

return (
<>
{generateScheduleRows(generateScheduleMatrix(data[weekValue[currentWeek]]))}
</>
);
};

export default ScheduleTable;
21 changes: 9 additions & 12 deletions src/containers/schedule/schedule.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import React from 'react';
import { range } from 'lodash-es';
import TimeDivider from '../../components/timeDivider';
import { CurrentDayContainer, GridContainer } from './schedule.style';
import ScheduleHeader from '../scheduleHeader';
import { ScheduleHeader } from '../ScheduleHeader';
import { TIME_POINTS } from '../../common/constants/scheduleParams';
import { useSliceOptionsContext } from '../../common/context/sliceOptionsContext';
import { useCurrentDateParams } from '../../common/utils/useCurrentDateParams';
import { useCurrentDateParams } from '../../common/hooks/useCurrentDateParams';

interface ScheduleProps {
children: React.ReactNode;
}

const Schedule = ({ children }: ScheduleProps) => {
const sliceOptions = useSliceOptionsContext();
const { slice } = useSliceOptionsContext();
const { currentDay } = useCurrentDateParams();

const dynamicGeneratedTable = React.Children.map(children, (child, index) => (
Expand All @@ -21,19 +22,15 @@ const Schedule = ({ children }: ScheduleProps) => {
</>
));

const isDayInSlice = () => {
if (sliceOptions.start && sliceOptions.end && currentDay) {
return currentDay >= sliceOptions.start && currentDay < sliceOptions.end;
}
const [start, end] = slice;

return true;
};

const gridDayStart = currentDay || 0 + 1;
const currentDayColumn =
range(start, end + 1)
.indexOf(currentDay) + 1;

return (
<GridContainer>
{gridDayStart > 0 && isDayInSlice() ? <CurrentDayContainer start={sliceOptions.start ? gridDayStart - sliceOptions.start : gridDayStart}/> : null}
{currentDayColumn ? <CurrentDayContainer start={currentDayColumn}/> : null}
<ScheduleHeader/>
{dynamicGeneratedTable}
</GridContainer>
Expand Down
56 changes: 21 additions & 35 deletions src/containers/scheduleDayToggler/scheduleDayToggler.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,33 @@
import OptionMultipleToggler from "../../components/optionMultipleToggler";
import { useCurrentMode } from "../../common/utils/useCurrentMode";
import { DAY_OPTIONS } from "../../common/constants/dayOptions";
import { useScreenSize } from "../../common/hooks/useScreenSize";
import { DAY_OPTIONS, DaysRange } from "../../common/constants/dayOptions";
import { ScheduleDayTogglerContainer } from "./scheduleDayToggler.style";
import { useCurrentDateParams } from "../../common/utils/useCurrentDateParams";
import { ScreenSize } from '../../types/ScreenSize';

interface ScheduleDayTogglerProps {
onChange: (value: string) => void;
}

const ScheduleDayToggler = ({ onChange }: ScheduleDayTogglerProps) => {
const mode = useCurrentMode();
const { currentDay } = useCurrentDateParams();

const getDayOption = () => {
if (!currentDay || currentDay === 6 || currentDay < 0) {
return 0;
}

switch (mode) {
case ScreenSize.ExtraSmall:
return currentDay;
case ScreenSize.Small:
return Math.floor(currentDay / 2);
case ScreenSize.Medium:
return Math.floor(currentDay / 3)
default:
return 0;
}
};
import { Slice, useSliceOptionsContext } from '../../common/context/sliceOptionsContext';

const ScheduleDayToggler = () => {
const { screenSize } = useScreenSize();
const { slice, setSlice } = useSliceOptionsContext();

if (!mode || mode === ScreenSize.Big) {
const options = DAY_OPTIONS[screenSize];

if (!options) {
return null;
}

const handleChange = (value: DaysRange) => {
const [start, end] = value.split('-');

setSlice([+start, +end]);
};

const convertSlice = ([start, end]: Slice): DaysRange => `${start}-${end}`;

return (
<ScheduleDayTogglerContainer>
<OptionMultipleToggler
currentValue={
DAY_OPTIONS[mode] && DAY_OPTIONS[mode][getDayOption()].value
}
onChange={onChange}
options={DAY_OPTIONS[mode]}
currentValue={convertSlice(slice)}
onChange={handleChange}
options={options}
/>
</ScheduleDayTogglerContainer>
);
Expand Down
File renamed without changes.
4 changes: 1 addition & 3 deletions src/containers/scheduleHeader/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1 @@
import ScheduleHeader from './scheduleHeader';

export default ScheduleHeader;
export { ScheduleHeader } from './ScheduleHeader';
Loading

0 comments on commit 0764d44

Please sign in to comment.