diff --git a/apps/xi.web/public/assets/brand/navigationlogo-small-dark-new.svg b/apps/xi.web/public/assets/brand/navigationlogo-small-dark-new.svg new file mode 100644 index 00000000..ac652a59 --- /dev/null +++ b/apps/xi.web/public/assets/brand/navigationlogo-small-dark-new.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/apps/xi.web/public/assets/brand/navigationlogo-small-dark.svg b/apps/xi.web/public/assets/brand/navigationlogo-small-dark.svg deleted file mode 100644 index 892b83c0..00000000 --- a/apps/xi.web/public/assets/brand/navigationlogo-small-dark.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/apps/xi.web/public/assets/brand/navigationlogo-small-light-new.svg b/apps/xi.web/public/assets/brand/navigationlogo-small-light-new.svg new file mode 100644 index 00000000..8235d540 --- /dev/null +++ b/apps/xi.web/public/assets/brand/navigationlogo-small-light-new.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/apps/xi.web/public/assets/brand/navigationlogo-small-light.svg b/apps/xi.web/public/assets/brand/navigationlogo-small-light.svg deleted file mode 100644 index 4fa72d9b..00000000 --- a/apps/xi.web/public/assets/brand/navigationlogo-small-light.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/apps/xi.web/src/index.css b/apps/xi.web/src/index.css index 39d12523..8b1f58ab 100644 --- a/apps/xi.web/src/index.css +++ b/apps/xi.web/src/index.css @@ -39,6 +39,7 @@ @source "../../../packages/pages.email/src"; @source "../../../packages/pages.notes/src"; @source "../../../packages/pages.email-confirm/src"; +@source "../../../packages/features.lesson.add/src"; @source "../../../node_modules/@xipkg"; diff --git a/apps/xi.web/src/pages/__root.tsx b/apps/xi.web/src/pages/__root.tsx index 4ca8b9e4..353c77ef 100644 --- a/apps/xi.web/src/pages/__root.tsx +++ b/apps/xi.web/src/pages/__root.tsx @@ -1,5 +1,5 @@ import { createRootRouteWithContext, HeadContent, Outlet, redirect } from '@tanstack/react-router'; -import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'; +// import { TanStackRouterDevtools } from '@tanstack/react-router-devtools'; import { AuthContextT } from 'common.auth'; interface MyRouterContext { @@ -75,7 +75,7 @@ export const Route = createRootRouteWithContext()({ <> - + {/* */} ), }); diff --git a/packages/common.ui/index.ts b/packages/common.ui/index.ts index d3404d35..81a81a32 100644 --- a/packages/common.ui/index.ts +++ b/packages/common.ui/index.ts @@ -5,3 +5,4 @@ export { LinkTanstack } from './src/LinkTanstack'; export { ErrorPage } from './src/ErrorPage'; export { Menu } from './src/Menu'; export { NetworkIndicator } from './src/NetworkIndicator'; +export { SmallLogo } from './src/SmallLogo'; diff --git a/packages/common.ui/package.json b/packages/common.ui/package.json index b62091ae..10a64097 100644 --- a/packages/common.ui/package.json +++ b/packages/common.ui/package.json @@ -14,7 +14,7 @@ "dependencies": { "@tanstack/react-router": "1.128.8", "@xipkg/button": "4.1.0", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/link": "2.0.12", "@xipkg/utils": "1.8.0", "common.env": "*", diff --git a/packages/common.ui/src/SmallLogo.tsx b/packages/common.ui/src/SmallLogo.tsx new file mode 100644 index 00000000..79e08e64 --- /dev/null +++ b/packages/common.ui/src/SmallLogo.tsx @@ -0,0 +1,20 @@ +export const SmallLogo = ({ width = 135, height = 16 }: { width?: number; height?: number }) => { + return ( + <> + logo + logo + + ); +}; diff --git a/packages/features.avatar.editor/package.json b/packages/features.avatar.editor/package.json index fa44d78f..b9b33bfa 100644 --- a/packages/features.avatar.editor/package.json +++ b/packages/features.avatar.editor/package.json @@ -20,7 +20,7 @@ "common.ui": "*", "i18next": "24.2.2", "react-i18next": "15.4.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/utils": "1.8.0", "@xipkg/slider": "2.0.12", "common.config": "*", diff --git a/packages/features.group.invite/package.json b/packages/features.group.invite/package.json index 73e8bd2f..df09aea9 100644 --- a/packages/features.group.invite/package.json +++ b/packages/features.group.invite/package.json @@ -14,12 +14,12 @@ "@tanstack/react-query": "^5.73.3", "@tanstack/react-router": "^1.128.8", "@xipkg/button": "4.1.0", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "^2.2.9", "@xipkg/modal": "^4.3.1", "@xipkg/scrollarea": "^2.2.0", "@xipkg/tooltip": "^2.1.0", - "@xipkg/userprofile": "^4.0.14", + "@xipkg/userprofile": "4.1.0", "@xipkg/utils": "^1.8.0", "common.api": "*", "common.config": "*", diff --git a/packages/features.group.manage/package.json b/packages/features.group.manage/package.json index 0d30467c..8f7a1393 100644 --- a/packages/features.group.manage/package.json +++ b/packages/features.group.manage/package.json @@ -14,12 +14,12 @@ "@tanstack/react-query": "^5.73.3", "@tanstack/react-router": "^1.128.8", "@xipkg/button": "4.1.0", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "^2.2.9", "@xipkg/modal": "^4.3.1", "@xipkg/scrollarea": "^2.2.0", "@xipkg/tooltip": "^2.1.0", - "@xipkg/userprofile": "^4.0.14", + "@xipkg/userprofile": "4.1.0", "@xipkg/utils": "^1.8.0", "common.api": "*", "common.config": "*", diff --git a/packages/features.invites/package.json b/packages/features.invites/package.json index a632ab4c..e4716982 100644 --- a/packages/features.invites/package.json +++ b/packages/features.invites/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@xipkg/button": "4.1.0", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/modal": "^4.3.1", "@xipkg/utils": "^1.8.0", "common.env": "*", diff --git a/packages/features.invoice.card/package.json b/packages/features.invoice.card/package.json index 89914d83..2da800bc 100644 --- a/packages/features.invoice.card/package.json +++ b/packages/features.invoice.card/package.json @@ -18,7 +18,7 @@ "common.api": "*", "common.utils": "*", "common.types": "*", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/button": "4.0.0" }, "devDependencies": { diff --git a/packages/features.invoice/package.json b/packages/features.invoice/package.json index 28c91ac6..23a3c2c8 100644 --- a/packages/features.invoice/package.json +++ b/packages/features.invoice/package.json @@ -15,7 +15,7 @@ "@tanstack/react-router": "1.120.11", "@xipkg/button": "4.1.0", "@xipkg/form": "4.2.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.2.9", "@xipkg/modal": "^4.3.1", "@xipkg/select": "2.2.5", diff --git a/packages/features.lesson.add/eslint.config.js b/packages/features.lesson.add/eslint.config.js new file mode 100644 index 00000000..15768bd7 --- /dev/null +++ b/packages/features.lesson.add/eslint.config.js @@ -0,0 +1,3 @@ +import config from 'common.eslint'; + +export default config; diff --git a/packages/features.lesson.add/index.ts b/packages/features.lesson.add/index.ts new file mode 100644 index 00000000..148fc8ed --- /dev/null +++ b/packages/features.lesson.add/index.ts @@ -0,0 +1 @@ +export { AddingLessonModal } from './src'; diff --git a/packages/features.lesson.add/package.json b/packages/features.lesson.add/package.json new file mode 100644 index 00000000..3936700a --- /dev/null +++ b/packages/features.lesson.add/package.json @@ -0,0 +1,56 @@ +{ + "name": "features.lesson.add", + "version": "0.0.0", + "type": "module", + "exports": { + ".": "./index.ts" + }, + "license": "MIT", + "scripts": { + "dev": "tsc --watch", + "lint": "eslint \"**/*.{ts,tsx}\"" + }, + "dependencies": { + "@tanstack/react-router": "1.120.11", + "@tanstack/react-query": "^5.73.3", + "react-i18next": "15.4.1", + "sonner": "^1.4.0", + "common.services": "*", + "common.utils": "*", + "common.config": "*", + "common.api": "*", + "common.env": "*", + "common.types": "*", + "@xipkg/modal": "4.3.1", + "@xipkg/select": "2.2.5", + "@xipkg/utils": "1.8.0", + "@xipkg/form": "4.2.1", + "@xipkg/button": "4.1.0", + "@xipkg/input": "2.2.9", + "@xipkg/icons": "^3.0.4", + "@xipkg/datepicker": "2.2.0", + "@xipkg/inputmask": "2.0.12" + }, + "devDependencies": { + "@eslint/js": "^9.19.0", + "common.typescript": "*", + "common.eslint": "*", + "@types/node": "^20.3.1", + "@types/react": "^19.0.2", + "@types/react-dom": "^19.0.2", + "@xipkg/eslint": "3.2.0", + "@xipkg/tailwind": "0.8.1", + "@xipkg/typescript": "latest", + "eslint": "^9.19.0", + "eslint-plugin-react-hooks": "^5.0.0", + "eslint-plugin-react-refresh": "^0.4.18", + "globals": "^15.14.0", + "typescript": "~5.7.2", + "typescript-eslint": "^8.22.0" + }, + "peerDependencies": { + "react": "19" + }, + "description": "adding lesson feature", + "author": "xi.effect" +} diff --git a/packages/features.lesson.add/src/hooks/index.ts b/packages/features.lesson.add/src/hooks/index.ts new file mode 100644 index 00000000..db7b1138 --- /dev/null +++ b/packages/features.lesson.add/src/hooks/index.ts @@ -0,0 +1,2 @@ +export { useAddingForm } from './useAddingForm'; +export { useConstants } from './useConstants'; diff --git a/packages/features.lesson.add/src/hooks/useAddingForm.ts b/packages/features.lesson.add/src/hooks/useAddingForm.ts new file mode 100644 index 00000000..b0d8fd18 --- /dev/null +++ b/packages/features.lesson.add/src/hooks/useAddingForm.ts @@ -0,0 +1,62 @@ +import { useForm } from '@xipkg/form'; +import { zodResolver } from '@hookform/resolvers/zod'; +import { toast } from 'sonner'; +import { formSchema, type FormData } from '../model/formSchema'; +import { useFetchClassrooms } from 'common.services'; + +const DEFAULT_VALUES: FormData = { + title: '', + description: '', + studentId: '', + startTime: '09:00', + endTime: '10:00', + startDate: new Date(), + shouldRepeat: 'dont_repeat', +}; + +export const useAddingForm = () => { + const { data: classrooms, isLoading: isClassroomsLoading } = useFetchClassrooms(); + + const form = useForm({ + resolver: zodResolver(formSchema), + mode: 'onSubmit', + defaultValues: DEFAULT_VALUES, + }); + + const { control, handleSubmit, reset } = form; + + const onSubmit = (data: FormData) => { + const classroom = classrooms?.find((c) => c.id === Number(data.studentId)); + const studentIds = classroom?.kind === 'individual' ? [classroom.student_id] : []; + + const payload = { + title: data.title, + description: data.description ?? '', + studentIds, + startTime: data.startTime, + endTime: data.endTime, + startDate: data.startDate, + shouldRepeat: data.shouldRepeat, + }; + + console.log('payload', payload); + + // TODO: подключить API создания урока (common.api или модуль календаря) + // await createLesson(payload); + toast.success('Урок назначен'); + }; + + const handleClearForm = () => { + reset(DEFAULT_VALUES); + }; + + return { + form, + control, + handleSubmit, + onSubmit, + handleClearForm, + classrooms: classrooms ?? [], + isClassroomsLoading, + }; +}; diff --git a/packages/features.lesson.add/src/hooks/useConstants.ts b/packages/features.lesson.add/src/hooks/useConstants.ts new file mode 100644 index 00000000..97ecd41d --- /dev/null +++ b/packages/features.lesson.add/src/hooks/useConstants.ts @@ -0,0 +1,24 @@ +import { useMemo } from 'react'; +import { useTranslation } from 'react-i18next'; + +type RepeatVariant = { + value: string; + label: string; +}; + +export const useConstants = () => { + const { t } = useTranslation('calendar'); + + const repeatVariants: RepeatVariant[] = useMemo(() => { + return [ + { value: 'dont_repeat', label: t('repeat_settings.dont_repeat') }, + { value: 'every_day', label: t('repeat_settings.every_day') }, + { value: 'every_work_day', label: t('repeat_settings.every_work_day') }, + { value: 'every_week', label: t('repeat_settings.every_week') }, + { value: 'every_2_weeks', label: t('repeat_settings.every_2_weeks') }, + { value: 'every_month', label: t('repeat_settings.every_month') }, + ]; + }, [t]); + + return { repeatVariants }; +}; diff --git a/packages/features.lesson.add/src/index.ts b/packages/features.lesson.add/src/index.ts new file mode 100644 index 00000000..276519d6 --- /dev/null +++ b/packages/features.lesson.add/src/index.ts @@ -0,0 +1,3 @@ +export { AddingLessonModal } from './ui/AddingLessonModal'; +export * from './hooks'; +export * from './model'; diff --git a/packages/features.lesson.add/src/model/formSchema.ts b/packages/features.lesson.add/src/model/formSchema.ts new file mode 100644 index 00000000..31fe6878 --- /dev/null +++ b/packages/features.lesson.add/src/model/formSchema.ts @@ -0,0 +1,48 @@ +import * as z from 'zod'; + +const timeToMinutes = (time: string): number => { + const [hours, minutes] = time.split(':').map(Number); + return hours * 60 + minutes; +}; + +// Валидация времени +const timeValidation = z.string().refine((time) => { + const timeRegex = /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/; + return timeRegex.test(time); +}, 'Неверный формат времени'); + +export const formSchema = z + .object({ + title: z.string(), + description: z.string().optional(), + studentId: z.string().min(1, 'Выберите студента'), + startTime: timeValidation, + endTime: timeValidation, + startDate: z.date({ required_error: 'Укажите дату' }), + shouldRepeat: z + .enum([ + 'dont_repeat', + 'every_day', + 'every_work_day', + 'every_week', + 'every_2_weeks', + 'every_month', + ]) + .default('dont_repeat'), + }) + .refine( + (data) => { + if (data.startTime && data.endTime) { + const startMinutes = timeToMinutes(data.startTime); + const endMinutes = timeToMinutes(data.endTime); + return startMinutes <= endMinutes; + } + return true; + }, + { + message: 'Время начала не может быть позже времени окончания', + path: ['startTime'], + }, + ); + +export type FormData = z.infer; diff --git a/packages/features.lesson.add/src/model/index.ts b/packages/features.lesson.add/src/model/index.ts new file mode 100644 index 00000000..5d5fd593 --- /dev/null +++ b/packages/features.lesson.add/src/model/index.ts @@ -0,0 +1 @@ +export { formSchema, type FormData } from './formSchema'; diff --git a/packages/features.lesson.add/src/ui/AddingLessonModal.tsx b/packages/features.lesson.add/src/ui/AddingLessonModal.tsx new file mode 100644 index 00000000..96e253e7 --- /dev/null +++ b/packages/features.lesson.add/src/ui/AddingLessonModal.tsx @@ -0,0 +1,46 @@ +import { + Modal, + ModalContent, + ModalFooter, + ModalCloseButton, + ModalHeader, + ModalTitle, + ModalBody, +} from '@xipkg/modal'; +import { Button } from '@xipkg/button'; + +import { AddingForm } from './components/AddingForm'; +import './AddingModal.css'; + +type AddingLessonModalProps = { + open: boolean; + onOpenChange: (open: boolean) => void; +}; + +export const AddingLessonModal = ({ open, onOpenChange }: AddingLessonModalProps) => { + const handleCloseModal = () => { + onOpenChange(false); + }; + + return ( + + + + + Назначение урока + + + + + + + + + + + ); +}; diff --git a/packages/features.lesson.add/src/ui/AddingModal.css b/packages/features.lesson.add/src/ui/AddingModal.css new file mode 100644 index 00000000..e15b533f --- /dev/null +++ b/packages/features.lesson.add/src/ui/AddingModal.css @@ -0,0 +1,13 @@ +/* Делаем календарь в DatePicker кликабельным */ +[data-radix-popover-content], +[data-radix-popper-content-wrapper] { + pointer-events: auto !important; +} + +/* Стили для всех элементов календаря */ +[data-radix-calendar], +[data-radix-calendar-cell], +[data-radix-calendar-day], +[data-radix-calendar-cell] button { + pointer-events: auto !important; +} \ No newline at end of file diff --git a/packages/features.lesson.add/src/ui/components/AddingForm.tsx b/packages/features.lesson.add/src/ui/components/AddingForm.tsx new file mode 100644 index 00000000..bdade425 --- /dev/null +++ b/packages/features.lesson.add/src/ui/components/AddingForm.tsx @@ -0,0 +1,165 @@ +import { Form, FormField, FormItem, FormLabel, FormControl, FormMessage } from '@xipkg/form'; +import { Input } from '@xipkg/input'; +import { useMaskInput } from '@xipkg/inputmask'; +import { ArrowRight, Clock } from '@xipkg/icons'; +import { useAddingForm } from '../../hooks'; +import { InputDate } from './InputDate'; +import { RepeatBlock } from './RepeatBlock'; +import { StudentSelector } from './StudentSelector'; + +import type { FC, PropsWithChildren } from 'react'; +import type { FormData } from '../../model'; + +interface AddingFormProps extends PropsWithChildren { + onClose: () => void; +} + +export const AddingForm: FC = ({ children, onClose }) => { + const { + form, + control, + handleSubmit, + handleClearForm, + onSubmit, + classrooms, + isClassroomsLoading, + } = useAddingForm(); + + const maskRefStartTime = useMaskInput('time'); + const maskRefEndTime = useMaskInput('time'); + + const handleReset = () => { + handleClearForm(); + onClose(); + }; + + const onFormSubmit = (data: FormData) => { + onSubmit(data); + onClose(); + }; + + return ( +
+ +
+ ( + + Название + + + + + + )} + /> + ( + + Описание + + + + + + )} + /> +
+
+ ( + + Ученик или группа + + + + + + )} + /> +
+
+
Время
+
+ ( + + + } + variant="s" + /> + + + + )} + /> + ( + + + } + variant="s" + /> + + + + )} + /> + ( + + + + + + + )} + /> + ( + + + + + + )} + /> +
+
+ {children} +
+ + ); +}; diff --git a/packages/features.lesson.add/src/ui/components/InputDate.tsx b/packages/features.lesson.add/src/ui/components/InputDate.tsx new file mode 100644 index 00000000..067252d5 --- /dev/null +++ b/packages/features.lesson.add/src/ui/components/InputDate.tsx @@ -0,0 +1,43 @@ +import { memo, useCallback, useEffect, useState } from 'react'; + +import { DatePicker } from '@xipkg/datepicker'; +import { Calendar } from '@xipkg/icons'; +import { Input } from '@xipkg/input'; +import { getFullDateString } from '../../utils/utils'; + +interface InputDateProps { + value?: Date; + onChange: (val: Date) => void; +} + +export const InputDate = memo(({ value, onChange }) => { + const [date, setDate] = useState(value || new Date()); + + const handleSelectDate = useCallback( + (newDate: Date) => { + setDate(newDate); + onChange(newDate); + }, + [onChange], + ); + + useEffect(() => { + if (value) { + setDate(value); + } + }, [value]); + + return ( + + } + /> + + ); +}); diff --git a/packages/features.lesson.add/src/ui/components/RepeatBlock.tsx b/packages/features.lesson.add/src/ui/components/RepeatBlock.tsx new file mode 100644 index 00000000..76d69378 --- /dev/null +++ b/packages/features.lesson.add/src/ui/components/RepeatBlock.tsx @@ -0,0 +1,52 @@ +import { useTranslation } from 'react-i18next'; + +import { + Select, + SelectTrigger, + SelectValue, + SelectContent, + SelectGroup, + SelectItem, + SelectSeparator, +} from '@xipkg/select'; +import { Redo } from '@xipkg/icons'; +import { useConstants } from '../../hooks'; + +import type { FC } from 'react'; + +interface RepeatBlockProps { + value: string; + onChange: (value: string) => void; +} + +export const RepeatBlock: FC = ({ value, onChange }) => { + const { t } = useTranslation('calendar'); + const { repeatVariants } = useConstants(); + + return ( + + ); +}; diff --git a/packages/features.lesson.add/src/ui/components/StudentSelector.tsx b/packages/features.lesson.add/src/ui/components/StudentSelector.tsx new file mode 100644 index 00000000..c8ca1f35 --- /dev/null +++ b/packages/features.lesson.add/src/ui/components/StudentSelector.tsx @@ -0,0 +1,35 @@ +import { Select, SelectValue, SelectTrigger, SelectContent, SelectItem } from '@xipkg/select'; +import type { ClassroomT } from 'common.api'; + +type StudentSelectorProps = { + value: string; + onChange: (value: string) => void; + classrooms: ClassroomT[]; + isLoading?: boolean; +}; + +export const StudentSelector = ({ + value, + onChange, + classrooms, + isLoading, +}: StudentSelectorProps) => { + return ( + + ); +}; diff --git a/packages/features.lesson.add/src/utils/utils.ts b/packages/features.lesson.add/src/utils/utils.ts new file mode 100644 index 00000000..4ebd70e2 --- /dev/null +++ b/packages/features.lesson.add/src/utils/utils.ts @@ -0,0 +1,12 @@ +const DEFAULT_LOCALE = 'ru-RU'; + +export const getFullDateString = ( + date: Date, + format: 'short' | 'long' = 'short', + locale: string = DEFAULT_LOCALE, +) => { + const weekDayName = date.toLocaleDateString(locale, { weekday: format }); + const monthName = date.toLocaleDateString(locale, { month: 'long' }); + + return `${weekDayName} ${date.getDate()} ${monthName}`; +}; diff --git a/packages/features.lesson.add/tsconfig.json b/packages/features.lesson.add/tsconfig.json new file mode 100644 index 00000000..7bc23fd3 --- /dev/null +++ b/packages/features.lesson.add/tsconfig.json @@ -0,0 +1,7 @@ +{ + "include": ["src/**/*"], + "extends": [ + "common.typescript/tsconfig.app.json", + ], + "exclude": ["dist", "build", "node_modules"] +} diff --git a/packages/features.materials.add/package.json b/packages/features.materials.add/package.json index c2c9103c..3ad151ff 100644 --- a/packages/features.materials.add/package.json +++ b/packages/features.materials.add/package.json @@ -13,7 +13,7 @@ "dependencies": { "@xipkg/button": "4.1.0", "@xipkg/dropdown": "^3.0.12", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/utils": "^1.8.0" }, "devDependencies": { diff --git a/packages/features.materials.card/package.json b/packages/features.materials.card/package.json index e8d629e6..0bc60f53 100644 --- a/packages/features.materials.card/package.json +++ b/packages/features.materials.card/package.json @@ -15,7 +15,7 @@ "@xipkg/button": "4.1.0", "@xipkg/badge": "2.0.12", "@xipkg/dropdown": "^3.0.12", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/utils": "^1.8.0", "common.services": "*", "common.types": "*", diff --git a/packages/features.materials.card/src/ui/MaterialsCard.tsx b/packages/features.materials.card/src/ui/MaterialsCard.tsx index 289dd8fd..f3bf3fc0 100644 --- a/packages/features.materials.card/src/ui/MaterialsCard.tsx +++ b/packages/features.materials.card/src/ui/MaterialsCard.tsx @@ -53,7 +53,7 @@ export const MaterialsCard = ({
{ }, []); return ( -
+

diff --git a/packages/modules.calls/package.json b/packages/modules.calls/package.json index 23c1d417..3dda401a 100644 --- a/packages/modules.calls/package.json +++ b/packages/modules.calls/package.json @@ -27,7 +27,7 @@ "@xipkg/breadcrumbs": "2.0.13", "@xipkg/button": "4.1.0", "@xipkg/dropdown": "3.0.12", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/modal": "^4.3.1", "@xipkg/scrollarea": "2.2.0", "@xipkg/select": "2.2.5", @@ -35,7 +35,7 @@ "@xipkg/sheet": "2.0.12", "@xipkg/textarea": "1.1.0", "@xipkg/tooltip": "2.1.0", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "@xipkg/utils": "1.8.0", "common.api": "*", "common.env": "*", diff --git a/packages/modules.calls/src/ui/Call.tsx b/packages/modules.calls/src/ui/Call.tsx index 0d1f80d1..8654ee5c 100644 --- a/packages/modules.calls/src/ui/Call.tsx +++ b/packages/modules.calls/src/ui/Call.tsx @@ -27,7 +27,7 @@ export const Call = () => { }, [pathname, mode, updateStore]); return ( -

+
{isStarted ? (
diff --git a/packages/modules.calls/src/ui/CompactView/CompactView.tsx b/packages/modules.calls/src/ui/CompactView/CompactView.tsx index 1beed5ab..01251477 100644 --- a/packages/modules.calls/src/ui/CompactView/CompactView.tsx +++ b/packages/modules.calls/src/ui/CompactView/CompactView.tsx @@ -108,7 +108,7 @@ export const Compact: FC = ({ children }) => { return ( -
+
{ return ( <> -
+
diff --git a/packages/modules.editor/package.json b/packages/modules.editor/package.json index 2f132b77..d8122e76 100644 --- a/packages/modules.editor/package.json +++ b/packages/modules.editor/package.json @@ -35,7 +35,7 @@ "@xipkg/button": "4.1.0", "@xipkg/dropdown": "^3.0.12", "@xipkg/file": "^2.0.12", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.2.9", "@xipkg/popover": "^2.1.0", "@xipkg/select": "^2.2.5", diff --git a/packages/modules.modals/package.json b/packages/modules.modals/package.json index ff205be4..e2ce85be 100644 --- a/packages/modules.modals/package.json +++ b/packages/modules.modals/package.json @@ -18,11 +18,11 @@ "react-i18next": "15.4.1", "@tanstack/react-router": "^1.128.8", "@xipkg/button": "4.1.0", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/link": "2.0.12", "@xipkg/utils": "1.8.0", "@xipkg/scrollarea": "2.2.0", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "@xipkg/dropdown": "3.0.12", "zod": "3.24.2", "zustand": "^5.0.3" diff --git a/packages/modules.navigation/package.json b/packages/modules.navigation/package.json index 8328474c..36d43896 100644 --- a/packages/modules.navigation/package.json +++ b/packages/modules.navigation/package.json @@ -15,13 +15,13 @@ "@xipkg/avatar": "3.0.10", "@xipkg/button": "4.1.0", "@xipkg/dropdown": "3.0.12", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/link": "2.0.12", "@xipkg/scrollarea": "2.2.0", "@xipkg/radio": "^2.0.6", "@xipkg/select": "^2.2.5", "@xipkg/sidebar": "0.2.0", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "@xipkg/utils": "1.8.0", "@xipkg/drawer": "0.1.0", "common.auth": "*", diff --git a/packages/modules.navigation/src/ui/Header/DesktopUserMenu.tsx b/packages/modules.navigation/src/ui/Header/DesktopUserMenu.tsx index c8fa48d2..9f65b61c 100644 --- a/packages/modules.navigation/src/ui/Header/DesktopUserMenu.tsx +++ b/packages/modules.navigation/src/ui/Header/DesktopUserMenu.tsx @@ -8,8 +8,11 @@ import { import { UserProfile } from '@xipkg/userprofile'; import { SelectRole } from './SelectRole'; +import { useCurrentUser } from 'common.services'; +import { Collapse } from '@xipkg/icons'; interface DesktopUserMenuProps { + withOutText: boolean; userId: number; onOpenProfile: () => void; onLogout: () => void; @@ -18,26 +21,38 @@ interface DesktopUserMenuProps { } export const DesktopUserMenu = ({ + withOutText, userId, onOpenProfile, onLogout, profileText, logoutText, }: DesktopUserMenuProps) => { + const { data: user } = useCurrentUser(); + return ( - + diff --git a/packages/modules.navigation/src/ui/Header/Header.tsx b/packages/modules.navigation/src/ui/Header/Header.tsx index 8ee2e446..ef5be45c 100644 --- a/packages/modules.navigation/src/ui/Header/Header.tsx +++ b/packages/modules.navigation/src/ui/Header/Header.tsx @@ -74,6 +74,7 @@ export const Header = () => { /> ) : ( { <> - + Уведомления diff --git a/packages/modules.navigation/src/ui/Navigation.tsx b/packages/modules.navigation/src/ui/Navigation.tsx index 6fd31c93..eb19db0c 100644 --- a/packages/modules.navigation/src/ui/Navigation.tsx +++ b/packages/modules.navigation/src/ui/Navigation.tsx @@ -1,7 +1,7 @@ import { useMediaQuery } from '@xipkg/utils'; import { Drawer, DrawerContent } from '@xipkg/drawer'; import { Sidebar, SidebarInset } from '@xipkg/sidebar'; -import { Header } from './Header'; +// import { Header } from './Header'; import { SideBarItems } from './SideBarItems'; import { SidebarProvider } from '@xipkg/sidebar'; import { useMenuStore } from '../store'; @@ -37,7 +37,7 @@ const NavigationLayout = ({ children }: { children: React.ReactNode }) => { @@ -46,7 +46,7 @@ const NavigationLayout = ({ children }: { children: React.ReactNode }) => { {/* Children всегда рендерятся в одном месте с одним ключом и одним типом элемента */} {/* Используем SidebarInset для обоих случаев, чтобы React сохранял состояние */} {stableChildren} @@ -78,7 +78,7 @@ export const Navigation = ({ children }: { children: React.ReactNode }) => { open={sidebarOpen} onOpenChange={sidebarOnOpenChange} > -
+ {/*
*/} {stableChildren} ); diff --git a/packages/modules.navigation/src/ui/SideBarItems.tsx b/packages/modules.navigation/src/ui/SideBarItems.tsx index 0ca1b51e..0fd84a34 100644 --- a/packages/modules.navigation/src/ui/SideBarItems.tsx +++ b/packages/modules.navigation/src/ui/SideBarItems.tsx @@ -6,21 +6,40 @@ import { SidebarMenu, SidebarMenuButton, SidebarMenuItem, + SidebarTrigger, } from '@xipkg/sidebar'; import { useLocation, useNavigate, useParams, useSearch } from '@tanstack/react-router'; import { useTranslation } from 'react-i18next'; -import { Group, Home, Payments, TelegramFilled, InfoCircle, BookOpened } from '@xipkg/icons'; +import { + Group, + Home, + Payments, + TelegramFilled, + InfoCircle, + BookOpened, + Calendar, +} from '@xipkg/icons'; import { useCurrentUser } from 'common.services'; import { useCallStore } from 'modules.calls'; import { useMenuStore } from '../store'; +import { Notifications } from './Header/Notifications'; +import { Logo, SmallLogo } from 'common.ui'; +import { useMediaQuery } from '@xipkg/utils'; +import { DesktopUserMenu } from './Header/DesktopUserMenu'; +import { useEffect, useState } from 'react'; +import { useAuth } from 'common.auth'; export const SideBarItems = () => { const { t } = useTranslation('navigation'); - const { close } = useMenuStore(); + const { close, isDesktopOpen } = useMenuStore(); + const isMobile = useMediaQuery('(max-width: 960px)'); const { data: user } = useCurrentUser(); const isTutor = user?.default_layout === 'tutor'; + // Определяем, закрыт ли сайдбар (для десктопа) + const isCollapsed = !isMobile && !isDesktopOpen; + const isStarted = useCallStore((state) => state.isStarted); const mode = useCallStore((state) => state.mode); const updateStore = useCallStore((state) => state.updateStore); @@ -32,6 +51,12 @@ export const SideBarItems = () => { url: '/', icon: Home, }, + { + id: 'calendar-menu-item', + titleKey: 'calendar', + url: '/calendar', + icon: Calendar, + }, { id: 'classrooms-menu-item', titleKey: 'classrooms', @@ -136,9 +161,53 @@ export const SideBarItems = () => { close(); }; + const { logout } = useAuth(); + + const [open, setOpen] = useState(false); + + // Синхронизируем состояние модалки с URL + useEffect(() => { + const profileParam = search.profile; + + const hasProfileParam = !!profileParam; + if (hasProfileParam !== open) { + setOpen(hasProfileParam); + } + }, [search.profile, open]); + + const handleOpenProfile = () => { + navigate({ + to: pathname, + search: { profile: 'personalInfo' }, + }); + setOpen(true); + }; + + const handleLogout = () => { + logout(); + // TODO: переделать, сделать редирект только по 200 + navigate({ to: '/signin' }); + }; + return ( <> + {/* Верхняя секция: профиль, бургер-меню, колокольчик */} +
+ {/* Профиль пользователя */} + +
+ +
+
+ {/* Основное меню */} @@ -150,7 +219,7 @@ export const SideBarItems = () => { data-umami-event={`navigation-${item.titleKey}`} data-umami-event-url={item.url} > - + {t(item.titleKey)} @@ -160,8 +229,9 @@ export const SideBarItems = () => {
- + + {footerMenu.map((item) => ( { ? { 'data-umami-event-url': 'https://t.me/sovlium_support_bot' } : {})} > - +
{t(item.titleKey)}
))}
+ {/* Логотип внизу — оба в DOM для плавного перехода без мигания */} +
+
+ +
+
+ +
+
); diff --git a/packages/modules.profile/package.json b/packages/modules.profile/package.json index 952c324e..f7b4cc68 100644 --- a/packages/modules.profile/package.json +++ b/packages/modules.profile/package.json @@ -15,11 +15,11 @@ "@xipkg/badge": "2.0.12", "@xipkg/button": "4.1.0", "@xipkg/dropdown": "3.0.12", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/modal": "^4.3.1", "@xipkg/select": "2.2.5", "@xipkg/toggle": "^2.0.13", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "@xipkg/utils": "1.8.0", "common.api": "*", "common.auth": "*", diff --git a/packages/pages.classroom/package.json b/packages/pages.classroom/package.json index 030ab971..d4533e64 100644 --- a/packages/pages.classroom/package.json +++ b/packages/pages.classroom/package.json @@ -16,14 +16,14 @@ "@xipkg/command": "1.0.0", "@xipkg/dropdown": "3.0.12", "@xipkg/form": "4.2.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.2.9", "@xipkg/link": "^2.0.12", "@xipkg/scrollarea": "2.2.0", "@xipkg/select": "^2.2.5", "@xipkg/tabs": "2.1.0", "@xipkg/tooltip": "2.1.0", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "common.utils": "*", "common.api": "*", "common.entities": "*", diff --git a/packages/pages.classrooms/package.json b/packages/pages.classrooms/package.json index 529dab0e..fd55fa82 100644 --- a/packages/pages.classrooms/package.json +++ b/packages/pages.classrooms/package.json @@ -16,14 +16,14 @@ "@xipkg/badge": "2.0.12", "@xipkg/button": "4.1.0", "@xipkg/dropdown": "3.0.12", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.2.9", "@xipkg/link": "^2.0.12", "@xipkg/modal": "^4.3.1", "@xipkg/scrollarea": "2.2.0", "@xipkg/select": "^2.2.5", "@xipkg/tooltip": "2.1.0", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "common.entities": "*", "common.env": "*", "common.services": "*", diff --git a/packages/pages.classrooms/src/ui/ClassroomsPage.tsx b/packages/pages.classrooms/src/ui/ClassroomsPage.tsx index 949514b6..b3a554c4 100644 --- a/packages/pages.classrooms/src/ui/ClassroomsPage.tsx +++ b/packages/pages.classrooms/src/ui/ClassroomsPage.tsx @@ -11,7 +11,7 @@ export const ClassroomsPage = () => { return (
-
+

Кабинеты

{isTutor && }
diff --git a/packages/pages.email-confirm/package.json b/packages/pages.email-confirm/package.json index 2a506c60..d043d1e1 100644 --- a/packages/pages.email-confirm/package.json +++ b/packages/pages.email-confirm/package.json @@ -16,7 +16,7 @@ "@xipkg/button": "4.1.0", "@xipkg/fileuploader": "^2.0.12", "@xipkg/form": "4.2.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.0.7", "@xipkg/utils": "1.8.0", "common.auth": "*", diff --git a/packages/pages.email/package.json b/packages/pages.email/package.json index b26658be..8e81c731 100644 --- a/packages/pages.email/package.json +++ b/packages/pages.email/package.json @@ -17,7 +17,7 @@ "@xipkg/button": "4.1.0", "@xipkg/fileuploader": "^2.0.12", "@xipkg/form": "4.2.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.0.7", "@xipkg/utils": "1.8.0", "common.auth": "*", diff --git a/packages/pages.main/package.json b/packages/pages.main/package.json index e2c5b356..4ced34e8 100644 --- a/packages/pages.main/package.json +++ b/packages/pages.main/package.json @@ -16,10 +16,10 @@ "@xipkg/alert": "1.1.0", "@xipkg/badge": "2.0.12", "@xipkg/button": "4.1.0", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/scrollarea": "2.2.0", "@xipkg/tooltip": "2.1.0", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "@xipkg/utils": "1.8.0", "common.api": "*", "common.auth": "*", @@ -30,6 +30,7 @@ "common.ui": "*", "features.invites": "*", "features.invoice": "*", + "features.lesson.add": "*", "features.materials.add": "*", "features.materials.card": "*", "features.group.add": "*", diff --git a/packages/pages.main/src/ui/MainPage.tsx b/packages/pages.main/src/ui/MainPage.tsx index ce4cc765..93add31a 100644 --- a/packages/pages.main/src/ui/MainPage.tsx +++ b/packages/pages.main/src/ui/MainPage.tsx @@ -1,10 +1,16 @@ /* eslint-disable no-irregular-whitespace */ import { ScrollArea } from '@xipkg/scrollarea'; -import { Materials, Payments, Classrooms } from './components'; +import { + Materials, + Payments, + Classrooms, + Lessons, + ActionButtons, + DateTimeDisplay, +} from './components'; import { Menu } from 'common.ui'; import { useCurrentUser } from 'common.services'; // import { Sidebar } from './components/Sidebar'; -// import { AssignLessonButton } from './components/AssignLessonButton'; export const MainPage = () => { const { data: user } = useCurrentUser(); @@ -115,20 +121,29 @@ export const MainPage = () => { ]; return ( -
- {/* */} - - {/* */} - - - {isTutor && } +
+ +
+ {/* Дата и время */} + + + {/* Три колонки: Расписание, Кабинеты, Payments и Materials */} +
+
+ +
+
+ +
+
+ + + {isTutor && } +
+
+
- {/* */}
); }; diff --git a/packages/pages.main/src/ui/components/ActionButtons/ActionButtons.tsx b/packages/pages.main/src/ui/components/ActionButtons/ActionButtons.tsx new file mode 100644 index 00000000..9f5f812e --- /dev/null +++ b/packages/pages.main/src/ui/components/ActionButtons/ActionButtons.tsx @@ -0,0 +1,44 @@ +import { Button } from '@xipkg/button'; +import { ModalInvitation } from 'features.invites'; +import { ModalAddGroup } from 'features.group.add'; +import { useCurrentUser } from 'common.services'; +import { Group, UserPlus } from '@xipkg/icons'; + +export const ActionButtons = () => { + const { data: user } = useCurrentUser(); + const isTutor = user?.default_layout === 'tutor'; + + if (!isTutor) { + return null; + } + + return ( +
+ + + + + + + +
+ ); +}; diff --git a/packages/pages.main/src/ui/components/ActionButtons/index.ts b/packages/pages.main/src/ui/components/ActionButtons/index.ts new file mode 100644 index 00000000..99548094 --- /dev/null +++ b/packages/pages.main/src/ui/components/ActionButtons/index.ts @@ -0,0 +1 @@ +export { ActionButtons } from './ActionButtons'; diff --git a/packages/pages.main/src/ui/components/AssignLessonButton/AssignLessonButton.tsx b/packages/pages.main/src/ui/components/AssignLessonButton/AssignLessonButton.tsx index 1abf1c5e..631e259d 100644 --- a/packages/pages.main/src/ui/components/AssignLessonButton/AssignLessonButton.tsx +++ b/packages/pages.main/src/ui/components/AssignLessonButton/AssignLessonButton.tsx @@ -2,8 +2,14 @@ import { useCurrentUser } from 'common.services'; import { Button } from '@xipkg/button'; import { Plus } from '@xipkg/icons'; import { cn } from '@xipkg/utils'; +import type { FC } from 'react'; -export const AssignLessonButton = ({ className }: { className?: string }) => { +type AssignLessonButtonProps = { + className?: string; + onButtonClick?: () => void; +}; + +export const AssignLessonButton: FC = ({ className, onButtonClick }) => { const { data: user } = useCurrentUser(); const isTutor = user?.default_layout === 'tutor'; @@ -12,12 +18,17 @@ export const AssignLessonButton = ({ className }: { className?: string }) => { <> {isTutor && (
- diff --git a/packages/pages.main/src/ui/components/Classrooms/Classroom.tsx b/packages/pages.main/src/ui/components/Classrooms/Classroom.tsx index 90ec5ead..f05d9bff 100644 --- a/packages/pages.main/src/ui/components/Classrooms/Classroom.tsx +++ b/packages/pages.main/src/ui/components/Classrooms/Classroom.tsx @@ -90,7 +90,7 @@ export const Classroom = ({ classroom, isLoading }: ClassroomProps) => { }; return ( -
+
- - К кабинетам - +
+ +
+
-
- - - + {/* Поиск */} + } + value={searchQuery} + onChange={(e) => setSearchQuery(e.target.value)} + /> - - - -
+ {/* Фильтры по предметам */} +
+ {subjects.map((subject) => ( + + ))}
-
- {classrooms && classrooms?.length > 0 && ( - -
- {!isHidden && classrooms && classrooms?.length > 0 && ( + {/* Список кабинетов */} +
+ {isLoading && ( +
+

Загрузка...

+
+ )} + + {!isLoading && filteredClassrooms && filteredClassrooms.length > 0 && ( + <> + {!isHidden && filteredClassrooms && filteredClassrooms.length > 0 && ( )} - {classrooms?.map((classroom) => ( + {filteredClassrooms.map((classroom) => ( ))} -
- - )} - {classrooms && classrooms.length === 0 && ( + + )} + + + {!isLoading && (!filteredClassrooms || filteredClassrooms.length === 0) && (

- Пригласите учеников — индивидуально или в группу + {searchQuery || selectedSubject !== 'all' + ? 'Ничего не найдено' + : 'Пригласите учеников — индивидуально или в группу'}

)} diff --git a/packages/pages.main/src/ui/components/DateTimeDisplay/DateTimeDisplay.tsx b/packages/pages.main/src/ui/components/DateTimeDisplay/DateTimeDisplay.tsx new file mode 100644 index 00000000..aa431b30 --- /dev/null +++ b/packages/pages.main/src/ui/components/DateTimeDisplay/DateTimeDisplay.tsx @@ -0,0 +1,35 @@ +import { useState, useEffect } from 'react'; + +export const DateTimeDisplay = () => { + const [currentDateTime, setCurrentDateTime] = useState(() => { + const now = new Date(); + const time = now.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }); + const weekday = now.toLocaleDateString('ru-RU', { weekday: 'long' }); + const day = now.getDate(); + const month = now.toLocaleDateString('ru-RU', { month: 'long' }); + return { time, date: `${weekday}, ${day} ${month}` }; + }); + + useEffect(() => { + const updateDateTime = () => { + const now = new Date(); + const time = now.toLocaleTimeString('ru-RU', { hour: '2-digit', minute: '2-digit' }); + const weekday = now.toLocaleDateString('ru-RU', { weekday: 'long' }); + const day = now.getDate(); + const month = now.toLocaleDateString('ru-RU', { month: 'long' }); + setCurrentDateTime({ time, date: `${weekday}, ${day} ${month}` }); + }; + + updateDateTime(); + const interval = setInterval(updateDateTime, 60000); // Обновляем каждую минуту + + return () => clearInterval(interval); + }, []); + + return ( +
+
{currentDateTime.time}
+
{currentDateTime.date}
+
+ ); +}; diff --git a/packages/pages.main/src/ui/components/DateTimeDisplay/index.ts b/packages/pages.main/src/ui/components/DateTimeDisplay/index.ts new file mode 100644 index 00000000..0b0264b3 --- /dev/null +++ b/packages/pages.main/src/ui/components/DateTimeDisplay/index.ts @@ -0,0 +1 @@ +export { DateTimeDisplay } from './DateTimeDisplay'; diff --git a/packages/pages.main/src/ui/components/Lessons/AllLessons.tsx b/packages/pages.main/src/ui/components/Lessons/AllLessons.tsx new file mode 100644 index 00000000..559f5d53 --- /dev/null +++ b/packages/pages.main/src/ui/components/Lessons/AllLessons.tsx @@ -0,0 +1,64 @@ +import { Badge } from '@xipkg/badge'; +import { UserProfile } from '@xipkg/userprofile'; +import { Clock } from '@xipkg/icons'; + +export const AllLessons = () => { + // TODO: Заменить на реальные данные из API + const lessons = [ + { + id: 1, + time: '15:45 - 16:30', + subject: 'Математика', + studentName: 'Иван Петров', + studentId: 2, + isPaid: true, + }, + { + id: 2, + time: '16:45 - 17:30', + subject: 'Физика', + studentName: 'Анна Кузнецова', + studentId: 3, + isPaid: false, + }, + { + id: 3, + time: '17:45 - 18:30', + subject: 'Химия', + studentName: 'Олег Смирнов', + studentId: 4, + isPaid: true, + }, + { + id: 4, + time: '19:45 - 20:30', + subject: 'История', + studentName: 'Елена Федорова', + studentId: 5, + isPaid: false, + }, + ]; + + return ( +
+ {lessons.map((lesson) => ( +
+
+
{lesson.time}
+
{lesson.subject}
+
+
+ + + + {lesson.isPaid ? 'оплачено' : 'ждёт оплату'} + +
+
+ ))} +
+ ); +}; diff --git a/packages/pages.main/src/ui/components/Lessons/Lessons.tsx b/packages/pages.main/src/ui/components/Lessons/Lessons.tsx index ca914fe0..d05e1761 100644 --- a/packages/pages.main/src/ui/components/Lessons/Lessons.tsx +++ b/packages/pages.main/src/ui/components/Lessons/Lessons.tsx @@ -1,55 +1,46 @@ import { Button } from '@xipkg/button'; -import { ArrowRight } from '@xipkg/icons'; -import { ScrollArea } from '@xipkg/scrollarea'; -import { Lesson } from './Lesson'; -import { useNavigate, useSearch } from '@tanstack/react-router'; -import { Tooltip, TooltipContent, TooltipTrigger } from '@xipkg/tooltip'; -import { AssignLessonButton } from '../AssignLessonButton'; +import { Group } from '@xipkg/icons'; +import { NextLesson } from './NextLesson'; +import { AllLessons } from './AllLessons'; +import { AddingLessonModal } from 'features.lesson.add'; +import { useState } from 'react'; export const Lessons = () => { - const navigate = useNavigate(); - const search = useSearch({ strict: false }); + const [open, setOpen] = useState(false); - const handleMore = () => { - // Сохраняем параметр call при переходе к календарю - const filteredSearch = search.call ? { call: search.call } : {}; - - navigate({ - to: '/calendar', - search: (prev: Record) => ({ - ...prev, - ...filteredSearch, - }), - }); + const handleOpenAddingModal = () => { + setOpen(true); }; return ( -
-
-

Ближайшие занятия

- - + <> + +
+
+

Расписание на сегодня

+
- - К календарю - - -
-
- -
- {[...new Array(10)].map((_, index) => ( - - ))}
-
+
+ +
+
+

Ближайшее занятие

+ +
+ +
+

Все занятие

+ +
+
-
+ ); }; diff --git a/packages/pages.main/src/ui/components/Lessons/NextLesson.tsx b/packages/pages.main/src/ui/components/Lessons/NextLesson.tsx new file mode 100644 index 00000000..6ff98076 --- /dev/null +++ b/packages/pages.main/src/ui/components/Lessons/NextLesson.tsx @@ -0,0 +1,44 @@ +import { Badge } from '@xipkg/badge'; +import { Button } from '@xipkg/button'; +import { UserProfile } from '@xipkg/userprofile'; +import { Conference } from '@xipkg/icons'; + +export const NextLesson = () => { + // TODO: Заменить на реальные данные из API + const lesson = { + id: 1, + time: '14:45 - 15:30', + subject: 'Английский язык', + studentName: 'Мария Сидорова', + studentId: 1, + isPaid: true, + }; + + return ( +
+
+
+
{lesson.time}
+
{lesson.subject}
+
+ + {lesson.isPaid ? 'оплачен' : 'ждёт оплату'} + +
+ +
+ +
+ +
+ + +
+
+ ); +}; diff --git a/packages/pages.main/src/ui/components/Materials/Materials.tsx b/packages/pages.main/src/ui/components/Materials/Materials.tsx index a2fc3500..9b9095dd 100644 --- a/packages/pages.main/src/ui/components/Materials/Materials.tsx +++ b/packages/pages.main/src/ui/components/Materials/Materials.tsx @@ -1,64 +1,90 @@ import { Button } from '@xipkg/button'; -import { ArrowRight } from '@xipkg/icons'; -import { ScrollArea } from '@xipkg/scrollarea'; -import { useNavigate, useSearch } from '@tanstack/react-router'; -import { Tooltip, TooltipContent, TooltipTrigger } from '@xipkg/tooltip'; +import { Search } from '@xipkg/icons'; +import { Input } from '@xipkg/input'; import { MaterialsAdd } from 'features.materials.add'; import { useGetMaterialsList } from 'common.services'; import { MaterialsDuplicateProvider, useMaterialsDuplicate } from 'pages.materials'; import { MaterialsDuplicate } from 'features.materials.duplicate'; import { MaterialsCard } from 'features.materials.card'; +import { useState, useMemo } from 'react'; +import { cn } from '@xipkg/utils'; +import { ScrollArea } from '@xipkg/scrollarea'; const MaterialsContent = () => { - const navigate = useNavigate(); - const search = useSearch({ strict: false }); const { materialId, open, closeModal, openModal } = useMaterialsDuplicate(); + const [searchQuery, setSearchQuery] = useState(''); + const [selectedFilter, setSelectedFilter] = useState<'all' | 'note' | 'board'>('all'); const { data: materials, isLoading } = useGetMaterialsList({ - content_type: null, // null означает все типы материалов + content_type: selectedFilter === 'all' ? null : selectedFilter === 'note' ? 'note' : 'board', }); - const handleMore = () => { - // Сохраняем параметр call при переходе к материалам - const filteredSearch = search.call ? { call: search.call } : {}; + // Фильтрация материалов по поисковому запросу + const filteredMaterials = useMemo(() => { + if (!materials) return []; - navigate({ - to: '/materials', - search: (prev: Record) => ({ - ...prev, - ...filteredSearch, - }), + return materials.filter((material) => { + if (searchQuery === '') return true; + const query = searchQuery.toLowerCase(); + return material.name?.toLowerCase().includes(query); }); - }; + }, [materials, searchQuery]); + + const filters = [ + { id: 'all' as const, label: 'Все' }, + { id: 'note' as const, label: 'Заметки' }, + { id: 'board' as const, label: 'Доски' }, + ]; return ( <> -
+

Материалы

- - - - - К материалам - - - +
+ +
-
- {materials && materials.length > 0 && ( - + {filters.map((filter) => ( + + ))} +
+ + {/* Поиск */} + } + value={searchQuery} + onChange={(e) => setSearchQuery(e.target.value)} + /> + + {/* Список материалов */} +
+ {isLoading && ( +
+

Загрузка...

+
+ )} + {!isLoading && filteredMaterials && filteredMaterials.length > 0 && ( + +
+ {filteredMaterials.map((material) => ( {
)} - {materials && materials.length === 0 && ( + {!isLoading && (!filteredMaterials || filteredMaterials.length === 0) && (
-

Здесь пока пусто

+

+ {searchQuery ? 'Ничего не найдено' : 'Здесь пока пусто'} +

)}
diff --git a/packages/pages.main/src/ui/components/Payments/Payments.tsx b/packages/pages.main/src/ui/components/Payments/Payments.tsx index 45fc3b79..aab9c5b4 100644 --- a/packages/pages.main/src/ui/components/Payments/Payments.tsx +++ b/packages/pages.main/src/ui/components/Payments/Payments.tsx @@ -1,35 +1,10 @@ -import { useState } from 'react'; import { useNavigate, useSearch } from '@tanstack/react-router'; import { Button } from '@xipkg/button'; -import { ArrowRight } from '@xipkg/icons'; -import { ScrollArea } from '@xipkg/scrollarea'; -import { Tooltip, TooltipContent, TooltipTrigger } from '@xipkg/tooltip'; -import { - useCurrentUser, - useGetStudentPaymentsList, - useGetTutorPaymentsList, -} from 'common.services'; -import { InvoiceModal } from 'features.invoice'; -import { InvoiceCard } from 'features.invoice.card'; +import { ArrowUpRight, Notification } from '@xipkg/icons'; export const Payments = () => { - const { data: user } = useCurrentUser(); - - const isTutor = user?.default_layout === 'tutor'; - - const { data: studentPayments, isLoading: isLoadingStudent } = useGetStudentPaymentsList({ - disabled: isTutor, - }); - const { data: tutorPayments, isLoading: isLoadingTutor } = useGetTutorPaymentsList({ - disabled: !isTutor, - }); - - const payments = isTutor ? tutorPayments : studentPayments; - const isLoading = isTutor ? isLoadingTutor : isLoadingStudent; - const navigate = useNavigate(); const search = useSearch({ strict: false }); - const [isInvoiceModalOpen, setIsInvoiceModalOpen] = useState(false); const handleMore = () => { // Сохраняем параметр call при переходе к оплатам @@ -44,69 +19,28 @@ export const Payments = () => { }); }; - return ( -
-
-

Оплаты

- - - - - К оплатам - + const handleRemind = () => { + // TODO: Реализовать функцию напоминания об оплате + console.log('Напомнить об оплате'); + }; - {isTutor && ( -
- -
- )} -
-
- {isLoading && ( -
-

Загрузка...

-
- )} - {!isLoading && payments && payments.length > 0 && ( - -
- {payments.map((payment) => ( - - ))} -
-
- )} - {!isLoading && (!payments || payments.length === 0) && ( -
-

Здесь пока пусто

-
- )} + return ( +
+
+ +
- -
); }; diff --git a/packages/pages.main/src/ui/components/index.ts b/packages/pages.main/src/ui/components/index.ts index 083ffb7c..aa5d5314 100644 --- a/packages/pages.main/src/ui/components/index.ts +++ b/packages/pages.main/src/ui/components/index.ts @@ -2,3 +2,5 @@ export { Lessons } from './Lessons'; export { Classrooms } from './Classrooms'; export { Materials } from './Materials'; export { Payments } from './Payments'; +export { ActionButtons } from './ActionButtons'; +export { DateTimeDisplay } from './DateTimeDisplay'; diff --git a/packages/pages.materials/package.json b/packages/pages.materials/package.json index 07a8dea3..f2118d41 100644 --- a/packages/pages.materials/package.json +++ b/packages/pages.materials/package.json @@ -18,7 +18,7 @@ "@xipkg/file": "2.0.12", "@xipkg/scrollarea": "2.2.0", "@xipkg/tabs": "^2.1.0", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "common.api": "*", "common.config": "*", "common.services": "*", diff --git a/packages/pages.materials/src/ui/MaterialsPage.tsx b/packages/pages.materials/src/ui/MaterialsPage.tsx index 97adfcb7..83abebd4 100644 --- a/packages/pages.materials/src/ui/MaterialsPage.tsx +++ b/packages/pages.materials/src/ui/MaterialsPage.tsx @@ -30,7 +30,7 @@ const MaterialsPageContent = () => { return ( <>
-
+
diff --git a/packages/pages.notes/package.json b/packages/pages.notes/package.json index 53df07a9..9617983a 100644 --- a/packages/pages.notes/package.json +++ b/packages/pages.notes/package.json @@ -14,7 +14,7 @@ "@tanstack/react-router": "^1.128.8", "@xipkg/utils": "^1.8.0", "@xipkg/button": "4.1.0", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/form": "4.2.1", "@xipkg/input": "2.0.7", "common.services": "*", diff --git a/packages/pages.payments/package.json b/packages/pages.payments/package.json index 0550569a..7b0cbed2 100644 --- a/packages/pages.payments/package.json +++ b/packages/pages.payments/package.json @@ -15,7 +15,7 @@ "@xipkg/avatar": "3.0.10", "@xipkg/fileuploader": "^2.0.12", "@xipkg/form": "4.2.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.0.7", "@xipkg/utils": "1.8.0", "common.auth": "*", @@ -34,7 +34,7 @@ "@xipkg/button": "4.1.0", "@xipkg/dropdown": "3.0.12", "@xipkg/tabs": "^2.1.0", - "@xipkg/userprofile": "4.0.14", + "@xipkg/userprofile": "4.1.0", "@tanstack/react-virtual": "3.13.9", "@xipkg/scrollarea": "2.2.0" }, diff --git a/packages/pages.payments/src/ui/Header.tsx b/packages/pages.payments/src/ui/Header.tsx index 21e55107..90ff23b8 100644 --- a/packages/pages.payments/src/ui/Header.tsx +++ b/packages/pages.payments/src/ui/Header.tsx @@ -6,7 +6,7 @@ export const Header = ({ onCreateInvoice }: { onCreateInvoice: () => void }) => const { data: user } = useCurrentUser(); return ( -
+

Контроль оплат

{user?.default_layout === 'tutor' && ( diff --git a/packages/pages.reset-password/package.json b/packages/pages.reset-password/package.json index fc263a45..cf492565 100644 --- a/packages/pages.reset-password/package.json +++ b/packages/pages.reset-password/package.json @@ -23,7 +23,7 @@ "@tanstack/react-router": "^1.128.8", "@xipkg/button": "4.1.0", "@xipkg/form": "4.2.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.0.7", "@xipkg/link": "2.0.12", "@xipkg/utils": "1.6.3", diff --git a/packages/pages.signin/package.json b/packages/pages.signin/package.json index 93b0ac97..71d6ec14 100644 --- a/packages/pages.signin/package.json +++ b/packages/pages.signin/package.json @@ -23,7 +23,7 @@ "@tanstack/react-router": "^1.128.8", "@xipkg/button": "4.1.0", "@xipkg/form": "4.2.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.0.7", "@xipkg/link": "2.0.12", "@xipkg/utils": "1.8.0", diff --git a/packages/pages.signup/package.json b/packages/pages.signup/package.json index c3f3ed60..f566b94b 100644 --- a/packages/pages.signup/package.json +++ b/packages/pages.signup/package.json @@ -19,7 +19,7 @@ "@xipkg/button": "4.1.0", "@xipkg/form": "4.2.1", "@xipkg/checkbox": "^5.0.0", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.0.7", "@xipkg/link": "2.0.12", "@xipkg/utils": "1.8.0", diff --git a/packages/pages.welcome/package.json b/packages/pages.welcome/package.json index 0ccb2160..80ce0fd5 100644 --- a/packages/pages.welcome/package.json +++ b/packages/pages.welcome/package.json @@ -15,7 +15,7 @@ "@xipkg/button": "4.1.0", "@xipkg/fileuploader": "5.0.0", "@xipkg/form": "4.2.1", - "@xipkg/icons": "^3.0.3", + "@xipkg/icons": "^3.0.4", "@xipkg/input": "2.0.7", "@xipkg/modal": "^4.3.1", "@xipkg/utils": "1.8.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ae2aa2df..8db957f0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -777,8 +777,8 @@ importers: specifier: 4.1.0 version: 4.1.0(@types/react@19.2.14)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/link': specifier: 2.0.12 version: 2.0.12(react@19.2.4) @@ -911,8 +911,8 @@ importers: specifier: 4.1.0 version: 4.1.0(@types/react@19.2.14)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/slider': specifier: 2.0.12 version: 2.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) @@ -1315,8 +1315,8 @@ importers: specifier: 4.1.0 version: 4.1.0(@types/react@19.2.14)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: ^2.2.9 version: 2.2.9(react@19.2.4) @@ -1330,8 +1330,8 @@ importers: specifier: ^2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: ^4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: ^1.8.0 version: 1.8.0(react@19.2.4) @@ -1412,8 +1412,8 @@ importers: specifier: 4.1.0 version: 4.1.0(@types/react@19.2.14)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: ^2.2.9 version: 2.2.9(react@19.2.4) @@ -1427,8 +1427,8 @@ importers: specifier: ^2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: ^4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: ^1.8.0 version: 1.8.0(react@19.2.4) @@ -1500,8 +1500,8 @@ importers: specifier: 4.1.0 version: 4.1.0(@types/react@19.2.14)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/modal': specifier: ^4.3.1 version: 4.3.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) @@ -1588,8 +1588,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.2.9 version: 2.2.9(react@19.2.4) @@ -1685,8 +1685,8 @@ importers: specifier: 4.0.0 version: 4.0.0(@types/react@19.2.14)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) common.api: specifier: '*' version: link:../common.api @@ -1752,6 +1752,112 @@ importers: specifier: ^8.22.0 version: 8.55.0(eslint@9.39.2)(typescript@5.7.3) + packages/features.lesson.add: + dependencies: + '@tanstack/react-query': + specifier: ^5.73.3 + version: 5.73.3(react@19.2.4) + '@tanstack/react-router': + specifier: 1.120.11 + version: 1.120.11(react-dom@19.2.4)(react@19.2.4) + '@xipkg/button': + specifier: 4.1.0 + version: 4.1.0(@types/react@19.2.14)(react@19.2.4) + '@xipkg/datepicker': + specifier: 2.2.0 + version: 2.2.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + '@xipkg/form': + specifier: 4.2.1 + version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + '@xipkg/icons': + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) + '@xipkg/input': + specifier: 2.2.9 + version: 2.2.9(react@19.2.4) + '@xipkg/inputmask': + specifier: 2.0.12 + version: 2.0.12(react-dom@19.2.4)(react@19.2.4) + '@xipkg/modal': + specifier: 4.3.1 + version: 4.3.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + '@xipkg/select': + specifier: 2.2.5 + version: 2.2.5(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + '@xipkg/utils': + specifier: 1.8.0 + version: 1.8.0(react@19.2.4) + common.api: + specifier: '*' + version: link:../common.api + common.config: + specifier: '*' + version: link:../common.config + common.env: + specifier: '*' + version: link:../common.env + common.services: + specifier: '*' + version: link:../common.services + common.types: + specifier: '*' + version: link:../common.types + common.utils: + specifier: '*' + version: link:../common.utils + react: + specifier: '19' + version: 19.2.4 + sonner: + specifier: ^1.4.0 + version: 1.7.4(react-dom@19.2.4)(react@19.2.4) + devDependencies: + '@eslint/js': + specifier: ^9.19.0 + version: 9.39.2 + '@types/node': + specifier: ^20.3.1 + version: 20.19.33 + '@types/react': + specifier: ^19.0.2 + version: 19.2.14 + '@types/react-dom': + specifier: ^19.0.2 + version: 19.2.3(@types/react@19.2.14) + '@xipkg/eslint': + specifier: 3.2.0 + version: 3.2.0(eslint-plugin-jsx-a11y@6.10.2)(eslint@9.39.2)(turbo@2.8.7)(typescript@5.7.3) + '@xipkg/tailwind': + specifier: 0.8.1 + version: 0.8.1 + '@xipkg/typescript': + specifier: latest + version: 0.2.0 + common.eslint: + specifier: '*' + version: link:../common.eslint + common.typescript: + specifier: '*' + version: link:../common.typescript + eslint: + specifier: ^9.19.0 + version: 9.39.2 + eslint-plugin-react-hooks: + specifier: ^5.0.0 + version: 5.2.0(eslint@9.39.2) + eslint-plugin-react-refresh: + specifier: ^0.4.18 + version: 0.4.18(eslint@9.39.2) + globals: + specifier: ^15.14.0 + version: 15.15.0 + typescript: + specifier: ~5.7.2 + version: 5.7.3 + typescript-eslint: + specifier: ^8.22.0 + version: 8.55.0(eslint@9.39.2)(typescript@5.7.3) + packages/features.materials.add: dependencies: '@xipkg/button': @@ -1761,8 +1867,8 @@ importers: specifier: ^3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/utils': specifier: ^1.8.0 version: 1.8.0(react@19.2.4) @@ -1834,8 +1940,8 @@ importers: specifier: ^3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/utils': specifier: ^1.8.0 version: 1.8.0(react@19.2.4) @@ -1913,8 +2019,8 @@ importers: specifier: ^3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/modal': specifier: 4.3.0 version: 4.3.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) @@ -2144,8 +2250,8 @@ importers: specifier: 4.1.0 version: 4.1.0(@types/react@19.2.14)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: ^2.2.9 version: 2.2.9(react@19.2.4) @@ -2159,8 +2265,8 @@ importers: specifier: ^2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: ^4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: ^1.8.0 version: 1.8.0(react@19.2.4) @@ -2241,8 +2347,8 @@ importers: specifier: ^3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: ^2.2.9 version: 2.2.9(react@19.2.4) @@ -2250,8 +2356,8 @@ importers: specifier: ^2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: ^4.0.12 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: ^1.8.0 version: 1.8.0(react@19.2.4) @@ -2350,8 +2456,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -2486,8 +2592,8 @@ importers: specifier: 2.2.0 version: 2.2.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/inputmask': specifier: 2.0.12 version: 2.0.12(react-dom@19.2.4)(react@19.2.4) @@ -2619,8 +2725,8 @@ importers: specifier: 3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/modal': specifier: ^4.3.1 version: 4.3.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) @@ -2643,8 +2749,8 @@ importers: specifier: 2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: 1.8.0 version: 1.8.0(react@19.2.4) @@ -2803,8 +2909,8 @@ importers: specifier: ^2.0.12 version: 2.0.12(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.2.9 version: 2.2.9(react@19.2.4) @@ -2927,8 +3033,8 @@ importers: specifier: 3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/link': specifier: 2.0.12 version: 2.0.12(react@19.2.4) @@ -2936,8 +3042,8 @@ importers: specifier: 2.2.0 version: 2.2.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: 1.8.0 version: 1.8.0(react@19.2.4) @@ -3030,8 +3136,8 @@ importers: specifier: 3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/link': specifier: 2.0.12 version: 2.0.12(react@19.2.4) @@ -3051,8 +3157,8 @@ importers: specifier: 0.2.0 version: 0.2.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: 1.8.0 version: 1.8.0(react@19.2.4) @@ -3166,8 +3272,8 @@ importers: specifier: 3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/modal': specifier: ^4.3.1 version: 4.3.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) @@ -3178,8 +3284,8 @@ importers: specifier: ^2.0.13 version: 2.0.13(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: 1.8.0 version: 1.8.0(react@19.2.4) @@ -3281,8 +3387,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.2.9 version: 2.2.9(react@19.2.4) @@ -3302,8 +3408,8 @@ importers: specifier: 2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) common.api: specifier: '*' version: link:../common.api @@ -3432,8 +3538,8 @@ importers: specifier: 3.0.12 version: 3.0.12(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.2.9 version: 2.2.9(react@19.2.4) @@ -3453,8 +3559,8 @@ importers: specifier: 2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) common.entities: specifier: '*' version: link:../common.entities @@ -3565,8 +3671,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -3680,8 +3786,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -3877,8 +3983,8 @@ importers: specifier: 4.1.0 version: 4.1.0(@types/react@19.2.14)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/scrollarea': specifier: 2.2.0 version: 2.2.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) @@ -3886,8 +3992,8 @@ importers: specifier: 2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: 1.8.0 version: 1.8.0(react@19.2.4) @@ -3927,6 +4033,9 @@ importers: features.invoice.card: specifier: '*' version: link:../features.invoice.card + features.lesson.add: + specifier: '*' + version: link:../features.lesson.add features.materials.add: specifier: '*' version: link:../features.materials.add @@ -4022,8 +4131,8 @@ importers: specifier: ^2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) common.api: specifier: '*' version: link:../common.api @@ -4110,8 +4219,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -4204,8 +4313,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -4216,8 +4325,8 @@ importers: specifier: ^2.1.0 version: 2.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/userprofile': - specifier: 4.0.14 - version: 4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + specifier: 4.1.0 + version: 4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': specifier: 1.8.0 version: 1.8.0(react@19.2.4) @@ -4334,8 +4443,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -4443,8 +4552,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -4552,8 +4661,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -4652,8 +4761,8 @@ importers: specifier: 4.2.1 version: 4.2.1(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/icons': - specifier: ^3.0.3 - version: 3.0.3(react@19.2.4) + specifier: ^3.0.4 + version: 3.0.4(react@19.2.4) '@xipkg/input': specifier: 2.0.7 version: 2.0.7(react@19.2.4) @@ -11232,6 +11341,21 @@ packages: - react-dom dev: false + /@xipkg/avatar@3.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4): + resolution: {integrity: sha512-jmweky9M0k8PoJp/a14PA2vSALfjIa2YyoSnS5Vc3+ZMwVoeD0D5ez72ikppe/Hs3E2GCaKvd8sdzGxIJA4Whw==} + peerDependencies: + react: ^19 + dependencies: + '@radix-ui/react-avatar': 1.1.11(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + '@xipkg/utils': 1.8.0(react@19.2.4) + class-variance-authority: 0.7.1 + react: 19.2.4 + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + - react-dom + dev: false + /@xipkg/badge@2.0.12(react@19.2.4): resolution: {integrity: sha512-TQXPdo/3pxe/Qb3Z81J4WTkg/OXENFR719YqUvqXzYiHnrtA7lXVsZVHsa1R2fKSf8dvrKKCUOkEQaJISrgU0w==} peerDependencies: @@ -11494,8 +11618,8 @@ packages: react: 19.2.4 dev: false - /@xipkg/icons@3.0.3(react@19.2.4): - resolution: {integrity: sha512-WMCPl3e+SsuHd3JpjmnkwM9LszR28U69AfNcDdV99KwxFhH1Og9UFfcXsZNn0R8x4E0txZ5MO4/sF7nB64rkeQ==} + /@xipkg/icons@3.0.4(react@19.2.4): + resolution: {integrity: sha512-0UQ/K2lCS23zXjy964zxjjmNn5Ij9yt4883ULmueoUVamuK5RZSC5jLYMaNv17T4uNkiiapvunE+OVcUoUeBBQ==} peerDependencies: react: ^19 dependencies: @@ -11832,12 +11956,12 @@ packages: resolution: {integrity: sha512-GGAb21wy0l5wuWp7w00lykVNDr2dxPVBtiZ8nCuMHyKKPmsAZrbgyt1OUnn+7AyhnDqQEABS9+i+rsvGvVn/GA==} dev: true - /@xipkg/userprofile@4.0.14(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4): - resolution: {integrity: sha512-vFcIFgYp+99xFP5hGSz3r2+pya8OVq6aph5+37oOYcVBTxshuHmKP7dRM4S6TWhq9BtbvbKUV7ZjbIOIZWnmiA==} + /@xipkg/userprofile@4.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4): + resolution: {integrity: sha512-+TzLGqzhi9t7o+SiNs+Tma6E1MXC5MuZf0ygR7+E0JTKJDhf+//EWuJ6G4CDGDSmo/G5Y8gra7UbCLaRKdn8OA==} peerDependencies: react: ^19 dependencies: - '@xipkg/avatar': 3.0.10(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) + '@xipkg/avatar': 3.1.0(@types/react-dom@19.2.3)(@types/react@19.2.14)(react-dom@19.2.4)(react@19.2.4) '@xipkg/utils': 1.8.0(react@19.2.4) class-variance-authority: 0.7.1 react: 19.2.4 @@ -15844,6 +15968,16 @@ packages: - supports-color dev: false + /sonner@1.7.4(react-dom@19.2.4)(react@19.2.4): + resolution: {integrity: sha512-DIS8z4PfJRbIyfVFDVnK9rO3eYDtse4Omcm6bt0oEr5/jtLgysmjuBl1frJ9E/EQZrFmKx2A8m/s5s9CRXIzhw==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + dependencies: + react: 19.2.4 + react-dom: 19.2.4(react@19.2.4) + dev: false + /sonner@2.0.7(react-dom@19.2.4)(react@19.2.4): resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} peerDependencies: