Skip to content

Commit

Permalink
Merge pull request #13 from Timur233/SOK-22_user_profile_page
Browse files Browse the repository at this point in the history
[SOK-22] User profile page
  • Loading branch information
VladToby authored Oct 3, 2024
2 parents a37af9c + 7bfdf3b commit af09e99
Show file tree
Hide file tree
Showing 25 changed files with 3,997 additions and 2,472 deletions.
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: $c_overlay-background;
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: $c_overlay-background;
transition: background-color 0.3s ease;

&:hover {
background-color: $c_overlay-background-hover;
}
}
}
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)
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) => {
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;

&: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>
)
}
19 changes: 7 additions & 12 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 @@ -33,20 +33,15 @@ export default function PrivateLayout() {
}
}, [])

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

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

0 comments on commit af09e99

Please sign in to comment.