Skip to content

Commit

Permalink
Merge pull request #49 from sulianova/VladimirFyodorov/small-landing-…
Browse files Browse the repository at this point in the history
…fixes

Vladimir fyodorov/small landing fixes
  • Loading branch information
VladimirFyodorov authored Nov 29, 2023
2 parents 5f0e6dd + 1852421 commit 8566174
Show file tree
Hide file tree
Showing 20 changed files with 211 additions and 78 deletions.
10 changes: 6 additions & 4 deletions src/assets/translations/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,8 @@
"navTubsPractice": "Задание",
"navTubsResults": "Итоги",
"navToLessons": "Все уроки",
"deadlineUploadText": "Дедлайн: ",
"deadlineUploadTime": " 23:59\u00A0по\u00A0Мск",
"deadlineResultsText": "Публикация итогов: ",
"uploadDeadline": "Дедлайн: %{date}\u00A0по\u00A0Мск",
"resultsDeadline": "Публикация итогов: %{date}",
"uploadBtn": "Загрузить работу",
"resultLinkTitle": "Результаты задания",
"editTitle": "Редактировать...",
Expand Down Expand Up @@ -201,7 +200,10 @@
"showMoreBtn": "показать больше",
"showLessBtn": "свернуть"
},
"fallback:lessonNotStartedYet": "Этот урок пока не начался. Он начнётся %{startDate}, будем вас ждать"
"fallback:lessonNotStartedYet": "Этот урок пока не начался. Он начнётся %{startDate}, будем вас ждать",
"fallback:noResults:beforeDeadline": "Дата публикации результатов %{resultsEndDate}. Приходите позже.",
"fallback:noResults:deadlineDay": "Результатов пока нет, но они должны появится сегодня.",
"fallback:noResults:pastDeadline": "Извиняемся за задержку результатов, мы их активно проверяем. Если задержка более дня, напишите, пожалуйста, в телеграм-чат курса."
},
"week": {
"one": "неделя",
Expand Down
1 change: 1 addition & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ export * from './const';
export * from './fetch';
export * from './getId';
export * from './guid';
export * from './isMounted';
export * from './memoize';
export * from './URLSection';
13 changes: 13 additions & 0 deletions src/hooks/isMounted.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { useEffect, useRef } from 'react';

export function useIsMounted() {
const isMounted = useRef(true);

useEffect(() => {
return () => {
isMounted.current = false;
};
}, []);

return isMounted;
}
5 changes: 2 additions & 3 deletions src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { Provider } from 'react-redux';

Expand All @@ -13,9 +12,9 @@ const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement)
store.dispatch(init({}));

root.render(
<React.StrictMode>
// <React.StrictMode> // fucks up isMounted hook
<Provider store={store}>
<Router/>
</Provider>
</React.StrictMode>
// </React.StrictMode>
);
2 changes: 1 addition & 1 deletion src/pages/Course/Landing/DiscountBanner/DiscountBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function DiscountBanner(props: IProps) {
</div>
</div>
<div className={classes.descriptionWrapper + ' s-text-24'}>
{t('description', { deadline: formatDate(discontDeadline, { timeZone: 'Europe/Moscow' }) })}
{t('description', { deadline: formatDate(discontDeadline, { timeZone: 'Europe/Moscow', wTime: true }) })}
</div>
</div>
<div className={classes.timerWrapper}>
Expand Down
29 changes: 19 additions & 10 deletions src/pages/Course/Lesson/Lesson.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,26 @@ import LessonUppload from './LessonUppload/LessonUppload';
import LessonWorks from './LessonWorks/LessonWorks';
import LessonHeader from './LessonHeader/LessonHeader';

import useCanShowResults from './useCanShowResults';
import useFetchHomework from './useFetchHomework';
import useHomeworkFallback from './useHomeworkFallback';
import useInitHomework from './useInitHomework';
import useLessonFallback from './useLessonFallback';

import type { IHomeworksState, ILessonState, IRootState } from 'types';
import type { ILessonState, IRootState } from 'types';
import Fallback from 'ui/Fallback';
import { i18n } from 'shared';
import { userService } from 'services/user.service';

export default connect(mapStateToProps)(Lesson);

interface IConnectedProps {
lessonState: ILessonState
homeworksState: IHomeworksState
authedUserId?: string
}

function mapStateToProps(state: IRootState): IConnectedProps {
return {
lessonState: state.lesson,
homeworksState: state.homeworks,
authedUserId: state.user?.user?.id,
};
}

Expand All @@ -39,11 +39,15 @@ interface IProps extends IConnectedProps {
}

function Lesson(props: IProps) {
const { lessonState, section, authedUserId } = props;
const { lessonState, section } = props;
const now = new Date();

const { courseId, lessonId } = useParams();
const [scrollToUpload, setScrollToUpload] = useState<boolean>(false);

const authedUser = userService.useAuthedUser();
const authedUserId = authedUser?.id;

useFetch<IFetchLessonPayload>(({
actionCreator: fetchLesson,
payload: {
Expand All @@ -55,17 +59,22 @@ function Lesson(props: IProps) {
useInitHomework({ courseId, lessonId, userId: authedUserId, lesson: lessonState.data });
const { homework, homeworkState } = useFetchHomework({ courseId, lessonId, userId: authedUserId });

const fallback = useLessonFallback(lessonState);
const fallback = useLessonFallback({ lessonState, authedUser });
const homeworkFallback = useHomeworkFallback(homeworkState);
const { canShowResults, fallBack: resultsFallback } = useCanShowResults({ courseId, lessonId, lesson: lessonState.data })

if (!lessonState.data || lessonState.data.startDate > new Date()) {
if (!lessonState.data || (authedUser?.role !== 'support' && lessonState.data.startDate > now)) {
return fallback;
}

if (lessonState.data.type === 'Practice' && !homework) {
return homeworkFallback;
}

if (section === 'results' && !canShowResults) {
return resultsFallback;
}

return (
<Page header wrapper='Lesson'>
<LessonHeader
Expand All @@ -82,13 +91,13 @@ function Lesson(props: IProps) {
scrollToUpload={() => setScrollToUpload(true)}
/>)
}
{section === 'task' && homework?.homework?.state === 'DRAFT' &&
{section === 'task' && lessonState.data.endDate > now && homework?.homework?.state === 'DRAFT' &&
<LessonUppload
homeworkWPopulate={homework}
scroll={scrollToUpload}
onScrollEnd={() => setScrollToUpload(false)}
/>
}
{section === 'results' && <LessonWorks/>}
{section === 'results' && canShowResults && <LessonWorks/>}
</Page>);
}
28 changes: 4 additions & 24 deletions src/pages/Course/Lesson/LessonContent/LessonContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import classes from './LessonContent.module.scss';
import { URLSections } from 'types';
import type { IHomeworkDataWPopulate, ILessonContent, ILessonData } from 'types';
import { homeworkService } from 'services';
import { formatDate } from 'utils';

export default LessonContent;

Expand Down Expand Up @@ -57,13 +58,13 @@ function Uppload(props: IUpploadProps) {
<Fragment>
<div className={classes.uploadDeadline}>
<p className='s-text-24'>
{t('deadlineUploadText')} {getWeekDay(endDate)} {formatLessonDate(endDate)} {t('deadlineUploadTime')}
{t('uploadDeadline', { date: formatDate(endDate, { timeZone: 'Europe/Moscow', wWeekDay: true, wTime: true }) })}
</p>
<p className='s-text-24'>
{t('deadlineResultsText')} {getWeekDay(resultsEndDate)} {formatLessonResultsDate(resultsEndDate)}
{t('resultsDeadline', { date: formatDate(resultsEndDate, { timeZone: 'Europe/Moscow', wWeekDay: true }) })}
</p>
</div>
{homework && homework.homework.state === 'SENT_FOR_REVIEW' && (
{homework && endDate > new Date() && homework.homework.state === 'SENT_FOR_REVIEW' && (
<div className={classes.resultLinkWrapper}>
<h3 className={classes.resultLinkTitle + ' s-text-28'}>{t('resultLinkTitle')}</h3>
<div className={classes.resultLinkGroup}>
Expand Down Expand Up @@ -95,24 +96,3 @@ function Uppload(props: IUpploadProps) {
</Fragment>
);
}

function getWeekDay(date: Date) {
const weekday = ['воскресенье','понедельник','вторник','среда','четверг','пятница','суббота'];
return weekday[date.getDay()];
}

function formatLessonDate(date: Date) {
const dateStr = date.toLocaleDateString(
['ru-RU'],
{ month: 'long', day: 'numeric' }
);
return `${dateStr} 2024, `;
}

function formatLessonResultsDate(date: Date) {
const dateStr = date.toLocaleDateString(
['ru-RU'],
{ month: 'long', day: 'numeric' }
);
return `${dateStr}`;
}
7 changes: 5 additions & 2 deletions src/pages/Course/Lesson/LessonHeader/LessonHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Subscription } from 'rxjs';

import { IUserData, userService } from 'services/user.service';
import { formatI18nT } from 'shared';

import useCanShowResults from '../useCanShowResults';
import useFilter from '../useFilter';

import Link from 'ui/Link/Link';
Expand All @@ -25,6 +27,7 @@ function LessonHeader(props: IProps) {
const { lesson, practice } = props;
const { courseId, lessonId } = useParams() as { courseId: string, lessonId: string };
const { filter } = useFilter();
const { canShowResults } = useCanShowResults({ lesson, lessonId, courseId });

const { userId } = filter;
const [user, setUser] = useState<IUserData | null>(null);
Expand All @@ -36,7 +39,7 @@ function LessonHeader(props: IProps) {

let subscription: Subscription;
userService
.getHomeworkBS({ filter: { id: userId }})
.getUserBS({ filter: { id: userId }})
.then(bs => {
subscription = bs.subscribe(action => {
if (action && !(action instanceof Error) && action.users.length) {
Expand All @@ -55,7 +58,7 @@ function LessonHeader(props: IProps) {
<span className='nav-link-arrow'>&rarr;</span>
</Link>
<h1 className={classes.title + ' s-text-56'}>{lesson.title}</h1>
{props.lesson.type === 'Practice' && (
{props.lesson.type === 'Practice' && canShowResults && (
<div className={classes.navTubs}>
<Link
className={classes.type + ' nav-link s-text-18' + (practice === 'task' ? ' isActive' : '')}
Expand Down
6 changes: 5 additions & 1 deletion src/pages/Course/Lesson/LessonUppload/LessonUppload.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useCallback, useEffect, useReducer, useRef } from 'react';
import { connect } from 'react-redux';
import { useParams } from 'react-router';

import { homeworkService } from 'services';
import { dataService, homeworkService } from 'services';
import { formatI18nT } from 'shared';

import File from './File/File';
Expand Down Expand Up @@ -254,6 +254,10 @@ function LessonUppload({ homeworkWPopulate, user, scroll, onScrollEnd }: IProps)
}

try {
const lesson = await dataService.lesson.get(state.courseId, state.lessonId);
if (lesson.endDate < new Date()) {
throw new Error('Cannot sent homework past deadline');
}
dispatch({ type: 'PATCH_STATE', payload: { formState: { type: 'pending' }}});
await homeworkService.patchHomework(state.id, { state: 'SENT_FOR_REVIEW' });
dispatch({ type: 'PATCH_STATE', payload: { formState: { type: 'success' }}});
Expand Down
61 changes: 61 additions & 0 deletions src/pages/Course/Lesson/useCanShowResults.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { useEffect, useState } from 'react';
import type { Subscription } from 'rxjs';

import { formatI18nT } from 'shared';
import { addDays, formatDate } from 'utils';

import { homeworkService } from 'services';
import { userService } from 'services/user.service';

import Fallback from 'ui/Fallback';

import type { ILessonData } from 'types';

const t = formatI18nT('courseLesson');

interface IProps {
lesson: ILessonData | undefined
courseId: string | undefined
lessonId: string | undefined
}

export default function useCanShowResults(props: Readonly<IProps>) {
const { lesson, courseId, lessonId } = props;

const authedUser = userService.useAuthedUser();
const [sentForReviewHomeworksCount, setSentForReviewHomeworksCount] = useState<number | null>(null);
const canShowResults = lesson && lesson.resultsEndDate < new Date() && sentForReviewHomeworksCount === 0
|| authedUser?.role === 'support';

useEffect(() => {
if (!courseId || !lessonId) {
return;
}

let subscription: Subscription;
homeworkService.getHomeworkBS({ filter: { courseId, lessonId, state: 'SENT_FOR_REVIEW' } })
.then(bs => {
subscription = bs.subscribe(e => {
if (e && !(e instanceof Error)) {
setSentForReviewHomeworksCount(e.homeworks.length)
}
});
});

return () => subscription?.unsubscribe();
}, [courseId, lessonId]);

const fallBackType = !lesson ? null:
lesson.resultsEndDate > new Date() ? 'beforeDeadline'
: addDays(lesson.resultsEndDate, 1) > new Date() ? 'deadlineDay'
: 'pastDeadline';
const fallBack = canShowResults || !fallBackType ? null : (
<Fallback.Info>
{t(`fallback:noResults:${fallBackType}`, {
resultsEndDate: formatDate(lesson!.resultsEndDate, { timeZone: 'Europe/Moscow', wWeekDay: true })
})}
</Fallback.Info>
);

return { canShowResults, fallBack };
}
14 changes: 11 additions & 3 deletions src/pages/Course/Lesson/useLessonFallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,16 @@ import Fallback from 'ui/Fallback';
import { ECommonErrorTypes, type ILessonState } from 'types';
import { i18n } from 'shared';
import { formatDate } from 'utils';
import { IUserData } from 'services/user.service';

interface IProps {
lessonState: ILessonState
authedUser: IUserData | null
}

export default function useLessonFallback(props: Readonly<IProps>) {
const { lessonState, authedUser } = props;

export default function useLessonFallback(lessonState: ILessonState) {
if (lessonState.state) {
if (lessonState.state.type === 'pending') {
return <Fallback.Pending text='loading lessons...'/>;
Expand All @@ -30,8 +38,8 @@ export default function useLessonFallback(lessonState: ILessonState) {
return <Fallback.Error/>;
}

if (lessonState.data.startDate > new Date()) {
const startDate = formatDate(lessonState.data.startDate, { timeZone: 'Europe/Moscow', woTime: true });
if (authedUser?.role !== 'support' && lessonState.data.startDate > new Date()) {
const startDate = formatDate(lessonState.data.startDate, { timeZone: 'Europe/Moscow' });
return <Fallback.Info>{i18n.t('courseLesson.fallback:lessonNotStartedYet', { startDate })}</Fallback.Info>;
}

Expand Down
Loading

0 comments on commit 8566174

Please sign in to comment.