diff --git a/app/(full-page)/pages/notfound/page.tsx b/app/(full-page)/pages/notfound/page.tsx
index 52c0b4ce..77df8132 100644
--- a/app/(full-page)/pages/notfound/page.tsx
+++ b/app/(full-page)/pages/notfound/page.tsx
@@ -1,54 +1,63 @@
import React from 'react';
import Link from 'next/link';
+import FancyLinkBtn from '@/app/components/buttons/FancyLinkBtn';
-const NotFoundPage = () => {
- return (
-
-
-

-
-
-
404
-
Not Found
-
Requested resource is not available
-
-
-
-
-
- Frequently Asked Questions
- Ultricies mi quis hendrerit dolor.
-
-
-
-
-
-
-
- Solution Center
- Phasellus faucibus scelerisque eleifend.
-
-
-
-
-
-
-
- Permission Manager
- Accumsan in nisl nisi scelerisque
-
-
-
-
-
+const NotFoundPage = ({titleMessege}) => {
+ return
;
+ // return (
+ //
+ //
+ //

+ //
+ //
+ //
404
+ //
Not Found
+ //
Requested resource is not available
+ //
+ //
+ //
+ //
+ //
+ // Frequently Asked Questions
+ // Ultricies mi quis hendrerit dolor.
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // Solution Center
+ // Phasellus faucibus scelerisque eleifend.
+ //
+ //
+ //
+ //
+ //
+ //
+ //
+ // Permission Manager
+ // Accumsan in nisl nisi scelerisque
+ //
+ //
+ //
+ //
+ //
+ //
+ // );
+};
export default NotFoundPage;
diff --git a/app/(main)/course/[courseTheme]/page.tsx b/app/(main)/course/[courseTheme]/page.tsx
new file mode 100644
index 00000000..7ee3de69
--- /dev/null
+++ b/app/(main)/course/[courseTheme]/page.tsx
@@ -0,0 +1,260 @@
+'use client';
+
+import ConfirmModal from '@/app/components/popUp/ConfirmModal';
+import FormModal from '@/app/components/popUp/FormModal';
+import GroupSkeleton from '@/app/components/skeleton/GroupSkeleton';
+import Link from 'next/link';
+import { Button } from 'primereact/button';
+import { Column } from 'primereact/column';
+import { DataTable } from 'primereact/datatable';
+import { InputText } from 'primereact/inputtext';
+import { LayoutContext } from '@/layout/context/layoutcontext';
+import React, { useContext, useEffect, useState } from 'react';
+import { getToken } from '@/utils/auth';
+import { useParams } from 'next/navigation';
+import { addThemes, deleteTheme, fetchCourseInfo, fetchThemes, updateTheme } from '@/services/courses';
+import NotFoundPage from '@/app/(full-page)/pages/notfound/page';
+
+export default function CourseTheme() {
+ const [hasThemes, setHasThemes] = useState(false);
+ const [themes, setThemes] = useState([]);
+ const [themeValue, setThemeValue] = useState({ title: '' });
+ const [themeInfo, setThemeInfo] = useState();
+ const [courseTitle, setCourseTitle] = useState('');
+ const [selectedCourse, setSelectedCourse] = useState(null);
+ const [formVisible, setFormVisible] = useState(false);
+ const [editMode, setEditMode] = useState(false);
+ const [forStart, setForStart] = useState(false);
+ const [skeleton, setSkeleton] = useState(false);
+ const { setMessage } = useContext(LayoutContext);
+
+ const { courseTheme } = useParams() as { courseTheme: string };
+
+ const handleFetchThemes = async () => {
+ const token = getToken('access_token');
+ const data = await fetchThemes(token, courseTheme);
+
+ if (data.lessons) {
+ setThemes(data.lessons.data);
+ setHasThemes(false);
+ } else {
+ setHasThemes(true);
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Проблема с соединением. Повторите заново' }
+ }); // messege - Ошибка загрузки курсов
+ }
+ };
+
+ const handleFetchInfo = async () => {
+ const token = getToken('access_token');
+ const data = await fetchCourseInfo(token, courseTheme);
+
+ setThemeInfo(data.course);
+ };
+
+ const handleAddTheme = async () => {
+ if (themeValue.title.length < 1) {
+ alert('hi');
+ return null;
+ }
+
+ const token = getToken('access_token');
+ const data = await addThemes(token, courseTheme, themeValue.title);
+ console.log(data);
+
+ if (data.success) {
+ toggleSkeleton();
+ handleFetchThemes();
+ setMessage({
+ state: true,
+ value: { severity: 'success', summary: 'Ийгиликтүү кошулду!', detail: '' }
+ }); // messege - Успех!
+ } else {
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Ошибка при при добавлении' }
+ }); // messege - Ошибка при добавлении
+ }
+ };
+
+ const handleDeleteCourse = async (id: number) => {
+ const token = getToken('access_token');
+
+ const data = await deleteTheme(token, id);
+ if (data.success) {
+ toggleSkeleton();
+ handleFetchThemes();
+ setMessage({
+ state: true,
+ value: { severity: 'success', summary: 'Ийгиликтүү өчүрүлдү!', detail: '' }
+ }); // messege - Успех!
+ } else {
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Ошибка при при удалении' }
+ }); // messege - Ошибка при добавлении
+ }
+ };
+
+ const handleUpdateTheme = async () => {
+ const token = getToken('access_token');
+
+ const data = await updateTheme(token, courseTheme, selectedCourse.id, themeValue);
+ if (data.success) {
+ toggleSkeleton();
+ handleFetchThemes();
+ clearValues();
+ setEditMode(false);
+ setSelectedCourse(null);
+ setMessage({
+ state: true,
+ value: { severity: 'success', summary: 'Ийгиликтүү өзгөртүлдү!', detail: '' }
+ }); // messege - Успех!
+ } else {
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка при при изменении темы', detail: 'Заполняйте поля правильно' }
+ }); // messege - Ошибка при изменении курса
+ }
+ };
+
+ const clearValues = () => {
+ setThemeValue({ title: '' });
+ setCourseTitle('');
+ setEditMode(false);
+ setSelectedCourse(null);
+ };
+
+ const getConfirmOptions = (id) => ({
+ message: 'Сиз чын эле өчүрүүнү каалайсызбы??',
+ header: 'Өчүрүү',
+ icon: 'pi pi-info-circle',
+ defaultFocus: 'reject',
+ acceptClassName: 'p-button-danger',
+ acceptLabel: 'Кийинки кадам', // кастомная надпись для "Yes"
+ rejectLabel: 'Артка',
+ accept: () => handleDeleteCourse(id),
+ reject: () => console.log('Удаление отменено')
+ });
+
+ const toggleSkeleton = () => {
+ setSkeleton(true);
+ setTimeout(() => {
+ setSkeleton(false);
+ }, 1000);
+ };
+
+ useEffect(() => {
+ handleFetchInfo();
+ handleFetchThemes();
+ }, []);
+
+ useEffect(() => {
+ const title = courseTitle.trim();
+ title.length > 0 ? setForStart(false) : setForStart(true);
+ }, [courseTitle]);
+
+ useEffect(() => {
+ themes.length < 1 ? setHasThemes(true)
+ : setHasThemes(false);
+ }, [themes]);
+
+ const titleInfoClass = `${!themeInfo?.image ? 'items-center' : 'w-full'} ${themeInfo?.image ? 'w-1/2' : 'w-full'}`;
+ const titleImageClass = `${themeInfo?.image ? 'md:w-1/3' : ''}`;
+
+ return (
+
+ {/* title section */}
+
+
+
+ {themeInfo?.title}
+
+
{themeInfo?.description}
+
+
+ {themeInfo?.created_at}
+ Home/theme
+
+
+
+
+

+
+
+
+ {/* add button*/}
+
+ );
+}
diff --git a/app/(main)/course/lessons/[lessons]/page.tsx b/app/(main)/course/lessons/[lessons]/page.tsx
new file mode 100644
index 00000000..ce34772a
--- /dev/null
+++ b/app/(main)/course/lessons/[lessons]/page.tsx
@@ -0,0 +1,9 @@
+'use client';
+
+export default function Lesson() {
+ return (
+
+ lorem
+
+ )
+}
diff --git a/app/(main)/course/page.tsx b/app/(main)/course/page.tsx
new file mode 100644
index 00000000..193c37d1
--- /dev/null
+++ b/app/(main)/course/page.tsx
@@ -0,0 +1,409 @@
+'use client';
+
+import FormModal from '@/app/components/popUp/FormModal';
+import { addCourse, deleteCourse, fetchCourseInfo, fetchCourses, updateCourse } from '@/services/courses';
+import { getToken } from '@/utils/auth';
+import { Button } from 'primereact/button';
+import { FileUpload, FileUploadSelectEvent } from 'primereact/fileupload';
+import { InputText } from 'primereact/inputtext';
+import { useContext, useEffect, useState } from 'react';
+import { LayoutContext } from '@/layout/context/layoutcontext';
+import { InputTextarea } from 'primereact/inputtextarea';
+import { DataTable } from 'primereact/datatable';
+import { Column } from 'primereact/column';
+import ConfirmModal from '@/app/components/popUp/ConfirmModal';
+import GroupSkeleton from '@/app/components/skeleton/GroupSkeleton';
+import Link from 'next/link';
+import { CourseCreateType } from '@/types/courseCreateType';
+import { CourseType } from '@/types/courseType';
+import { Paginator } from 'primereact/paginator';
+import NotFoundPage from '@/app/(full-page)/pages/notfound/page';
+
+export default function Course() {
+ const [courses, setCourses] = useState([]);
+ const [hasCourses, setHasCourses] = useState(false);
+ const [courseValue, setCourseValue] = useState
({ title: '', description: '', video_url: '', image: '' });
+ const [courseTitle, setCourseTitle] = useState('');
+ const [video_url, setVideo_url] = useState('');
+ const [description, setDesciption] = useState('');
+ const [editMode, setEditMode] = useState(false);
+ const [selectedCourse, setSelectedCourse] = useState(null);
+ const [formVisible, setFormVisible] = useState(false);
+ const [image, setImage] = useState('');
+ const [forStart, setForStart] = useState(false);
+ const [skeleton, setSkeleton] = useState(false);
+ const [courseCash, setCourseCash] = useState<{ [key: number]: any[] }>({});
+ const [pagination, setPagination] = useState({
+ currentPage: 1,
+ total: 0,
+ perPage: 0
+ });
+
+ const { setMessage } = useContext(LayoutContext);
+
+ const fetchData = async (page = 1) => {
+ console.log('Запрашиваем курсы...');
+
+ const token = getToken('access_token');
+ const headers: HeadersInit = token ? { Authorization: `Bearer ${token}` } : {};
+
+ try {
+ console.log('Номер запрашиваемой страницы ', page);
+
+ const res = await fetch(`http://api.mooc.oshsu.kg/public/api/v1/teacher/courses?page=${Number(page)}&limit=3`, {
+ headers
+ });
+ const data = await res.json();
+
+ if (data.courses) {
+ setHasCourses(false);
+ setCourses(data.courses.data);
+ setPagination({
+ currentPage: data.courses.current_page,
+ total: data.courses.total,
+ perPage: data.courses.per_page
+ });
+ setCourseCash((prev) => ({ ...prev, [page]: data.courses.data }));
+ localStorage.setItem('lastPage', JSON.stringify(page));
+ } else {
+ setHasCourses(true);
+ setCourseCash({});
+ localStorage.removeItem('lastPage');
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Проблема с соединением. Повторите заново' }
+ }); // messege - Ошибка загрузки курсов
+ }
+ } catch (error) {
+ console.error('Ошибка загрузки:', error);
+ localStorage.removeItem('lastPage');
+ setCourseCash({});
+ setHasCourses(true);
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Повторите заново' }
+ }); // messege - Ошибка загрузки курсов
+ }
+ };
+
+ const handleAddCourse = async () => {
+ if (courseValue.title.length < 1) {
+ alert('hi');
+ return null;
+ }
+ const token = getToken('access_token');
+ const data = await addCourse(token, courseValue);
+ if (data.success) {
+ toggleSkeleton();
+ fetchData();
+ setCourseCash({});
+ setMessage({
+ state: true,
+ value: { severity: 'success', summary: 'Ийгиликтүү кошулду!', detail: '' }
+ }); // messege - Успех!
+ } else {
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Ошибка при при добавлении' }
+ }); // messege - Ошибка при добавлении
+ }
+ };
+
+ const handleDeleteCourse = async (id: number) => {
+ const token = getToken('access_token');
+
+ const data = await deleteCourse(token, id);
+ if (data.success) {
+ toggleSkeleton();
+ fetchData();
+ setCourseCash({});
+ setMessage({
+ state: true,
+ value: { severity: 'success', summary: 'Ийгиликтүү өчүрүлдү!', detail: '' }
+ }); // messege - Успех!
+ } else {
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Ошибка при при удалении' }
+ }); // messege - Ошибка при добавлении
+ }
+ };
+
+ const handleUpdateCourse = async () => {
+ const token = getToken('access_token');
+
+ const data = await updateCourse(token, selectedCourse, courseValue);
+ if (data.success) {
+ toggleSkeleton();
+ fetchData();
+ clearValues();
+ setEditMode(false);
+ setSelectedCourse(null);
+ setCourseCash({});
+ setMessage({
+ state: true,
+ value: { severity: 'success', summary: 'Ийгиликтүү өзгөртүлдү!', detail: '' }
+ }); // messege - Успех!
+ } else {
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка при при изменении курса', detail: 'Заполняйте поля правильно' }
+ }); // messege - Ошибка при изменении курса
+ }
+ };
+
+ const clearValues = () => {
+ setCourseValue({ title: '', description: '', video_url: '', image: '' });
+ setCourseTitle('');
+ setVideo_url('');
+ setDesciption('');
+ setImage('');
+ setEditMode(false);
+ setSelectedCourse(null);
+ setCourseCash({});
+ };
+
+ const onSelect = (e: FileUploadSelectEvent) => {
+ setImage(e.files[0].name); // сохраняешь файл
+ console.log(e.files[0]);
+
+ setCourseValue((prev) => ({
+ ...prev,
+ image: e.files[0]
+ }));
+ };
+
+ const imageBodyTemplate = (product: CourseType) => {
+ const image = product.image;
+
+ if (typeof image === 'string') {
+ return (
+
+

+
+ );
+ }
+
+ return (
+
+

+
+ );
+ };
+
+ const getConfirmOptions = (id: number) => ({
+ message: 'Сиз чын эле өчүрүүнү каалайсызбы??',
+ header: 'Өчүрүү',
+ icon: 'pi pi-info-circle',
+ defaultFocus: 'reject',
+ acceptClassName: 'p-button-danger',
+ acceptLabel: 'Кийинки кадам', // кастомная надпись для "Yes"
+ rejectLabel: 'Артка',
+ accept: () => handleDeleteCourse(id),
+ reject: () => console.log('Удаление отменено')
+ });
+
+ const toggleSkeleton = () => {
+ setSkeleton(true);
+ setTimeout(() => {
+ setSkeleton(false);
+ }, 1000);
+ };
+
+ // Ручное управление пагинацией
+ const handlePageChange = (page: number) => {
+ console.log(courseCash, courseCash[page]);
+
+ if (page in courseCash) {
+ setCourses(courseCash[page]);
+ setPagination((prev) => ({ ...prev, currentPage: page }));
+ } else {
+ fetchData(page);
+ }
+ };
+
+ useEffect(() => {
+ const title = courseTitle.trim();
+ if (title.length > 0) {
+ setForStart(false);
+ } else {
+ setForStart(true);
+ }
+ }, [courseTitle]);
+
+ useEffect(() => {
+ fetchData();
+ }, []);
+
+ useEffect(() => {
+ console.log('Курсы ', courses);
+ courses.length < 1 ? setHasCourses(true) : setHasCourses(false);
+ }, [courses]);
+
+ useEffect(() => {
+ console.log('edit mode ', editMode);
+
+ const handleShow = async () => {
+ const token = getToken('access_token');
+ const data = await fetchCourseInfo(token, selectedCourse);
+ console.log(data);
+ setCourseTitle(data.course.title);
+ setVideo_url(data.course.video_url);
+ setDesciption(data.course.description);
+ setImage(data.course.image);
+ };
+
+ if (editMode) {
+ handleShow();
+ }
+ }, [editMode]);
+
+ return (
+
+
+
+
+
+
+ {
+ setCourseTitle(e.target.value);
+ setCourseValue((prev) => ({
+ ...prev,
+ title: e.target.value
+ }));
+ }}
+ />
+
+
+
+ {
+ setVideo_url(e.target.value);
+ setCourseValue((prev) => ({
+ ...prev,
+ video_url: e.target.value
+ }));
+ }}
+ />
+
+
+
+
+
+
+ {
+ setDesciption(e.target.value);
+ setCourseValue((prev) => ({
+ ...prev,
+ description: e.target.value
+ }));
+ }}
+ />
+
+
+
+
+
+ {image ? (
+
+ Сүрөт: {image}
+
+ ) : (
+
jpeg, png, jpg
+ )}
+
+
+
+
+
+
+
+
Курстар
+
+
+
{
+ setEditMode(false);
+ clearValues();
+ setFormVisible(true);
+ }}
+ />
+
+
+ {hasCourses ? (
+
+ ) : (
+
+ {skeleton ? (
+
+ ) : (
+ <>
+
+
+ (
+
+ {rowData.title}
+
+ )}
+ >
+
+ (
+
+ {
+ setEditMode(true);
+ setSelectedCourse(rowData.id);
+ setCourseValue({
+ title: rowData.title || '',
+ description: rowData.description || '',
+ video_url: rowData.video_url || '',
+ image: rowData.image || ''
+ });
+ setFormVisible(true);
+ }}
+ />
+
+
+
+
+
+ )}
+ />
+
+
handlePageChange(e.page + 1)}
+ template="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink"
+ />
+ >
+ )}
+
+ )}
+
+ );
+}
diff --git a/app/(main)/layout.tsx b/app/(main)/layout.tsx
index 5cb39fdb..122640dd 100644
--- a/app/(main)/layout.tsx
+++ b/app/(main)/layout.tsx
@@ -19,7 +19,7 @@ export const metadata: Metadata = {
ttl: 604800
},
icons: {
- icon: '/favicon.ico'
+ // icon: ''
}
};
diff --git a/app/(main)/page.tsx b/app/(main)/teacher/page.tsx
similarity index 99%
rename from app/(main)/page.tsx
rename to app/(main)/teacher/page.tsx
index afe44527..a06710d5 100644
--- a/app/(main)/page.tsx
+++ b/app/(main)/teacher/page.tsx
@@ -6,8 +6,8 @@ import { Column } from 'primereact/column';
import { DataTable } from 'primereact/datatable';
import { Menu } from 'primereact/menu';
import React, { useContext, useEffect, useRef, useState } from 'react';
-import { ProductService } from '../../demo/service/ProductService';
-import { LayoutContext } from '../../layout/context/layoutcontext';
+import { ProductService } from '../../../demo/service/ProductService';
+import { LayoutContext } from '../../../layout/context/layoutcontext';
import Link from 'next/link';
import { Demo } from '@/types';
import { ChartData, ChartOptions } from 'chart.js';
diff --git a/app/(student)/layout.tsx b/app/(student)/layout.tsx
new file mode 100644
index 00000000..0eec769f
--- /dev/null
+++ b/app/(student)/layout.tsx
@@ -0,0 +1,15 @@
+import Layout from "../../layout/layout";
+
+export default function LayoutStudent({
+ children,
+}: Readonly<{
+ children: React.ReactNode;
+}>) {
+
+ return (
+
+ {/* {children} */}
+ {children};
+
+ );
+}
\ No newline at end of file
diff --git a/app/components/BaseLayout.tsx b/app/components/BaseLayout.tsx
new file mode 100644
index 00000000..101fd3fb
--- /dev/null
+++ b/app/components/BaseLayout.tsx
@@ -0,0 +1,19 @@
+"use client";
+
+import AppTopbar from "@/layout/AppTopbar";
+import HomeClient from "./HomeClient";
+import AppFooter from "@/layout/AppFooter";
+
+export default function BaseLayout() {
+ return (
+ <>
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/app/components/CounterBanner.tsx b/app/components/CounterBanner.tsx
new file mode 100644
index 00000000..efa045af
--- /dev/null
+++ b/app/components/CounterBanner.tsx
@@ -0,0 +1,58 @@
+import React from 'react';
+import { faCircle, faChalkboard, faUserGraduate, faBookOpen, faShieldHeart } from '@fortawesome/free-solid-svg-icons';
+import MyFontAwesome from './MyFontAwesome';
+import CountUp from 'react-countup';
+
+export default function CounterBanner() {
+
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
Курстар & видеосабактар
+
+
+
+
+
+
+
+
+
+
+
+
Катталган студенттер
+
+
+
+
+
+
+
+
+
+
+
+
%
+
Канааттануу деңгээли
+
+
+
+
+ );
+}
diff --git a/app/components/HomeClient.tsx b/app/components/HomeClient.tsx
new file mode 100644
index 00000000..0ecdc498
--- /dev/null
+++ b/app/components/HomeClient.tsx
@@ -0,0 +1,171 @@
+"use client";
+
+import AOS from "aos";
+import "aos/dist/aos.css";
+import { useEffect } from "react";
+import CounterBanner from "./CounterBanner";
+import Link from "next/link";
+import { faClock, faVideo,} from "@fortawesome/free-solid-svg-icons";
+import MyFontAwesome from "./MyFontAwesome";
+import VideoPlay from "./VideoPlay";
+
+export default function HomeClient() {
+ useEffect(() => {
+ AOS.init();
+ }, []);
+
+ return (
+
+
+
+
+
+
+

+
+ ЫҢГАЙЛУУ ОКУУ ҮЧҮН ОНЛАЙН МЕЙКИНДИК
+
+
+
+ Аралыктан окутуу порталына кош келиңиз!
+
+
+ {" "}
+ Университеттин онлайн билим берүү жаатындагы долбоорлорун
+ бириктирүүдөбүз:
+
+ - ачык онлайн курстар
+ - жогорку билим берүү программалары
+
+
+
+
+
+
+
+
+
+
+

+
+
+

+
+
+

+
+
+
+

+
+
+
+
+
+
+
Куттуктайбыз!
+
Сиздин кабыл алуу ийгиликтүү аяктады
+
+
+
+
+
+
User experience className
+
Today at 12.00 PM
+
+
+ Join now
+
+
+
+
+
+
+
+
+ {/* Counter Statistics */}
+
+
+ {/* Oshgu Video */}
+
+
Видеоэкскурсия по главному зданию ОшГУ
+
+
+
+ );
+}
diff --git a/app/components/InfoBanner.tsx b/app/components/InfoBanner.tsx
new file mode 100644
index 00000000..862aefc0
--- /dev/null
+++ b/app/components/InfoBanner.tsx
@@ -0,0 +1,10 @@
+'use client';
+
+export default function InfoBanner({title}:{title:string}) {
+
+ return (
+
+
{title}
+
+ );
+};
diff --git a/app/components/MyFontAwesome.tsx b/app/components/MyFontAwesome.tsx
new file mode 100644
index 00000000..28e58167
--- /dev/null
+++ b/app/components/MyFontAwesome.tsx
@@ -0,0 +1,17 @@
+"use client"; // обязательно в app/ структуре
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { IconProp } from "@fortawesome/fontawesome-svg-core";
+import { ComponentProps } from "react";
+
+interface IconProps extends ComponentProps {
+ icon: IconProp;
+ className?: string;
+ size?: "xs" | "lg" | "sm" | "1x" | "2x" | "3x" | "4x" | "5x" | "6x" | "7x" | "8x" | "9x" | "10x";
+}
+
+export default function MyFontAwesome({ icon, className, size, ...props }:IconProps ) {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/app/components/SessionManager.tsx b/app/components/SessionManager.tsx
new file mode 100644
index 00000000..741cddac
--- /dev/null
+++ b/app/components/SessionManager.tsx
@@ -0,0 +1,98 @@
+'use client';
+
+import { getToken } from '@/utils/auth';
+import { useContext, useEffect } from 'react';
+import { LayoutContext } from '@/layout/context/layoutcontext';
+import { getUser } from '@/services/auth';
+import { logout } from '@/utils/logout';
+
+const SessionManager = () => {
+ const { setMessage } = useContext(LayoutContext);
+ const { user, setUser } = useContext(LayoutContext);
+ const { setGlobalLoading } = useContext(LayoutContext);
+
+ useEffect(() => {
+ console.log('Пользователь ', user);
+ }, [user]);
+
+ useEffect(() => {
+ console.log('Роутинг!');
+
+ const init = async () => {
+ const token = getToken('access_token');
+ if (token) {
+ const res = await getUser(token);
+ setGlobalLoading(true);
+ try {
+ if (res?.success) {
+ setGlobalLoading(false);
+ const userVisit = localStorage.getItem('userVisit');
+ console.log('Данные успешно пришли ', res);
+
+ if (!userVisit) {
+ localStorage.setItem('userVisit', JSON.stringify(true));
+
+ setMessage({
+ state: true,
+ value: { severity: 'success', summary: 'Успешная авторизация!', detail: '' }
+ }); // messege - Успех!
+ }
+ setUser(res.user);
+ } else {
+ logout({setUser, setGlobalLoading});
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Ошибка при авторизации' }
+ }); // messege - Ошибка при авторизации
+ console.log('Ошибка при получении пользователя');
+ }
+ } catch (error) {
+ logout({setUser, setGlobalLoading});
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Ошибка', detail: 'Ошибка при авторизации' }
+ }); // messege - Ошибка при авторизации
+ console.log('Ошибка при получении пользователя');
+ }
+ } else {
+ setGlobalLoading(false);
+ }
+ };
+ init();
+ }, []);
+
+ useEffect(() => {
+ const checkToken = () => {
+ const token = getToken('access_token');
+
+ if (!token) {
+ const userVisit = localStorage.getItem('userVisit');
+ if(userVisit){
+ setMessage({
+ state: true,
+ value: { severity: 'error', summary: 'Сессия завершилось', detail: 'Войдите заново' }
+ }); // messege - Время сесси завершилось
+ }
+ logout({setUser, setGlobalLoading});
+ console.log('Токен отсутствует - завершаем сессию');
+ return false; // сигнал для остановки интервала
+ }
+ return true;
+ };
+
+ // немедленная проверка
+ if (!checkToken()) return;
+
+ const interval = setInterval(() => {
+ if (!checkToken()) {
+ clearInterval(interval);
+ }
+ }, 5000);
+
+ return () => clearInterval(interval);
+ }, []);
+
+ return null;
+};
+
+export default SessionManager;
diff --git a/app/components/VideoPlay.tsx b/app/components/VideoPlay.tsx
new file mode 100644
index 00000000..fb45968c
--- /dev/null
+++ b/app/components/VideoPlay.tsx
@@ -0,0 +1,49 @@
+'use client';
+
+import { faPlay} from "@fortawesome/free-solid-svg-icons";
+
+import Image from "next/image";
+import { useState } from "react";
+import { Dialog } from 'primereact/dialog';
+// import 'primereact/resources/themes/lara-light-blue/theme.css'; // или другая тема
+import 'primereact/resources/primereact.min.css';
+import 'primeicons/primeicons.css';
+import MyFontAwesome from "./MyFontAwesome";
+
+export default function VideoPlay() {
+ const [videoCall, setVideoCall] = useState(false);
+
+ return (
+
+
+
+
+
setVideoCall(true)}
+ >
+ {/* Волна */}
+
+
+ {/* Иконка-кнопка */}
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/app/components/buttons/FancyLinkBtn.tsx b/app/components/buttons/FancyLinkBtn.tsx
new file mode 100644
index 00000000..64cd4d2c
--- /dev/null
+++ b/app/components/buttons/FancyLinkBtn.tsx
@@ -0,0 +1,31 @@
+'use client';
+
+import Link from 'next/link';
+import { useState } from 'react';
+
+export default function FancyLinkBtn({ btnWidth, backround, effectBg, title }) {
+ const [position, setPosition] = useState(false);
+
+ return (
+
+ setPosition(true)}
+ onMouseLeave={() => setPosition(false)}
+ className="default-btn p-[7px] md:p-[15px]"
+ onClick={() => setPosition((prev) => !prev)}
+ style={{
+ backgroundColor: `var(${backround})`,
+ width: `${ btnWidth }`,
+ }}
+ >
+ {/* */}
+ {title}
+ {/* */}
+
+
+
+ );
+}
diff --git a/app/components/loading/GlobalLoading.tsx b/app/components/loading/GlobalLoading.tsx
new file mode 100644
index 00000000..65be1f01
--- /dev/null
+++ b/app/components/loading/GlobalLoading.tsx
@@ -0,0 +1,27 @@
+import React, { useContext } from 'react';
+import { LayoutContext } from '@/layout/context/layoutcontext';
+
+export default function GlobalLoading() {
+ const { globalLoading } = useContext(LayoutContext);
+
+ if(globalLoading){
+ return (
+ <>
+
+ >
+ );
+ }
+}
diff --git a/app/components/messages/Message.tsx b/app/components/messages/Message.tsx
new file mode 100644
index 00000000..9224acf4
--- /dev/null
+++ b/app/components/messages/Message.tsx
@@ -0,0 +1,29 @@
+'use client';
+import { Button } from 'primereact/button';
+import { Toast } from 'primereact/toast';
+import { useContext, useEffect, useRef } from 'react';
+import { LayoutContext } from '@/layout/context/layoutcontext';
+
+export default function Message() {
+ const { message } = useContext(LayoutContext);
+ const toast = useRef(null);
+
+ const showError = () => {
+ toast.current?.show({ severity: message.value.severity, summary: message.value.summary, detail: message.value.detail, life: 3000 });
+ };
+
+ useEffect(() => {
+ const timer = setTimeout(() => {
+ showError();
+ }, 0); // откладываем до следующей итерации event loop
+
+ return () => clearTimeout(timer);
+ }, [message]);
+
+ return (
+
+ {/* */}
+
+
+ );
+}
diff --git a/app/components/popUp/ConfirmModal.tsx b/app/components/popUp/ConfirmModal.tsx
new file mode 100644
index 00000000..017fc105
--- /dev/null
+++ b/app/components/popUp/ConfirmModal.tsx
@@ -0,0 +1,15 @@
+'use client';
+import { confirmDialog } from 'primereact/confirmdialog';
+import { Button } from 'primereact/button';
+
+export default function ConfirmModal({confirmVisible}) {
+ const handleClick = () => {
+ confirmDialog(confirmVisible);
+ };
+
+ return (
+
+
+
+ );
+}
diff --git a/app/components/popUp/FormModal.tsx b/app/components/popUp/FormModal.tsx
new file mode 100644
index 00000000..ebc1a9e9
--- /dev/null
+++ b/app/components/popUp/FormModal.tsx
@@ -0,0 +1,37 @@
+'use client';
+
+import { Button } from 'primereact/button';
+import { Dialog } from 'primereact/dialog';
+
+export default function FormModal({children, title, fetchValue, clearValues, visible, setVisible, start}) {
+
+ const footerContent = (
+
+ {
+ setVisible(false);
+ clearValues();
+ }} className="p-button-text" />
+ { {
+ setVisible(false);
+ fetchValue();
+ }} autoFocus />}
+
+ );
+
+ return (
+
+
+
+ );
+}
diff --git a/app/components/popUp/Tiered.tsx b/app/components/popUp/Tiered.tsx
new file mode 100644
index 00000000..bc8082a5
--- /dev/null
+++ b/app/components/popUp/Tiered.tsx
@@ -0,0 +1,57 @@
+'use client';
+
+import { useEffect, useRef, useState } from 'react';
+import { Button } from 'primereact/button';
+import { TieredMenu } from 'primereact/tieredmenu';
+import { useMediaQuery } from '@/hooks/useMediaQuery';
+
+export default function Tiered({title, items, insideColor}) {
+ const [mobile, setMobile] = useState(false);
+
+ const menu = useRef(null);
+ const media = useMediaQuery('(max-width: 1000px)');
+
+ const menuItems = items.map(item => ({
+ ...item,
+ url: item.link && item.link
+ }));
+
+ const toggleMenu = (e)=> {
+ menu.current.toggle(e);
+ setMobile(prev => !prev);
+ }
+ // Общий фонт который закрывает кнопку бургер меню, Close
+ return (
+
+ toggleMenu(e)}
+ style={{color: 'black', fontSize: title.name ? '16px' : '20px'}}
+ className={`${ title.font } ${
+ title.name ?
+ 'flex gap-2 items-center pb-3 px-0'
+ : 'text-blue-300'
+ } bg-white p-2`}
+ />
+
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/app/components/skeleton/GroupSkeleton.tsx b/app/components/skeleton/GroupSkeleton.tsx
new file mode 100644
index 00000000..be1a31e8
--- /dev/null
+++ b/app/components/skeleton/GroupSkeleton.tsx
@@ -0,0 +1,14 @@
+import React, { useState } from 'react';
+import { Skeleton } from 'primereact/skeleton';
+
+export default function GroupSkeleton({ count, size }) {
+ const usingSkeleton = () => {
+ return (
+
+
+
+ );
+ };
+
+ return {Array.from({ length: count }).map((_, i) => usingSkeleton())}
;
+}
diff --git a/app/favicon.ico b/app/favicon.ico
deleted file mode 100644
index a614a31e..00000000
Binary files a/app/favicon.ico and /dev/null differ
diff --git a/app/globals.css b/app/globals.css
new file mode 100644
index 00000000..01f330f4
--- /dev/null
+++ b/app/globals.css
@@ -0,0 +1,320 @@
+@import 'primeflex/primeflex.css';
+@import 'tailwindcss/index.css';
+
+:root {
+ --bodyFonts: "Jost", sans-serif;
+ --mainColor: #08A9E6;
+ --redColor: #EC272F;
+ --titleColor: #21225F;
+ --bodyColor: #555555;
+ --whiteColor: #ffffff;
+ --fontSize: 16px;
+ --transition: 0.5s;
+}
+
+p {
+ color: var(--bodyColor);
+ margin-bottom: 10px;
+}
+p:last-child {
+ margin-bottom: 0;
+}
+
+a {
+ display: inline-block;
+ transition: var(--transition);
+ text-decoration: none;
+}
+a:hover, a:focus {
+ text-decoration: none;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ color: var(--titleColor);
+}
+
+.mainColor-hover:hover{
+ color: #08A9E6;
+}
+
+/* animate */
+.animateContent{
+ animation: content linear 6s infinite;
+}
+
+@keyframes content {
+ 10%{
+ transform: translateX(2px);
+ }
+ 50%{
+ transform: translateX(-4px);
+ }
+ 80%{
+ transform: translateY(-2px);
+ }
+ 100%{
+ transform: translateY(4px);
+ }
+}
+
+.animateFaster{
+ animation: faster linear 4s infinite forwards;
+}
+
+@keyframes faster {
+ 10%{
+ transform: translateX(-2px);
+ }
+ 50%{
+ transform: translateX(4px);
+ }
+ 80%{
+ transform: translateY(2px);
+ }
+ 100%{
+ transform: translateY(-4px);
+ }
+}
+
+.user-img {
+ position: relative;
+ margin-bottom: 30px;
+}
+.user-img img {
+ /* border: solid .5px ; */
+ box-shadow: 0px 1px 9px 4px;
+ animation: border-transform 10s linear infinite alternate forwards;
+}
+
+@keyframes border-transform {
+ 0%, 100% {
+ border-radius: 60% 40% 56% 33%/73% 82% 18% 27%;
+ }
+ 14% {
+ border-radius: 40% 60% 54% 46%/49% 60% 40% 51%;
+ }
+ 28% {
+ border-radius: 54% 46% 38% 62%/49% 70% 30% 51%;
+ }
+ 42% {
+ border-radius: 61% 39% 55% 45%/61% 38% 62% 39%;
+ }
+ 56% {
+ border-radius: 61% 39% 67% 33%/70% 50% 50% 30%;
+ }
+ 70% {
+ border-radius: 50% 50% 34% 66%/56% 68% 32% 44%;
+ }
+ 84% {
+ border-radius: 46% 54% 50% 50%/35% 61% 39% 65%;
+ }
+}
+
+#preloader {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ z-index: 9999;
+}
+
+#preloader-area {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ height: 60px;
+ width: 60px;
+}
+#preloader-area .spinner {
+ position: absolute;
+ z-index: 9999;
+ width: 6px;
+ height: 90px;
+ margin-top: -45px;
+ border-radius: 10px;
+ background-color: var(--whiteColor);
+ animation: rotate40deg 0.8s infinite;
+ animation-direction: alternate-reverse;
+}
+#preloader-area .spinner:nth-child(1) {
+ margin-left: 0px;
+}
+#preloader-area .spinner:nth-child(2) {
+ margin-left: -14px;
+ animation-delay: 0.1s;
+}
+#preloader-area .spinner:nth-child(3) {
+ margin-left: -28px;
+ animation-delay: 0.2s;
+}
+#preloader-area .spinner:nth-child(4) {
+ margin-left: -42px;
+ animation-delay: 0.3s;
+}
+#preloader-area .spinner:nth-child(5) {
+ margin-left: -56px;
+ animation-delay: 0.4s;
+}
+#preloader-area .spinner:nth-child(6) {
+ margin-left: -70px;
+ animation-delay: 0.5s;
+}
+#preloader-area .spinner:nth-child(7) {
+ margin-left: -84px;
+ animation-delay: 0.6s;
+}
+#preloader-area .spinner:nth-child(8) {
+ margin-left: -98px;
+ animation-delay: 0.7s;
+}
+
+#preloader .preloader-section {
+ position: fixed;
+ top: 0;
+ width: 51%;
+ height: 100%;
+ background-color: var(--mainColor);
+ z-index: 999;
+ transform: translateX(0);
+}
+#preloader .preloader-section.preloader-left {
+ left: 0;
+}
+#preloader .preloader-section.preloader-right {
+ right: 0;
+}
+
+.p-password .p-password-toggle-icon {
+ top: 50% !important;
+ transform: translateY(-50%);
+}
+
+
+.loaded #preloader-area {
+ opacity: 0;
+ visibility: hidden;
+ transition: all 0.3s ease-out;
+}
+.loaded #preloader .preloader-section.preloader-left {
+ transform: translateX(-100%);
+ transition: all 0.8s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
+}
+.loaded #preloader .preloader-section.preloader-right {
+ transform: translateX(100%);
+ transition: all 0.8s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1);
+}
+
+.loaded #preloader {
+ visibility: hidden;
+ transform: translateY(-100%);
+ transition: all 0.3s 1s ease-out;
+}
+
+@keyframes rotate40deg {
+ 0% {
+ height: 5px;
+ margin-top: 0;
+ transform: rotate(40deg);
+ }
+ 100% {
+ height: 90px;
+ transform: rotate(0deg);
+ }
+}
+@keyframes ripple {
+ 0% {
+ transform: scale(1);
+ }
+ 75% {
+ transform: scale(1.5);
+ opacity: 1;
+ }
+ 100% {
+ transform: scale(1.75);
+ opacity: 0;
+ }
+}
+@keyframes moveleftbounce {
+ 0% {
+ transform: translateX(0px);
+ }
+ 50% {
+ transform: translateX(20px);
+ }
+ 100% {
+ transform: translateX(0px);
+ }
+}
+@keyframes fadeInUp {
+ 0% {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+@keyframes fadeInDown {
+ 0% {
+ opacity: 0;
+ transform: translateY(-20px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+@keyframes movebounce {
+ 0% {
+ transform: translateY(0);
+ }
+ 50% {
+ transform: translateY(15px);
+ }
+ 100% {
+ transform: translateY(0);
+ }
+}
+@keyframes rotate-in {
+ 0% {
+ transform: perspective(120px) rotateX(0deg) rotateY(0deg);
+ }
+ 50% {
+ transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
+ }
+ 100% {
+ transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
+ }
+}
+@keyframes rotated360 {
+ 0% {
+ transform: rotateZ(0deg);
+ }
+ 100% {
+ transform: rotateZ(-360deg);
+ }
+}
+
+.my-custom-table {
+ /* border-collapse: collapse;
+ border: 1px solid #ccc; */
+ /* width: 90%; */
+ /* margin: auto; */
+}
+
+.my-custom-table td,
+.my-custom-table th {
+ border: 1px solid #ccc;
+ padding: 8px;
+}
+
+.my-custom-table thead {
+ /* background-color: #f5f5f5; */
+}
+
+.my-custom-table .p-datatable-tbody > tr:nth-child(even) {
+ /* background-color: rgb(255, 239, 239); */
+ background-color: #f5f5f5;
+}
diff --git a/app/layout.tsx b/app/layout.tsx
index 4114afcf..1d243994 100644
--- a/app/layout.tsx
+++ b/app/layout.tsx
@@ -1,12 +1,16 @@
'use client';
import { LayoutProvider } from '../layout/context/layoutcontext';
import { PrimeReactProvider } from 'primereact/api';
+import { config } from "@fortawesome/fontawesome-svg-core";
+import "@fortawesome/fontawesome-svg-core/styles.css"; // Импорт стилей
+config.autoAddCss = false;
import 'primereact/resources/primereact.css';
-import 'primeflex/primeflex.css';
import 'primeicons/primeicons.css';
import '../styles/layout/layout.scss';
import '../styles/demo/Demos.scss';
+import './globals.css';
+
interface RootLayoutProps {
children: React.ReactNode;
}
diff --git a/app/page.tsx b/app/page.tsx
new file mode 100644
index 00000000..39c48471
--- /dev/null
+++ b/app/page.tsx
@@ -0,0 +1,10 @@
+import React from 'react'
+import BaseLayout from './components/BaseLayout'
+
+export default function page() {
+ return (
+
+
+
+ )
+}
diff --git a/hooks/useMediaQuery.tsx b/hooks/useMediaQuery.tsx
new file mode 100644
index 00000000..89e61dca
--- /dev/null
+++ b/hooks/useMediaQuery.tsx
@@ -0,0 +1,19 @@
+"use client";
+
+import { useState, useEffect } from "react";
+
+export function useMediaQuery(query:string) {
+ const [matches, setMatches] = useState(false);
+
+ useEffect(() => {
+ const mediaQuery = window.matchMedia(query);
+ setMatches(mediaQuery.matches);
+
+ const handler = (e:MediaQueryListEvent) => setMatches(e.matches);
+ mediaQuery.addEventListener("change", handler);
+
+ return () => mediaQuery.removeEventListener("change", handler);
+ }, [query]);
+
+ return matches;
+}
diff --git a/layout/AppFooter.tsx b/layout/AppFooter.tsx
index 424b9987..628b21cf 100644
--- a/layout/AppFooter.tsx
+++ b/layout/AppFooter.tsx
@@ -2,16 +2,59 @@
import React, { useContext } from 'react';
import { LayoutContext } from './context/layoutcontext';
+import Image from 'next/image';
+import { faChalkboard, faPhone,} from "@fortawesome/free-solid-svg-icons";
+import MyFontAwesome from '@/app/components/MyFontAwesome';
+import Link from 'next/link';
const AppFooter = () => {
const { layoutConfig } = useContext(LayoutContext);
+
+ // dark mode
+ //
return (
-
-

- by
-
PrimeReact
+
);
};
diff --git a/layout/AppTopbar.tsx b/layout/AppTopbar.tsx
index 9a2c8849..eafab757 100644
--- a/layout/AppTopbar.tsx
+++ b/layout/AppTopbar.tsx
@@ -1,13 +1,19 @@
/* eslint-disable @next/next/no-img-element */
import Link from 'next/link';
-import { classNames } from 'primereact/utils';
import React, { forwardRef, useContext, useImperativeHandle, useRef } from 'react';
+import Tiered from '@/app/components/popUp/Tiered';
+import FancyLinkBtn from '@/app/components/buttons/FancyLinkBtn';
+import { classNames } from 'primereact/utils';
import { AppTopbarRef } from '@/types';
import { LayoutContext } from './context/layoutcontext';
+import { useMediaQuery } from '@/hooks/useMediaQuery';
+import { usePathname } from 'next/navigation';
+import { logout } from '@/utils/logout';
const AppTopbar = forwardRef
((props, ref) => {
- const { layoutConfig, layoutState, onMenuToggle, showProfileSidebar } = useContext(LayoutContext);
+ const { layoutConfig, layoutState, onMenuToggle, showProfileSidebar, user, setUser, setGlobalLoading } = useContext(LayoutContext);
+
const menubuttonRef = useRef(null);
const topbarmenuRef = useRef(null);
const topbarmenubuttonRef = useRef(null);
@@ -18,36 +24,223 @@ const AppTopbar = forwardRef((props, ref) => {
topbarmenubutton: topbarmenubuttonRef.current
}));
+ const pathName = usePathname();
+ const media = useMediaQuery('(max-width: 1000px)');
+
+ const items = [
+ {
+ label: 'Ачык онлайн курстар',
+ icon: 'pi pi-file',
+ items: [],
+ link: '/login'
+ },
+ {
+ label: 'Бакалавриат',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Магистратура',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Кошумча билим берүү',
+ icon: 'pi pi-file',
+ items: []
+ }
+ ];
+
+ const mobileMenu = [
+ user
+ ? {
+ label: 'Профиль',
+ icon: 'pi pi-user',
+ items: [
+ {
+ label: (
+
+
+ {user?.last_name}
+ {user?.name}
+
+
{user?.email}
+
+ ),
+ },
+ {
+ label: 'Чыгуу',
+ icon: 'pi pi-sign-out',
+ items: [],
+ command: () => {
+ logout({ setUser, setGlobalLoading });
+ }
+ }
+ ]
+ }
+ : {
+ label: 'Кирүү',
+ icon: 'pi pi-sign-in',
+ items: [],
+ link: '/auth/login'
+ },
+ {
+ label: 'Каталог',
+ icon: 'pi pi-list',
+ items: [
+ {
+ label: 'Ачык онлайн курстар',
+ icon: 'pi pi-file',
+ items: [],
+ link: '/login'
+ },
+ {
+ label: 'Бакалавриат',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Магистратура',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Кошумча билим берүү',
+ icon: 'pi pi-file',
+ items: []
+ }
+ ]
+ },
+ {
+ label: 'Бакалавриат',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Магистратура',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Кошумча билим берүү',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Кошумча билим берүү',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'КАТАЛОГ',
+ icon: 'pi pi-list',
+ items: [
+ {
+ label: 'Ачык онлайн курстар',
+ icon: 'pi pi-file',
+ items: [],
+ link: '/login'
+ },
+ {
+ label: 'Бакалавриат',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Магистратура',
+ icon: 'pi pi-file',
+ items: []
+ },
+ {
+ label: 'Кошумча билим берүү',
+ icon: 'pi pi-file',
+ items: []
+ }
+ ]
+ }
+ ];
+
+ // profile
+ const profileItems = [
+ {
+ label: (
+
+
+ {user?.last_name}
+ {user?.name}
+
+
{user?.email}
+
+ )
+ },
+ {
+ label: 'Чыгуу',
+ icon: 'pi pi-sign-out',
+ items: [],
+ command: () => {
+ logout({ setUser, setGlobalLoading });
+ }
+ }
+ ];
+
return (
-

-
SAKAI
+ {/*

*/}
+

+
Цифровой кампус ОшГУ
-
-
-
-
-
-
-
+ {pathName !== '/' ? (
+
+
+
+ ) : (
+ ''
+ )}
-
-
- Calendar
-
-
-
- Profile
-
-
-
-
- Settings
-
-
+
+ {media ? (
+
+ ) : (
+
+
+
+
+ ОшМУнун сайты
+
+
+ Байланыш
+
+
+ )}
+
+ {user && user ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
);
diff --git a/layout/context/layoutcontext.tsx b/layout/context/layoutcontext.tsx
index 58e491dc..3581eb9d 100644
--- a/layout/context/layoutcontext.tsx
+++ b/layout/context/layoutcontext.tsx
@@ -1,6 +1,13 @@
'use client';
-import React, { useState, createContext } from 'react';
+import React, { useState, createContext, useEffect } from 'react';
import { LayoutState, ChildContainerProps, LayoutConfig, LayoutContextProps } from '@/types';
+import SessionManager from '@/app/components/SessionManager';
+import GlobalLoading from '@/app/components/loading/GlobalLoading';
+import Message from '@/app/components/messages/Message';
+import { ConfirmDialog } from 'primereact/confirmdialog';
+import { User } from '@/types/user';
+import { MessageType } from '@/types/messageType';
+
export const LayoutContext = createContext({} as LayoutContextProps);
export const LayoutProvider = ({ children }: ChildContainerProps) => {
@@ -22,6 +29,15 @@ export const LayoutProvider = ({ children }: ChildContainerProps) => {
menuHoverActive: false
});
+ // 👇 Добавляем пользователя
+ const [user, setUser] = useState(null);
+
+ // Глобальная загрузка
+ const [globalLoading, setGlobalLoading] = useState(true);
+
+ // Сообщение об ошибке/успехе
+ const [message, setMessage] = useState({state:false, value:{}});
+
const onMenuToggle = () => {
if (isOverlay()) {
setLayoutState((prevLayoutState) => ({ ...prevLayoutState, overlayMenuActive: !prevLayoutState.overlayMenuActive }));
@@ -52,8 +68,20 @@ export const LayoutProvider = ({ children }: ChildContainerProps) => {
layoutState,
setLayoutState,
onMenuToggle,
- showProfileSidebar
+ showProfileSidebar,
+ user,
+ setUser,
+ globalLoading,
+ setGlobalLoading,
+ message,
+ setMessage
};
- return {children};
+ return
+
+
+
+ {message.state && }
+ {children}
+ ;
};
diff --git a/layout/layout.tsx b/layout/layout.tsx
index 8421b2ca..ef069787 100644
--- a/layout/layout.tsx
+++ b/layout/layout.tsx
@@ -131,7 +131,7 @@ const Layout = ({ children }: ChildContainerProps) => {
diff --git a/package-lock.json b/package-lock.json
index 332e8ef7..49904664 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,23 +8,36 @@
"name": "sakai-react",
"version": "10.1.0",
"dependencies": {
+ "@fortawesome/fontawesome-svg-core": "^6.7.2",
+ "@fortawesome/free-solid-svg-icons": "^6.7.2",
+ "@fortawesome/react-fontawesome": "^0.2.2",
+ "@hookform/resolvers": "^5.0.1",
"@types/node": "20.3.1",
"@types/react": "18.2.12",
"@types/react-dom": "18.2.5",
+ "aos": "^2.3.4",
"chart.js": "4.2.1",
+ "countup": "^1.8.2",
"next": "13.4.8",
"primeflex": "^3.3.1",
"primeicons": "^6.0.1",
"primereact": "10.2.1",
"react": "18.2.0",
+ "react-countup": "^6.5.3",
"react-dom": "18.2.0",
- "typescript": "5.1.3"
+ "react-hook-form": "^7.57.0",
+ "typescript": "5.1.3",
+ "yup": "^1.6.1"
},
"devDependencies": {
+ "@tailwindcss/postcss": "^4.1.8",
+ "autoprefixer": "^10.4.21",
"eslint": "8.43.0",
"eslint-config-next": "13.4.6",
+ "postcss": "^8.5.4",
"prettier": "^2.8.8",
- "sass": "^1.63.4"
+ "sass": "^1.63.4",
+ "tailwindcss": "^4.1.8"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -36,6 +49,31 @@
"node": ">=0.10.0"
}
},
+ "node_modules/@alloc/quick-lru": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
+ "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
"node_modules/@babel/runtime": {
"version": "7.23.6",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.6.tgz",
@@ -103,6 +141,59 @@
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
}
},
+ "node_modules/@fortawesome/fontawesome-common-types": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.7.2.tgz",
+ "integrity": "sha512-Zs+YeHUC5fkt7Mg1l6XTniei3k4bwG/yo3iFUtZWd/pMx9g3fdvkSK9E0FOC+++phXOka78uJcYb8JaFkW52Xg==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/fontawesome-svg-core": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.7.2.tgz",
+ "integrity": "sha512-yxtOBWDrdi5DD5o1pmVdq3WMCvnobT0LU6R8RyyVXPvFRd2o79/0NCuQoCjNTeZz9EzA9xS3JxNWfv54RIHFEA==",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.7.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/free-solid-svg-icons": {
+ "version": "6.7.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.7.2.tgz",
+ "integrity": "sha512-GsBrnOzU8uj0LECDfD5zomZJIjrPhIlWU82AHwa2s40FKH+kcxQaBvBo3Z4TxyZHIyX8XTDxsyA33/Vx9eFuQA==",
+ "dependencies": {
+ "@fortawesome/fontawesome-common-types": "6.7.2"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@fortawesome/react-fontawesome": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz",
+ "integrity": "sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==",
+ "dependencies": {
+ "prop-types": "^15.8.1"
+ },
+ "peerDependencies": {
+ "@fortawesome/fontawesome-svg-core": "~1 || ~6",
+ "react": ">=16.3"
+ }
+ },
+ "node_modules/@hookform/resolvers": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/@hookform/resolvers/-/resolvers-5.0.1.tgz",
+ "integrity": "sha512-u/+Jp83luQNx9AdyW2fIPGY6Y7NG68eN2ZW8FOJYL+M0i4s49+refdJdOp/A9n9HFQtQs3HIDHQvX3ZET2o7YA==",
+ "dependencies": {
+ "@standard-schema/utils": "^0.3.0"
+ },
+ "peerDependencies": {
+ "react-hook-form": "^7.55.0"
+ }
+ },
"node_modules/@humanwhocodes/config-array": {
"version": "0.11.13",
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz",
@@ -136,6 +227,66 @@
"integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==",
"dev": true
},
+ "node_modules/@isaacs/fs-minipass": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz",
+ "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^7.0.4"
+ },
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.8",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz",
+ "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/set-array": "^1.2.1",
+ "@jridgewell/sourcemap-codec": "^1.4.10",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/set-array": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "dev": true,
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
+ "dev": true
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
"node_modules/@kurkle/color": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.2.tgz",
@@ -331,6 +482,11 @@
"integrity": "sha512-UY+FGM/2jjMkzQLn8pxcHGMaVLh9aEitG3zY2CiY7XHdLiz3bZOwa6oDxNqEMv7zZkV+cj5DOdz0cQ1BP5Hjgw==",
"dev": true
},
+ "node_modules/@standard-schema/utils": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/@standard-schema/utils/-/utils-0.3.0.tgz",
+ "integrity": "sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g=="
+ },
"node_modules/@swc/helpers": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.1.tgz",
@@ -339,6 +495,267 @@
"tslib": "^2.4.0"
}
},
+ "node_modules/@tailwindcss/node": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.8.tgz",
+ "integrity": "sha512-OWwBsbC9BFAJelmnNcrKuf+bka2ZxCE2A4Ft53Tkg4uoiE67r/PMEYwCsourC26E+kmxfwE0hVzMdxqeW+xu7Q==",
+ "dev": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.3.0",
+ "enhanced-resolve": "^5.18.1",
+ "jiti": "^2.4.2",
+ "lightningcss": "1.30.1",
+ "magic-string": "^0.30.17",
+ "source-map-js": "^1.2.1",
+ "tailwindcss": "4.1.8"
+ }
+ },
+ "node_modules/@tailwindcss/oxide": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.8.tgz",
+ "integrity": "sha512-d7qvv9PsM5N3VNKhwVUhpK6r4h9wtLkJ6lz9ZY9aeZgrUWk1Z8VPyqyDT9MZlem7GTGseRQHkeB1j3tC7W1P+A==",
+ "dev": true,
+ "hasInstallScript": true,
+ "dependencies": {
+ "detect-libc": "^2.0.4",
+ "tar": "^7.4.3"
+ },
+ "engines": {
+ "node": ">= 10"
+ },
+ "optionalDependencies": {
+ "@tailwindcss/oxide-android-arm64": "4.1.8",
+ "@tailwindcss/oxide-darwin-arm64": "4.1.8",
+ "@tailwindcss/oxide-darwin-x64": "4.1.8",
+ "@tailwindcss/oxide-freebsd-x64": "4.1.8",
+ "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.8",
+ "@tailwindcss/oxide-linux-arm64-gnu": "4.1.8",
+ "@tailwindcss/oxide-linux-arm64-musl": "4.1.8",
+ "@tailwindcss/oxide-linux-x64-gnu": "4.1.8",
+ "@tailwindcss/oxide-linux-x64-musl": "4.1.8",
+ "@tailwindcss/oxide-wasm32-wasi": "4.1.8",
+ "@tailwindcss/oxide-win32-arm64-msvc": "4.1.8",
+ "@tailwindcss/oxide-win32-x64-msvc": "4.1.8"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-android-arm64": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.8.tgz",
+ "integrity": "sha512-Fbz7qni62uKYceWYvUjRqhGfZKwhZDQhlrJKGtnZfuNtHFqa8wmr+Wn74CTWERiW2hn3mN5gTpOoxWKk0jRxjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-arm64": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.8.tgz",
+ "integrity": "sha512-RdRvedGsT0vwVVDztvyXhKpsU2ark/BjgG0huo4+2BluxdXo8NDgzl77qh0T1nUxmM11eXwR8jA39ibvSTbi7A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-darwin-x64": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.8.tgz",
+ "integrity": "sha512-t6PgxjEMLp5Ovf7uMb2OFmb3kqzVTPPakWpBIFzppk4JE4ix0yEtbtSjPbU8+PZETpaYMtXvss2Sdkx8Vs4XRw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-freebsd-x64": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.8.tgz",
+ "integrity": "sha512-g8C8eGEyhHTqwPStSwZNSrOlyx0bhK/V/+zX0Y+n7DoRUzyS8eMbVshVOLJTDDC+Qn9IJnilYbIKzpB9n4aBsg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.8.tgz",
+ "integrity": "sha512-Jmzr3FA4S2tHhaC6yCjac3rGf7hG9R6Gf2z9i9JFcuyy0u79HfQsh/thifbYTF2ic82KJovKKkIB6Z9TdNhCXQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-gnu": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.8.tgz",
+ "integrity": "sha512-qq7jXtO1+UEtCmCeBBIRDrPFIVI4ilEQ97qgBGdwXAARrUqSn/L9fUrkb1XP/mvVtoVeR2bt/0L77xx53bPZ/Q==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-arm64-musl": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.8.tgz",
+ "integrity": "sha512-O6b8QesPbJCRshsNApsOIpzKt3ztG35gfX9tEf4arD7mwNinsoCKxkj8TgEE0YRjmjtO3r9FlJnT/ENd9EVefQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-gnu": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.8.tgz",
+ "integrity": "sha512-32iEXX/pXwikshNOGnERAFwFSfiltmijMIAbUhnNyjFr3tmWmMJWQKU2vNcFX0DACSXJ3ZWcSkzNbaKTdngH6g==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-linux-x64-musl": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.8.tgz",
+ "integrity": "sha512-s+VSSD+TfZeMEsCaFaHTaY5YNj3Dri8rST09gMvYQKwPphacRG7wbuQ5ZJMIJXN/puxPcg/nU+ucvWguPpvBDg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-wasm32-wasi": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.8.tgz",
+ "integrity": "sha512-CXBPVFkpDjM67sS1psWohZ6g/2/cd+cq56vPxK4JeawelxwK4YECgl9Y9TjkE2qfF+9/s1tHHJqrC4SS6cVvSg==",
+ "bundleDependencies": [
+ "@napi-rs/wasm-runtime",
+ "@emnapi/core",
+ "@emnapi/runtime",
+ "@tybys/wasm-util",
+ "@emnapi/wasi-threads",
+ "tslib"
+ ],
+ "cpu": [
+ "wasm32"
+ ],
+ "dev": true,
+ "optional": true,
+ "dependencies": {
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@emnapi/wasi-threads": "^1.0.2",
+ "@napi-rs/wasm-runtime": "^0.2.10",
+ "@tybys/wasm-util": "^0.9.0",
+ "tslib": "^2.8.0"
+ },
+ "engines": {
+ "node": ">=14.0.0"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-arm64-msvc": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.8.tgz",
+ "integrity": "sha512-7GmYk1n28teDHUjPlIx4Z6Z4hHEgvP5ZW2QS9ygnDAdI/myh3HTHjDqtSqgu1BpRoI4OiLx+fThAyA1JePoENA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/oxide-win32-x64-msvc": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.8.tgz",
+ "integrity": "sha512-fou+U20j+Jl0EHwK92spoWISON2OBnCazIc038Xj2TdweYV33ZRkS9nwqiUi2d/Wba5xg5UoHfvynnb/UB49cQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/@tailwindcss/postcss": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.1.8.tgz",
+ "integrity": "sha512-vB/vlf7rIky+w94aWMw34bWW1ka6g6C3xIOdICKX2GC0VcLtL6fhlLiafF0DVIwa9V6EHz8kbWMkS2s2QvvNlw==",
+ "dev": true,
+ "dependencies": {
+ "@alloc/quick-lru": "^5.2.0",
+ "@tailwindcss/node": "4.1.8",
+ "@tailwindcss/oxide": "4.1.8",
+ "postcss": "^8.4.41",
+ "tailwindcss": "4.1.8"
+ }
+ },
"node_modules/@types/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
@@ -561,6 +978,16 @@
"node": ">= 8"
}
},
+ "node_modules/aos": {
+ "version": "2.3.4",
+ "resolved": "https://registry.npmjs.org/aos/-/aos-2.3.4.tgz",
+ "integrity": "sha512-zh/ahtR2yME4I51z8IttIt4lC1Nw0ktsFtmeDzID1m9naJnWXhCoARaCgNOGXb5CLy3zm+wqmRAEgMYB5E2HUw==",
+ "dependencies": {
+ "classlist-polyfill": "^1.0.3",
+ "lodash.debounce": "^4.0.6",
+ "lodash.throttle": "^4.0.1"
+ }
+ },
"node_modules/argparse": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@@ -721,6 +1148,43 @@
"has-symbols": "^1.0.3"
}
},
+ "node_modules/autoprefixer": {
+ "version": "10.4.21",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
+ "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "browserslist": "^4.24.4",
+ "caniuse-lite": "^1.0.30001702",
+ "fraction.js": "^4.3.7",
+ "normalize-range": "^0.1.2",
+ "picocolors": "^1.1.1",
+ "postcss-value-parser": "^4.2.0"
+ },
+ "bin": {
+ "autoprefixer": "bin/autoprefixer"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ },
+ "peerDependencies": {
+ "postcss": "^8.1.0"
+ }
+ },
"node_modules/available-typed-arrays": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz",
@@ -788,6 +1252,38 @@
"node": ">=8"
}
},
+ "node_modules/browserslist": {
+ "version": "4.25.0",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz",
+ "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001718",
+ "electron-to-chromium": "^1.5.160",
+ "node-releases": "^2.0.19",
+ "update-browserslist-db": "^1.1.3"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ }
+ },
"node_modules/busboy": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
@@ -823,9 +1319,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001572",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001572.tgz",
- "integrity": "sha512-1Pbh5FLmn5y4+QhNyJE9j3/7dK44dGB83/ZMjv/qJk86TvDbjk0LosiZo0i0WB0Vx607qMX9jYrn1VLHCkN4rw==",
+ "version": "1.0.30001720",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
+ "integrity": "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==",
"funding": [
{
"type": "opencollective",
@@ -907,6 +1403,20 @@
"node": ">= 6"
}
},
+ "node_modules/chownr": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz",
+ "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/classlist-polyfill": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/classlist-polyfill/-/classlist-polyfill-1.2.0.tgz",
+ "integrity": "sha512-GzIjNdcEtH4ieA2S8NmrSxv7DfEV5fmixQeyTmqmRmRJPGpRBaSnA2a0VrCjyT8iW8JjEdMbKzDotAJf+ajgaQ=="
+ },
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
@@ -936,6 +1446,16 @@
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
+ "node_modules/countup": {
+ "version": "1.8.2",
+ "resolved": "https://registry.npmjs.org/countup/-/countup-1.8.2.tgz",
+ "integrity": "sha512-1qOuy+h+dgLY4TroLb4ZC2hK7HYS2Z7mnSUvdzoYAU7EZbqOse1mKZta/KYPhDPfd9lPDyP3Tb4pH6a10RkoCw=="
+ },
+ "node_modules/countup.js": {
+ "version": "2.8.2",
+ "resolved": "https://registry.npmjs.org/countup.js/-/countup.js-2.8.2.tgz",
+ "integrity": "sha512-UtRoPH6udaru/MOhhZhI/GZHJKAyAxuKItD2Tr7AbrqrOPBX/uejWBBJt8q86169AMqKkE9h9/24kFWbUk/Bag=="
+ },
"node_modules/cross-spawn": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@@ -1024,6 +1544,15 @@
"node": ">=6"
}
},
+ "node_modules/detect-libc": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz",
+ "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -1057,6 +1586,12 @@
"csstype": "^3.0.2"
}
},
+ "node_modules/electron-to-chromium": {
+ "version": "1.5.161",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.161.tgz",
+ "integrity": "sha512-hwtetwfKNZo/UlwHIVBlKZVdy7o8bIZxxKs0Mv/ROPiQQQmDgdm5a+KvKtBsxM8ZjFzTaCeLoodZ8jiBE3o9rA==",
+ "dev": true
+ },
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
@@ -1064,9 +1599,9 @@
"dev": true
},
"node_modules/enhanced-resolve": {
- "version": "5.15.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz",
- "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==",
+ "version": "5.18.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz",
+ "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.4",
@@ -1191,6 +1726,15 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/escalade": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
+ "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -1738,6 +2282,19 @@
"is-callable": "^1.1.3"
}
},
+ "node_modules/fraction.js": {
+ "version": "4.3.7",
+ "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
+ "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "type": "patreon",
+ "url": "https://github.com/sponsors/rawify"
+ }
+ },
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
@@ -2449,6 +3006,15 @@
"set-function-name": "^2.0.1"
}
},
+ "node_modules/jiti": {
+ "version": "2.4.2",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz",
+ "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==",
+ "dev": true,
+ "bin": {
+ "jiti": "lib/jiti-cli.mjs"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -2484,71 +3050,299 @@
"integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==",
"dev": true
},
- "node_modules/json5": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
- "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "node_modules/json5": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
+ "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
+ "dev": true,
+ "dependencies": {
+ "minimist": "^1.2.0"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ }
+ },
+ "node_modules/jsx-ast-utils": {
+ "version": "3.3.5",
+ "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
+ "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+ "dev": true,
+ "dependencies": {
+ "array-includes": "^3.1.6",
+ "array.prototype.flat": "^1.3.1",
+ "object.assign": "^4.1.4",
+ "object.values": "^1.1.6"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/keyv": {
+ "version": "4.5.4",
+ "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
+ "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "dev": true,
+ "dependencies": {
+ "json-buffer": "3.0.1"
+ }
+ },
+ "node_modules/language-subtag-registry": {
+ "version": "0.3.22",
+ "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
+ "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
+ "dev": true
+ },
+ "node_modules/language-tags": {
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
+ "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
+ "dev": true,
+ "dependencies": {
+ "language-subtag-registry": "^0.3.20"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
+ "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "dev": true,
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/lightningcss": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz",
+ "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==",
+ "dev": true,
+ "dependencies": {
+ "detect-libc": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ },
+ "optionalDependencies": {
+ "lightningcss-darwin-arm64": "1.30.1",
+ "lightningcss-darwin-x64": "1.30.1",
+ "lightningcss-freebsd-x64": "1.30.1",
+ "lightningcss-linux-arm-gnueabihf": "1.30.1",
+ "lightningcss-linux-arm64-gnu": "1.30.1",
+ "lightningcss-linux-arm64-musl": "1.30.1",
+ "lightningcss-linux-x64-gnu": "1.30.1",
+ "lightningcss-linux-x64-musl": "1.30.1",
+ "lightningcss-win32-arm64-msvc": "1.30.1",
+ "lightningcss-win32-x64-msvc": "1.30.1"
+ }
+ },
+ "node_modules/lightningcss-darwin-arm64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz",
+ "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-darwin-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz",
+ "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-freebsd-x64": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz",
+ "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm-gnueabihf": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz",
+ "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-linux-arm64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz",
+ "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "minimist": "^1.2.0"
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
},
- "bin": {
- "json5": "lib/cli.js"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/jsx-ast-utils": {
- "version": "3.3.5",
- "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
- "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==",
+ "node_modules/lightningcss-linux-arm64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz",
+ "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "array-includes": "^3.1.6",
- "array.prototype.flat": "^1.3.1",
- "object.assign": "^4.1.4",
- "object.values": "^1.1.6"
- },
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=4.0"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/keyv": {
- "version": "4.5.4",
- "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
- "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==",
+ "node_modules/lightningcss-linux-x64-gnu": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz",
+ "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "dependencies": {
- "json-buffer": "3.0.1"
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/language-subtag-registry": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
- "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
- "dev": true
- },
- "node_modules/language-tags": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
- "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
+ "node_modules/lightningcss-linux-x64-musl": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz",
+ "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
- "dependencies": {
- "language-subtag-registry": "^0.3.20"
- },
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=0.10"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
- "node_modules/levn": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
- "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==",
+ "node_modules/lightningcss-win32-arm64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz",
+ "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "prelude-ls": "^1.2.1",
- "type-check": "~0.4.0"
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 12.0.0"
},
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
+ }
+ },
+ "node_modules/lightningcss-win32-x64-msvc": {
+ "version": "1.30.1",
+ "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz",
+ "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "win32"
+ ],
"engines": {
- "node": ">= 0.8.0"
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/parcel"
}
},
"node_modules/locate-path": {
@@ -2566,12 +3360,22 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/lodash.debounce": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
+ "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
+ },
"node_modules/lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==",
"dev": true
},
+ "node_modules/lodash.throttle": {
+ "version": "4.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
+ "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ=="
+ },
"node_modules/loose-envify": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@@ -2595,6 +3399,15 @@
"node": ">=10"
}
},
+ "node_modules/magic-string": {
+ "version": "0.30.17",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
+ "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
+ "dev": true,
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0"
+ }
+ },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -2638,6 +3451,42 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/minipass": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "dev": true,
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ }
+ },
+ "node_modules/minizlib": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz",
+ "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==",
+ "dev": true,
+ "dependencies": {
+ "minipass": "^7.1.2"
+ },
+ "engines": {
+ "node": ">= 18"
+ }
+ },
+ "node_modules/mkdirp": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz",
+ "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==",
+ "dev": true,
+ "bin": {
+ "mkdirp": "dist/cjs/src/bin.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
"node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@@ -2645,9 +3494,9 @@
"dev": true
},
"node_modules/nanoid": {
- "version": "3.3.7",
- "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
- "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
"funding": [
{
"type": "github",
@@ -2717,6 +3566,35 @@
}
}
},
+ "node_modules/next/node_modules/postcss": {
+ "version": "8.4.14",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
+ "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ }
+ ],
+ "dependencies": {
+ "nanoid": "^3.3.4",
+ "picocolors": "^1.0.0",
+ "source-map-js": "^1.0.2"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "2.0.19",
+ "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
+ "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==",
+ "dev": true
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
@@ -2726,6 +3604,15 @@
"node": ">=0.10.0"
}
},
+ "node_modules/normalize-range": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+ "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -2954,9 +3841,9 @@
}
},
"node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="
},
"node_modules/picomatch": {
"version": "2.3.1",
@@ -2971,9 +3858,10 @@
}
},
"node_modules/postcss": {
- "version": "8.4.14",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
- "integrity": "sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==",
+ "version": "8.5.4",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.4.tgz",
+ "integrity": "sha512-QSa9EBe+uwlGTFmHsPKokv3B/oEMQZxfqW0QqNCyhpa6mB1afzulwn8hihglqAb2pOw+BJgNlmXQ8la2VeHB7w==",
+ "dev": true,
"funding": [
{
"type": "opencollective",
@@ -2982,17 +3870,27 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
- "nanoid": "^3.3.4",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
+ "node_modules/postcss-value-parser": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+ "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==",
+ "dev": true
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
@@ -3059,6 +3957,11 @@
"react-is": "^16.13.1"
}
},
+ "node_modules/property-expr": {
+ "version": "2.0.6",
+ "resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.6.tgz",
+ "integrity": "sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA=="
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
@@ -3099,6 +4002,17 @@
"node": ">=0.10.0"
}
},
+ "node_modules/react-countup": {
+ "version": "6.5.3",
+ "resolved": "https://registry.npmjs.org/react-countup/-/react-countup-6.5.3.tgz",
+ "integrity": "sha512-udnqVQitxC7QWADSPDOxVWULkLvKUWrDapn5i53HE4DPRVgs+Y5rr4bo25qEl8jSh+0l2cToJgGMx+clxPM3+w==",
+ "dependencies": {
+ "countup.js": "^2.8.0"
+ },
+ "peerDependencies": {
+ "react": ">= 16.3.0"
+ }
+ },
"node_modules/react-dom": {
"version": "18.2.0",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
@@ -3111,6 +4025,21 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-hook-form": {
+ "version": "7.57.0",
+ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.57.0.tgz",
+ "integrity": "sha512-RbEks3+cbvTP84l/VXGUZ+JMrKOS8ykQCRYdm5aYsxnDquL0vspsyNhGRO7pcH6hsZqWlPOjLye7rJqdtdAmlg==",
+ "engines": {
+ "node": ">=18.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/react-hook-form"
+ },
+ "peerDependencies": {
+ "react": "^16.8.0 || ^17 || ^18 || ^19"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
@@ -3414,9 +4343,9 @@
}
},
"node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"engines": {
"node": ">=0.10.0"
}
@@ -3573,6 +4502,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tailwindcss": {
+ "version": "4.1.8",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.8.tgz",
+ "integrity": "sha512-kjeW8gjdxasbmFKpVGrGd5T4i40mV5J2Rasw48QARfYeQ8YS9x02ON9SFWax3Qf616rt4Cp3nVNIj6Hd1mP3og==",
+ "dev": true
+ },
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
@@ -3582,12 +4517,43 @@
"node": ">=6"
}
},
+ "node_modules/tar": {
+ "version": "7.4.3",
+ "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz",
+ "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==",
+ "dev": true,
+ "dependencies": {
+ "@isaacs/fs-minipass": "^4.0.0",
+ "chownr": "^3.0.0",
+ "minipass": "^7.1.2",
+ "minizlib": "^3.0.1",
+ "mkdirp": "^3.0.1",
+ "yallist": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tar/node_modules/yallist": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
+ "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
"integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==",
"dev": true
},
+ "node_modules/tiny-case": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-case/-/tiny-case-1.0.3.tgz",
+ "integrity": "sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q=="
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -3600,6 +4566,11 @@
"node": ">=8.0"
}
},
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
+ "integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
+ },
"node_modules/tsconfig-paths": {
"version": "3.15.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
@@ -3754,6 +4725,36 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/update-browserslist-db": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz",
+ "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/browserslist"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "dependencies": {
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
+ },
+ "bin": {
+ "update-browserslist-db": "cli.js"
+ },
+ "peerDependencies": {
+ "browserslist": ">= 4.21.0"
+ }
+ },
"node_modules/uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
@@ -3890,6 +4891,28 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/yup": {
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/yup/-/yup-1.6.1.tgz",
+ "integrity": "sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==",
+ "dependencies": {
+ "property-expr": "^2.0.5",
+ "tiny-case": "^1.0.3",
+ "toposort": "^2.0.2",
+ "type-fest": "^2.19.0"
+ }
+ },
+ "node_modules/yup/node_modules/type-fest": {
+ "version": "2.19.0",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz",
+ "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/zod": {
"version": "3.21.4",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.21.4.tgz",
diff --git a/package.json b/package.json
index 8071b50b..d1a8ca92 100644
--- a/package.json
+++ b/package.json
@@ -10,22 +10,35 @@
"lint": "next lint"
},
"dependencies": {
+ "@fortawesome/fontawesome-svg-core": "^6.7.2",
+ "@fortawesome/free-solid-svg-icons": "^6.7.2",
+ "@fortawesome/react-fontawesome": "^0.2.2",
+ "@hookform/resolvers": "^5.0.1",
"@types/node": "20.3.1",
"@types/react": "18.2.12",
"@types/react-dom": "18.2.5",
+ "aos": "^2.3.4",
"chart.js": "4.2.1",
+ "countup": "^1.8.2",
"next": "13.4.8",
"primeflex": "^3.3.1",
"primeicons": "^6.0.1",
"primereact": "10.2.1",
"react": "18.2.0",
+ "react-countup": "^6.5.3",
"react-dom": "18.2.0",
- "typescript": "5.1.3"
+ "react-hook-form": "^7.57.0",
+ "typescript": "5.1.3",
+ "yup": "^1.6.1"
},
"devDependencies": {
+ "@tailwindcss/postcss": "^4.1.8",
+ "autoprefixer": "^10.4.21",
"eslint": "8.43.0",
"eslint-config-next": "13.4.6",
+ "postcss": "^8.5.4",
"prettier": "^2.8.8",
- "sass": "^1.63.4"
+ "sass": "^1.63.4",
+ "tailwindcss": "^4.1.8"
}
-}
\ No newline at end of file
+}
diff --git a/postcss.config.js b/postcss.config.js
new file mode 100644
index 00000000..8f3250b7
--- /dev/null
+++ b/postcss.config.js
@@ -0,0 +1,6 @@
+module.exports = {
+ plugins: {
+ '@tailwindcss/postcss': {}, // Используем новый плагин
+ autoprefixer: {},
+ }
+}
\ No newline at end of file
diff --git a/public/layout/images/home-banner-phone.png b/public/layout/images/home-banner-phone.png
new file mode 100644
index 00000000..399a19dc
Binary files /dev/null and b/public/layout/images/home-banner-phone.png differ
diff --git a/public/layout/images/logo-kg.svg b/public/layout/images/logo-kg.svg
new file mode 100644
index 00000000..ac33ea12
--- /dev/null
+++ b/public/layout/images/logo-kg.svg
@@ -0,0 +1,205 @@
+
+
+
+
diff --git a/public/layout/images/logo-remove-white.png b/public/layout/images/logo-remove-white.png
new file mode 100644
index 00000000..3d28f7d5
Binary files /dev/null and b/public/layout/images/logo-remove-white.png differ
diff --git a/public/layout/images/logo-remove.png b/public/layout/images/logo-remove.png
new file mode 100644
index 00000000..929f087a
Binary files /dev/null and b/public/layout/images/logo-remove.png differ
diff --git a/public/layout/images/man.png b/public/layout/images/man.png
new file mode 100644
index 00000000..0168ee16
Binary files /dev/null and b/public/layout/images/man.png differ
diff --git a/public/layout/images/no-image.png b/public/layout/images/no-image.png
new file mode 100644
index 00000000..3f257212
Binary files /dev/null and b/public/layout/images/no-image.png differ
diff --git a/public/layout/images/shape.png b/public/layout/images/shape.png
new file mode 100644
index 00000000..a82ce023
Binary files /dev/null and b/public/layout/images/shape.png differ
diff --git a/public/layout/images/shape1.png b/public/layout/images/shape1.png
new file mode 100644
index 00000000..bee24c65
Binary files /dev/null and b/public/layout/images/shape1.png differ
diff --git a/public/layout/images/shape2.png b/public/layout/images/shape2.png
new file mode 100644
index 00000000..f1fe1c5b
Binary files /dev/null and b/public/layout/images/shape2.png differ
diff --git a/public/layout/svg/red-logo.svg b/public/layout/svg/red-logo.svg
new file mode 100644
index 00000000..69deed08
--- /dev/null
+++ b/public/layout/svg/red-logo.svg
@@ -0,0 +1,46 @@
+
+
+
+
diff --git a/public/layout/svg/white-logo.svg b/public/layout/svg/white-logo.svg
new file mode 100644
index 00000000..d76c8ff6
--- /dev/null
+++ b/public/layout/svg/white-logo.svg
@@ -0,0 +1,47 @@
+
+
+
+
diff --git a/schemas/schema.tsx b/schemas/schema.tsx
new file mode 100644
index 00000000..6d8159a5
--- /dev/null
+++ b/schemas/schema.tsx
@@ -0,0 +1,22 @@
+import * as yup from 'yup';
+
+export const schema = yup.object().shape({
+ email: yup.string()
+ .email('email туура эмес форматта')
+ .required('email талап кылынат!')
+ .matches(
+ /^[a-zA-Z0-9._%+-]+@oshsu\.kg$/,
+ 'email "@oshsu.kg" форматында болуш керек'
+ )
+ .matches(
+ /^[a-zA-Z0-9._%+-]+@oshsu\.kg$/, // Стандартный формат email (только буквы, цифры, точки, подчеркивания и плюсы)
+ 'email "@oshsu.kg" форматында жана тыюу салынган символдор камтылбашы керек'
+ ),
+ password: yup.string()
+ .required('Сырсөз талап кылынат!')
+ .max(20, 'Сырсөз эң көп дегенде 20 белгиден турушу керек')
+ .matches(
+ /^[^!@#$%^&*()_+={}[\]:;"'`<>,.?/\\|]*$/,
+ 'Сырсөздө тыюу салынган символдор камтылбашы керек'
+ ),
+});
\ No newline at end of file
diff --git a/services/auth.tsx b/services/auth.tsx
new file mode 100644
index 00000000..72fa6843
--- /dev/null
+++ b/services/auth.tsx
@@ -0,0 +1,50 @@
+import { LoginType } from "@/types/login";
+
+let url = '';
+
+// const params = new URLSearchParams({
+// category_id: String(id),
+// active: '' + param.active,
+// ending: '' + param.ending,
+// });
+
+export const login = async (value:LoginType) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + '/login?';
+
+ try {
+ const res = await fetch(url, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify(value)
+ });
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при авторизации', err);
+ return [];
+ }
+};
+
+export const getUser = async (token:string) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + '/v1/user';
+
+ const headers: HeadersInit = token
+ ? {
+ Authorization: `Bearer ${token}`
+ }
+ : {};
+
+ try {
+ const res = await fetch(url, {
+ headers
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при получении пользователя', err);
+ return [];
+ }
+};
diff --git a/services/courses.tsx b/services/courses.tsx
new file mode 100644
index 00000000..a14e15a9
--- /dev/null
+++ b/services/courses.tsx
@@ -0,0 +1,234 @@
+import { AuthBaseType } from "@/types/authBaseType";
+import { CourseCreateType } from "@/types/courseCreateType";
+
+let url = '';
+
+type OnlyTitle = Pick;
+
+export const fetchCourses = async (token:string | null) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + '/v1/teacher/courses';
+
+ const headers: HeadersInit = token
+ ? {
+ Authorization: `Bearer ${token}`
+ }
+ : {};
+
+ try {
+ const res = await fetch(url, {
+ headers
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при получении курсов', err);
+ return [];
+ }
+};
+
+export const addCourse = async (token:string | null, value:CourseCreateType) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + '/v1/teacher/courses/store';
+ console.log(value);
+
+ const headers: HeadersInit = token
+ ? { Authorization: `Bearer ${token}` }
+ : {};
+
+ console.log(value);
+
+ const formData = new FormData();
+ formData.append('title', value.title);
+ formData.append('description', value.description);
+ formData.append('image', value.image);
+ formData.append('video_url', value.video_url);
+
+ try {
+ const res = await fetch(url, {
+ method: 'POST',
+ headers,
+ body: formData
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при добавлении курса', err);
+ return [];
+ }
+};
+
+export const deleteCourse = async (token:string | null, id:number) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + `/v1/teacher/courses/delete?course_id=${id}`;
+ console.log(id);
+
+ const headers: HeadersInit = token
+ ? { Authorization: `Bearer ${token}` }
+ : {};
+
+ try {
+ const res = await fetch(url, {
+ method: 'DELETE',
+ headers
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при удалении курса', err);
+ return [];
+ }
+};
+
+export const updateCourse = async (token: string | null, id:number | null, value) => {
+ console.log(value);
+
+ url = process.env.NEXT_PUBLIC_BASE_URL + `/v1/teacher/courses/update?course_id=${id}`;
+
+ const formData = new FormData();
+ formData.append('title', value.title);
+ formData.append('description', value.description);
+ if (value.image instanceof File) {
+ formData.append('image', value.image);
+ }
+ formData.append('video_url', value.video_url);
+
+ const headers: HeadersInit = token
+ ? { Authorization: `Bearer ${token}` }
+ : {};
+
+ try {
+ const res = await fetch(url, {
+ method: 'POST',
+ headers,
+ body: formData
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при обновлении курса', err);
+ return [];
+ }
+};
+
+// Themes
+
+export const fetchCourseInfo = async (token:AuthBaseType, id:AuthBaseType) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + `/v1/teacher/courses/show?course_id=${id}`;
+
+ const headers: HeadersInit = token
+ ? {
+ Authorization: `Bearer ${token}`
+ }
+ : {};
+
+ try {
+ const res = await fetch(url, {
+ headers
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при получении темы', err);
+ return [];
+ }
+};
+
+export const addThemes = async (token:string | null, id:number, value:OnlyTitle) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + `/v1/teacher/lessons/store?course_id=${id}&title=${value}`;
+ console.log(value);
+
+ const headers: HeadersInit = token
+ ? { Authorization: `Bearer ${token}` }
+ : {};
+
+ const formData = new FormData();
+ formData.append('title', value);
+
+ try {
+ const res = await fetch(url, {
+ method: 'POST',
+ headers,
+ body: formData
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при добавлении темы', err);
+ return [];
+ }
+};
+
+export const fetchThemes = async (token:string | null, id:number) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + `/v1/teacher/lessons?course_id=${id}`;
+
+ const headers: HeadersInit = token
+ ? {
+ Authorization: `Bearer ${token}`
+ }
+ : {};
+
+ try {
+ const res = await fetch(url, {
+ headers
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при получении темы', err);
+ return [];
+ }
+};
+
+export const updateTheme = async (token: string | null, course_id:number | null, theme_id: number, value:CourseCreateType) => {
+ console.log(value);
+
+ url = process.env.NEXT_PUBLIC_BASE_URL + `/v1/teacher/lessons/update?course_id=${course_id}&title=${value}&lesson_id=${theme_id}`;
+
+ const formData = new FormData();
+ formData.append('title', value.title);
+
+ const headers: HeadersInit = token
+ ? { Authorization: `Bearer ${token}` }
+ : {};
+
+ try {
+ const res = await fetch(url, {
+ method: 'POST',
+ headers,
+ body: formData
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при обновлении темы', err);
+ return [];
+ }
+};
+
+export const deleteTheme = async (token:string | null, id:number) => {
+ url = process.env.NEXT_PUBLIC_BASE_URL + `/v1/teacher/lessons/delete?lesson_id=${id}`;
+ console.log(id);
+
+ const headers: HeadersInit = token
+ ? { Authorization: `Bearer ${token}` }
+ : {};
+
+ try {
+ const res = await fetch(url, {
+ method: 'DELETE',
+ headers
+ });
+
+ const data = await res.json();
+ return data;
+ } catch (err) {
+ console.log('Ошибка при удалении темы', err);
+ return [];
+ }
+};
\ No newline at end of file
diff --git a/styles/layout/_button.scss b/styles/layout/_button.scss
new file mode 100644
index 00000000..91dd1188
--- /dev/null
+++ b/styles/layout/_button.scss
@@ -0,0 +1,51 @@
+button {
+ outline: 0;
+ border: none;
+
+ &:focus {
+ outline: 0;
+ border: 0;
+ }
+}
+
+.default-btn {
+ // padding: 15px 35px;
+ text-align: center;
+ color: var(--whiteColor);
+ font-size: var(--fontSize);
+ font-weight: 400;
+ transition: var(--transition);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ z-index: 0;
+ box-shadow: none;
+ overflow: hidden;
+ white-space: nowrap;
+ cursor: pointer;
+}
+
+.fancyEffect {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 50%;
+ width: 550px;
+ height: 550px;
+ margin: auto;
+ border-radius: 50%;
+ z-index: -1;
+}
+
+.fancyBefore {
+ transform-origin: top center;
+ transform: translateX(-50%) translateY(-5%) scale(0.4);
+ transition: transform 0.9s;
+}
+
+.fancyAfter {
+ transition: transform 1s;
+ transform: translateX(-45%) translateY(0) scale(1);
+ transform-origin: bottom center;
+}
diff --git a/styles/layout/_topbar.scss b/styles/layout/_topbar.scss
index 79402366..d6a02350 100644
--- a/styles/layout/_topbar.scss
+++ b/styles/layout/_topbar.scss
@@ -1,6 +1,6 @@
.layout-topbar {
position: fixed;
- height: 5rem;
+ height: 6rem;
z-index: 997;
left: 0;
top: 0;
@@ -18,12 +18,12 @@
color: var(--surface-900);
font-size: 1.5rem;
font-weight: 500;
- width: 300px;
+ // width: 300px;
border-radius: 12px;
img {
- height: 2.5rem;
- margin-right: .5rem;
+ // height: 2.5rem;
+ // margin-right: .5rem;
}
&:focus {
@@ -63,7 +63,7 @@
}
.layout-menu-button {
- margin-left: 2rem;
+ // margin-left: 2rem;
}
.layout-topbar-menu-button {
@@ -81,7 +81,7 @@
display: flex;
.layout-topbar-button {
- margin-left: 1rem;
+ // margin-left: 1rem;
}
}
}
@@ -91,35 +91,35 @@
justify-content: space-between;
.layout-topbar-logo {
- width: auto;
+ // width: auto;
order: 2;
}
.layout-menu-button {
margin-left: 0;
- order: 1;
+ order: 3;
}
.layout-topbar-menu-button {
display: inline-flex;
margin-left: 0;
- order: 3;
+ // order: 1;
}
.layout-topbar-menu {
margin-left: 0;
- position: absolute;
- flex-direction: column;
- background-color: var(--surface-overlay);
- box-shadow: 0px 3px 5px rgba(0,0,0,.02), 0px 0px 2px rgba(0,0,0,.05), 0px 1px 4px rgba(0,0,0,.08);
- border-radius: 12px;
- padding: 1rem;
- right: 2rem;
- top: 5rem;
- min-width: 15rem;
- display: none;
- -webkit-animation: scalein 0.15s linear;
- animation: scalein 0.15s linear;
+ // position: absolute;
+ // flex-direction: column;
+ // background-color: var(--surface-overlay);
+ // box-shadow: 0px 3px 5px rgba(0,0,0,.02), 0px 0px 2px rgba(0,0,0,.05), 0px 1px 4px rgba(0,0,0,.08);
+ // border-radius: 12px;
+ // padding: 1rem;
+ // right: 2rem;
+ // top: 5rem;
+ // min-width: 15rem;
+ // display: none;
+ // -webkit-animation: scalein 0.15s linear;
+ // animation: scalein 0.15s linear;
&.layout-topbar-menu-mobile-active {
display: block
diff --git a/styles/layout/_typography.scss b/styles/layout/_typography.scss
index b9a0c8ff..6278de2f 100644
--- a/styles/layout/_typography.scss
+++ b/styles/layout/_typography.scss
@@ -3,37 +3,13 @@ h1, h2, h3, h4, h5, h6 {
font-family: inherit;
font-weight: 500;
line-height: 1.2;
- color: var(--surface-900);
+ // color: var(--surface-900);
&:first-child {
margin-top: 0;
}
}
-h1 {
- font-size: 2.5rem;
-}
-
-h2 {
- font-size: 2rem;
-}
-
-h3 {
- font-size: 1.75rem;
-}
-
-h4 {
- font-size: 1.5rem;
-}
-
-h5 {
- font-size: 1.25rem;
-}
-
-h6 {
- font-size: 1rem;
-}
-
mark {
background: #FFF8E1;
padding: .25rem .4rem;
diff --git a/styles/layout/layout.scss b/styles/layout/layout.scss
index fef2ed48..0b5314a9 100644
--- a/styles/layout/layout.scss
+++ b/styles/layout/layout.scss
@@ -8,4 +8,5 @@
@import "./_footer";
@import "./_responsive";
@import "./_utils";
-@import "./_typography";
\ No newline at end of file
+@import "./_typography";
+@import "./_button";
\ No newline at end of file
diff --git a/types/authBaseType.tsx b/types/authBaseType.tsx
new file mode 100644
index 00000000..2aab9c9e
--- /dev/null
+++ b/types/authBaseType.tsx
@@ -0,0 +1,4 @@
+export interface AuthBaseType {
+ token: string | null;
+ id: number;
+}
\ No newline at end of file
diff --git a/types/courseCreateType.tsx b/types/courseCreateType.tsx
new file mode 100644
index 00000000..3be660c4
--- /dev/null
+++ b/types/courseCreateType.tsx
@@ -0,0 +1,6 @@
+export interface CourseCreateType {
+ title: string;
+ description: string;
+ video_url: string;
+ image?: string | File;
+}
\ No newline at end of file
diff --git a/types/courseType.tsx b/types/courseType.tsx
new file mode 100644
index 00000000..7b339e63
--- /dev/null
+++ b/types/courseType.tsx
@@ -0,0 +1,10 @@
+export interface CourseType {
+ created_at: string;
+ description: string;
+ id: number;
+ image: string;
+ status: boolean;
+ title: string;
+ user_id: number;
+ video_url: string;
+}
diff --git a/types/layout.d.ts b/types/layout.d.ts
index fe94e601..fd7dbba4 100644
--- a/types/layout.d.ts
+++ b/types/layout.d.ts
@@ -2,6 +2,8 @@ import React, { ReactElement, Dispatch, SetStateAction, HTMLAttributeAnchorTarge
import { NextPage } from 'next';
import { Demo } from './demo';
import { Toast } from 'primereact/toast';
+import { User } from './user';
+import { MessageType } from './messageType';
/* Breadcrumb Types */
export interface AppBreadcrumbProps {
@@ -45,6 +47,14 @@ export interface LayoutContextProps {
setLayoutState: Dispatch>;
onMenuToggle: () => void;
showProfileSidebar: () => void;
+ user: User | null;
+ setUser: React.Dispatch>;
+ globalLoading: boolean;
+ setGlobalLoading: React.Dispatch>;
+ message: MessageType;
+ setMessage: React.Dispatch>;
+ // message: { state: boolean; value: MessageType };
+ // setMessage: React.Dispatch>;
}
export interface MenuContextProps {
diff --git a/types/login.tsx b/types/login.tsx
new file mode 100644
index 00000000..2cae126b
--- /dev/null
+++ b/types/login.tsx
@@ -0,0 +1,4 @@
+export interface LoginType {
+ email: string;
+ password: string;
+}
diff --git a/types/messageType.tsx b/types/messageType.tsx
new file mode 100644
index 00000000..589dbb8c
--- /dev/null
+++ b/types/messageType.tsx
@@ -0,0 +1,8 @@
+export interface MessageType {
+ state: boolean;
+ value: {
+ severity?:string;
+ summary?:string;
+ detail?:string;
+ }
+}
\ No newline at end of file
diff --git a/types/user.tsx b/types/user.tsx
new file mode 100644
index 00000000..442e50e9
--- /dev/null
+++ b/types/user.tsx
@@ -0,0 +1,12 @@
+export interface User {
+ birth_date: null;
+ email: string;
+ father_name: string;
+ id: number;
+ is_student: boolean;
+ is_working: boolean;
+ last_name: string;
+ name: string;
+ phone: string;
+ pin: null;
+}
diff --git a/utils/auth.tsx b/utils/auth.tsx
new file mode 100644
index 00000000..8ec683b5
--- /dev/null
+++ b/utils/auth.tsx
@@ -0,0 +1,28 @@
+'use client';
+
+export function getToken(name:string) {
+ if (typeof document === 'undefined') {
+ return null;
+ }
+
+ const cookies = document.cookie ? document.cookie.split("; ") : [];
+ for (let cookie of cookies) {
+ const [key, value] = cookie.split("=");
+ if (key === name) return decodeURIComponent(value);
+ }
+ return null;
+};
+
+export function isTokenExpired() {
+ const testToken = getToken('access_token');
+
+ try {
+ if (!testToken) throw new Error("Токен отсутствует");
+
+ const { exp } = JSON.parse(atob(testToken.split(".")[1]));
+ return exp - Math.floor(Date.now() / 1000) <= 300;
+ } catch (error) {
+ console.log("Ошибка при разборе токена:", error);
+ return true; // В случае ошибки считаем, что истёк
+ }
+}
\ No newline at end of file
diff --git a/utils/logout.tsx b/utils/logout.tsx
new file mode 100644
index 00000000..38d88fbf
--- /dev/null
+++ b/utils/logout.tsx
@@ -0,0 +1,14 @@
+'use client';
+
+export const logout = ({setGlobalLoading, setUser}) => {
+ console.log('logout');
+ setGlobalLoading(true);
+
+ setTimeout(() => {
+ setGlobalLoading(false);
+ }, 1000);
+
+ setUser(null);
+ localStorage.removeItem('userVisit');
+ document.cookie = 'access_token=; path=/; expires=Thu, 01 Jan 1970 00:00:00 UTC;';
+};