diff --git a/.env.development b/.env.development index f5c14d6..49882ac 100644 --- a/.env.development +++ b/.env.development @@ -1,4 +1,5 @@ VITE_AUTH0_DOMAIN="dev-txpc5harm481cb6o.us.auth0.com" VITE_AUTH0_CLIENT_ID="BOU97TMrp85ftAnrXSLTiYYiuifp9jfz" VITE_API='https://network-class-server.ru' -VITE_WS_API='wss://network-class-server.ru' \ No newline at end of file +VITE_WS_API='wss://network-class-server.ru' +VITE_VIDEOSDK_APP='http://localhost:3000/react-rtc-demo' \ No newline at end of file diff --git a/.env.production b/.env.production index 5a6a593..169fb1e 100644 --- a/.env.production +++ b/.env.production @@ -1,4 +1,5 @@ VITE_AUTH0_DOMAIN="dev-txpc5harm481cb6o.us.auth0.com" VITE_AUTH0_CLIENT_ID="fOB3CWsgCnNLI5q7OMWe9DfWaAXOme2o" VITE_API='https://network-class-server.ru' -VITE_WS_API='wss://network-class-server.ru' \ No newline at end of file +VITE_WS_API='wss://network-class-server.ru' +VITE_VIDEOSDK_APP='https://network-class-videosdk-client.pages.dev' \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 1b882d4..c152833 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@types/lodash": "^4.14.196", "@types/react-webcam": "^3.0.0", "axios": "^1.4.0", + "classnames": "^2.3.2", "dotenv": "^16.3.1", "jest": "^29.5.0", "lib-jitsi-meet": "^1.0.6", @@ -4312,6 +4313,11 @@ "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" }, + "node_modules/classnames": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz", + "integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==" + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", diff --git a/package.json b/package.json index 50524cb..376102c 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@types/lodash": "^4.14.196", "@types/react-webcam": "^3.0.0", "axios": "^1.4.0", + "classnames": "^2.3.2", "dotenv": "^16.3.1", "jest": "^29.5.0", "lib-jitsi-meet": "^1.0.6", diff --git a/public/icons/check_small.svg b/public/icons/check_small.svg new file mode 100644 index 0000000..559ca06 --- /dev/null +++ b/public/icons/check_small.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/loader.gif b/public/icons/loader.gif new file mode 100644 index 0000000..22bce2e Binary files /dev/null and b/public/icons/loader.gif differ diff --git a/src/app/App.tsx b/src/app/App.tsx index 21ebc50..8386027 100644 --- a/src/app/App.tsx +++ b/src/app/App.tsx @@ -4,20 +4,19 @@ import "./index.css"; import Join from "../pages/Join/Join"; import Lobby from "../pages/Lobby/Lobby"; -import LobbyAccess from "../pages/Lobby/LobbyAccess"; -import LobbyMy from "../pages/Lobby/LobbyMy"; import JoinCall from "../pages/JoinCall/JoinCall"; import CallPage from "../pages/CallPage/CallPage"; import CallPageUI from "../pages/CallPageCustomUI/CallPage"; import Loader from "../shared/ui/loader/Loader"; import { useAuth0 } from "@auth0/auth0-react"; +import Profile from "../pages/Profile/Profile"; const App: React.FC = () => { const { loginWithRedirect, isAuthenticated, isLoading } = useAuth0(); useEffect(() => { if (!isAuthenticated && !isLoading) { - loginWithRedirect(); + loginWithRedirect(); } }, [isLoading]); @@ -29,11 +28,10 @@ const App: React.FC = () => { } /> } /> - } /> - } /> } /> } /> - } /> + } /> + } /> )} diff --git a/src/app/index.css b/src/app/index.css index 4fc75bd..3731cd0 100644 --- a/src/app/index.css +++ b/src/app/index.css @@ -60,6 +60,11 @@ input::-ms-clear { display: none; } +input[type="checkbox"] { + -webkit-appearance: none; + appearance: none; +} + button { cursor: pointer; } diff --git a/src/entities/room/api/models.ts b/src/entities/room/api/models.ts index 8e11f79..e084f3c 100644 --- a/src/entities/room/api/models.ts +++ b/src/entities/room/api/models.ts @@ -7,4 +7,4 @@ export interface IRoom { isActive: boolean, owner_email: string, owner_fullname: string -} \ No newline at end of file +} diff --git a/src/entities/room/ui/JoinButton.tsx b/src/entities/room/ui/JoinButton.tsx index cf8d91f..9a255a9 100644 --- a/src/entities/room/ui/JoinButton.tsx +++ b/src/entities/room/ui/JoinButton.tsx @@ -3,7 +3,7 @@ import styled from "styled-components"; const Path = styled.path``; -const Button = styled.button` +const Button = styled.a` font-family: var(--font); font-size: 18px; font-style: normal; @@ -30,15 +30,13 @@ const Button = styled.button` `; interface Props { - href: number, + href: string, } const JoinButton: React.FC = ({ href }) => { return ( - ) -} + + Выйти + + + ); +}; diff --git a/src/pages/CallPageCustomUI/CallPage.tsx b/src/pages/CallPageCustomUI/CallPage.tsx index 89f2f30..6d80595 100644 --- a/src/pages/CallPageCustomUI/CallPage.tsx +++ b/src/pages/CallPageCustomUI/CallPage.tsx @@ -8,6 +8,8 @@ import avatar from "../../../public/icons/avatar.svg"; import Sidebar from "../../widgets/layout/Sidebar/Sidebar"; import storeSidebar from "./store/sidebarState"; import { observer } from "mobx-react-lite"; +import settingsState from "./store/settingsState"; +import SettingsCallPopup from "../../widgets/layout/SettingsCallPopup/SettingsCallPopup"; const Container = styled.div` width: 100%; @@ -30,6 +32,17 @@ const Content = styled.div` transition: all 0.3s ease-out; `; +const Overlay = styled.div` + background: white; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + opacity: 0.4; + z-index: 100; +`; + const peopleList: IUser[] = [ { email: "jjj", @@ -178,6 +191,10 @@ const peopleList: IUser[] = [ ]; const CallPage: React.FC = observer(() => { + function closePopup() { + settingsState.closeSettings(); + } + return ( { } > - + + {settingsState.isActive && } + {settingsState.isActive && } ); }); diff --git a/src/pages/CallPageCustomUI/store/settingsState.ts b/src/pages/CallPageCustomUI/store/settingsState.ts new file mode 100644 index 0000000..0eddd3d --- /dev/null +++ b/src/pages/CallPageCustomUI/store/settingsState.ts @@ -0,0 +1,28 @@ +import { makeAutoObservable } from "mobx"; + +class SettingsState { + isActive = false; + selected = "My"; + + constructor() { + makeAutoObservable(this); + } + + openSettings() { + this.isActive = true; + } + + closeSettings() { + this.isActive = false; + } + + selectClass() { + this.selected = "Class"; + } + + selectMy() { + this.selected = "My"; + } +} + +export default new SettingsState(); diff --git a/src/pages/Join/Join.tsx b/src/pages/Join/Join.tsx index 91d57dd..2e0419a 100644 --- a/src/pages/Join/Join.tsx +++ b/src/pages/Join/Join.tsx @@ -9,15 +9,24 @@ import { EnterClassForm } from "../../features/EnterClass/index.ts"; import FunctionsList from "../../widgets/FunctionsList/FunctionsList.tsx"; import functions from "../../widgets/FunctionsList/functionsObject.tsx"; import ProfilePanel from "../../widgets/ProfilePanel/ProfilePanel.tsx" +import { useAuth0 } from "@auth0/auth0-react"; +import { useAddUser } from "../../entities/user/api/useAddUser.ts"; const Join: React.FC = () => { + const { isAuthenticated, user } = useAuth0(); + + if (isAuthenticated) { + useAddUser(user?.name, 'test', user?.email); + } return (
- Логотип -
Сетевой учебный класс
+
+ Логотип +
Сетевой учебный класс
+
diff --git a/src/pages/Join/styles.module.css b/src/pages/Join/styles.module.css index 2fd1f50..200d2fb 100644 --- a/src/pages/Join/styles.module.css +++ b/src/pages/Join/styles.module.css @@ -19,10 +19,17 @@ width: 100%; display: flex; align-items: center; + justify-content: space-between; margin-bottom: 100px; position: relative; } +.logo { + display: flex; + align-items: center; + gap: 24px; +} + .header > img { margin-right: 24px; } diff --git a/src/pages/Lobby/Lobby.tsx b/src/pages/Lobby/Lobby.tsx index 10602ed..1e3b49a 100644 --- a/src/pages/Lobby/Lobby.tsx +++ b/src/pages/Lobby/Lobby.tsx @@ -1,21 +1,26 @@ import React from 'react'; +import { observer } from 'mobx-react-lite'; +import navbarState from './store/navbarState'; +import roomsFormState from './store/roomsFormState'; import { useRoomsList } from '../../entities/room/api/useRoomsList'; import Header from '../../widgets/layout/Header'; import Navbar from '../../widgets/layout/Navbar'; +import { CreateRoomForm } from '../../features/createRoom'; import RoomsList from '../../widgets/RoomsList'; -import user from './store/user'; -const Lobby: React.FC = () => { +const Lobby: React.FC = observer(() => { const { rooms, loading, error } = useRoomsList(); - console.log(user.state); + + const roomsFormStateLS = localStorage.getItem("trigger"); return ( <>
- + + {roomsFormState.state || roomsFormStateLS === 'create' && navbarState.state === 'my' ? : null} ) -} +}) export default Lobby; diff --git a/src/pages/Lobby/LobbyAccess.tsx b/src/pages/Lobby/LobbyAccess.tsx deleted file mode 100644 index f7b9593..0000000 --- a/src/pages/Lobby/LobbyAccess.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import React from 'react'; -import { useRoomsList } from '../../entities/room/api/useRoomsList'; -import Header from '../../widgets/layout/Header'; -import Navbar from '../../widgets/layout/Navbar'; -import RoomsList from '../../widgets/RoomsList'; - -const LobbyAccess: React.FC = () => { - const { rooms, loading, error } = useRoomsList(); - - return ( - <> -
- - - - ) -} - -export default LobbyAccess; diff --git a/src/pages/Lobby/LobbyMy.tsx b/src/pages/Lobby/LobbyMy.tsx deleted file mode 100644 index bb74a69..0000000 --- a/src/pages/Lobby/LobbyMy.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import React, { useEffect } from "react"; -import { useRoomsList } from '../../entities/room/api/useRoomsList'; -import Header from "../../widgets/layout/Header"; -import Navbar from "../../widgets/layout/Navbar"; -import { CreateRoomForm } from "../../features/createRoom/index.ts"; -import RoomsList from "../../widgets/RoomsList"; -import { observer } from "mobx-react-lite"; -import roomsFormState from "./store/roomsFormState.ts"; -// import { useAuth0 } from "@auth0/auth0-react"; - -const LobbyMy: React.FC = observer(() => { - const { rooms, loading, error } = useRoomsList(); - - useEffect(() => { - if (localStorage.getItem("trigger") === "create") { - roomsFormState.openCreateForm(); - localStorage.removeItem("trigger"); - } - }, []); - - return ( - <> -
- - {roomsFormState.state === "create" ? : <>} - - - ); -}); - -export default LobbyMy; diff --git a/src/pages/Lobby/store/navbarState.ts b/src/pages/Lobby/store/navbarState.ts new file mode 100644 index 0000000..64a9a13 --- /dev/null +++ b/src/pages/Lobby/store/navbarState.ts @@ -0,0 +1,36 @@ +import { makeAutoObservable } from "mobx"; + +const roomsFormStateLS = localStorage.getItem("trigger"); + +function defaultState() { + if (roomsFormStateLS === 'create') { + return 'my'; + } + + if (roomsFormStateLS === 'all') { + return 'all'; + } +} + +console.log(defaultState()); + +class NavbarState { + state = defaultState(); + constructor() { + makeAutoObservable(this) + } + + openAll() { + this.state = 'all'; + } + + openAccess() { + this.state = 'access'; + } + + openMy() { + this.state = 'my'; + } +} + +export default new NavbarState(); \ No newline at end of file diff --git a/src/pages/Lobby/store/user.ts b/src/pages/Lobby/store/userState.ts similarity index 82% rename from src/pages/Lobby/store/user.ts rename to src/pages/Lobby/store/userState.ts index 9f724c4..03b4dd4 100644 --- a/src/pages/Lobby/store/user.ts +++ b/src/pages/Lobby/store/userState.ts @@ -1,7 +1,7 @@ import { makeAutoObservable } from "mobx"; import { IUser } from "../../../entities/user/api/models"; -class User { +class UserState { state = {}; constructor() { makeAutoObservable(this) @@ -12,4 +12,4 @@ state = {}; } } -export default new User(); +export default new UserState(); diff --git a/src/pages/Profile/Profile.tsx b/src/pages/Profile/Profile.tsx new file mode 100644 index 0000000..48f49f2 --- /dev/null +++ b/src/pages/Profile/Profile.tsx @@ -0,0 +1,37 @@ +import React from "react"; +import { styled } from "styled-components"; +import Header from "../../widgets/layout/Header"; +import UserCard from "../../entities/user/ui/UserCard"; +import Statistics from "../../widgets/Statistics/Statistics"; +import profileFormState from "./store/profileFormState"; +import { EditUserForm } from "../../features/editUser"; +import { observer } from "mobx-react-lite"; + +const Container = styled.div``; + +const Title = styled.div` + color: #000; + font-family: var(--font); + font-size: 28px; + font-weight: 500; + margin: 84px 0 34px 123px; +`; + +const ProfileCard = styled.div` + margin: 0 121px 73px 123px; +`; + +const Profile: React.FC = observer(() => { + return ( + +
+ Мой профиль + + {profileFormState.state ? : } + + + + ); +}); + +export default Profile; diff --git a/src/pages/Profile/store/profileFormState.tsx b/src/pages/Profile/store/profileFormState.tsx new file mode 100644 index 0000000..1f62fe8 --- /dev/null +++ b/src/pages/Profile/store/profileFormState.tsx @@ -0,0 +1,23 @@ +import { makeAutoObservable } from "mobx"; + +class FormState { + state = ""; + isEmailConfirmed = false; + constructor() { + makeAutoObservable(this); + } + + openEditForm() { + this.state = "edit"; + } + + closeEditForm() { + this.state = ""; + } + + confirmEmail() { + this.isEmailConfirmed = true; + } +} + +export default new FormState(); diff --git a/src/shared/ui/Select.tsx b/src/shared/ui/Select.tsx index 92b52c5..ea72e30 100644 --- a/src/shared/ui/Select.tsx +++ b/src/shared/ui/Select.tsx @@ -1,5 +1,5 @@ -import React from 'react'; -import styled from 'styled-components'; +import React from "react"; +import styled from "styled-components"; const Container = styled.div` position: absolute; @@ -8,29 +8,35 @@ const Container = styled.div` z-index: 1; padding: 20px 16px 16px; - border-radius: 10px ; + border-radius: 10px; background: var(--white); box-shadow: 5px 5px 10px 0px var(--grey_5); - transition: all .3s ease; -` + transition: all 0.3s ease; -const Content = styled.div` + &:hover { + cursor: default; + } +`; -` +const Content = styled.div``; interface Props { - children?: React.ReactNode, - active: boolean, + children?: React.ReactNode; + active: boolean; } const Select: React.FC = ({ children, active }) => { return ( - - - {children} - + + {children} - ) -} + ); +}; -export default Select \ No newline at end of file +export default Select; diff --git a/src/shared/ui/Tooltip.tsx b/src/shared/ui/Tooltip.tsx index e6b660f..7ca4e51 100644 --- a/src/shared/ui/Tooltip.tsx +++ b/src/shared/ui/Tooltip.tsx @@ -17,6 +17,7 @@ const Content = styled.div` box-shadow: 0px 2px 6px 0px #c5ccd5; border-radius: 4px; + white-space: nowrap; font-family: var(--font); font-size: 14px; font-style: normal; @@ -38,9 +39,10 @@ const Content = styled.div` interface Props { active: boolean; children: React.ReactNode; + message: string; } -const Tooltip: React.FC = ({ active, children }) => { +const Tooltip: React.FC = ({ active, children, message }) => { return ( = ({ active, children }) => { : { opacity: 0, visibility: "hidden" } } > - Ссылка скопирована! + {message} {children} diff --git a/src/shared/ui/cardButton/CardButton.tsx b/src/shared/ui/cardButton/CardButton.tsx new file mode 100644 index 0000000..d2b75ac --- /dev/null +++ b/src/shared/ui/cardButton/CardButton.tsx @@ -0,0 +1,33 @@ +import React from "react"; +import styled from "styled-components"; + +const Button = styled.button` + display: flex; + padding: 10px; + justify-content: center; + align-items: center; + border-radius: 8px; + border: 1px solid var(--blue, #175ef1); + background: var(--white, #fff); + color: var(--blue, #175ef1); + font-size: 18px; + font-weight: 400; + line-height: normal; + transition: all 0.3s ease; + + &:hover { + color: var(--white); + background: var(--blue, #175ef1); + } +`; + +interface Props { + children?: string; + onClick?: () => void; +} + +const CardButton: React.FC = ({ children, onClick }) => { + return ; +}; + +export default CardButton; diff --git a/src/shared/ui/checkBox/CheckBox.tsx b/src/shared/ui/checkBox/CheckBox.tsx new file mode 100644 index 0000000..9d09a79 --- /dev/null +++ b/src/shared/ui/checkBox/CheckBox.tsx @@ -0,0 +1,58 @@ +import React, { useState } from "react"; +import styled from "styled-components"; +import check from "../../../../public/icons/check_small.svg"; + +const Container = styled.div` + display: flex; + align-items: center; + gap: 15px; +`; + +const Input = styled.input` + width: 18px; + height: 18px; + border-radius: 2px; + border: 1.5px solid var(--grey-4, #c5ccd5); + + &:checked { + background: var(--blue, #175ef1) url(${check}) center no-repeat; + } + &:hover { + cursor: pointer; + } +`; + +const Title = styled.div` + color: var(--grey-3, #a0afc1); + font-family: var(--font); + font-size: 16px; + font-weight: 400; +`; + +interface Props { + text: string; +} + +const CheckBox: React.FC = ({ text }) => { + const [selected, setSelected] = useState(true); + + function changeSelected() { + selected ? setSelected(false) : setSelected(true); + } + + return ( + + + + {text} + + + ); +}; + +export default CheckBox; diff --git a/src/shared/ui/loader/Loader.tsx b/src/shared/ui/loader/Loader.tsx index a2fef6c..a314ba4 100644 --- a/src/shared/ui/loader/Loader.tsx +++ b/src/shared/ui/loader/Loader.tsx @@ -1,13 +1,32 @@ import React from "react"; -import styles from "./styles.module.css"; +// import styles from "./styles.module.css"; +import loader from '../../../../public/icons/loader.gif'; +import styled from 'styled-components'; + +const Page = styled.div` + width: 100wh; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; + background-color: #fff; +` + +const Gif = styled.img` + width: 200px; + height: 200px; +` const Loader: React.FC = () => { return ( -
-
-
-
-
+ //
+ //
+ //
+ //
+ //
+ + + ); }; diff --git a/src/shared/ui/switchButton/SwitchButton.tsx b/src/shared/ui/switchButton/SwitchButton.tsx new file mode 100644 index 0000000..19e1161 --- /dev/null +++ b/src/shared/ui/switchButton/SwitchButton.tsx @@ -0,0 +1,20 @@ +import React, { useState } from "react"; +import styles from "./styles.module.css"; +import classNames from "classnames"; + +const SwitchButton: React.FC = () => { + const [selected, setSelected] = useState(true); + + function changeSelected() { + selected ? setSelected(false) : setSelected(true); + } + + return ( +
+ ); +}; + +export default SwitchButton; diff --git a/src/shared/ui/switchButton/styles.module.css b/src/shared/ui/switchButton/styles.module.css new file mode 100644 index 0000000..335aa23 --- /dev/null +++ b/src/shared/ui/switchButton/styles.module.css @@ -0,0 +1,28 @@ +.switchBtn { + display: inline-block; + width: 36px; + height: 20px; + border-radius: 15px; + background: var(--grey_4); + cursor: pointer; + position: relative; + transition-duration: 300ms; +} +.switchBtn::after { + content: ""; + height: 17px; + width: 16px; + border-radius: 50%; + background: #fff; + top: 1.5px; + left: 1.5px; + transition-duration: 300ms; + position: absolute; + z-index: 1; +} +.switchOn { + background: var(--blue); +} +.switchOn::after { + left: 18.5px; +} diff --git a/src/widgets/CallControllers.tsx b/src/widgets/CallControllers.tsx index d7c4a1f..b08a0ee 100644 --- a/src/widgets/CallControllers.tsx +++ b/src/widgets/CallControllers.tsx @@ -1,42 +1,42 @@ -import React from 'react'; -import styled from 'styled-components'; -import ControllersWrapper from './layout/ControllersWrapper'; -import { MicrophoneController } from '../features/MicrophoneController'; -import { CameraController } from '../features/CameraController'; -import { RecordController } from '../features/RecordController'; -import { HandController } from '../features/HandController/ui/HandController'; -import { ScreenController } from '../features/ScreenController'; -import { MenuController } from '../features/ControllersMenu'; -import { LeaveCall } from '../features/LeaveCall'; +import React from "react"; +import styled from "styled-components"; +import ControllersWrapper from "./layout/ControllersWrapper"; +import { MicrophoneController } from "../features/MicrophoneController"; +import { CameraController } from "../features/CameraController"; +import { RecordController } from "../features/RecordController"; +import { HandController } from "../features/HandController/ui/HandController"; +import { ScreenController } from "../features/ScreenController"; +import { MenuController } from "../features/ControllersMenu"; +import { LeaveCall } from "../features/LeaveCall"; const Left = styled.div` display: flex; gap: 20px; justify-content: space-between; -` +`; const Center = styled.div` display: flex; gap: 20px; justify-content: space-between; -` +`; const CallControllers: React.FC = () => { return ( - - - - -
- - - - -
- + + + + +
+ + + + +
+
- ) -} + ); +}; -export default CallControllers \ No newline at end of file +export default CallControllers; diff --git a/src/widgets/FunctionsList/functionsObject.tsx b/src/widgets/FunctionsList/functionsObject.tsx index b0d60b9..808d94f 100644 --- a/src/widgets/FunctionsList/functionsObject.tsx +++ b/src/widgets/FunctionsList/functionsObject.tsx @@ -10,9 +10,9 @@ const functions: IFunction[] = [ { icon: createClass, iconActive: createClassActive, - title: "Новый класс", + title: "Мои классы", description: "Создать свой класс и провести занятие онлайн", - link: "/lobby/my", + link: "/lobby", onClick: () => { localStorage.setItem("trigger", "create"); }, @@ -23,13 +23,16 @@ const functions: IFunction[] = [ title: "Поиск", description: "Найти класс и получить новые знания", link: "/lobby", + onClick: () => { + localStorage.setItem("trigger", "all"); + }, }, { icon: settings, iconActive: settingsActive, title: "Настройки", description: "Редактировать свой профиль и классы", - link: "/", + link: "/profile", }, ]; diff --git a/src/widgets/ProfilePanel/ProfilePanel.tsx b/src/widgets/ProfilePanel/ProfilePanel.tsx index e971b8a..85f304e 100644 --- a/src/widgets/ProfilePanel/ProfilePanel.tsx +++ b/src/widgets/ProfilePanel/ProfilePanel.tsx @@ -1,13 +1,12 @@ -import React, { useState } from 'react'; -import styled from 'styled-components'; -import Select from '../../shared/ui/Select'; -import { LogoutButton } from '../../features/logout'; +import React, { useState } from "react"; +import styled from "styled-components"; +import Select from "../../shared/ui/Select"; +import { LogoutButton } from "../../features/logout"; import avatarIcon from "../../../public/icons/avatar.svg"; import selectIcon from "../../../public/icons/select.svg"; -import settingsIcon from "../../../public/icons/setting-mini.svg"; -import logoutIcon from "../../../public/icons/logout.svg"; import { useAuth0 } from "@auth0/auth0-react"; -import Paragraph from '../../shared/ui/Paragraph'; +import Paragraph from "../../shared/ui/Paragraph"; +import { EnterProfileButton } from "../../features/EnterProfile"; const Container = styled.div` position: relative; @@ -17,7 +16,7 @@ const Container = styled.div` align-items: center; gap: 15px; - &:hover{ + &:hover { cursor: pointer; } `; @@ -26,7 +25,7 @@ const Avatar = styled.img` width: 44px; height: 44px; border-radius: 10px; -` +`; const Text = styled.div` display: flex; @@ -43,7 +42,7 @@ const Text = styled.div` background: linear-gradient(90deg, transparent 0, #fff 100%); content: ""; } -` +`; const Button = styled.button` display: flex; @@ -51,53 +50,56 @@ const Button = styled.button` align-items: center; width: 34px; height: 34px; -` +`; -const SelectLink = styled.a` - display: flex; - gap: 8px; - align-items: center; +const SelectLink = styled.div` color: inherit; + + &:hover { + cursor: pointer; + } `; const Divider = styled.div` margin: 10px 0; - width: 192px; + width: 100%; height: 0.5px; background: var(--grey_5); `; const ProfilePanel: React.FC = () => { - const [selectActive, setSelectActive] = useState(false); - const { user, isAuthenticated } = useAuth0(); - - function changeSelectVisibility() { - setSelectActive(!selectActive); - } + const [selectActive, setSelectActive] = useState(false); + const { user, isAuthenticated } = useAuth0(); + + function changeSelectVisibility() { + setSelectActive(!selectActive); + } return ( - - - - {isAuthenticated ? {user?.name} : Loading...} - - + + + + {isAuthenticated ? ( + {user?.name} + ) : ( + Loading... + )} + + - - - ) + + + ); }; export default ProfilePanel; diff --git a/src/widgets/RoomsList.tsx b/src/widgets/RoomsList.tsx index aa92820..30a0582 100644 --- a/src/widgets/RoomsList.tsx +++ b/src/widgets/RoomsList.tsx @@ -37,8 +37,7 @@ const Container = styled.div` const Header = styled.div` display: flex; - width: 80%; - justify-content: space-between; + width: 100%; align-items: center; margin: 0 auto 27px; ` @@ -76,15 +75,13 @@ const RoomsList: React.FC = observer(({ rooms, loading, error }) => { console.log(searchedRooms); }; - console.log(rooms); - return (
- Название - Владелец - Статус - Доступ + Название + Владелец + Статус + Доступ
{searchedRooms.length > 0 ? <> diff --git a/src/widgets/SettingsClass/SettingsClass.tsx b/src/widgets/SettingsClass/SettingsClass.tsx new file mode 100644 index 0000000..c7dd78b --- /dev/null +++ b/src/widgets/SettingsClass/SettingsClass.tsx @@ -0,0 +1,70 @@ +import React from "react"; +import styled from "styled-components"; +import { SettingClassLayout } from "../layout/SettingClassLayout"; +import SwitchButton from "../../shared/ui/switchButton/SwitchButton"; + +const Setting = styled.div` + display: flex; + justify-content: space-between; + align-items: center; + gap: 15px; +`; + +const SettingText = styled.div` + color: var(--black, #000); + font-family: var(--font); + font-size: 16px; + font-weight: 400; + line-height: normal; +`; + +const SettingsClass: React.FC = () => { + return ( + <> + + <> + + + Разрешить участникам видеть все демонстрации + + + + + + Разрешить участникам выбирать вкладку для показа + + + + + + + <> + + Разрешить участникам использовать камеру + + + + + + <> + + + Разрешить участникам использовать микрофон + + + + + + + <> + + Разрешить участникам записывать встречи + + + + + + ); +}; + +export default SettingsClass; diff --git a/src/widgets/SettingsMy/SettingsMy.tsx b/src/widgets/SettingsMy/SettingsMy.tsx new file mode 100644 index 0000000..1ccde53 --- /dev/null +++ b/src/widgets/SettingsMy/SettingsMy.tsx @@ -0,0 +1,104 @@ +import React, { useState } from "react"; +import styled from "styled-components"; +import { SelectDevice } from "../../features/DeviceSetting"; +import { useAuth0 } from "@auth0/auth0-react"; + +const Input = styled.input` + display: flex; + width: 100%; + min-height: 54px; + padding: 4px 0px 4px 16px; + align-items: center; + border-radius: 10px; + background: #fff; + border: 1.5px solid var(--blue); + margin-bottom: 10px; + color: var(--black, #000); + font-family: var(--font); + font-size: 20px; + font-weight: 400; + line-height: 24px; + letter-spacing: 0.5px; +`; + +const Title = styled.label` + position: absolute; + top: -9px; + left: 14px; + color: var(--blue, #175ef1); + background: white; + padding: 0 5px; + font-family: var(--font); + font-size: 18px; + font-weight: 400; + line-height: 16px; + letter-spacing: 0.4px; +`; + +const stylesText = { + color: "var(--black, #000)", + fontSize: "20px", + fontWeight: "600", + lineHeight: "normal", +}; + +const stylesBlock = { + border: "1px solid var(--grey-5, #D5DEE8)", + boxShadow: "none", +}; + +const stylesList = { + border: "1px solid var(--grey-5, #D5DEE8)", + boxShadow: "none", +}; + +const stylesContainer = { + flex: "0 0", +}; + +const SettingsMy: React.FC = () => { + const { user } = useAuth0(); + const [name, setName] = useState(user?.name); + + return ( + <> +
+ Имя в классе + ) => + setName(e.target.value) + } + /> +
+ + + + + ); +}; + +export default SettingsMy; diff --git a/src/widgets/Statistics/Statistics.tsx b/src/widgets/Statistics/Statistics.tsx new file mode 100644 index 0000000..8eb6c5e --- /dev/null +++ b/src/widgets/Statistics/Statistics.tsx @@ -0,0 +1,66 @@ +import React from "react"; +import styled from "styled-components"; + +const Container = styled.div` + display: grid; + grid-template-columns: repeat(3, max-content); + justify-content: space-between; + gap: 30px; + margin: 0 136px 0 144px; + color: #000; + font-family: var(--font); + line-height: normal; +`; + +const StatisticsBlock = styled.div` + display: flex; + flex-direction: column; + justify-content: center; + align-items: flex-start; + gap: 10px; +`; + +const StatisticsTitle = styled.div` + font-size: 22px; + font-weight: 500; +`; + +const StatisticsText = styled.div` + font-size: 20px; + font-weight: 300; +`; + +const Statistics: React.FC = () => { + return ( + + + Дата регистрации + 08.08.2023 + + + Дата последней онлайн-встречи + 09.08.2023 + + + Частота проведения встреч + 2.8 встреч в месяц + + + Всего участников + 1784 + + + Всего моих классов + 15 + + + + Всего онлайн участников в моих классах + + 12 + + + ); +}; + +export default Statistics; diff --git a/src/widgets/UserGrid/UserGrid.tsx b/src/widgets/UserGrid/UserGrid.tsx index fce7228..bd069e7 100644 --- a/src/widgets/UserGrid/UserGrid.tsx +++ b/src/widgets/UserGrid/UserGrid.tsx @@ -64,7 +64,7 @@ const ShowMoreButton = styled.button` position: absolute; top: 50%; transform: translate(0, -50%); - z-index: 1000; + z-index: 10; &:hover { cursor: pointer; diff --git a/src/widgets/layout/Navbar.tsx b/src/widgets/layout/Navbar.tsx index 8c87428..c7d9036 100644 --- a/src/widgets/layout/Navbar.tsx +++ b/src/widgets/layout/Navbar.tsx @@ -1,10 +1,12 @@ // import React from 'react'; import styled from 'styled-components'; +import { observer } from 'mobx-react-lite'; import { AddRoomButton } from '../../features/AddRoom.tsx/index.ts'; import { SearchInput } from '../../features/Search/index.ts'; import roomsFormState from '../../pages/Lobby/store/roomsFormState.ts'; import roomsState from '../../pages/Lobby/store/roomsState.ts'; import editIcon from '../../../public/icons/edit.svg'; +import navbarState from '../../pages/Lobby/store/navbarState.ts'; const Container = styled.div` display: flex; @@ -21,7 +23,7 @@ const Left = styled.div` justify-content: space-between; ` -const Link = styled.a` +const Link = styled.button` font-family: var(--font); font-size: 20px; font-style: normal; @@ -53,41 +55,50 @@ const EditButton = styled.button` box-shadow: 0px 3px 6px 0px #E5EAF8; ` -interface Props { - activeLink: string, - allLength?: number, - accessLength?: number, - myLength?: number, -} +const Navbar: React.FC = observer(() => { -const Navbar: React.FC = ({ activeLink, /*allLength, accessLength, myLength*/ }) => { + function openAll() { + navbarState.openAll(); + } + + function openAccess() { + navbarState.openAccess(); + } + + function openMy() { + navbarState.openMy(); + } function addRoom() { - const currentUrl = window.location.href; - if (currentUrl !== "http://localhost:5173/lobby/my") { - window.location.href = '/lobby/my'; + if (roomsFormState.state === '' && navbarState.state === 'my') { roomsFormState.openCreateForm(); + return 0; } - roomsFormState.openCreateForm(); + if (roomsFormState.state === 'create') { + roomsFormState.closeCreateForm(); + return 0; + } } function editRooms() { - if (roomsState.state === '') { - roomsState.openEditForm(); - return 0; - } - if (roomsState.state === 'edit') { - roomsState.closeEditForm(); - return 0; + if (navbarState.state === 'my') { + if (roomsState.state === '') { + roomsState.openEditForm(); + return 0; + } + if (roomsState.state === 'edit') { + roomsState.closeEditForm(); + return 0; + } } } return ( - Все классы({121}) - Доступные({5}) - Мои({2}) + Все классы + Доступные + Мои @@ -98,6 +109,6 @@ const Navbar: React.FC = ({ activeLink, /*allLength, accessLength, myLeng ) -} +}) export default Navbar; \ No newline at end of file diff --git a/src/widgets/layout/ProfileFormLayout.tsx b/src/widgets/layout/ProfileFormLayout.tsx new file mode 100644 index 0000000..3086275 --- /dev/null +++ b/src/widgets/layout/ProfileFormLayout.tsx @@ -0,0 +1,26 @@ +import React from "react"; +import styled from "styled-components"; + +const Container = styled.div` + position: relative; + width: 100%; + padding: 20px; + border-radius: 10px; + background: var(--white); + box-shadow: 0px 0px 4px 0px #e5eaf8; + font-family: var(--font); + color: #000; + display: flex; + justify-content: space-between; + align-items: center; +`; + +interface Props { + children?: React.ReactNode; +} + +const ProfileFormLayout: React.FC = ({ children }) => { + return {children}; +}; + +export default ProfileFormLayout; diff --git a/src/widgets/layout/SettingClassLayout.tsx b/src/widgets/layout/SettingClassLayout.tsx new file mode 100644 index 0000000..6b3cff0 --- /dev/null +++ b/src/widgets/layout/SettingClassLayout.tsx @@ -0,0 +1,52 @@ +import React from "react"; +import { styled } from "styled-components"; +import CheckBox from "../../shared/ui/checkBox/CheckBox"; + +const Container = styled.div` + width: 100%; + display: flex; + padding-bottom: 20px; + flex-direction: column; + align-items: flex-start; + gap: 20px; +`; + +const Head = styled.div` + display: flex; + width: 100%; + justify-content: space-between; + align-items: center; + gap: 100px; +`; + +const Title = styled.div` + color: var(--black, #000); + font-family: var(--font); + font-size: 20px; + font-weight: 600; + line-height: normal; +`; + +const Main = styled.div` + display: flex; + width: 100%; + flex-direction: column; + gap: 20px; +`; + +interface Props { + title: string; + children?: React.ReactNode; +} + +export const SettingClassLayout: React.FC = ({ title, children }) => { + return ( + + + {title} + + +
{children}
+
+ ); +}; diff --git a/src/widgets/layout/SettingsCallPopup/SettingsCallPopup.tsx b/src/widgets/layout/SettingsCallPopup/SettingsCallPopup.tsx new file mode 100644 index 0000000..e25f357 --- /dev/null +++ b/src/widgets/layout/SettingsCallPopup/SettingsCallPopup.tsx @@ -0,0 +1,133 @@ +import React from "react"; +import styled from "styled-components"; +import settingsState from "../../../pages/CallPageCustomUI/store/settingsState"; +import { observer } from "mobx-react-lite"; +import FormButton from "../../../shared/ui/formButton/FormButton"; +import SettingsMy from "../../SettingsMy/SettingsMy"; +import SettingsClass from "../../SettingsClass/SettingsClass"; + +const Container = styled.div` + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + min-width: 530px; + max-height: 100vh; + padding: 30px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + gap: 30px; + border-radius: 8px; + background: var(--white, #fff); + box-shadow: 0px 0px 2px 0px #c5ccd5; + z-index: 101; +`; + +const Header = styled.div` + display: flex; + justify-content: center; + align-items: center; + gap: 10px; + width: 100%; + padding-bottom: 20px; + border-bottom: 0.5px solid var(--grey-5, #d5dee8); +`; + +const HeaderText = styled.div` + display: flex; + padding: 8px 16px; + align-items: flex-start; + gap: 10px; + color: var(--grey-1, #5f6a77); + font-family: var(--font); + font-size: 20px; + font-weight: 400; + line-height: normal; + + &:hover { + cursor: pointer; + } +`; + +const Settings = styled.form` + overflow: auto; + width: 100%; + display: flex; + flex-direction: column; + align-items: stretch; + gap: 20px; + padding-bottom: 5px; + + &::-webkit-scrollbar { + width: 0; + } +`; + +const Buttons = styled.div` + display: flex; + justify-content: center; + align-items: center; + gap: 30px; +`; + +const Back = styled.button` + color: var(--grey-1, #5f6a77); + font-family: var(--font); + font-size: 20px; + font-weight: 400; + line-height: normal; +`; + +const styleSelected = { + color: "var(--blue, #175EF1)", + fontWeight: 600, +}; + +const SettingsCallPopup: React.FC = observer(() => { + function openMy() { + settingsState.selectMy(); + } + + function openClass() { + settingsState.selectClass(); + } + + function saveChanges() { + settingsState.closeSettings(); + } + + function backChanges() { + settingsState.closeSettings(); + } + + return ( + +
+ + Мои настройки + + + Настройки класса + +
+ + {settingsState.selected === "My" && } + {settingsState.selected === "Class" && } + + Сохранить + Отмена + + +
+ ); +}); + +export default SettingsCallPopup;