diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 0000000..7e257db
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +1,3 @@
+{
+ "recommendations": []
+}
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
index 0e5ad34..6377851 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,6 +20,9 @@
"react-scripts": "5.0.1",
"sass": "^1.61.0",
"web-vitals": "^2.1.4"
+ },
+ "devDependencies": {
+ "tailwindcss": "^3.3.1"
}
},
"node_modules/@adobe/css-tools": {
diff --git a/package.json b/package.json
index dbe10d9..ed26391 100644
--- a/package.json
+++ b/package.json
@@ -39,5 +39,8 @@
"last 1 firefox version",
"last 1 safari version"
]
+ },
+ "devDependencies": {
+ "tailwindcss": "^3.3.1"
}
}
diff --git a/src/App.js b/src/App.js
index 59d5fbc..16dac44 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,9 +1,30 @@
-import './App.css';
+import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
+import LoginPage from './pages/LoginPage/LoginPage';
+import AllCoursesPage from './pages/AllCoursesPage/AllCoursesPage';
+import MyCoursesPage from './pages/MyCoursesPage/MyCoursesPage';
+import NewCoursePage from './pages/NewCoursePage/NewCoursePage';
+import HomePage from './pages/HomePage/HomePage';
+import Layout from './components/Layout/Layout';
+import PrivateRoute from './router/PrivateRoute';
function App() {
return (
-
- gkgkgkgkg
+
+
+ {/* */}
+
+
+ } />
+ }>
+ } />
+ } />
+ } />
+ } />
+ {/* }>
+ */}
+
+
+
);
}
diff --git a/src/axios/index.js b/src/axios/index.js
new file mode 100644
index 0000000..7d5cf83
--- /dev/null
+++ b/src/axios/index.js
@@ -0,0 +1,17 @@
+import axios from "axios";
+
+const token = localStorage.getItem("token");
+
+const BASE_URL = 'https://inverse-tracker.ru/api';
+
+export const instanceLogged = axios.create({
+ baseURL: BASE_URL,
+ timeout: 30000,
+ headers: { Authorization: `Token ${token}` }, //Переделать
+ // headers: { Authorization: "Token db87a3d921c5f19f4367c808a85287d0f82cd258" }, //Переделать
+});
+
+export const instance = axios.create({
+ baseURL: BASE_URL,
+ timeout: 1000,
+});
\ No newline at end of file
diff --git a/src/components/AllCourses/AllCourses.js b/src/components/AllCourses/AllCourses.js
new file mode 100644
index 0000000..8a7559b
--- /dev/null
+++ b/src/components/AllCourses/AllCourses.js
@@ -0,0 +1,47 @@
+import React, { useEffect } from 'react';
+import CardCourse from '../CardCourse/CardCourse';
+import { getAllCourses } from './getAllCourses';
+import { useSelector, useDispatch } from 'react-redux';
+import { Statuses } from '../../constant/statuses';
+
+const AllCourses = () => {
+ const dispatch = useDispatch();
+
+ const isLoading =
+ useSelector((state) => state.courses.status) === Statuses.inProgress;
+ // console.log(isLoading);
+
+
+ const coursesData = useSelector((state) => state.courses.courses);
+ // console.log(coursesData);
+
+ useEffect(() => {
+ getAllCourses(dispatch, coursesData.length);
+ }, []);
+
+ if (isLoading) {
+ return
Loading...;
+ }
+ return (
+
+ {coursesData.length > 0 &&
+ coursesData.map((course) => (
+ // console.log(course.name)
+ //
+
+ ))}
+
+ );
+};
+
+export default AllCourses;
diff --git a/src/components/AllCourses/getAllCourses.js b/src/components/AllCourses/getAllCourses.js
new file mode 100644
index 0000000..f005722
--- /dev/null
+++ b/src/components/AllCourses/getAllCourses.js
@@ -0,0 +1,21 @@
+import { instanceLogged } from '../../axios';
+import {coursesSlice} from '../../store/slices/courses';
+
+export const getAllCourses = async (dispatch, len) => {
+ console.log(len)
+ if (len > 0) {
+ return;
+ }
+ try {
+ //Get courses
+ dispatch(coursesSlice.actions.startLoading());
+ const getCourses = await instanceLogged.get('courses/');
+ dispatch(coursesSlice.actions.successLoading(getCourses.data));
+
+ // console.log(getCourses.data);
+ } catch (e) {
+ console.log(e);
+ dispatch(coursesSlice.actions.failLoading());
+ return e;
+ }
+};
diff --git a/src/components/CardCourse/CardCourse.js b/src/components/CardCourse/CardCourse.js
new file mode 100644
index 0000000..3679996
--- /dev/null
+++ b/src/components/CardCourse/CardCourse.js
@@ -0,0 +1,42 @@
+import React from 'react';
+import time from '../../img/Course/time.svg';
+import title from '../../img/titleWrap.svg';
+import laptop from '../../img/laptop.svg';
+import './CardCourse.scss'
+
+const CardCourse = (props) => {
+ // const course = {
+ // name: 'Вязание бархатных тяг',
+ // description: 'Вы научитесь вязать лучшие бархатные тяги в мире.',
+ // category: 'вязание',
+ // };
+ // console.log(props)
+
+ return (
+
+
+

+

+
+
+
+ {props.name}
+
+
+

+
+ Пн, Ср, Пт
+
+
+
+ {props.description}
+
+
+ {props.category}
+
+
+
+ );
+};
+
+export default CardCourse;
diff --git a/src/components/CardCourse/CardCourse.scss b/src/components/CardCourse/CardCourse.scss
new file mode 100644
index 0000000..3d4404c
--- /dev/null
+++ b/src/components/CardCourse/CardCourse.scss
@@ -0,0 +1,10 @@
+
+
+.description {
+// @apply font-mont-semibold text-xs text-darkGray mb-3;
+
+ -webkit-line-clamp: 1; /* Число отображаемых строк */
+ display: -webkit-box; /* Включаем флексбоксы */
+ -webkit-box-orient: vertical; /* Вертикальная ориентация */
+ overflow: hidden;
+}
diff --git a/src/components/Layout/Layout.js b/src/components/Layout/Layout.js
new file mode 100644
index 0000000..a312ac9
--- /dev/null
+++ b/src/components/Layout/Layout.js
@@ -0,0 +1,21 @@
+import React from 'react';
+import { Navigate, Outlet } from 'react-router-dom';
+import LeftBar from '../LeftBar/LeftBar';
+import { useAuth } from '../../hooks/useAuth';
+
+// import "./Layout.scss";
+
+const Layout = () => {
+ const auth = useAuth();
+
+ return auth ? (
+
+
+
+
+ ) : (
+
+ );
+};
+
+export default Layout;
diff --git a/src/components/LeftBar/LeftBar.js b/src/components/LeftBar/LeftBar.js
new file mode 100644
index 0000000..339c4e6
--- /dev/null
+++ b/src/components/LeftBar/LeftBar.js
@@ -0,0 +1,102 @@
+import React from 'react';
+import group from '../../img/LeftBar/Group.svg';
+import vector from '../../img/LeftBar/Vector.svg';
+import allcoursesActive from '../../img/LeftBar/allCoursesActive.svg';
+import title from '../../img/title.svg';
+import './LeftBar.scss';
+import AllCoursesIcon from '../../img/icon/AllCoursesIcon';
+import { Link } from 'react-router-dom';
+
+const LeftBar = () => {
+ const pathName = window.location.pathname;
+
+ return (
+
+ {/*
*/}
+ {/*
*/}
+ {/*

*/}
+
+

+
+ -
+
+ {pathName === '/my-courses' ? (
+
+ ) : (
+ <>
+
+
+ Мои курсы
+
+ >
+ )}
+
+
+ -
+
+ {pathName === '/courses' ? (
+ <>
+
+
+ Все курсы
+
+ >
+ ) : (
+ <>
+
+
+ Все курсы
+
+ >
+ )}
+
+
+ -
+
+ {pathName === '/news' ? (
+ <>
+
+
+ Новости
+
+ >
+ ) : (
+ <>
+
+
+ Новости
+
+ >
+ )}
+
+
+ -
+
+ {pathName === '/profile' ? (
+ <>
+
+
+ Профиль
+
+ >
+ ) : (
+ <>
+
+
+ Профиль
+
+ >
+ )}
+
+
+
+
+ );
+};
+
+export default LeftBar;
diff --git a/src/components/LeftBar/LeftBar.scss b/src/components/LeftBar/LeftBar.scss
new file mode 100644
index 0000000..bae7b36
--- /dev/null
+++ b/src/components/LeftBar/LeftBar.scss
@@ -0,0 +1,115 @@
+// .li-title{
+// @apply font-mont-bold text-2xl text-darkGrey;
+// }
+// .li-title {
+// @apply font-mont-bold text-2xl text-darkGrey;
+// }
+
+// .test{
+// fill: red;
+// }
+
+.link-my-courses {
+ @apply flex mb-8;
+
+ &:hover .icon {
+ background-image: url('../../img/LeftBar/myCoursesActive.svg');
+ }
+ .icon {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/myCoursesGrey.svg');
+ }
+
+ .iconActive {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/myCoursesActive.svg');
+ }
+}
+
+.link-all-courses {
+ @apply flex mb-8;
+
+ &:hover .icon {
+ background-image: url('../../img/LeftBar/allCoursesActive.svg');
+ }
+ .icon {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/allCoursesGrey.svg');
+ }
+
+ .iconActive {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/allCoursesActive.svg');
+ }
+}
+
+
+
+.link-all-courses {
+ @apply flex mb-8;
+
+ &:hover .icon {
+ background-image: url('../../img/LeftBar/allCoursesActive.svg');
+ }
+ .icon {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/allCoursesGrey.svg');
+ }
+
+ .iconActive {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/allCoursesActive.svg');
+ }
+}
+.link-all-courses {
+ @apply flex mb-8;
+
+ &:hover .icon {
+ background-image: url('../../img/LeftBar/allCoursesActive.svg');
+ }
+ .icon {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/allCoursesGrey.svg');
+ }
+
+ .iconActive {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/allCoursesActive.svg');
+ }
+}
+
+
+.link-news {
+ @apply flex mb-8;
+
+ &:hover .icon {
+ background-image: url('../../img/LeftBar/newsActive.svg');
+ }
+ .icon {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/newsGrey.svg');
+ }
+
+ .iconActive {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/newsActive.svg');
+ }
+}
+
+
+.link-all-courses {
+ @apply flex;
+
+ &:hover .icon {
+ background-image: url('../../img/LeftBar/allCoursesActive.svg');
+ }
+ .icon {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/allCoursesGrey.svg');
+ }
+
+ .iconActive {
+ @apply w-6 h-6 mr-2;
+ background-image: url('../../img/LeftBar/allCoursesActive.svg');
+ }
+}
diff --git a/src/components/Login/HandleLogin.js b/src/components/Login/HandleLogin.js
new file mode 100644
index 0000000..ffb3b62
--- /dev/null
+++ b/src/components/Login/HandleLogin.js
@@ -0,0 +1,35 @@
+import { instance } from '../../axios';
+import { userSlice } from '../../store/slices/user';
+
+
+export const handleLogin = async (dispatch, email, password) => {
+
+ try {
+ const userData = { email, password };
+
+ //Login user
+ const loginUser = await instance.post('users/auth/token/login/', userData);
+
+ // console.log(loginUser.data);
+
+ localStorage.setItem('token', loginUser.data.auth_token);
+
+
+ // Get user`s data
+
+ dispatch(userSlice.actions.startLoading());
+
+ const getUserData = await instance.get('users/auth/users/me/', {
+ headers: { Authorization: `Token ${loginUser.data.auth_token}` },
+ });
+
+ dispatch(userSlice.actions.successLoading(getUserData.data));
+
+ // console.log(getUserData.data);
+
+
+ } catch (e) {
+ dispatch(userSlice.actions.failLoading());
+ return e;
+ }
+};
diff --git a/src/components/Login/Login.js b/src/components/Login/Login.js
new file mode 100644
index 0000000..6833542
--- /dev/null
+++ b/src/components/Login/Login.js
@@ -0,0 +1,72 @@
+import React, { useState } from 'react';
+import { handleLogin } from './HandleLogin';
+import { useDispatch, useSelector } from 'react-redux';
+import { Statuses } from '../../constant/statuses';
+import title from '../../img/title.svg';
+import { useAuth } from '../../hooks/useAuth';
+
+import './Login.scss';
+import laptop from '../../img/laptop.svg';
+import { useNavigate } from 'react-router-dom';
+
+const Login = ({ setModal }) => {
+ const dispatch = useDispatch();
+ const navigate = useNavigate();
+
+ const auth = useAuth();
+ const [email, setEmail] = useState('');
+ const [password, setPassword] = useState('');
+
+ const isLoading =
+ useSelector((state) => state.user.status) === Statuses.inProgress;
+
+ const usersData = useSelector((state) => state.user.user);
+
+ if (auth) {
+ navigate('/courses')
+ }
+ // console.log(isLoading);
+ // console.log(usersData);
+
+ return (
+
+
+

+

+
+
+
+ );
+};
+
+export default Login;
diff --git a/src/components/Login/Login.scss b/src/components/Login/Login.scss
new file mode 100644
index 0000000..a9dd8de
--- /dev/null
+++ b/src/components/Login/Login.scss
@@ -0,0 +1,9 @@
+.img-laptop {
+ /* width: 470px; */
+ width: 100%;
+ height: 40%;
+}
+
+.data-layout {
+ @apply w-96 flex flex-col justify-center items-start;
+}
diff --git a/src/components/MyCourses/MyCourses.js b/src/components/MyCourses/MyCourses.js
new file mode 100644
index 0000000..a263d33
--- /dev/null
+++ b/src/components/MyCourses/MyCourses.js
@@ -0,0 +1,28 @@
+import React from 'react';
+import CardCourse from '../CardCourse/CardCourse';
+import { useDispatch, useSelector } from 'react-redux';
+import { Statuses } from '../../constant/statuses';
+
+const MyCourses = () => {
+ const dispatch = useDispatch();
+
+ const isLoading =
+ useSelector((state) => state.myCourses.status) === Statuses.inProgress;
+ const myCoursesData = useSelector((state) => state.myCourses.myCourses);
+
+ return (
+
+ {myCoursesData.length > 0 &&
+ myCoursesData.map((course) => (
+
+ ))}
+
+ );
+};
+
+export default MyCourses;
diff --git a/src/components/MyCourses/getMyCourses.js b/src/components/MyCourses/getMyCourses.js
new file mode 100644
index 0000000..38c30fd
--- /dev/null
+++ b/src/components/MyCourses/getMyCourses.js
@@ -0,0 +1,20 @@
+import { instanceLogged } from '../../axios';
+import myCoursesSlice from '../../store/slices/myCourses';
+
+export const getMyCourses = async (dispatch, len) => {
+ if (len > 0) {
+ return;
+ }
+ try {
+ //Get courses
+ dispatch(myCoursesSlice.actions.startLoading());
+ const getMyCourses = await instanceLogged.get('users/me/teacher/courses/');
+ dispatch(myCoursesSlice.actions.successLoading(getMyCourses.data));
+
+ // console.log(getCourses.data);
+ } catch (e) {
+ console.log(e);
+ dispatch(myCoursesSlice.actions.failLoading());
+ return e;
+ }
+};
diff --git a/src/components/NewCourse/ListCategories/ListCategories.js b/src/components/NewCourse/ListCategories/ListCategories.js
new file mode 100644
index 0000000..dc468df
--- /dev/null
+++ b/src/components/NewCourse/ListCategories/ListCategories.js
@@ -0,0 +1,129 @@
+import React, { useEffect } from 'react';
+import { useSelector, useDispatch } from 'react-redux';
+import { Statuses } from '../../../constant/statuses';
+import { getCategories } from './getCategories';
+
+const ListCategories = () => {
+ const dispatch = useDispatch();
+
+ // const isLoading =
+ // useSelector((state) => state.categories.status) === Statuses.inProgress;
+
+ // const categoriesData = useSelector((state) => state.categories.categories);
+ // console.log(coursesData.length);
+
+ // useEffect(() => {
+ // getCategories(dispatch, categoriesData.length);
+ // }, []);
+
+ return (
+
+ );
+};
+
+export default ListCategories;
diff --git a/src/components/NewCourse/ListCategories/getCategories.js b/src/components/NewCourse/ListCategories/getCategories.js
new file mode 100644
index 0000000..b1ffa19
--- /dev/null
+++ b/src/components/NewCourse/ListCategories/getCategories.js
@@ -0,0 +1,20 @@
+import { categoriesSlice } from '../../../store/slices/categories';
+import { instanceLogged } from '../../../axios';
+
+export const getCategories = async (dispatch, len) => {
+ if (len > 0) {
+ return;
+ }
+ try {
+ //Get categories
+ dispatch(categoriesSlice.actions.startLoading());
+ const getCategories = await instanceLogged.get('courses/categories/');
+ dispatch(categoriesSlice.actions.successLoading(getCategories.data));
+
+ console.log(getCategories.data);
+ } catch (e) {
+ console.log(e);
+ dispatch(categoriesSlice.actions.failLoading());
+ return e;
+ }
+};
diff --git a/src/components/NewCourse/NewCourse.js b/src/components/NewCourse/NewCourse.js
new file mode 100644
index 0000000..a23344f
--- /dev/null
+++ b/src/components/NewCourse/NewCourse.js
@@ -0,0 +1,168 @@
+import React, { useState } from 'react';
+import folder from '../../img/Course/Folder.svg';
+import ListCategories from './ListCategories/ListCategories';
+import { useSelector } from 'react-redux';
+
+const NewCourse = () => {
+ const [name, setName] = useState('');
+ const [place, setPlace] = useState('');
+ const [description, setDescription] = useState('');
+ const [groupName, setGroupName] = useState('');
+ const [number, setNumber] = useState('');
+ const [time, setTime] = useState('');
+
+ const teacherData = useSelector((state) => state.user.user);
+ console.log(teacherData);
+
+ const courseData = {
+ name: name,
+ description: description,
+ };
+
+ return (
+
+
+ Новый курс
+
+
+
+
+ Название
+
+
setName(e.target.value)}
+ />
+
Место
+
setName(e.target.value)}
+ />
+
+ Описание
+
+
+
+
+
+
Групп
+
Название
+
setName(e.target.value)}
+ />
+
+ Лимит учеников
+
+
setName(e.target.value)}
+ />
+
+
+ День занятий
+
+
+
+
+
Время
+
setTime(e.target.value)}
+ />
+
+
+
+ );
+};
+
+export default NewCourse;
diff --git a/src/components/NewCourse/postNewCourse.js b/src/components/NewCourse/postNewCourse.js
new file mode 100644
index 0000000..4c84f24
--- /dev/null
+++ b/src/components/NewCourse/postNewCourse.js
@@ -0,0 +1,21 @@
+import { instanceLogged } from '../../axios';
+import { coursesSlice } from '../../store/slices/courses';
+
+export const getAllCourses = async (dispatch, len) => {
+ if (len > 0) {
+ return;
+ }
+ try {
+ //Post New Course
+
+ dispatch(coursesSlice.actions.startLoading());
+ const postNewCourse = await instanceLogged.post('courses/create/', );
+ dispatch(coursesSlice.actions.addOneCourse(postNewCourse.data));
+
+ // console.log(getCourses.data);
+ } catch (e) {
+ console.log(e);
+ dispatch(coursesSlice.actions.failLoading());
+ return e;
+ }
+};
diff --git a/src/constant/statuses.js b/src/constant/statuses.js
new file mode 100644
index 0000000..93c56b5
--- /dev/null
+++ b/src/constant/statuses.js
@@ -0,0 +1,6 @@
+export const Statuses = {
+ idle: 'idle',
+ inProgress: 'inProgress',
+ success: 'success',
+ failed: 'failed',
+}
\ No newline at end of file
diff --git a/src/font/Mont-Bold.ttf b/src/font/Mont-Bold.ttf
new file mode 100644
index 0000000..4952bac
Binary files /dev/null and b/src/font/Mont-Bold.ttf differ
diff --git a/src/font/Mont-Regular.ttf b/src/font/Mont-Regular.ttf
new file mode 100644
index 0000000..ee599fc
Binary files /dev/null and b/src/font/Mont-Regular.ttf differ
diff --git a/src/font/Mont-SemiBold.ttf b/src/font/Mont-SemiBold.ttf
new file mode 100644
index 0000000..5ca92c5
Binary files /dev/null and b/src/font/Mont-SemiBold.ttf differ
diff --git a/src/hooks/useAuth.js b/src/hooks/useAuth.js
new file mode 100644
index 0000000..9713e98
--- /dev/null
+++ b/src/hooks/useAuth.js
@@ -0,0 +1,6 @@
+import { useSelector } from "react-redux";
+
+export function useAuth() {
+ const { isLogged } = useSelector((state) => state.user);
+ return isLogged;
+}
\ No newline at end of file
diff --git a/src/img/Course/Folder.svg b/src/img/Course/Folder.svg
new file mode 100644
index 0000000..287a137
--- /dev/null
+++ b/src/img/Course/Folder.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/img/Course/time.svg b/src/img/Course/time.svg
new file mode 100644
index 0000000..82f082a
--- /dev/null
+++ b/src/img/Course/time.svg
@@ -0,0 +1,16 @@
+
diff --git a/src/img/LeftBar/Group.svg b/src/img/LeftBar/Group.svg
new file mode 100644
index 0000000..415d9da
--- /dev/null
+++ b/src/img/LeftBar/Group.svg
@@ -0,0 +1,6 @@
+
diff --git a/src/img/LeftBar/Vector.svg b/src/img/LeftBar/Vector.svg
new file mode 100644
index 0000000..2536217
--- /dev/null
+++ b/src/img/LeftBar/Vector.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/img/LeftBar/allCoursesActive.svg b/src/img/LeftBar/allCoursesActive.svg
new file mode 100644
index 0000000..c495a75
--- /dev/null
+++ b/src/img/LeftBar/allCoursesActive.svg
@@ -0,0 +1,18 @@
+
diff --git a/src/img/LeftBar/allCoursesGrey.svg b/src/img/LeftBar/allCoursesGrey.svg
new file mode 100644
index 0000000..650fb42
--- /dev/null
+++ b/src/img/LeftBar/allCoursesGrey.svg
@@ -0,0 +1,18 @@
+
diff --git a/src/img/LeftBar/myCoursesActive.svg b/src/img/LeftBar/myCoursesActive.svg
new file mode 100644
index 0000000..77311f1
--- /dev/null
+++ b/src/img/LeftBar/myCoursesActive.svg
@@ -0,0 +1,12 @@
+
diff --git a/src/img/LeftBar/myCoursesGrey.svg b/src/img/LeftBar/myCoursesGrey.svg
new file mode 100644
index 0000000..e060e40
--- /dev/null
+++ b/src/img/LeftBar/myCoursesGrey.svg
@@ -0,0 +1,12 @@
+
diff --git a/src/img/LeftBar/newsActive.svg b/src/img/LeftBar/newsActive.svg
new file mode 100644
index 0000000..81d30af
--- /dev/null
+++ b/src/img/LeftBar/newsActive.svg
@@ -0,0 +1,17 @@
+
diff --git a/src/img/LeftBar/newsGrey.svg b/src/img/LeftBar/newsGrey.svg
new file mode 100644
index 0000000..66fd832
--- /dev/null
+++ b/src/img/LeftBar/newsGrey.svg
@@ -0,0 +1,18 @@
+
diff --git a/src/img/LeftBar/profileGrey.svg b/src/img/LeftBar/profileGrey.svg
new file mode 100644
index 0000000..251897a
--- /dev/null
+++ b/src/img/LeftBar/profileGrey.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/img/arrow.svg b/src/img/arrow.svg
new file mode 100644
index 0000000..6ea78d1
--- /dev/null
+++ b/src/img/arrow.svg
@@ -0,0 +1,10 @@
+
diff --git a/src/img/icon/AllCoursesIcon.js b/src/img/icon/AllCoursesIcon.js
new file mode 100644
index 0000000..df1e05a
--- /dev/null
+++ b/src/img/icon/AllCoursesIcon.js
@@ -0,0 +1,69 @@
+import React from 'react';
+
+const AllCoursesIcon = () => {
+ return (
+
+ );
+};
+
+export default AllCoursesIcon;
diff --git a/src/img/laptop.svg b/src/img/laptop.svg
new file mode 100644
index 0000000..a8c9bc7
--- /dev/null
+++ b/src/img/laptop.svg
@@ -0,0 +1,34 @@
+
diff --git a/src/img/title.svg b/src/img/title.svg
new file mode 100644
index 0000000..f828d5c
--- /dev/null
+++ b/src/img/title.svg
@@ -0,0 +1,50 @@
+
diff --git a/src/img/titleWrap.svg b/src/img/titleWrap.svg
new file mode 100644
index 0000000..23b1b5f
--- /dev/null
+++ b/src/img/titleWrap.svg
@@ -0,0 +1,6 @@
+
diff --git a/src/index.css b/src/index.css
deleted file mode 100644
index ec2585e..0000000
--- a/src/index.css
+++ /dev/null
@@ -1,13 +0,0 @@
-body {
- margin: 0;
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
- 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
- sans-serif;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-code {
- font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
- monospace;
-}
diff --git a/src/index.js b/src/index.js
index 16134be..0f51906 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,13 +1,19 @@
-import React from "react";
-import ReactDOM from "react-dom/client";
-import "./index.css";
-import App from "./App";
-import reportWebVitals from "./reportWebVitals";
+import React from 'react';
+import ReactDOM from 'react-dom/client';
+import './index.scss';
+import App from './App';
+import reportWebVitals from './reportWebVitals';
+import { Provider } from "react-redux";
+import store from "./store";
-const root = ReactDOM.createRoot(document.getElementById("root"));
+import './font/Mont-Bold.ttf';
+
+const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
-
+
+
+
);
reportWebVitals();
diff --git a/src/index.scss b/src/index.scss
new file mode 100644
index 0000000..7efecd0
--- /dev/null
+++ b/src/index.scss
@@ -0,0 +1,105 @@
+@import 'tailwindcss/base';
+@import 'tailwindcss/components';
+@import 'tailwindcss/utilities';
+/* @tailwind base;
+@tailwind components;
+@tailwind utilities; */
+
+@font-face {
+ font-family: 'Mont';
+ src: local('Bold'), url('./font/Mont-Bold.ttf') format('truetype');
+ font-weight: bold;
+}
+
+@font-face {
+ font-family: 'Mont';
+ src: local('Mont'), url('./font/Mont-SemiBold.ttf') format('truetype');
+ font-weight: semibold;
+}
+@font-face {
+ font-family: 'Mont';
+ src: local('Mont'), url('./font/Mont-Regular.ttf') format('truetype');
+ font-weight: regular;
+}
+
+body {
+ margin: 0;
+ padding: 0;
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+ sans-serif;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+}
+
+code {
+ font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
+ monospace;
+}
+
+.font-mont-bold {
+ font-family: 'Mont';
+ font-weight: bold;
+
+}
+.font-mont-semibold {
+ font-family: 'Mont';
+ font-weight: semibold;
+}
+.font-mont-regular {
+ font-family: 'Mont';
+ font-weight: regular;
+
+}
+
+.btn-main {
+ background-color: #7ca4d9;
+ height: 60px;
+ width: 396px;
+ color: white;
+ border-radius: 14px;
+ font-family: 'Mont';
+ font-weight: bold;
+ font-size: 20px;
+}
+
+.btn-additional {
+ background-color: #e3ecf6;
+ height: 60px;
+ width: 396px;
+ color: #7CA4D9;
+ border-radius: 14px;
+ font-family: 'Mont';
+ font-weight: bold;
+ font-size: 20px;
+}
+
+.input_text {
+ background-color: #f8f9fb;
+ height: 65px;
+ width: 396px;
+ color: #191919;
+ border-radius: 12px;
+ border: none;
+ outline: none;
+ padding: 20px;
+ box-sizing: border-box;
+ font-size: 20px;
+ font-family: 'Mont';
+ font-weight: semibold;
+}
+
+.textarea {
+ background-color: #f8f9fb;
+ height: 125px;
+ width: 396px;
+ color: #191919;
+ border-radius: 12px;
+ border: none;
+ outline: none;
+ padding: 20px;
+ box-sizing: border-box;
+ font-size: 20px;
+ font-family: 'Mont';
+ font-weight: semibold;
+}
diff --git a/src/pages/AllCoursesPage/AllCoursesPage.js b/src/pages/AllCoursesPage/AllCoursesPage.js
new file mode 100644
index 0000000..ed9f936
--- /dev/null
+++ b/src/pages/AllCoursesPage/AllCoursesPage.js
@@ -0,0 +1,18 @@
+import React from 'react';
+import AllCourses from '../../components/AllCourses/AllCourses';
+
+const AllCoursesPage = () => {
+
+
+ return (
+
+ );
+};
+
+export default AllCoursesPage;
diff --git a/src/pages/HomePage/HomePage.js b/src/pages/HomePage/HomePage.js
new file mode 100644
index 0000000..a082c29
--- /dev/null
+++ b/src/pages/HomePage/HomePage.js
@@ -0,0 +1,9 @@
+import React from 'react'
+
+const HomePage = () => {
+ return (
+
HomePage
+ )
+}
+
+export default HomePage
\ No newline at end of file
diff --git a/src/pages/LoginPage/LoginPage.js b/src/pages/LoginPage/LoginPage.js
new file mode 100644
index 0000000..84aa597
--- /dev/null
+++ b/src/pages/LoginPage/LoginPage.js
@@ -0,0 +1,31 @@
+import React, { useState } from 'react';
+import './LoginPage.scss';
+import Login from '../../components/Login/Login';
+
+const LoginPage = () => {
+ const [modalIsOpen, setModalIsOpen] = useState(false);
+
+ return (
+
+
+ {modalIsOpen && (
+
+
+
+ Восстановление пароля
+
+
+ Для смены пароля нужно обратиться к администратору
+
+
+
+
setModalIsOpen(false)} />
+
+ )}
+
+ );
+};
+
+export default LoginPage;
diff --git a/src/pages/LoginPage/LoginPage.scss b/src/pages/LoginPage/LoginPage.scss
new file mode 100644
index 0000000..c2fbbcc
--- /dev/null
+++ b/src/pages/LoginPage/LoginPage.scss
@@ -0,0 +1,14 @@
+
+.modal-layout {
+ @apply w-screen h-screen fixed top-0 left-0 flex justify-center items-center;
+
+ .modal {
+ @apply relative z-2 bg-white p-9 rounded-xl flex flex-col justify-center items-center;
+ width: 450px;
+ height: 265px;
+ }
+
+ .background {
+ @apply absolute h-full w-full z-0 bg-black opacity-30;
+ }
+}
diff --git a/src/pages/MyCoursesPage/MyCoursesPage.js b/src/pages/MyCoursesPage/MyCoursesPage.js
new file mode 100644
index 0000000..702764d
--- /dev/null
+++ b/src/pages/MyCoursesPage/MyCoursesPage.js
@@ -0,0 +1,16 @@
+import React from 'react'
+import MyCourses from '../../components/MyCourses/MyCourses'
+
+const MyCoursesPage = () => {
+ return (
+
+
+ Мои курсы
+
+
+
+
+ )
+}
+
+export default MyCoursesPage
\ No newline at end of file
diff --git a/src/pages/NewCoursePage/NewCoursePage.js b/src/pages/NewCoursePage/NewCoursePage.js
new file mode 100644
index 0000000..bf8218c
--- /dev/null
+++ b/src/pages/NewCoursePage/NewCoursePage.js
@@ -0,0 +1,24 @@
+import React from 'react';
+import arrow from '../../img/arrow.svg';
+import NewCourse from '../../components/NewCourse/NewCourse';
+import { Link } from 'react-router-dom';
+
+const NewCoursePage = () => {
+ return (
+
+
+
+ Мои курсы
+
+

+
Новый курс
+
+
+
+ );
+};
+
+export default NewCoursePage;
diff --git a/src/router/PrivateRoute.js b/src/router/PrivateRoute.js
new file mode 100644
index 0000000..9696d19
--- /dev/null
+++ b/src/router/PrivateRoute.js
@@ -0,0 +1,13 @@
+import { Navigate, Outlet } from "react-router-dom";
+import { useAuth } from "../hooks/useAuth";
+
+
+const PrivateRoute = () =>{
+ const auth = useAuth();
+ console.log(auth);
+ return(
+ auth ?
:
+ )
+}
+
+export default PrivateRoute;
\ No newline at end of file
diff --git a/src/store/index.js b/src/store/index.js
new file mode 100644
index 0000000..abe5ed6
--- /dev/null
+++ b/src/store/index.js
@@ -0,0 +1,16 @@
+import { configureStore } from '@reduxjs/toolkit';
+import userSlice from './slices/user';
+import coursesSlice from './slices/courses';
+import categoriesSlice from './slices/categories';
+import myCoursesSlice from './slices/myCourses';
+
+const store = configureStore({
+ reducer: {
+ user: userSlice,
+ courses: coursesSlice,
+ myCourses: myCoursesSlice,
+ categories: categoriesSlice,
+ },
+});
+
+export default store;
diff --git a/src/store/slices/categories/index.js b/src/store/slices/categories/index.js
new file mode 100644
index 0000000..2692fe3
--- /dev/null
+++ b/src/store/slices/categories/index.js
@@ -0,0 +1,37 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { Statuses } from '../../../constant/statuses';
+
+const initialState = {
+ categories: [],
+ status: Statuses.idle,
+};
+
+export const categoriesSlice = createSlice({
+ name: 'categories',
+ initialState,
+ reducers: {
+ startLoading: (state, action) => {
+ state.status = Statuses.inProgress;
+ state.categories = [];
+ console.log(state.status);
+ },
+ successLoading: (state, action) => {
+ state.status = Statuses.success;
+ state.categories = action.payload;
+ console.log(state.status);
+ },
+ failLoading: (state, action) => {
+ state.status = Statuses.failed;
+ state.categories = [];
+ console.log(state.status);
+ },
+ addOneCourse: (state, action) => {
+ state.status = Statuses.success;
+ state.categories = action.payload;
+ console.log(state.status);
+ },
+ },
+});
+
+export const { categories } = categoriesSlice.actions;
+export default categoriesSlice.reducer;
diff --git a/src/store/slices/courses/index.js b/src/store/slices/courses/index.js
new file mode 100644
index 0000000..7ea0ca3
--- /dev/null
+++ b/src/store/slices/courses/index.js
@@ -0,0 +1,37 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { Statuses } from '../../../constant/statuses';
+
+const initialState = {
+ courses: [],
+ status: Statuses.idle,
+};
+
+export const coursesSlice = createSlice({
+ name: 'courses',
+ initialState,
+ reducers: {
+ startLoading: (state, action) => {
+ state.status = Statuses.inProgress;
+ state.courses = [];
+ console.log(state.status);
+ },
+ successLoading: (state, action) => {
+ state.status = Statuses.success;
+ state.courses = action.payload;
+ console.log(state.status);
+ },
+ failLoading: (state, action) => {
+ state.status = Statuses.failed;
+ state.courses = [];
+ console.log(state.status);
+ },
+ addOneCourse: (state, action) => {
+ state.status = Statuses.success;
+ state.courses = action.payload;
+ console.log(state.status);
+ },
+ },
+});
+
+export const { courses } = coursesSlice.actions;
+export default coursesSlice.reducer;
diff --git a/src/store/slices/myCourses/index.js b/src/store/slices/myCourses/index.js
new file mode 100644
index 0000000..5c01ab5
--- /dev/null
+++ b/src/store/slices/myCourses/index.js
@@ -0,0 +1,37 @@
+import { createSlice } from '@reduxjs/toolkit';
+import { Statuses } from '../../../constant/statuses';
+
+const initialState = {
+ myCourses: [],
+ status: Statuses.idle,
+};
+
+export const myCoursesSlice = createSlice({
+ name: 'myCourses',
+ initialState,
+ reducers: {
+ startLoading: (state, action) => {
+ state.status = Statuses.inProgress;
+ state.myCourses = [];
+ console.log(state.status);
+ },
+ successLoading: (state, action) => {
+ state.status = Statuses.success;
+ state.myCourses = action.payload;
+ console.log(state.status);
+ },
+ failLoading: (state, action) => {
+ state.status = Statuses.failed;
+ state.myCourses = [];
+ console.log(state.status);
+ },
+ addOneCourse: (state, action) => {
+ state.status = Statuses.success;
+ state.myCourses = action.payload;
+ console.log(state.status);
+ },
+ },
+});
+
+export const { myCourses } = myCoursesSlice.actions;
+export default myCoursesSlice.reducer;
diff --git a/src/store/slices/user/index.js b/src/store/slices/user/index.js
new file mode 100644
index 0000000..2b757d4
--- /dev/null
+++ b/src/store/slices/user/index.js
@@ -0,0 +1,37 @@
+import { createSlice } from "@reduxjs/toolkit";
+import {Statuses} from '../../../constant/statuses'
+
+
+const initialState = {
+ user: {},
+ isLogged: false,
+ status: Statuses.idle,
+ };
+
+ export const userSlice = createSlice({
+ name: "user",
+ initialState,
+ reducers: {
+ startLoading: (state, action) => {
+ state.status = Statuses.inProgress;
+ state.user = {};
+ state.isLogged = false;
+ console.log('start')
+ },
+ successLoading: (state, action) => {
+ state.status = Statuses.success;
+ state.user = action.payload;
+ state.isLogged = true;
+ console.log('success')
+ },
+ failLoading: (state, action) => {
+ state.status = Statuses.failed;
+ state.user = {};
+ state.isLogged = false;
+ console.log('fail')
+ },
+ },
+ });
+
+ export const { user } = userSlice.actions;
+ export default userSlice.reducer;
\ No newline at end of file
diff --git a/tailwind.config.js b/tailwind.config.js
new file mode 100644
index 0000000..d006f6f
--- /dev/null
+++ b/tailwind.config.js
@@ -0,0 +1,65 @@
+const plugin = require('tailwindcss/plugin')
+
+module.exports = {
+ content: ['./src/**/*.{js,jsx,ts,tsx}'],
+ theme: {
+ extend: {
+ text: {
+ 32: '32',
+ },
+ width:{
+ 96: '96',
+ 396: '396',
+ },
+ height: {
+ 60: '60',
+ },
+ colors: {
+ mainBlue: '#7CA4D9',
+ black: '#191919',
+ darkGray: '#888A8C',
+ lightGray: '#F8F9FB',
+ blueGray: '#E3ECF6',
+ },
+ transitionTimingFunction: {
+ DEFULT: 'ease-in-out',
+ },
+ transitionDuration: {
+ DEFULT: '400ms',
+ },
+ keyframes: {
+ fadeIn: {
+ from: {
+ opacity: 0,
+ },
+ to: {
+ opacity: 1,
+ },
+ },
+ },
+ animation: {
+ fade: 'fadeIn .5s ease-in-out',
+ },
+ zIndex: {
+ 1: '1',
+ 2: '2',
+ },
+ },
+ },
+ plugins: [
+ // plugin(({ addComponents, theme, addUtilities }) => {
+ // addComponents({
+ // '.btn-main': {
+ // background: '#7CA4D9',
+ // height: '60px',
+ // width: '396px',
+ // color: 'white',
+ // borderRadius: '14px',
+ // '&:hover': {
+
+ // }
+ // },
+ // });
+ // }),
+ ],
+};