Skip to content

Commit

Permalink
+Docs +Profile-info
Browse files Browse the repository at this point in the history
  • Loading branch information
Daniil-Oberlev committed Aug 18, 2024
1 parent d24522b commit 1d7665f
Show file tree
Hide file tree
Showing 21 changed files with 5,634 additions and 275 deletions.
11 changes: 10 additions & 1 deletion app/(auth)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,22 @@ const Login = () => {
passwordError,
} = useAuthForm('login', formValues)

const handleFormSubmit = async (e: React.FormEvent) => {
e.preventDefault()
await handleSubmit(e)
}

return (
<div className={styles.container}>
<div>
<h1 className={styles.title}>Вход</h1>
<p className={styles.subtitle}>Войдите в свой аккаунт</p>
</div>
<form className={styles.form} onSubmit={handleSubmit} autoComplete="on">
<form
className={styles.form}
onSubmit={handleFormSubmit}
autoComplete="on"
>
<Layout.InputField
id="email"
label="Email"
Expand Down
2 changes: 1 addition & 1 deletion app/not-found.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Image from 'next/image'
import styles from '../styles/not-found.module.css'
import styles from '~/styles/not-found.module.css'

const NotFound = () => (
<main className={styles.main}>
Expand Down
55 changes: 4 additions & 51 deletions app/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -1,54 +1,7 @@
import Layout from '@/components/layout'
import Profile from '@/components/layout/Profile/Profile'

const ProfilePage = () => {
const mockProfileData = {
avatarUrl: 'https://via.placeholder.com/150',
name: 'Иван Иванов',
nickname: 'ivan_dev',
status: 'Доступен',
bio: 'Я опытный разработчик с более чем 5 годами опыта в разработке веб-приложений. Моя специализация - фронтенд разработка с использованием React и TypeScript.',
skills: [
{ name: 'JavaScript', level: 90 },
{ name: 'TypeScript', level: 85 },
{ name: 'React', level: 80 },
{ name: 'Next.js', level: 75 },
{ name: 'Tailwind CSS', level: 70 },
],
projects: [
{
title: 'Проект 1',
description: 'Описание проекта 1',
link: '#',
image: 'https://via.placeholder.com/400',
},
{
title: 'Проект 2',
description: 'Описание проекта 2',
link: '#',
image: 'https://via.placeholder.com/400',
},
],
reviews: [
{
client: 'ООО "Компания"',
comment: 'Отличная работа! Быстро и качественно.',
rating: 5,
clientImage: 'https://via.placeholder.com/50',
},
{
client: 'ИП "Клиент"',
comment: 'Хороший специалист, рекомендую!',
rating: 4,
clientImage: 'https://via.placeholder.com/50',
},
],
}

return (
<div className="min-h-screen bg-gray-100">
<Layout.Profile {...mockProfileData} />
</div>
)
const App = () => {
return <Profile name="Ваня КК" />
}

export default ProfilePage
export default App
2 changes: 1 addition & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const jestConfig = {
transform: {
'^.+\\.ts$': 'ts-jest',
},
testMatch: ['<rootDir>/src/test/utils/validation.test.ts'],
testMatch: ['<rootDir>/src/test/**/*.test.ts'],
collectCoverageFrom: ['src/**/*.{ts,tsx}', '!src/**/*.d.ts', '!src/test/**'],
coverageReporters: ['text'],
}
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@
"js-cookie": "^3.0.5",
"lucide-react": "^0.427.0",
"next": "14.2.5",
"prettier": "^3.3.1",
"prettier": "^3.3.3",
"react": "^18",
"react-dom": "^18",
"react-loading-skeleton": "^3.4.0",
"react-redux": "^9.1.2",
"redux": "^5.0.1",
"sitemap": "^8.0.0"
Expand Down
20 changes: 20 additions & 0 deletions src/Docs/getInitialLetter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Функции работы со строками

Этот документ описывает функции работы со строками, предоставленные в коде.

## `getInitialLetter(str: string | null | undefined): string`

Возвращает первую букву строки в верхнем регистре.

**Параметры:**

- `str` (string | null | undefined): Строка, из которой нужно извлечь первую букву. Может быть пустой, `null`, или `undefined`.

**Возвращает:**

- (string): Первая буква строки в верхнем регистре, или пустая строка, если входная строка пуста, `null`, или `undefined`.

**Критерии:**

- Строка обрезается с обеих сторон для удаления лишних пробелов.
- Если строка пустая или не определена, возвращается пустая строка.
105 changes: 105 additions & 0 deletions src/Docs/validation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
# Функции валидации

Этот документ описывает функции валидации, предоставленные в коде.

## `validateSingleCyrillicName(name: string, isFirstName: boolean): string`

Проверяет корректность одного кириллического имени (имя или фамилия).

**Параметры:**

- `name` (string): Имя или фамилия, которую нужно проверить.
- `isFirstName` (boolean): Флаг, указывающий, является ли проверяемое значение именем (`true`) или фамилией (`false`).

**Возвращает:**

- (string): Сообщение об ошибке, если имя не соответствует требованиям, иначе пустая строка.

**Критерии:**

- Имя должно содержать только кириллические буквы и пробелы.
- Имя должно быть не короче 2 символов.

## `validateName(name: string): string`

Проверяет корректность имени.

**Параметры:**

- `name` (string): Имя, которое нужно проверить.

**Возвращает:**

- (string): Сообщение об ошибке, если имя не соответствует требованиям, иначе пустая строка.

**Критерии:**

- Имя должно соответствовать критериям функции `validateSingleCyrillicName` с `isFirstName`, установленным в `true`.

## `validateEmail(email: string): string`

Проверяет корректность адреса электронной почты.

**Параметры:**

- `email` (string): Адрес электронной почты, который нужно проверить.

**Возвращает:**

- (string): Сообщение об ошибке, если адрес электронной почты не соответствует требованиям, иначе пустая строка.

**Критерии:**

- Адрес электронной почты должен соответствовать стандартному формату: `username@domain.tld`.

## `validatePassword(password: string): string`

Проверяет корректность пароля.

**Параметры:**

- `password` (string): Пароль, который нужно проверить.

**Возвращает:**

- (string): Сообщение об ошибке, если пароль не соответствует требованиям, иначе пустая строка.

**Критерии:**

- Пароль должен быть не короче 7 символов.

## `validateConfirmPassword(password: string, confirmPassword: string): string`

Проверяет соответствие пароля и его подтверждения.

**Параметры:**

- `password` (string): Оригинальный пароль.
- `confirmPassword` (string): Подтверждение пароля.

**Возвращает:**

- (string): Сообщение об ошибке, если пароли не совпадают, иначе пустая строка.

**Критерии:**

- Пароли должны совпадать.

## `validateFullName(fullName: string): string`

Проверяет корректность полного имени, состоящего из имени и фамилии.

**Параметры:**

- `fullName` (string): Полное имя, которое нужно проверить.

**Возвращает:**

- (string): Сообщение об ошибке, если полное имя не соответствует требованиям, иначе пустая строка.

**Критерии:**

- Полное имя должно состоять из двух частей (имя и фамилия), разделённых пробелом.
- Каждая часть должна соответствовать критериям, установленным в `validateSingleCyrillicName` (с соответствующим значением `isFirstName`).

---
7 changes: 6 additions & 1 deletion src/components/layout/Header/Header.module.css
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
.header {
display: flex;
justify-content: space-between;
justify-content: flex-end;
align-items: center;
padding: 10px 20px;
background-color: #fff;
border-bottom: 1px solid #ddd;
}

.header__buttons {
display: flex;
gap: 15px;
}
66 changes: 56 additions & 10 deletions src/components/layout/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,80 @@ import { initializeAuth } from '@/redux/slices/authSlice'
import { RootState } from '@/redux/store'
import Cookies from 'js-cookie'
import Link from 'next/link'
import { useEffect } from 'react'
import { useEffect, useState } from 'react'
import Skeleton from 'react-loading-skeleton'
import 'react-loading-skeleton/dist/skeleton.css'
import { useDispatch, useSelector } from 'react-redux'
import styles from './Header.module.css'

export const Header = () => {
const dispatch = useDispatch()
const isLoggedIn = useSelector((state: RootState) => state.auth.isLoggedIn)
const [showLoginOptions, setShowLoginOptions] = useState<boolean | null>(null)

// Убедитесь, что состояние инициализируется один раз
useEffect(() => {
const token = Cookies.get('token')
const loggedIn = localStorage.getItem('isLoggedIn') === 'true'
dispatch(initializeAuth())
const checkAuth = async () => {
if (typeof window === 'undefined') return

// Если есть токен или состояние в localStorage указывает на авторизацию
if (token || loggedIn) {
dispatch(initializeAuth())
const token = Cookies.get('token')
const loggedIn = localStorage.getItem('isLoggedIn') === 'true'

if (!token) {
setShowLoginOptions(true)
} else if (!loggedIn) {
try {
await dispatch(initializeAuth())
} catch (error) {
console.error('Ошибка инициализации авторизации:', error)
} finally {
setShowLoginOptions(false)
}
} else {
setShowLoginOptions(false)
}
}

checkAuth()
}, [dispatch])

// Прямое использование состояния isLoggedIn
useEffect(() => {
if (typeof window !== 'undefined') {
const token = Cookies.get('token')
const loggedIn = localStorage.getItem('isLoggedIn') === 'true'

if (token && loggedIn) {
setShowLoginOptions(false)
} else {
setShowLoginOptions(true)
}
}
}, [isLoggedIn])

if (showLoginOptions === null) {
return (
<header className={styles.header}>
<ul className={styles.header__buttons}>
<li>
<Skeleton width={80} height={16} />
</li>
<li>
<Skeleton width={40} height={16} />
</li>
<li>
<Skeleton width={80} height={16} />
</li>
</ul>
</header>
)
}

return (
<header className={styles.header}>
<ul className={styles.header__buttons}>
<li>
<Link href="/make-order">Сделать заказ</Link>
</li>
{!isLoggedIn && (
{(showLoginOptions || !isLoggedIn) && (
<>
<li>
<Link href="/login">Вход</Link>
Expand Down
29 changes: 0 additions & 29 deletions src/components/layout/Profile/Profile.d.ts

This file was deleted.

Loading

0 comments on commit 1d7665f

Please sign in to comment.