Skip to content

Commit

Permalink
Merge pull request #32 from scffs/add-days-etc
Browse files Browse the repository at this point in the history
feat(add-days-etc): новое отображение дней + улучшена работа периодов
  • Loading branch information
scffs authored Sep 7, 2023
2 parents ad26f55 + b770133 commit a241221
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 78 deletions.
15 changes: 0 additions & 15 deletions frontend/index-b3.3.html

This file was deleted.

32 changes: 23 additions & 9 deletions frontend/src/components/LessonCard.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { FC } from 'react';
import {CSSProperties, FC} from 'react';
import {
Card, Group, Header, Placeholder, SimpleCell,
Card, Footnote, Group, Header, Placeholder, SimpleCell,
} from '@vkontakte/vkui';
import { useRouteNavigator } from '@vkontakte/vk-mini-apps-router';

import {
Day, Grade, Gradebook, LessonWorkType, Timetable,
} from '../../../shared';
import setDefaultMark from '../utils/setDefaultMark';
import { formatLessonDate } from '../utils/formatLessonDate';
import { formatLessonDate, getDayOfWeek } from '../utils/formatLessonDate';

import { MODAL_PAGE_LESSON } from '../modals/ModalRoot';

Expand All @@ -17,6 +17,7 @@ import { useModal } from '../modals/ModalContext';
import SubtitleWithBorder from './SubtitleWithBorder';
import TimeRemaining from './TimeRemaining';
import Mark from './Mark';
import {isToday} from "../utils/isToday.ts";

interface ILessonCard {
lesson: Day;
Expand Down Expand Up @@ -58,22 +59,35 @@ const LessonCard: FC<ILessonCard> = ({ lesson }) => {
const lessonYear = lessonDate.getFullYear().toString();
const lessonMonth = (lessonDate.getMonth() + 1).toString().padStart(2, '0');
const lessonDay = lessonDate.getDate().toString().padStart(2, '0');

const lessonDayOfWeek = getDayOfWeek(lessonDate);
const isLessonToday = isToday(lessonDate);

const currentYear = currentDate.getFullYear().toString();
const currentMonth = (currentDate.getMonth() + 1).toString().padStart(2, '0');
const currentDay = currentDate.getDate().toString().padStart(2, '0');

const dayEnded = currentYear === lessonYear && currentMonth === lessonMonth && currentDay > lessonDay;


const displayDay = dayEnded ? ' День завершён' : isLessonToday ? 'Сегодня' : ''
const displayEndDayStyles = dayEnded && 'var(--vkui--color_icon_negative)';
const displayCurrDayStyles = isLessonToday && 'var(--vkui--color_background_accent)';

const displayDayStyles: CSSProperties = {
color: displayEndDayStyles || displayCurrDayStyles || undefined,
padding: '3px 5px',
borderRadius: '5px',
border: `1px solid ${displayEndDayStyles || displayCurrDayStyles}`
}

return (
<Card key={lesson.date as unknown as string} style={{ height: '100%' }}>
<Group
/* Без этого Group не растягивается и немного уезжает на планшетах */
style={{ height: '100%', marginTop: '4px' }}
header={(
<Header mode='secondary'>
<Header mode='secondary' aside={<Footnote style={displayDayStyles}>{displayDay}</Footnote>}>
{lessonDayOfWeek && `${lessonDayOfWeek}. `}
{formattedLessonDate}
{dayEnded ? ' День завершён' : ''}
</Header>
)}
>
Expand All @@ -88,9 +102,9 @@ const LessonCard: FC<ILessonCard> = ({ lesson }) => {
subtitle={!name || (
<div>
<div style={{ display: 'flex', alignItems: 'center' }}>
<div style={{ display: 'flex', margin: '5px 5px 5px 0px' }}>
<div style={{ display: 'flex' }}>
{gradebook?.lessonType && (
<SubtitleWithBorder>
<SubtitleWithBorder style={{ margin: '5px 5px 5px 0px' }}>
{LessonWorkType[gradebook?.lessonType]}
</SubtitleWithBorder>
)}
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/components/SubtitleWithBorder.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { FC, ReactNode } from 'react';
import { CSSProperties, FC, ReactNode } from 'react';

interface ISubtitleWithBorder {
children: ReactNode | string;
color?: 'red' | 'green' | 'default';
style?: CSSProperties;
}

const SubtitleWithBorder: FC<ISubtitleWithBorder> = ({ children, color = 'default' }) => {
const SubtitleWithBorder: FC<ISubtitleWithBorder> = ({ children, color = 'default', style }) => {
const getColorStyles = () => {
switch (color) {
case 'red':
Expand Down Expand Up @@ -39,6 +40,7 @@ const SubtitleWithBorder: FC<ISubtitleWithBorder> = ({ children, color = 'defaul
display: 'inline-block',
...getColorStyles(),
padding: '3px 5px',
...style,
}}
>
{children}
Expand Down
22 changes: 11 additions & 11 deletions frontend/src/modals/ModalRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -142,24 +142,24 @@ const ModalRoot = () => {
</InfoRow>
</SimpleCell>
</Group>
{((lessonData.gradebook?.absenceType && lessonData.gradebook.absenceType === 'IsAbsent') ||
(lessonData.gradebook?.tasks?.length && lessonData.gradebook.tasks.length > 0))
{((lessonData.gradebook?.absenceType && lessonData.gradebook.absenceType === 'IsAbsent')
|| (lessonData.gradebook?.tasks?.length && lessonData.gradebook.tasks.length > 0))
? (
<Group header={<Header mode='tertiary'>Успеваемость</Header>}>
{lessonData.gradebook?.tasks?.map((tasks, index) => (
(tasks.isRequired || (Grade[setDefaultMark(tasks)] !== 'Д')) && (
<Group header={<Header mode='tertiary'>Успеваемость</Header>}>
{lessonData.gradebook?.tasks?.map((tasks, index) => (
(tasks.isRequired || (Grade[setDefaultMark(tasks)] !== 'Д')) && (
<SimpleCell key={index} after={<Mark mark={Grade[setDefaultMark(tasks)]} size='s' />}>
{LessonType[tasks.type]}
</SimpleCell>
)
))}
{lessonData.gradebook?.absenceType === 'IsAbsent' && (
)
))}
{lessonData.gradebook?.absenceType === 'IsAbsent' && (
<SimpleCell after={<Mark mark={'Н' as TMark} size='s' />}>
Опоздание
</SimpleCell>
)}
</Group>
) : null}
)}
</Group>
) : null}
</ModalPage>
</VKUIModalRoot>
);
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/utils/formatLessonDate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,8 @@ export const formatLessonDate = (dateString: Date | string) => {
// @ts-ignore
return new Date(dateString).toLocaleDateString(undefined, options);
};

export function getDayOfWeek(date: Date) {
const daysOfWeek = ['Вс', 'Пн', 'Вт', 'Ср', 'Чт', 'Пт', 'Сб'];
return daysOfWeek[date.getDay()];
}
8 changes: 8 additions & 0 deletions frontend/src/utils/isToday.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const isToday = (date: Date) => {
const today = new Date();
return (
date.getDate() === today.getDate() &&
date.getMonth() === today.getMonth() &&
date.getFullYear() === today.getFullYear()
);
}
100 changes: 59 additions & 41 deletions frontend/src/views/Schedule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
} from '@vkontakte/icons';

import { endOfWeek, startOfWeek } from '@vkontakte/vkui/dist/lib/date';
import { debounce } from '@vkontakte/vkui/dist/lib/utils';
import { Day } from '../../../shared';
import { getLessons } from '../methods';

Expand All @@ -37,6 +38,8 @@ const Schedule: FC<{ id: string }> = ({ id }) => {
const [endDate, setEndDate] = useState<Date>(endOfWeek(currentDate));
const [isLoading, setIsLoading] = useState<boolean>(false);
const [isError, setIsError] = useState<boolean>(false);
const [clickCount, setClickCount] = useState<number>(0);
const [timeoutId, setTimeoutId] = useState<NodeJS.Timeout | null>(null);

const updateDatesFromData = (data: Day[]) => {
const firstLessonDate = data && data.length > 0 ? new Date(data[0].date) : startDate;
Expand All @@ -46,8 +49,8 @@ const Schedule: FC<{ id: string }> = ({ id }) => {
};

const handleReloadData = async () => {
setIsError(false);
setIsLoading(true);
setIsError(false);
const newEndDate = new Date(endDate);
newEndDate.setDate(newEndDate.getDate() + 7);

Expand All @@ -73,6 +76,8 @@ const Schedule: FC<{ id: string }> = ({ id }) => {
onActionClick: handleReloadData,
});
console.error(error);
} finally {
setIsLoading(false);
}
};

Expand Down Expand Up @@ -136,6 +141,7 @@ const Schedule: FC<{ id: string }> = ({ id }) => {
gettedLessons();
}, []);
const sendToServerIfValid = async (start: Date, end: Date) => {
setIsLoading(true);
if (start <= end) {
const differenceInDays = (end.getTime() - start.getTime()) / (1000 * 3600 * 24);
if (differenceInDays <= 14) {
Expand Down Expand Up @@ -194,6 +200,7 @@ const Schedule: FC<{ id: string }> = ({ id }) => {
localStorage.setItem('savedLessons', JSON.stringify(data));
}
}
setIsLoading(false);
};

const handleStartDateChange = (newStartDate: Date) => {
Expand All @@ -212,36 +219,49 @@ const Schedule: FC<{ id: string }> = ({ id }) => {
sendToServerIfValid(startDate, newEndDate);
};

const [lastClickTime, setLastClickTime] = useState<number | null>(null);
const debouncedChangeWeek = debounce((direction: 'prev' | 'next') => {
const newStartDate = new Date(startDate);
const newEndDate = new Date(endDate);

const debouncedChangeWeek = (direction: 'prev' | 'next') => {
if (lastClickTime && Date.now() - lastClickTime <= 500) {
setTimeout(() => {
debouncedChangeWeek(direction);
}, 800);
} else {
setLastClickTime(Date.now());
const newStartDate = new Date(startDate);
const newEndDate = new Date(endDate);
if (direction === 'prev') {
newStartDate.setDate(newStartDate.getDate() - 7);
newEndDate.setDate(newEndDate.getDate() - 7);
} else if (direction === 'next') {
newStartDate.setDate(newStartDate.getDate() + 7);
newEndDate.setDate(newEndDate.getDate() + 7);
}
setStartDate(newStartDate);
setEndDate(newEndDate);
sendToServerIfValid(newStartDate, newEndDate);
if (clickCount > 0) {
const weekDifference = clickCount * 7;
newStartDate.setDate(newStartDate.getDate() + weekDifference);
newEndDate.setDate(newEndDate.getDate() + weekDifference);
setClickCount(0);
} else if (direction === 'prev') {
newStartDate.setDate(newStartDate.getDate() - 7);
newEndDate.setDate(newEndDate.getDate() - 7);
} else if (direction === 'next') {
newStartDate.setDate(newStartDate.getDate() + 7);
newEndDate.setDate(newEndDate.getDate() + 7);
}

setStartDate(newStartDate);
setEndDate(newEndDate);

sendToServerIfValid(newStartDate, newEndDate);
}, 1);

const handleButtonClick = (direction: 'prev' | 'next') => {
setClickCount((prevCount) => prevCount + 1);

if (timeoutId) {
clearTimeout(timeoutId);
}

const newTimeoutId = setTimeout(() => {
debouncedChangeWeek(direction);
}, 1000);

setTimeoutId(newTimeoutId);
};

const Buttons = (
<ButtonGroup>
<IconButton aria-label='Prev' onClick={() => debouncedChangeWeek('prev')}>
<ButtonGroup style={{ position: 'relative', top: 20, color: 'var(--vkui--color_stroke_accent_themed)'}}>
<IconButton aria-label='Prev' onClick={() => handleButtonClick('prev')}>
<Icon16ArrowLeftOutline />
</IconButton>
<IconButton aria-label='Next' onClick={() => debouncedChangeWeek('next')}>
<IconButton aria-label='Next' onClick={() => handleButtonClick('next')}>
<Icon16ArrowRightOutline />
</IconButton>
</ButtonGroup>
Expand Down Expand Up @@ -277,24 +297,22 @@ const Schedule: FC<{ id: string }> = ({ id }) => {
onDateChange={handleEndDateChange}
/>
</Suspense>
{isLoading ? <PanelSpinner size='medium' /> : (
<Suspense id='ScheduleGroup' mode='screen'>
<Group
header={(
<Header
aside={Buttons}
mode='secondary'
>
Период
{' '}
{weekString}
</Header>
)}
>
<Suspense id='ScheduleGroup' mode='screen'>
<Group
header={(
<Header
aside={Buttons}
mode='secondary'
>
{weekString}
</Header>
)}
>
{isLoading ? <PanelSpinner size='medium' /> : (
<ScheduleGroup lessonsState={lessonsState} />
</Group>
</Suspense>
)}
)}
</Group>
</Suspense>
{isError
&& (
<Placeholder
Expand Down

0 comments on commit a241221

Please sign in to comment.