Thanks to visit codestin.com
Credit goes to github.com

Skip to content

lcaohoanq/shoppe

Repository files navigation

Shopee Clone Cross-Platform [Web, Mobile]

Preview

image

image

Quick Start

  • Via Go
cd scripts
./start start

Chức năng trong dự án

  • Authentication module: Quản lý bằng JWT

    • Đăng ký
    • Đăng nhập
    • Đăng xuất
  • Trang danh sách sản phẩm:

    • Có phân trang
    • Sort (sắp xếp) theo từng thuộc tính sản phẩm
    • filter nâng cao theo từng thuộc tính sản phẩm
    • Tìm kiếm sản phẩm
  • Trang chi tiết sản phẩm:

    • Hiển thị thông tin chi tiết
    • Ảnh hiển thị theo slider + hover zoom effect
    • Mô tả thì hiển thị rich text dạng WYSIWYG HTML
    • Có chức năng mua hàng
  • Giỏ hàng

    • Quản lý đơn hàng: Thêm, sửa, xóa sản phẩm
    • Mua hàng
  • Quản lý Profile khách hàng

    • Update thông tin cá nhân
    • Upload Avatar
    • Đổi mật khẩu
    • Xem tình trạng đơn hàng

Công nghệ sử dụng

  • UI / CSS Library: Tailwindcss + HeadlessUI
  • State Management: React Query cho async state và React Context cho state thường
  • Form Management: React Hook Form
  • Router: React Router
  • Build tool: Vite
  • API: Rest API dựa trên server mình cung cấp sẵn
  • Hỗ trợ đa ngôn ngữ với react.i18next
  • Hỗ trợ SEO với React Helmet
  • Mô hình hóa các component với story book
  • Unit Test
  • Và còn nhiều thứ nữa khi làm chúng ta sẽ áp dụng...

Cài đặt package cho dự án Vite React TS

Cài các depedency

Bộ ESLint và Prettier trước

Chúng ta sẽ cài hơi nhiều package 1 tí vì chúng ta setup từ đầu, còn Create React App setup sẵn 1 số thứ về ESLint rồi.

Dưới đây là những depedency mà chúng ta cần cài

  • ESLint: linter (bộ kiểm tra lỗi) chính

  • Prettier: code formatter chính

  • @typescript-eslint/eslint-plugin: ESLint plugin cung cấp các rule cho Typescript

  • @typescript-eslint/parser: Parser cho phép ESLint kiểm tra lỗi Typescript.

  • eslint-config-prettier: Bộ config ESLint để vô hiệu hóa các rule của ESLint mà xung đột với Prettier.

  • eslint-plugin-import: Để ESLint hiểu về cú pháp import... trong source code.

  • eslint-plugin-jsx-a11y: Kiểm tra các vấn đề liên quan đến accessiblity (Tính thân thiện website, ví dụ cho thiết bị máy đọc sách).

  • eslint-plugin-react: Các rule ESLint cho React

  • eslint-plugin-prettier: Dùng thêm 1 số rule Prettier cho ESLint

  • prettier-plugin-tailwindcss: Sắp xếp class tailwindcss

  • eslint-plugin-react-hooks: ESLint cho React hook

Chạy câu lệnh dưới đây

yarn add eslint prettier @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-plugin-prettier prettier-plugin-tailwindcss eslint-plugin-react-hooks -D

Cấu hình ESLint

Tạo file .eslintrc.cjs tại thư mục root

/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path')

module.exports = {
  extends: [
    // Chúng ta sẽ dùng các rule mặc định từ các plugin mà chúng ta đã cài.
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
    'plugin:import/recommended',
    'plugin:import/typescript',
    'plugin:jsx-a11y/recommended',
    'plugin:@typescript-eslint/recommended',
    // Disable các rule mà eslint xung đột với prettier.
    // Để cái này ở dưới để nó override các rule phía trên!.
    'eslint-config-prettier',
    'prettier'
  ],
  plugins: ['prettier'],
  settings: {
    react: {
      // Nói eslint-plugin-react tự động biết version của React.
      version: 'detect'
    },
    // Nói ESLint cách xử lý các import
    'import/resolver': {
      node: {
        paths: [path.resolve(__dirname, '')],
        extensions: ['.js', '.jsx', '.ts', '.tsx']
      }
    }
  },
  env: {
    node: true
  },
  rules: {
    // Tắt rule yêu cầu import React trong file jsx
    'react/react-in-jsx-scope': 'off',
    // Cảnh báo khi thẻ <a target='_blank'> mà không có rel="noreferrer"
    'react/jsx-no-target-blank': 'warn',
    // Tăng cường một số rule prettier (copy từ file .prettierrc qua)
    'prettier/prettier': [
      'warn',
      {
        arrowParens: 'always',
        semi: false,
        trailingComma: 'none',
        tabWidth: 2,
        endOfLine: 'auto',
        useTabs: false,
        singleQuote: true,
        printWidth: 120,
        jsxSingleQuote: true
      }
    ]
  }
}

Tạo file .eslintignore

node_modules/
dist/

Tạo file .prettierrc

{
  "arrowParens": "always",
  "semi": false,
  "trailingComma": "none",
  "tabWidth": 2,
  "endOfLine": "auto",
  "useTabs": false,
  "singleQuote": true,
  "printWidth": 120,
  "jsxSingleQuote": true
}

Tạo file .prettierignore

node_modules/
dist/

Thêm script mới vào package.json

  "scripts": {
    ...
    "lint": "eslint --ext ts,tsx src/",
    "lint:fix": "eslint --fix --ext ts,tsx src/",
    "prettier": "prettier --check \"src/**/(*.tsx|*.ts|*.css|*.scss)\"",
    "prettier:fix": "prettier --write \"src/**/(*.tsx|*.ts|*.css|*.scss)\""
  },

Cài editorconfig

Tạo file .editorconfig ở thư mục root

[*]
indent_size = 2
indent_style = space

Cấu hình tsconfig.json

Set "target": "ES2015""baseUrl": "." trong compilerOptions

Cài tailwindcss

Cài các package dưới đây: Tham khảo https://tailwindcss.com/docs/guides/vite

yarn add -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

Cấu hình file config

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {}
  },
  plugins: []
}

Thêm vào file src/index.css

@tailwind base;
@tailwind components;
@tailwind utilities;

Cấu hình vite config

Cài package @types/node để sử dụng node js trong file ts không bị lỗi

yarn add -D @types/node

file vite.config.ts

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import path from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [react()],
  server: {
    port: 3000
  },
  css: {
    devSourcemap: true
  },
  resolve: {
    alias: {
      src: path.resolve(__dirname, './src')
    }
  }
})

Cài extension và setup VS Code

Các Extension nên cài

  • ESLint

  • Prettier - Code formatter

  • Tailwindcss

  • EditorConfig for VS Code

Cấu hình VS Code

  • Bật Format On Save
  • Chọn Default Formatter là Prettier

Có 3 môi trường khi làm việc

  1. Môi trường VS Code, khi chúng ta đưa chuột vào click thì chạy đến đúng file
  2. Môi trường ES Lint
  3. Môi trường Terminal*

Ghi chú code

Code xóa các ký tự đặc biệt trên bàn phím

export const removeSpecialCharacter = (str: string) =>
  // eslint-disable-next-line no-useless-escape
  str.replace(
    /!|@|%|\^|\*|\(|\)|\+|\=|\<|\>|\?|\/|,|\.|\:|\;|\'|\"|\&|\#|\[|\]|~|\$|_|`|-|{|}|\||\\/g,
    ''
  )

Sữa lỗi Tailwindcss Extension không gợi ý class

Các bạn thêm đoạn code này vào settings.json của VS Code

{
  //...
  "tailwindCSS.experimental.classRegex": ["[a-zA-Z]*class[a-zA-Z]*='([^']+)'"]
}

Error Handling Flow

Request Flow:

1. JwtTokenFilter (Authentication)
   ├── No token/Invalid token -> AuthenticationEntryPoint (401)
   └── Valid token -> Continue

2. Security Filter (Authorization)
   ├── Insufficient role -> AccessDeniedHandler (403)
   └── Sufficient role -> Continue to Controller

  • Example scenario
// Scenario 1: Public endpoint (no JWT needed)
@GetMapping("/api/v1/public")
public ResponseEntity<?> publicEndpoint() {
// No security checks needed
return ResponseEntity.ok("Public data");
}

// Scenario 2: Protected endpoint (JWT required, any role)
@GetMapping("/api/v1/protected")
@PreAuthorize("isAuthenticated()")  // Just needs valid JWT
public ResponseEntity<?> protectedEndpoint() {
// User must have valid JWT
return ResponseEntity.ok("Protected data");
}

// Scenario 3: Role-specific endpoint (JWT + specific role required)
@GetMapping("/api/v1/admin")
@PreAuthorize("hasRole('MANAGER')")  // Needs JWT + MANAGER role
public ResponseEntity<?> adminEndpoint() {
// User must have valid JWT and MANAGER role
return ResponseEntity.ok("Admin data");
}
  • Request Flow
GET /roles/1 (no token)
↓
JwtTokenFilter (no token found)
↓
AuthenticationEntryPoint (returns 401 Unauthorized)

GET /roles/1 (invalid token)
↓
JwtTokenFilter (invalid token)
↓
AuthenticationEntryPoint (returns 401 Unauthorized)

GET /roles/1 (valid token, wrong role)
↓
JwtTokenFilter (valid token)
↓
@PreAuthorize check fails
↓
AccessDeniedHandler (returns 403 Forbidden)

Service Discovery

  • Eureka là một service discovery server, cho phép các microservices đăng ký và tìm kiếm nhau.
  • Spring Cloud Netflix Eureka là một thư viện giúp tích hợp Eureka vào ứng dụng Spring Boot.
  • Eureka Server là nơi các microservices đăng ký và tìm kiếm nhau.

Spring Cloud Gateway

  • Spring Cloud Gateway là một API Gateway cho phép định tuyến và xử lý các yêu cầu đến các microservices.