From 11f4f4290bf515fcc7303a61b464bc274180ef5a Mon Sep 17 00:00:00 2001 From: BodySites <100404530+BodySites@users.noreply.github.com> Date: Thu, 17 Aug 2023 12:51:30 +0600 Subject: [PATCH 1/6] add editForm for UserProfile --- src/entities/user/ui/UserCard.tsx | 37 ++-- src/features/editUser/index.ts | 1 + src/features/editUser/ui/EditUserForm.tsx | 177 +++++++++++++++++++ src/pages/Profile/Profile.tsx | 9 +- src/pages/Profile/store/profileFormState.tsx | 23 +++ src/shared/ui/cardButton/CardButton.tsx | 5 +- src/widgets/layout/ProfileFormLayout.tsx | 26 +++ 7 files changed, 251 insertions(+), 27 deletions(-) create mode 100644 src/features/editUser/index.ts create mode 100644 src/features/editUser/ui/EditUserForm.tsx create mode 100644 src/pages/Profile/store/profileFormState.tsx create mode 100644 src/widgets/layout/ProfileFormLayout.tsx diff --git a/src/entities/user/ui/UserCard.tsx b/src/entities/user/ui/UserCard.tsx index 816eacf..546a522 100644 --- a/src/entities/user/ui/UserCard.tsx +++ b/src/entities/user/ui/UserCard.tsx @@ -1,21 +1,11 @@ import { useAuth0 } from "@auth0/auth0-react"; -import React, { useState } from "react"; +import React from "react"; import { styled } from "styled-components"; import avatar from "../../../../public/icons/avatar.svg"; import CardButton from "../../../shared/ui/cardButton/CardButton"; - -const Container = styled.div` - font-family: var(--font); - color: #000; - display: flex; - width: 100%; - padding: 20px; - justify-content: space-between; - align-items: center; - border-radius: 10px; - background: var(--white, #fff); - box-shadow: 0px 0px 4px 0px #e5eaf8; -`; +import ProfileFormLayout from "../../../widgets/layout/ProfileFormLayout"; +import profileFormState from "../../../pages/Profile/store/profileFormState"; +import { observer } from "mobx-react-lite"; const User = styled.div` height: 100%; @@ -69,16 +59,19 @@ const AccessText = styled.a` } `; -const UserCard: React.FC = () => { - const [isEmailConfirmed, setIsEmailConfirmed] = useState(false); +const UserCard: React.FC = observer(() => { const { user } = useAuth0(); const sendAccess = () => { - setIsEmailConfirmed(true); + profileFormState.confirmEmail(); + }; + + const openForm = () => { + profileFormState.openEditForm(); }; return ( - + @@ -87,7 +80,7 @@ const UserCard: React.FC = () => { {user?.email} {!user?.email_verified ? ( - {isEmailConfirmed ? ( + {profileFormState.isEmailConfirmed ? ( На вашу почту выслано письмо с подтверждением @@ -103,9 +96,9 @@ const UserCard: React.FC = () => { - Изменить - + Изменить + ); -}; +}); export default UserCard; diff --git a/src/features/editUser/index.ts b/src/features/editUser/index.ts new file mode 100644 index 0000000..f33886e --- /dev/null +++ b/src/features/editUser/index.ts @@ -0,0 +1 @@ +export { EditUserForm } from "./ui/EditUserForm"; diff --git a/src/features/editUser/ui/EditUserForm.tsx b/src/features/editUser/ui/EditUserForm.tsx new file mode 100644 index 0000000..94a16b7 --- /dev/null +++ b/src/features/editUser/ui/EditUserForm.tsx @@ -0,0 +1,177 @@ +import React, { useState } from "react"; +import styled from "styled-components"; +import ProfileFormLayout from "../../../widgets/layout/ProfileFormLayout"; +import { useAuth0 } from "@auth0/auth0-react"; +import avatarDefault from "../../../../public/icons/avatar.svg"; +import FormButton from "../../../shared/ui/formButton/FormButton"; +import profileFormState from "../../../pages/Profile/store/profileFormState"; +import { observer } from "mobx-react-lite"; + +const Form = styled.form` + width: 100%; + height: 100%; + display: flex; + justify-content: space-between; + align-items: center; + + &::before { + content: ""; + position: absolute; + top: -2px; + bottom: -2px; + left: -2px; + right: -2px; + border-radius: 12px; + background: linear-gradient( + 223deg, + rgba(255, 178, 64, 0.9) 0%, + rgba(216, 97, 196, 0.9) 50.52%, + rgba(23, 94, 241, 0.9) 100% + ); + z-index: -1; + } +`; + +const User = styled.div` + height: 100%; + display: flex; + align-items: center; + gap: 20px; +`; + +const Avatar = styled.div` + width: 86px; + height: 86px; + border-radius: 10px; + border: 2px dashed #175ef1; + position: relative; +`; + +const InputAvatar = styled.input` + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + color: transparent; + + &:hover { + cursor: pointer; + } + + &::file-selector-button { + display: none; + } +`; + +const Info = styled.div` + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; +`; + +const Name = styled.input` + width: 100%; + font-size: 22px; + font-weight: 500; +`; + +const Email = styled.div` + display: flex; + align-items: center; + gap: 12px; +`; + +const EmailText = styled.div` + font-size: 20px; + font-weight: 300; + line-height: normal; +`; + +const AccessEmail = styled.a` + font-size: 20px; + font-weight: 300; + line-height: normal; +`; + +const AccessText = styled.a` + color: var(--red, #f95a39); + + &:hover { + text-decoration: underline; + cursor: pointer; + } +`; + +export const EditUserForm: React.FC = observer(() => { + const { user } = useAuth0(); + const [avatar, setAvatar] = useState(user?.picture || avatarDefault); + const [name, setName] = useState(user?.name); + + const sendAccess = () => { + profileFormState.confirmEmail(); + }; + + const saveChanges = () => { + profileFormState.closeEditForm(); + }; + + const onImageChange = (event: React.ChangeEvent) => { + if (event.target.files && event.target.files[0]) { + setAvatar(URL.createObjectURL(event.target.files[0])); + } + }; + + return ( + + + + + + + + + ) => + setName(e.target.value) + } + autoFocus + /> + + {user?.email} + {!user?.email_verified ? ( + + {profileFormState.isEmailConfirmed ? ( + + На вашу почту выслано письмо с подтверждением + + ) : ( + + Подтвердите почту + + )} + + ) : ( + "" + )} + + + + Сохранить + + + ); +}); diff --git a/src/pages/Profile/Profile.tsx b/src/pages/Profile/Profile.tsx index 1f63a56..48f49f2 100644 --- a/src/pages/Profile/Profile.tsx +++ b/src/pages/Profile/Profile.tsx @@ -3,6 +3,9 @@ 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``; @@ -18,17 +21,17 @@ const ProfileCard = styled.div` margin: 0 121px 73px 123px; `; -const Profile: React.FC = () => { +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/cardButton/CardButton.tsx b/src/shared/ui/cardButton/CardButton.tsx index 4cc95ef..d2b75ac 100644 --- a/src/shared/ui/cardButton/CardButton.tsx +++ b/src/shared/ui/cardButton/CardButton.tsx @@ -23,10 +23,11 @@ const Button = styled.button` interface Props { children?: string; + onClick?: () => void; } -const CardButton: React.FC = ({ children }) => { - return {children}; +const CardButton: React.FC = ({ children, onClick }) => { + return {children}; }; export default CardButton; 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; From 88a5e6a729b405db698028a1eae870f7f36c2e9d Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Aug 2023 19:06:14 +0600 Subject: [PATCH 2/6] fix header layout --- src/pages/Join/Join.tsx | 6 ++++-- src/pages/Join/styles.module.css | 7 +++++++ src/widgets/layout/Header.tsx | 4 +++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/pages/Join/Join.tsx b/src/pages/Join/Join.tsx index 91d57dd..0d23159 100644 --- a/src/pages/Join/Join.tsx +++ b/src/pages/Join/Join.tsx @@ -16,8 +16,10 @@ const Join: React.FC = () => { - - Сетевой учебный класс + + + Сетевой учебный класс + 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/widgets/layout/Header.tsx b/src/widgets/layout/Header.tsx index 243c5cd..1bcf9b1 100644 --- a/src/widgets/layout/Header.tsx +++ b/src/widgets/layout/Header.tsx @@ -14,7 +14,9 @@ const Container = styled.div` background-color: var(--white); `; -const Left = styled.div``; +const Left = styled.div` + +`; const Logo = styled.a` text-align: center; From 8eb248d30afb2c47e9a3d64e3c63b64133b122d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 17 Aug 2023 19:28:41 +0600 Subject: [PATCH 3/6] fix opening create form --- src/entities/room/ui/RoomCard.tsx | 2 +- src/shared/ui/Tooltip.tsx | 6 ++++-- src/widgets/FunctionsList/functionsObject.tsx | 2 +- src/widgets/RoomsList.tsx | 2 -- src/widgets/layout/Navbar.tsx | 9 ++++++++- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/entities/room/ui/RoomCard.tsx b/src/entities/room/ui/RoomCard.tsx index 16c51cb..bc7919a 100644 --- a/src/entities/room/ui/RoomCard.tsx +++ b/src/entities/room/ui/RoomCard.tsx @@ -102,7 +102,7 @@ const RoomCard: React.FC = ({ room }) => { )} - + = ({ active, children }) => { +const Tooltip: React.FC = ({ active, children, message }) => { return ( = ({ active, children }) => { : { opacity: 0, visibility: "hidden" } } > - Ссылка скопирована! + {message} {children} diff --git a/src/widgets/FunctionsList/functionsObject.tsx b/src/widgets/FunctionsList/functionsObject.tsx index dbb9006..808d94f 100644 --- a/src/widgets/FunctionsList/functionsObject.tsx +++ b/src/widgets/FunctionsList/functionsObject.tsx @@ -10,7 +10,7 @@ const functions: IFunction[] = [ { icon: createClass, iconActive: createClassActive, - title: "Новый класс", + title: "Мои классы", description: "Создать свой класс и провести занятие онлайн", link: "/lobby", onClick: () => { diff --git a/src/widgets/RoomsList.tsx b/src/widgets/RoomsList.tsx index 791640b..30a0582 100644 --- a/src/widgets/RoomsList.tsx +++ b/src/widgets/RoomsList.tsx @@ -75,8 +75,6 @@ const RoomsList: React.FC = observer(({ rooms, loading, error }) => { console.log(searchedRooms); }; - console.log(rooms); - return ( diff --git a/src/widgets/layout/Navbar.tsx b/src/widgets/layout/Navbar.tsx index 2b30891..c7d9036 100644 --- a/src/widgets/layout/Navbar.tsx +++ b/src/widgets/layout/Navbar.tsx @@ -70,7 +70,14 @@ const Navbar: React.FC = observer(() => { } function addRoom() { - roomsFormState.openCreateForm(); + if (roomsFormState.state === '' && navbarState.state === 'my') { + roomsFormState.openCreateForm(); + return 0; + } + if (roomsFormState.state === 'create') { + roomsFormState.closeCreateForm(); + return 0; + } } function editRooms() { From 06e6f7a1baa1ff3b78ce991376cff6607b17ac8c Mon Sep 17 00:00:00 2001 From: BodySites <100404530+BodySites@users.noreply.github.com> Date: Thu, 17 Aug 2023 21:08:06 +0600 Subject: [PATCH 4/6] put styles for ProfilePage in a separate file --- src/features/editUser/ui/EditUserForm.tsx | 109 +++++---------------- src/features/editUser/ui/styles.module.css | 71 ++++++++++++++ 2 files changed, 93 insertions(+), 87 deletions(-) create mode 100644 src/features/editUser/ui/styles.module.css diff --git a/src/features/editUser/ui/EditUserForm.tsx b/src/features/editUser/ui/EditUserForm.tsx index 94a16b7..90b19db 100644 --- a/src/features/editUser/ui/EditUserForm.tsx +++ b/src/features/editUser/ui/EditUserForm.tsx @@ -1,5 +1,6 @@ import React, { useState } from "react"; import styled from "styled-components"; +import styles from "./styles.module.css"; import ProfileFormLayout from "../../../widgets/layout/ProfileFormLayout"; import { useAuth0 } from "@auth0/auth0-react"; import avatarDefault from "../../../../public/icons/avatar.svg"; @@ -32,78 +33,6 @@ const Form = styled.form` } `; -const User = styled.div` - height: 100%; - display: flex; - align-items: center; - gap: 20px; -`; - -const Avatar = styled.div` - width: 86px; - height: 86px; - border-radius: 10px; - border: 2px dashed #175ef1; - position: relative; -`; - -const InputAvatar = styled.input` - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - color: transparent; - - &:hover { - cursor: pointer; - } - - &::file-selector-button { - display: none; - } -`; - -const Info = styled.div` - display: flex; - flex-direction: column; - align-items: flex-start; - gap: 8px; -`; - -const Name = styled.input` - width: 100%; - font-size: 22px; - font-weight: 500; -`; - -const Email = styled.div` - display: flex; - align-items: center; - gap: 12px; -`; - -const EmailText = styled.div` - font-size: 20px; - font-weight: 300; - line-height: normal; -`; - -const AccessEmail = styled.a` - font-size: 20px; - font-weight: 300; - line-height: normal; -`; - -const AccessText = styled.a` - color: var(--red, #f95a39); - - &:hover { - text-decoration: underline; - cursor: pointer; - } -`; - export const EditUserForm: React.FC = observer(() => { const { user } = useAuth0(); const [avatar, setAvatar] = useState(user?.picture || avatarDefault); @@ -132,17 +61,23 @@ export const EditUserForm: React.FC = observer(() => { encType="multipart/form-data" onSubmit={saveChanges} > - - + + - - - - + + + ) => @@ -150,26 +85,26 @@ export const EditUserForm: React.FC = observer(() => { } autoFocus /> - - {user?.email} + + {user?.email} {!user?.email_verified ? ( - + {profileFormState.isEmailConfirmed ? ( На вашу почту выслано письмо с подтверждением ) : ( - + Подтвердите почту - + )} - + ) : ( "" )} - - - + + + Сохранить diff --git a/src/features/editUser/ui/styles.module.css b/src/features/editUser/ui/styles.module.css new file mode 100644 index 0000000..d3e9e4a --- /dev/null +++ b/src/features/editUser/ui/styles.module.css @@ -0,0 +1,71 @@ +.user { + height: 100%; + display: flex; + align-items: center; + gap: 20px; +} + +.avatar { + width: 86px; + height: 86px; + border-radius: 10px; + border: 2px dashed #175ef1; + position: relative; +} + +.inputAvatar { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + color: transparent; + + &:hover { + cursor: pointer; + } + + &::file-selector-button { + display: none; + } +} + +.info { + display: flex; + flex-direction: column; + align-items: flex-start; + gap: 8px; +} + +.name { + width: 100%; + font-size: 22px; + font-weight: 500; +} + +.email { + display: flex; + align-items: center; + gap: 12px; +} + +.emailText { + font-size: 20px; + font-weight: 300; + line-height: normal; +} + +.accessEmail { + font-size: 20px; + font-weight: 300; + line-height: normal; +} + +.accessText { + color: var(--red, #f95a39); + + &:hover { + text-decoration: underline; + cursor: pointer; + } +} From e1970891e439b7bd17a1842b432d1252cb9cfb12 Mon Sep 17 00:00:00 2001 From: BodySites <100404530+BodySites@users.noreply.github.com> Date: Thu, 17 Aug 2023 21:11:22 +0600 Subject: [PATCH 5/6] fix error --- src/features/Copy/ui/CopyLink.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/features/Copy/ui/CopyLink.tsx b/src/features/Copy/ui/CopyLink.tsx index 459ceb0..73b3445 100644 --- a/src/features/Copy/ui/CopyLink.tsx +++ b/src/features/Copy/ui/CopyLink.tsx @@ -28,7 +28,7 @@ export const CopyLink: React.FC = () => { } return ( - + Date: Sat, 19 Aug 2023 22:56:54 +0600 Subject: [PATCH 6/6] fix creating classes --- .env.development | 2 +- .env.production | 2 +- src/entities/room/ui/RoomCard.tsx | 2 +- src/entities/user/api/addUser.ts | 25 ------------------- src/entities/user/api/useAddUser.ts | 34 ++++++++++++++++++++++++++ src/features/createRoom/model/index.ts | 4 +-- src/pages/Join/Join.tsx | 7 ++++++ 7 files changed, 46 insertions(+), 30 deletions(-) delete mode 100644 src/entities/user/api/addUser.ts create mode 100644 src/entities/user/api/useAddUser.ts diff --git a/.env.development b/.env.development index 4330e9d..49882ac 100644 --- a/.env.development +++ b/.env.development @@ -2,4 +2,4 @@ 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' -VITE_VIDEOSDK_HREF='' \ No newline at end of file +VITE_VIDEOSDK_APP='http://localhost:3000/react-rtc-demo' \ No newline at end of file diff --git a/.env.production b/.env.production index f31acec..169fb1e 100644 --- a/.env.production +++ b/.env.production @@ -2,4 +2,4 @@ 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' -VITE_VIDEOSDK_HREF='' \ No newline at end of file +VITE_VIDEOSDK_APP='https://network-class-videosdk-client.pages.dev' \ No newline at end of file diff --git a/src/entities/room/ui/RoomCard.tsx b/src/entities/room/ui/RoomCard.tsx index bc7919a..62fc3f4 100644 --- a/src/entities/room/ui/RoomCard.tsx +++ b/src/entities/room/ui/RoomCard.tsx @@ -101,7 +101,7 @@ const RoomCard: React.FC = ({ room }) => { )} - + { - const API = String(import.meta.env.VITE_API); - - const newUser = { - full_name: fullname, - photo_url: photo_url, - email: email - } - - fetch(`${API}/users`, { - method : 'POST', - headers: { - 'Content-type': 'application/json', - }, - body : JSON.stringify(newUser), - }) - .then(response => response.text()) - .then(response => { - response = JSON.parse(response); - console.log(response); - userState.addUser(JSON.parse(response)); - }) -} diff --git a/src/entities/user/api/useAddUser.ts b/src/entities/user/api/useAddUser.ts new file mode 100644 index 0000000..f53e1db --- /dev/null +++ b/src/entities/user/api/useAddUser.ts @@ -0,0 +1,34 @@ +import { useState, useEffect } from 'react'; + +export const useAddUser = (fullname: any, photo_url: string, email: any) => { + const API = String(import.meta.env.VITE_API); + const [user, setUser] = useState({}); + + const newUser = { + full_name: fullname, + photo_url: photo_url, + email: email + } + + async function createUser() { + await fetch(`${API}/users`, { + method : 'POST', + headers: { + 'Content-type': 'application/json', + }, + body : JSON.stringify(newUser), + }) + .then(response => response.text()) + .then(response => { + response = JSON.parse(response); + console.log(response); + setUser(response); + }) + } + + useEffect(() => { + createUser(); + }, []) + + return user; +} diff --git a/src/features/createRoom/model/index.ts b/src/features/createRoom/model/index.ts index fbca02c..ff15fbf 100644 --- a/src/features/createRoom/model/index.ts +++ b/src/features/createRoom/model/index.ts @@ -1,11 +1,11 @@ import { IUser } from "../../../shared/api/models"; -import { AddUserThunk } from "../../../entities/user/api/addUser"; export const CreateThunk = (event: any, title: string, isPublic: boolean, user: IUser) => { event.preventDefault(); - AddUserThunk(user?.name, 'test', user?.email); const API = String(import.meta.env.VITE_API); + console.log(user?.email); + const newRoom = { title: title, url: 'https://network-class.pages.dev/joinlesson/1', diff --git a/src/pages/Join/Join.tsx b/src/pages/Join/Join.tsx index 0d23159..2e0419a 100644 --- a/src/pages/Join/Join.tsx +++ b/src/pages/Join/Join.tsx @@ -9,8 +9,15 @@ 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 (