Рефакторинг импорта dayjs и добавление утилиты форматирования дат. Все компоненты, использующие dayjs, теперь используют новую функцию formatDate для форматирования дат с учетом локали. Также добавлена поддержка обновления локали dayjs при изменении языка в i18next.
This commit is contained in:
parent
3d383f2e25
commit
2901f51862
@ -2,16 +2,13 @@ import React from 'react';
|
||||
import { Helmet } from 'react-helmet';
|
||||
import { Global } from '@emotion/react'
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import ruLocale from 'dayjs/locale/ru';
|
||||
import dayjs from 'dayjs';
|
||||
import dayjs from './utils/dayjs-config';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { ChakraProvider, ColorModeScript, extendTheme } from '@chakra-ui/react'
|
||||
|
||||
import { Dashboard } from './dashboard';
|
||||
import { globalStyles } from './global.styles';
|
||||
|
||||
dayjs.locale('ru', ruLocale);
|
||||
|
||||
// Расширяем тему Chakra UI
|
||||
const theme = extendTheme({
|
||||
config: {
|
||||
|
@ -21,7 +21,8 @@ import {
|
||||
useColorMode,
|
||||
} from "@chakra-ui/react";
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import dayjs from 'dayjs';
|
||||
import dayjs from "../../../utils/dayjs-config";
|
||||
import { formatDate } from "../../../utils/dayjs-config";
|
||||
import UserSelect from "../../../components/user-select";
|
||||
|
||||
interface AttendanceEntry {
|
||||
@ -41,7 +42,7 @@ const AddDataDialog = ({ isOpen, onClose, onAddData }: AddDataDialogProps) => {
|
||||
const { colorMode } = useColorMode();
|
||||
const { t } = useTranslation();
|
||||
const [name, setName] = useState("");
|
||||
const [date, setDate] = useState(dayjs().format('YYYY-MM-DD'));
|
||||
const [date, setDate] = useState(formatDate(dayjs().toDate(), 'YYYY-MM-DD'));
|
||||
const [selectedStudents, setSelectedStudents] = useState<any[]>([]);
|
||||
const [selectedTeachers, setSelectedTeachers] = useState<any[]>([]);
|
||||
|
||||
@ -60,7 +61,7 @@ const AddDataDialog = ({ isOpen, onClose, onAddData }: AddDataDialogProps) => {
|
||||
|
||||
const resetForm = () => {
|
||||
setName("");
|
||||
setDate(dayjs().format('YYYY-MM-DD'));
|
||||
setDate(formatDate(dayjs().toDate(), 'YYYY-MM-DD'));
|
||||
setSelectedStudents([]);
|
||||
setSelectedTeachers([]);
|
||||
};
|
||||
|
@ -33,6 +33,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { getGravatarURL } from '../../../utils/gravatar'
|
||||
import { ShortText } from './ShortText'
|
||||
import { AttendanceData } from '../hooks'
|
||||
import { formatDate } from '../../../utils/dayjs-config'
|
||||
|
||||
interface AttendanceTableProps {
|
||||
data: AttendanceData
|
||||
@ -120,7 +121,7 @@ export const AttendanceTable: React.FC<AttendanceTableProps> = ({ data }) => {
|
||||
})
|
||||
|
||||
// Добавляем дату
|
||||
row.push(dayjs(lesson.date).format('DD.MM.YYYY'))
|
||||
row.push(formatDate(lesson.date, 'DD.MM.YYYY'))
|
||||
|
||||
// Добавляем полное название занятия (без сокращений)
|
||||
row.push(lesson.name)
|
||||
@ -230,7 +231,7 @@ export const AttendanceTable: React.FC<AttendanceTableProps> = ({ data }) => {
|
||||
</Td>
|
||||
)
|
||||
})}
|
||||
<Td>{dayjs(lesson.date).format('DD.MM.YYYY')}</Td>
|
||||
<Td>{formatDate(lesson.date, 'DD.MM.YYYY')}</Td>
|
||||
<Td><ShortText text={lesson.name} /></Td>
|
||||
|
||||
{data.students.map((st) => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { useCallback, useEffect, useState, useMemo } from 'react'
|
||||
import { formatDate } from '../../utils/dayjs-config'
|
||||
import dayjs from 'dayjs'
|
||||
import { Link as ConnectedLink, generatePath } from 'react-router-dom'
|
||||
import { getNavigationValue } from '@brojs/cli'
|
||||
@ -231,7 +232,7 @@ export const CourseCard = ({ course }: { course: Course }) => {
|
||||
<Badge colorScheme="blue">
|
||||
<HStack spacing={1}>
|
||||
<CalendarIcon boxSize="3" />
|
||||
<Text>{dayjs(course.startDt).format('DD.MM.YYYY')}</Text>
|
||||
<Text>{formatDate(course.startDt, 'DD.MM.YYYY')}</Text>
|
||||
</HStack>
|
||||
</Badge>
|
||||
<Badge colorScheme="purple">
|
||||
@ -243,7 +244,7 @@ export const CourseCard = ({ course }: { course: Course }) => {
|
||||
<Badge colorScheme="blue">
|
||||
<HStack spacing={1}>
|
||||
<CalendarIcon boxSize="3" />
|
||||
<Text>{dayjs(course.startDt).format('DD.MM.YYYY')}</Text>
|
||||
<Text>{formatDate(course.startDt, 'DD.MM.YYYY')}</Text>
|
||||
</HStack>
|
||||
</Badge>
|
||||
<Badge colorScheme="purple">
|
||||
@ -311,10 +312,12 @@ export const CourseCard = ({ course }: { course: Course }) => {
|
||||
{populatedCourse.data?.lessons
|
||||
.filter(lesson => dayjs(lesson.date).isAfter(dayjs()))
|
||||
.sort((a, b) => dayjs(a.date).valueOf() - dayjs(b.date).valueOf())[0]?.date
|
||||
? dayjs(populatedCourse.data?.lessons
|
||||
.filter(lesson => dayjs(lesson.date).isAfter(dayjs()))
|
||||
.sort((a, b) => dayjs(a.date).valueOf() - dayjs(b.date).valueOf())[0]?.date)
|
||||
.format('DD.MM.YYYY')
|
||||
? formatDate(
|
||||
populatedCourse.data?.lessons
|
||||
.filter(lesson => dayjs(lesson.date).isAfter(dayjs()))
|
||||
.sort((a, b) => dayjs(a.date).valueOf() - dayjs(b.date).valueOf())[0]?.date,
|
||||
'DD.MM.YYYY'
|
||||
)
|
||||
: t('journal.pl.common.noData')
|
||||
}
|
||||
</Text>
|
||||
@ -455,7 +458,7 @@ export const CourseCard = ({ course }: { course: Course }) => {
|
||||
<HStack spacing={2} mt={1} flexWrap="wrap">
|
||||
<Tag size="sm" colorScheme={isPast ? "green" : "blue"} borderRadius="full">
|
||||
<TagLeftIcon as={CalendarIcon} boxSize='10px' />
|
||||
<TagLabel>{dayjs(lesson.date).format('DD.MM.YYYY')}</TagLabel>
|
||||
<TagLabel>{formatDate(lesson.date, 'DD.MM.YYYY')}</TagLabel>
|
||||
</Tag>
|
||||
{isPast && lessonAttendance && (
|
||||
<Tag
|
||||
|
@ -1,8 +1,9 @@
|
||||
import { useRef, useEffect } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import dayjs from '../../../utils/dayjs-config'
|
||||
import { useForm } from 'react-hook-form'
|
||||
import { useToast } from '@chakra-ui/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { formatDate } from '../../../utils/dayjs-config'
|
||||
|
||||
import { api } from '../../../__data__/api/api'
|
||||
|
||||
@ -30,7 +31,7 @@ export const useCreateCourse = (onSuccess: () => void) => {
|
||||
getValues,
|
||||
} = useForm<NewCourseForm>({
|
||||
defaultValues: {
|
||||
startDt: dayjs().format('YYYY-MM-DD'),
|
||||
startDt: formatDate(dayjs().toDate(), 'YYYY-MM-DD'),
|
||||
name: t('journal.pl.course.defaultName'),
|
||||
},
|
||||
})
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { useMemo } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import dayjs, { formatDate } from '../../../utils/dayjs-config'
|
||||
import { Course } from '../../../__data__/model'
|
||||
|
||||
/**
|
||||
@ -20,7 +20,7 @@ export const useGroupedCourses = (courses?: Course[]) => {
|
||||
|
||||
// Группируем по годам
|
||||
sortedCourses.forEach(course => {
|
||||
const year = dayjs(course.startDt).format('YYYY')
|
||||
const year = formatDate(course.startDt, 'YYYY')
|
||||
if (!grouped[year]) {
|
||||
grouped[year] = []
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import React, { useEffect, useRef, useMemo } from 'react'
|
||||
import { useParams, Link } from 'react-router-dom'
|
||||
import dayjs from 'dayjs'
|
||||
import QRCode from 'qrcode'
|
||||
import { sha256 } from 'js-sha256'
|
||||
import { getConfigValue, getNavigationValue } from '@brojs/cli'
|
||||
@ -21,6 +20,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { api } from '../__data__/api/api'
|
||||
import { User } from '../__data__/model'
|
||||
import { UserCard } from '../components/user-card'
|
||||
import { formatDate } from '../utils/dayjs-config'
|
||||
|
||||
import {
|
||||
QRCanvas,
|
||||
@ -209,8 +209,8 @@ const LessonDetail = () => {
|
||||
borderRadius="xl"
|
||||
bg={colorMode === "light" ? "gray.50" : "gray.700"}
|
||||
boxShadow="md"
|
||||
><Box as="span">
|
||||
{dayjs(accessCode?.body?.lesson?.date).format(t('journal.pl.lesson.dateFormat'))}{' '}
|
||||
><Box pb={3}>
|
||||
{formatDate(accessCode?.body?.lesson?.date, t('journal.pl.lesson.dateFormat'))}{' '}
|
||||
{t('journal.pl.common.marked')} - {accessCode?.body?.lesson?.students?.length}{' '}
|
||||
{AllStudents.isSuccess
|
||||
? `/ ${AllStudents?.data?.body?.length}`
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useRef, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import { formatDate } from '../../../utils/dayjs-config'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { getNavigationValue, getFeatures } from '@brojs/cli'
|
||||
import {
|
||||
@ -133,7 +133,7 @@ export const Item: React.FC<ItemProps> = ({
|
||||
<>
|
||||
<Flex justify="space-between" align="center" mb={2}>
|
||||
<Text fontWeight="medium">{name}</Text>
|
||||
<Text fontSize="sm">{dayjs(date).format(groupByDate ? 'HH:mm' : 'HH:mm DD.MM.YY')}</Text>
|
||||
<Text fontSize="sm">{formatDate(date, groupByDate ? 'HH:mm' : 'HH:mm DD.MM.YY')}</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex justify="space-between" align="center">
|
||||
@ -193,7 +193,7 @@ export const Item: React.FC<ItemProps> = ({
|
||||
</Td>
|
||||
)}
|
||||
<Td textAlign="center">
|
||||
{dayjs(date).format(groupByDate ? 'HH:mm' : 'HH:mm DD.MM.YY')}
|
||||
{formatDate(date, groupByDate ? 'HH:mm' : 'HH:mm DD.MM.YY')}
|
||||
</Td>
|
||||
<Td>{name}</Td>
|
||||
{isTeacher && (
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import { formatDate } from '../../../utils/dayjs-config'
|
||||
import {
|
||||
Tr,
|
||||
Td,
|
||||
@ -45,7 +45,7 @@ export const LessonItems: React.FC<LessonItemProps> = ({
|
||||
borderRadius="md"
|
||||
_dark={{ bg: "gray.700" }}
|
||||
>
|
||||
<Text fontWeight="bold">{dayjs(date).format('DD MMMM YYYY')}</Text>
|
||||
<Text fontWeight="bold">{formatDate(date, 'DD MMMM YYYY')}</Text>
|
||||
</Box>
|
||||
)}
|
||||
{lessons.map((lesson) => (
|
||||
@ -78,7 +78,7 @@ export const LessonItems: React.FC<LessonItemProps> = ({
|
||||
{date && (
|
||||
<Tr>
|
||||
<Td colSpan={isTeacher ? 5 : 3}>
|
||||
{dayjs(date).format('DD MMMM YYYY')}
|
||||
{formatDate(date, 'DD MMMM YYYY')}
|
||||
</Td>
|
||||
</Tr>
|
||||
)}
|
||||
|
@ -30,6 +30,7 @@ import { AddIcon, CheckIcon, WarningIcon, RepeatIcon } from '@chakra-ui/icons'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { FaRobot } from 'react-icons/fa'
|
||||
import dayjs from 'dayjs'
|
||||
import { formatDate } from '../../../utils/dayjs-config'
|
||||
|
||||
import { dateToCalendarFormat } from '../../../utils/time'
|
||||
import { Lesson } from '../../../__data__/model'
|
||||
@ -294,7 +295,7 @@ export const LessonForm = ({
|
||||
{isSelected && <CheckIcon color="green.400" />}
|
||||
</Flex>
|
||||
<Text fontSize="sm" color={textSecondaryColor}>
|
||||
{dayjs(suggestion.date).format('DD.MM.YYYY HH:mm')}
|
||||
{formatDate(suggestion.date, 'DD.MM.YYYY HH:mm')}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import React, { useMemo } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import { formatDate } from '../../../utils/dayjs-config'
|
||||
import {
|
||||
Box,
|
||||
Heading,
|
||||
@ -45,7 +46,7 @@ export const CourseStatistics: React.FC<CourseStatisticsProps> = ({ lessons = []
|
||||
|
||||
// Вычисляем статистику курса
|
||||
const stats = useMemo(() => {
|
||||
if (!lessons.length) {
|
||||
if (!lessons || lessons.length === 0) {
|
||||
return {
|
||||
totalLessons: 0,
|
||||
completedLessons: 0,
|
||||
@ -215,10 +216,10 @@ export const CourseStatistics: React.FC<CourseStatisticsProps> = ({ lessons = []
|
||||
{stats.attendanceTrend !== 0 && (
|
||||
<Flex align="center">
|
||||
<StatArrow
|
||||
type={stats.attendanceTrend > 0 ? 'increase' : 'decrease'}
|
||||
type={Number(stats.attendanceTrend) > 0 ? 'increase' : 'decrease'}
|
||||
/>
|
||||
<Text>
|
||||
{Math.abs(Math.round(stats.attendanceTrend))}%
|
||||
{Math.abs(Math.round(Number(stats.attendanceTrend)))}%
|
||||
</Text>
|
||||
</Flex>
|
||||
)}
|
||||
@ -261,7 +262,7 @@ export const CourseStatistics: React.FC<CourseStatisticsProps> = ({ lessons = []
|
||||
</Flex>
|
||||
<StatNumber fontSize="xl">
|
||||
{stats.nextLessonDate
|
||||
? dayjs(stats.nextLessonDate).format('DD.MM.YYYY')
|
||||
? formatDate(stats.nextLessonDate, 'DD.MM.YYYY')
|
||||
: t('journal.pl.statistics.noUpcoming')
|
||||
}
|
||||
</StatNumber>
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
||||
import dayjs from 'dayjs'
|
||||
import dayjs, { formatDate } from '../../utils/dayjs-config'
|
||||
import { generatePath, Link, useParams } from 'react-router-dom'
|
||||
import { getNavigationValue, getFeatures } from '@brojs/cli'
|
||||
import {
|
||||
@ -277,7 +277,7 @@ const LessonList = () => {
|
||||
<AlertDialogOverlay>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader fontSize="lg" fontWeight="bold">
|
||||
{t('journal.pl.lesson.deleteConfirm', { date: dayjs(lessonToDelete?.date).format('DD.MM.YY') })}
|
||||
{t('journal.pl.lesson.deleteConfirm', { date: formatDate(lessonToDelete?.date, 'DD.MM.YY') })}
|
||||
</AlertDialogHeader>
|
||||
|
||||
<AlertDialogBody>
|
||||
|
@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { motion, AnimatePresence } from 'framer-motion'
|
||||
|
||||
import { api } from '../__data__/api/api'
|
||||
import dayjs from 'dayjs'
|
||||
import { formatDate } from '../utils/dayjs-config'
|
||||
import {
|
||||
Alert,
|
||||
AlertIcon,
|
||||
@ -145,7 +145,7 @@ const UserPage = () => {
|
||||
|
||||
<Flex align="center" justify="space-between" mt={3}>
|
||||
<Text color={colorMode === "light" ? "gray.600" : "gray.300"}>
|
||||
{dayjs(ls.data?.body?.date).format(t('journal.pl.lesson.dateFormat'))}
|
||||
{formatDate(ls.data?.body?.date, t('journal.pl.lesson.dateFormat'))}
|
||||
</Text>
|
||||
|
||||
<Badge colorScheme="green" fontSize="md" borderRadius="full" px={3} py={1}>
|
||||
|
30
src/utils/dayjs-config.ts
Normal file
30
src/utils/dayjs-config.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import dayjs from 'dayjs';
|
||||
import 'dayjs/locale/ru';
|
||||
import 'dayjs/locale/en';
|
||||
import i18next from 'i18next';
|
||||
|
||||
// Функция для обновления локали dayjs при изменении языка в i18next
|
||||
export const updateDayjsLocale = () => {
|
||||
const currentLocale = i18next.language;
|
||||
|
||||
// Убедимся, что локаль поддерживается, иначе используем 'en'
|
||||
const locale = ['ru', 'en'].includes(currentLocale) ? currentLocale : 'en';
|
||||
|
||||
// Установим локаль для dayjs
|
||||
dayjs.locale(locale);
|
||||
};
|
||||
|
||||
// Слушаем изменения языка и обновляем локаль dayjs
|
||||
i18next.on('languageChanged', () => {
|
||||
updateDayjsLocale();
|
||||
});
|
||||
|
||||
// Вызываем функцию инициализации при импорте
|
||||
updateDayjsLocale();
|
||||
|
||||
// Хелпер для форматирования даты с учетом текущей локали
|
||||
export const formatDate = (date: string | Date | number, format = 'DD.MM.YYYY') => {
|
||||
return dayjs(date).format(format);
|
||||
};
|
||||
|
||||
export default dayjs;
|
@ -1,3 +1,3 @@
|
||||
import dayjs from "dayjs";
|
||||
import dayjs, { formatDate } from "./dayjs-config";
|
||||
|
||||
export const dateToCalendarFormat = (date?: string) => dayjs(date).format('YYYY-MM-DDTHH:mm')
|
||||
export const dateToCalendarFormat = (date?: string) => formatDate(date, 'YYYY-MM-DDTHH:mm')
|
||||
|
Loading…
x
Reference in New Issue
Block a user