Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SOK-22] User profile page #13

Merged
merged 26 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
4110c13
[SOK-16]
gloginov Sep 27, 2024
1597380
[SOK-16]
gloginov Sep 27, 2024
442c996
[SOK-16]
gloginov Sep 27, 2024
ab29ccb
[SOK-16]
gloginov Sep 27, 2024
82efa62
Верстка главной страницы сайта
Timur233 Sep 26, 2024
c08cc7f
Error Page. Обернул станицу в layout
Timur233 Sep 27, 2024
901e7f1
Правки
Timur233 Sep 27, 2024
888ba27
- Добавил компонент заголовка PageTitle, заголовок
Timur233 Sep 27, 2024
a4590ad
Pre-commit settings
Timur233 Sep 26, 2024
0533838
Pre-commit settings
Timur233 Sep 26, 2024
5f8153f
Отключил eslint в некоторых фалах
Timur233 Sep 26, 2024
44d145a
format
Timur233 Sep 27, 2024
01a321d
Добавил поддержку jsx
Timur233 Sep 27, 2024
a61b010
added: profile page, change password page, from component, input comp…
VladToby Sep 30, 2024
f9a4f97
added: profile page, change password page, from component, input comp…
VladToby Sep 30, 2024
61ab747
Merge branch 'develop' of https://github.com/Timur233/falcon-tanks in…
Timur233 Sep 30, 2024
0d46090
fix profile page layout, fix styles
VladToby Oct 1, 2024
7b59c39
fix avatar component, fix profile page layout, fix default form class…
VladToby Oct 1, 2024
dff7926
Fix input, fix change password page, fix page & styles
VladToby Oct 2, 2024
3cb9e99
Fix profile page background images
VladToby Oct 2, 2024
b39dbb2
Merge with develop
VladToby Oct 2, 2024
ee6ad2b
Merge with develop
VladToby Oct 2, 2024
bd06de6
Fix form erros, rework user reducer, fix avatar src
VladToby Oct 2, 2024
eef02e0
Input max width
VladToby Oct 3, 2024
c3d32aa
Added overlay colors to vars
VladToby Oct 3, 2024
7bfdf3b
delete comments
VladToby Oct 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ TRAEFIK_NETWORK_NAME=traefik_traefik
DOCKER_BUILDKIT=1 #Build only stages required for target
COMPOSE_FILE=docker-compose.yml:docker-compose.dev.yml
VITE_AUTH_URL='https://ya-praktikum.tech/api/v2'
VITE_SRC_URL='https://ya-praktikum.tech/api/v2/resources'
2,851 changes: 1,615 additions & 1,236 deletions package-lock.json

Large diffs are not rendered by default.

13 changes: 6 additions & 7 deletions packages/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
},
"dependencies": {
"dotenv": "^16.0.2",
"esbuild-linux-64": "^0.15.18",
"eslint-config-prettier": "^8.5.0",
"prettier": "^2.7.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-toastify": "^10.0.5"
},
"devDependencies": {
"react-redux": "^9.1.2",
"axios": "^1.7.7",
"@reduxjs/toolkit": "^2.2.7",
"@testing-library/react": "^13.3.0",
"@types/jest": "^28.1.8",
Expand All @@ -28,19 +29,17 @@
"@typescript-eslint/eslint-plugin": "^5.35.1",
"@typescript-eslint/parser": "^5.35.1",
"@vitejs/plugin-react": "^2.0.1",
"axios": "^1.7.7",
"eslint": "^8.23.0",
"jest": "^28",
"jest-environment-jsdom": "^29.0.1",
"lefthook": "^1.7.15",
"normalize": "^0.3.1",
"prettier": "^2.7.1",
"react-redux": "^9.1.2",
"react-router-dom": "^6.26.2",
"sass": "^1.79.1",
"ts-jest": "^28.0.8",
"typescript": "^4.8.2",
"vite": "^3.0.7"
"vite": "^3.0.7",
"normalize": "^0.3.1",
"react-router-dom": "^6.26.2",
"sass": "^1.79.1"
},
"license": "MIT"
}
23 changes: 9 additions & 14 deletions packages/client/src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import AuthLayout from '@/layouts/AuthLayout/AuthLayout'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import RootLayout from '@/layouts/RootLayout/RootLayout'
import PrivateLayout from '@/layouts/PrivateLayout/PrivateLayout'
import AuthLayout from '@/layouts/AuthLayout/AuthLayout'
import PublicLayout from '@/layouts/PublicLayout/PublicLayout'
import RootLayout from '@/layouts/RootLayout/RootLayout'
import { Error } from '@/pages/Error/Error'
import { Forum } from '@/pages/Forum/Forum'
import { Game } from '@/pages/Game/Game'
import { Leaderboard } from '@/pages/Leaderboard/Leaderboard'
import { Main } from '@/pages/Main/Main'
import { ChangePassword } from '@/pages/Profile/ChangePassword'
import { ProfileEdit } from '@/pages/Profile/Edit'
import { Profile } from '@/pages/Profile/Profile'
import { SignIn } from '@/pages/SignIn/SignIn'
import { SignUp } from '@/pages/SignUp/SignUp'
import { Game } from '@/pages/Game/Game'
import { Forum } from '@/pages/Forum/Forum'
import { Error } from '@/pages/Error/Error'
import { Thread } from '@/pages/Thread/Thread'
import { createBrowserRouter, RouterProvider } from 'react-router-dom'
import { Leaderboard } from '@/pages/Leaderboard/Leaderboard'
import { Profile } from '@/pages/Profile/Profile'
import { ChangePassword } from '@/pages/Profile/ChangePassword'

const routerConfig = createBrowserRouter([
{
Expand Down Expand Up @@ -52,10 +51,6 @@ const routerConfig = createBrowserRouter([
path: '/profile',
element: <Profile />,
},
{
path: '/profile/edit',
element: <ProfileEdit />,
},
{
path: '/profile/change-password',
element: <ChangePassword />,
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added packages/client/src/assets/images/tank-dead.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions packages/client/src/components/common/Header/Header.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
@import '../../../scss/vars';

.main-header {
z-index: 100;
position: relative;

&__container {
display: flex;
justify-content: space-between;
Expand Down
58 changes: 58 additions & 0 deletions packages/client/src/components/ui/Avatar/Avatar.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
@import '../../../scss/vars.scss';

.avatar {
width: 160px;
max-width: 100%;
height: 158px;
max-height: 100%;
position: relative;

&__image, &__image-placeholder {
border-radius: 50%;
border: 5px solid $c_avatar-border-color;
width: inherit;
height: inherit;
}

&__overlay {
opacity: 0;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
transition: opacity 0.3s ease;
border-radius: 50%;

&:hover {
opacity: 1;
}
}

&:hover {
.overlay {
opacity: 1;
}
}

&__change-button {
border: none;
color: white;
font-size: 14px;
font-weight: bold;
text-transform: uppercase;
cursor: pointer;
padding: 8px 16px;
border-radius: 20px;
background-color: rgba(0, 0, 0, 0.5);
transition: background-color 0.3s ease;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Мне кажется, что такие цвета лучше вынести в константы

&:hover {
background-color: rgba(0, 0, 0, 0.7);
}
}
}
70 changes: 70 additions & 0 deletions packages/client/src/components/ui/Avatar/Avatar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import './Avatar.scss'
import React, { useState, useRef, useEffect } from 'react'
import { Image } from '@/components/ui/Image/Image'
import AvatarPlaceholder from '@/assets/images/avatar-placeholder.png'

export const AVATAR_SRC = import.meta.env.VITE_SRC_URL

export const Avatar = (props: {
src: string
containerClassName?: string
imageClassName?: string
onChange: (file: File) => void
}) => {
const { src, containerClassName, imageClassName, onChange } = props
const [previewUrl, setPreviewUrl] = useState<string | null>(null)
const fileInputRef = useRef<HTMLInputElement>(null)

useEffect(() => {
return () => {
if (previewUrl) {
URL.revokeObjectURL(previewUrl)
}
}
}, [previewUrl])

const handleFileChange = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0]
if (file) {
const fileUrl = URL.createObjectURL(file)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Логику с генерацией url я бы вынес в отдельный хук

setPreviewUrl(fileUrl)
onChange(file)
}
}

const handleButtonClick = () => {
fileInputRef.current?.click()
}

const displaySrc = previewUrl || src

return (
<div className={`avatar ${containerClassName}`}>
{displaySrc ? (
<Image
src={displaySrc}
className={`avatar__image ${imageClassName}`}
alt="Avatar"
/>
) : (
<Image
src={AvatarPlaceholder}
className={'avatar__image-placeholder'}
alt="Avatar"
/>
)}
<div className="avatar__overlay">
<button className={'avatar__change-button'} onClick={handleButtonClick}>
{'Изменить аватар'}
</button>
</div>
<input
ref={fileInputRef}
type="file"
accept="image/png, image/jpeg, image/jpg, image/gif"
onChange={handleFileChange}
style={{ display: 'none' }}
/>
</div>
)
}
22 changes: 22 additions & 0 deletions packages/client/src/components/ui/Button/Button.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
background-color: $c_button;
transition: border-color $animation-base-speed;

padding: 16px 12px;
padding: 16px 12px;
display: block;

Expand Down Expand Up @@ -47,3 +48,24 @@
text-shadow: $main-text-shadow;
}
}

.link-button {
background: none;
border-color: transparent;
font-size: $nav_link-font-size;
font-weight: $nav_link-font-weight;
letter-spacing: 1px;

text-shadow: $main-text-shadow;
text-transform: uppercase;
text-decoration: none;

color: $text-color;
transition: color $animation-base-speed;

&:hover,
&_active {
border-color: transparent;
color: $primary-color;
}
}
3 changes: 2 additions & 1 deletion packages/client/src/components/ui/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import './Button.scss'
import React from 'react'

export const Button = (props: {
text: string
className?: string | undefined
useFixWidth?: boolean | undefined
onClick?: () => void
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void | Promise<void>
}) => {
const { text, className, useFixWidth = false, onClick } = props
return (
Expand Down
Empty file.
17 changes: 17 additions & 0 deletions packages/client/src/components/ui/Form/Form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import './Form.scss'
import React from 'react'

interface FormProps {
className?: string
children?: React.ReactNode
onSubmit?: () => void
}

export const Form = (props: FormProps) => {
const { onSubmit, className, children } = props
return (
<form onSubmit={onSubmit} className={`form-fields ${className}`}>
{children}
</form>
)
}
10 changes: 10 additions & 0 deletions packages/client/src/components/ui/Image/Image.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
interface ImageProps {
src: string
className?: string
alt?: string
}

export const Image = (props: ImageProps) => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Честно говоря, не понимаю зачем нужен этот компонент, выглядит как будто проще написать img

const { src, className, alt } = props
return <img {...props} />
}
17 changes: 17 additions & 0 deletions packages/client/src/components/ui/Input/Input.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@import '../../../scss/vars';

.input-default {
padding: 12px 15px;
border-radius: 12px;
border: 2px solid $c_input-default-border;
text-align: center;
background-color: $c_default-background;
color: $c_font-default;
font-size: 18px;

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Забыл указать размер шрифта

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Исправил

&:focus-visible,
&:hover {
outline: none;
border-color: $c_input-default-border-hover;
}
}
32 changes: 32 additions & 0 deletions packages/client/src/components/ui/Input/Input.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import './Input.scss'
import React, { ChangeEventHandler, CSSProperties } from 'react'

interface InputProps {
placeholder?: string
name?: string
className?: string
disabled?: boolean
value?: string
type?: string
label?: string
onChange?: ChangeEventHandler | undefined
style?: CSSProperties | undefined
}

export const Input = (props: InputProps) => {
const { value, name, className, label, disabled, onChange, style } = props
return (
<div className={'input-wrapper'}>
{label && <label htmlFor={name}>{label}</label>}
<input
{...props}
name={name}
value={value}
className={`input-default ${className}`}
disabled={disabled}
onChange={onChange}
style={style}
/>
</div>
)
}
17 changes: 8 additions & 9 deletions packages/client/src/layouts/PrivateLayout/PrivateLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Header } from '@/components/common/Header/Header'
import {Outlet, useNavigate} from 'react-router-dom'
import {useSelector} from "react-redux";
import {RootState, useAppDispatch} from "@/store";
import {actions, getUser, UserType} from "@/store/reducers/auth-reducer";
import {useEffect} from "react";
import {toast} from "react-toastify";
import { Outlet, useNavigate } from 'react-router-dom'
import { useSelector } from 'react-redux'
import { RootState, useAppDispatch } from '@/store'
import { actions, getUser, UserType } from '@/store/reducers/auth-reducer'
import { useEffect } from 'react'
import { toast } from 'react-toastify'

export default function PrivateLayout() {
const user = useSelector<RootState, UserType>(state => state.authReducer.user)
Expand Down Expand Up @@ -34,19 +34,18 @@ export default function PrivateLayout() {
}, [])

// useEffect(() => {
// console.log(user)
// console.log(user)
// }, [user])
Copy link

@kyzinatra kyzinatra Oct 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Лишние комментарии стоит убрать


if (userIsLogged) {
return (
<div className="private-layout">
<Header className="private-layout__header"></Header>
<main className="private-layout__body">
<Outlet/>
<Outlet />
</main>
</div>
)
}
return user === null ? <h1>Загрузка...</h1> : <Outlet />

}
Loading
Loading