Skip to content

BlackDarkes/F.palace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

55 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

F.palace

📜 Лицензия

Этот проект распространяется под лицензией MIT.
Подробнее см. LICENSE.

Описание проекта: House — это сайт ресторана с модальными окнами, регистрацией(авторизацией) и fsd архитектурой, он написан на NextJS(TypeScript), NestJS и Scss. License: MIT NextJS NestJS Version

Функционал

  • Адаптивный дизайн
  • Анимации при наведении, фокусировании и нажатии
  • Анимированный header
  • Регистрация
  • Авторизация
  • JWT
  • Модальные окна
  • Валидация данных
  • Автоматическая прокрутка
  • Бизнес логика

Технологии

  • Frontend: React 18, TypeScript, Zustand, React Router 6, React Query, Axios, Vite, SCSS, SVGR. NextJS TypeScript
    Zustand React Query
    Zod React Hook Form Axios
    SCSS
    SVGR
    FSD
  • Backend: Express, MySQL, TypeORM. NestJS
    PostgreSQL
    TypeORM
  • Дизайн: Figma. Figma

Установка

  1. Клонирование репозитория:

    https://github.com/BlackDarkes/F.palace.git
    
  2. Запустите проект:

    Node.js >= 18.x npm >= 9.x

    cd api && npm install && npm start
    cd frontend && npm install && npm run dev

Пример кода

  1. React
"use client"

import { SubmitHandler, useForm } from "react-hook-form";
import { zodResolver } from "@hookform/resolvers/zod";
import z from "zod";
import { useLogin } from "../../api/useLogin";
import { ILogin } from "../../model/types/login.interface";
import { useStore } from "@/app/store/store";
import { Button } from "@/shared/ui";
import styles from "./LoginForm.module.scss";

const loginSchema = z.object({
  email: z
    .email("Некорректный формат email")
    .min(1, "Email не может быть пустым"),
  password: z.string().min(6, "Пароль должен содержать минимум 6 символов"),
});

export const LoginForm = () => {
  const {
    register,
    reset,
    formState: { errors },
    handleSubmit,
  } = useForm({
    resolver: zodResolver(loginSchema),
  });

  const { handleModelFormOpen, handleType } = useStore();

  const { mutate } = useLogin();

  const onSubmit: SubmitHandler<ILogin> = (data) => {
    mutate(data);
    reset();
    handleModelFormOpen();
  };

  return (
    <div className={styles.login}>
      <h2 className={styles.loginTitle}>Login</h2>

      <form action="" method="post" onSubmit={handleSubmit(onSubmit)}>
        <div className={styles.loginInputs}>
          <p>
            <input
              type="email"
              className={styles.loginInput}
              {...register("email")}
              placeholder="email..."
            />
            {errors.email && (
              <span className={styles.loginError}>{errors.email?.message}</span>
            )}
          </p>
          <p>
            <input
              type="password"
              className={styles.loginInput}
              {...register("password")}
              placeholder="password..."
            />
            {errors.password && (
              <span className={styles.loginError}>
                {errors.password?.message}
              </span>
            )}
          </p>
        </div>

        <div className={styles.loginButtons}>
          <button type="button"  className={styles.loginLink} onClick={() => handleType("register")}>
            To register
          </button>

          <Button>Login</Button>
        </div>
      </form>
    </div>
  );
};
  1. NestJs
import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { UsersEntity } from './entities/user.entity';
import { InjectRepository } from '@nestjs/typeorm';

@Injectable()
export class UserService {
  constructor(
    @InjectRepository(UsersEntity)
    private readonly userRepository: Repository<UsersEntity>,
  ) {}

  async getByEmail(email: string): Promise<UsersEntity | null> {
    return this.userRepository.findOne({ where: { email } })
  }

  async getById(id: string): Promise<UsersEntity | null> {
    return this.userRepository.findOne({ where: { id } });
  }

  async create(user: Partial<UsersEntity>) {
    const newUser = this.userRepository.create(user);
    const saveUser = this.userRepository.save(newUser);

    return saveUser;
  }
}

Структура проекта:

project/  
├── frontend/       
├── api/        
└── README.md  

Изображения проекта:

  1. Desktop изображения: Главная страница (десктоп) Рис. 1: Главная страница сайта в десктопной версии.

Бургер меню (десктоп) Рис. 2: Бургер меню в десктопной версии.

Форма авторизации (десктоп) Рис. 3: Форма авторизации.

Валидация формы (десктоп) Рис. 4: Валидация формы.

Toast сообщение (десктоп) Рис. 5: Toast сообщение.

Корзина (десктоп) Рис. 6: Корзина.

Поиск (десктоп) Рис. 7: Поиск.

  1. Mobile изображения:

    Главная страница (мобильный)

    Рис. 8: Главная страница сайта в мобильной версии.

    Header (мобильный)

    Рис. 9: Header в мобильной версии.

    Footer (мобильный)

    Рис. 10: Footer в мобильной версии.

    Бургер меню (мобильный)

    Рис. 11: Бургер меню в мобильной версии.

    Форма авторизации (мобильный)

    Рис. 12: Форма авторизации в мобильной версии.

    Форма авторизации с валидацией (мобильный)

    Рис. 13: Форма авторизации с валидацией.

    Toast сообщение от успешной авторизацией (мобильный)

    Рис. 14: Toast сообщение от успешной авторизацией в мобильной версии.

    Cart (мобильный)

    Рис. 15: Cart в мобильной версии.

    Search (мобильный)

    Рис. 16: Search в мобильной версии.