diff --git a/vite-project/eslint.config.js b/vite-project/eslint.config.js index ec2b712d..8cf17d62 100644 --- a/vite-project/eslint.config.js +++ b/vite-project/eslint.config.js @@ -1,33 +1,34 @@ -import js from '@eslint/js' -import globals from 'globals' -import reactHooks from 'eslint-plugin-react-hooks' -import reactRefresh from 'eslint-plugin-react-refresh' +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; export default [ - { ignores: ['dist'] }, + { ignores: ["dist"] }, { - files: ['**/*.{js,jsx}'], + files: ["**/*.{js,jsx}"], languageOptions: { ecmaVersion: 2020, globals: globals.browser, parserOptions: { - ecmaVersion: 'latest', + ecmaVersion: "latest", ecmaFeatures: { jsx: true }, - sourceType: 'module', + sourceType: "module", }, }, plugins: { - 'react-hooks': reactHooks, - 'react-refresh': reactRefresh, + "react-hooks": reactHooks, + "react-refresh": reactRefresh, }, rules: { ...js.configs.recommended.rules, ...reactHooks.configs.recommended.rules, - 'no-unused-vars': ['error', { varsIgnorePattern: '^[A-Z_]' }], - 'react-refresh/only-export-components': [ - 'warn', + "no-unused-vars": ["warn", { varsIgnorePattern: "^[A-Z_]" }], + "react-refresh/only-export-components": [ + "warn", { allowConstantExport: true }, ], + "no-console": ["warn", { allow: ["warn", "error"] }], }, }, -] +]; diff --git a/vite-project/package-lock.json b/vite-project/package-lock.json index 7f1e275a..58b22412 100644 --- a/vite-project/package-lock.json +++ b/vite-project/package-lock.json @@ -8,12 +8,14 @@ "name": "vite-project", "version": "0.0.0", "dependencies": { + "@tanstack/react-query": "^5.85.5", "axios": "^1.11.0", "dotenv": "^17.2.1", "react": "^19.1.0", "react-dom": "^19.1.0", "react-responsive": "^10.0.1", - "react-router": "^7.7.0" + "react-router": "^7.7.0", + "zustand": "^5.0.8" }, "devDependencies": { "@eslint/js": "^9.25.0", @@ -1311,6 +1313,32 @@ "win32" ] }, + "node_modules/@tanstack/query-core": { + "version": "5.85.5", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.85.5.tgz", + "integrity": "sha512-KO0WTob4JEApv69iYp1eGvfMSUkgw//IpMnq+//cORBzXf0smyRwPLrUvEe5qtAEGjwZTXrjxg+oJNP/C00t6w==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.85.5", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.85.5.tgz", + "integrity": "sha512-/X4EFNcnPiSs8wM2v+b6DqS5mmGeuJQvxBglmDxl6ZQb5V26ouD2SJYAcC3VjbNwqhY2zjxVD15rDA5nGbMn3A==", + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "5.85.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1374,7 +1402,7 @@ "version": "19.1.8", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.8.tgz", "integrity": "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -1683,7 +1711,7 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, + "devOptional": true, "license": "MIT" }, "node_modules/debug": { @@ -3205,6 +3233,35 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zustand": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.8.tgz", + "integrity": "sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==", + "license": "MIT", + "engines": { + "node": ">=12.20.0" + }, + "peerDependencies": { + "@types/react": ">=18.0.0", + "immer": ">=9.0.6", + "react": ">=18.0.0", + "use-sync-external-store": ">=1.2.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "immer": { + "optional": true + }, + "react": { + "optional": true + }, + "use-sync-external-store": { + "optional": true + } + } } } } diff --git a/vite-project/package.json b/vite-project/package.json index f1c069c4..596ed67d 100644 --- a/vite-project/package.json +++ b/vite-project/package.json @@ -10,12 +10,14 @@ "preview": "vite preview" }, "dependencies": { + "@tanstack/react-query": "^5.85.5", "axios": "^1.11.0", "dotenv": "^17.2.1", "react": "^19.1.0", "react-dom": "^19.1.0", "react-responsive": "^10.0.1", - "react-router": "^7.7.0" + "react-router": "^7.7.0", + "zustand": "^5.0.8" }, "devDependencies": { "@eslint/js": "^9.25.0", diff --git a/vite-project/public/images/ic_plus.svg b/vite-project/public/images/ic_plus.svg new file mode 100644 index 00000000..5bb9abf5 --- /dev/null +++ b/vite-project/public/images/ic_plus.svg @@ -0,0 +1,4 @@ + + + + diff --git a/vite-project/public/images/ic_x.svg b/vite-project/public/images/ic_x.svg new file mode 100644 index 00000000..5e2e3e92 --- /dev/null +++ b/vite-project/public/images/ic_x.svg @@ -0,0 +1,4 @@ + + + + diff --git a/vite-project/src/App.css b/vite-project/src/App.css index 8152f4e9..cd559b3c 100644 --- a/vite-project/src/App.css +++ b/vite-project/src/App.css @@ -1,5 +1,17 @@ :root { --primary100: #3692ff; + --primary200: #1967d6; + --primary300: #1251aa; + + --gray50: #f9fafb; + --gray100: #f3f4f6; + --gray200: #e5e7eb; + --gray400: #9ca3af; + --gray500: #6b7280; + --gray600: #4b5563; + --gray700: #374151; + --gray800: #1f2937; + --gray900: #111827; } * { @@ -45,12 +57,69 @@ p { .wrap { padding: 0 240px; +} + +.btn-large { + height: 56px; + padding: 16px 124px; + border-radius: 40px; + border: none; + font-weight: 600; + font-size: 20px; + color: var(--gray100); +} + +.btn-medium { + height: 48px; + padding: 12px 71px; + border-radius: 40px; + border: none; + font-weight: 600; + font-size: 18px; + color: var(--gray100); +} + +.btn-small-40 { + height: 42px; + padding: 12px 23px; + border-radius: 8px; + border: none; + font-weight: 600; + font-size: 16px; + color: var(--gray100); +} + +.btn-small-48 { + height: 48px; + padding: 12px 23px; + border-radius: 8px; + border: none; + font-weight: 600; + font-size: 16px; + color: var(--gray100); +} + +.btn-large:disabled, +.btn-medium:disabled, +.btn-small-40:disabled, +.btn-small-48:disabled { + background-color: #9ca3af; +} + +.ic-x-btn { + background-color: var(--gray400); + color: #f9fafb; + width: 20px; + height: 20px; + border-radius: 100%; display: flex; justify-content: center; + align-items: center; } .container { max-width: 1200px; + margin: 0 auto; } @media screen and (max-width: 1199px) { diff --git a/vite-project/src/App.jsx b/vite-project/src/App.jsx index b43d95c5..8ad11bfe 100644 --- a/vite-project/src/App.jsx +++ b/vite-project/src/App.jsx @@ -1,10 +1,9 @@ -import { useState } from "react"; import "./App.css"; import { Route, Routes, Navigate } from "react-router"; -import ItemsPage from "./pages/Items-Page/ItemsPage"; -import AddItemPage from "./pages/AddItem-Page/AddItemPage"; +import ItemsPage from "./pages/ItemsPage"; +import AddItemPage from "./pages/AddItemPage"; import Layout from "./layout/Layout"; -import FreeBoard from "./pages/FreeBoard-Page/FreeBoard"; +import FreeBoard from "./pages/FreeBoardPage"; function App() { return ( diff --git a/vite-project/src/utils/api.js b/vite-project/src/api/axiosInstance.js similarity index 75% rename from vite-project/src/utils/api.js rename to vite-project/src/api/axiosInstance.js index 00661b44..6fcdc49a 100644 --- a/vite-project/src/utils/api.js +++ b/vite-project/src/api/axiosInstance.js @@ -2,9 +2,11 @@ import axios from "axios"; const VITE_BACKEND_URL = import.meta.env.VITE_BACKEND_URL; -export const instance = axios.create({ +const instance = axios.create({ baseURL: VITE_BACKEND_URL, headers: { "Content-Type": "application/json", }, }); + +export default instance; diff --git a/vite-project/src/common/Dropdown/DropDown.jsx b/vite-project/src/common/Dropdown/index.jsx similarity index 100% rename from vite-project/src/common/Dropdown/DropDown.jsx rename to vite-project/src/common/Dropdown/index.jsx diff --git a/vite-project/src/common/ErrorMessage/ErrorMessage.style.css b/vite-project/src/common/ErrorMessage/ErrorMessage.style.css new file mode 100644 index 00000000..732cd942 --- /dev/null +++ b/vite-project/src/common/ErrorMessage/ErrorMessage.style.css @@ -0,0 +1,4 @@ +.error-message { + color: #f74747; + padding: 6px 8px; +} diff --git a/vite-project/src/common/ErrorMessage/index.jsx b/vite-project/src/common/ErrorMessage/index.jsx new file mode 100644 index 00000000..a51f4e39 --- /dev/null +++ b/vite-project/src/common/ErrorMessage/index.jsx @@ -0,0 +1,7 @@ +import "./ErrorMessage.style.css"; + +const ErrorMessage = ({ errorMessage }) => { + return
{errorMessage}
; +}; + +export default ErrorMessage; diff --git a/vite-project/src/common/LoadingSpinner/LoadingSpinner.style.css b/vite-project/src/common/LoadingSpinner/LoadingSpinner.style.css new file mode 100644 index 00000000..8bddf0c0 --- /dev/null +++ b/vite-project/src/common/LoadingSpinner/LoadingSpinner.style.css @@ -0,0 +1,21 @@ +.spinner-container { + display: flex; + justify-content: center; + align-items: center; + height: 100px; +} + +.spinner { + width: 40px; + height: 40px; + border: 4px solid rgba(0, 0, 0, 0.1); + border-left-color: var(--primary100); + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} diff --git a/vite-project/src/common/LoadingSpinner/index.jsx b/vite-project/src/common/LoadingSpinner/index.jsx new file mode 100644 index 00000000..c33e26eb --- /dev/null +++ b/vite-project/src/common/LoadingSpinner/index.jsx @@ -0,0 +1,11 @@ +import "./LoadingSpinner.style.css"; + +const LoadingSpinner = () => { + return ( +
+
+
+ ); +}; + +export default LoadingSpinner; diff --git a/vite-project/src/common/Navbar/Navbar.style.css b/vite-project/src/common/Navbar/Navbar.style.css index bb52a84a..379a9b7b 100644 --- a/vite-project/src/common/Navbar/Navbar.style.css +++ b/vite-project/src/common/Navbar/Navbar.style.css @@ -58,3 +58,9 @@ padding: 0 16px; } } + +@media screen and (max-width: 767px) { + .nav-logo { + width: 100px; + } +} diff --git a/vite-project/src/common/Navbar/Navbar.jsx b/vite-project/src/common/Navbar/index.jsx similarity index 72% rename from vite-project/src/common/Navbar/Navbar.jsx rename to vite-project/src/common/Navbar/index.jsx index 2014eb8e..de2624a3 100644 --- a/vite-project/src/common/Navbar/Navbar.jsx +++ b/vite-project/src/common/Navbar/index.jsx @@ -1,5 +1,5 @@ import React from "react"; -import { Link, NavLink } from "react-router"; +import { Link, NavLink, useLocation } from "react-router"; import "./Navbar.style.css"; import { useMediaQuery } from "react-responsive"; @@ -10,6 +10,7 @@ const navLinks = [ const Navbar = () => { const isMobile = useMediaQuery({ maxWidth: 767 }); + const location = useLocation(); return (
@@ -27,7 +28,16 @@ const Navbar = () => { diff --git a/vite-project/src/common/Pagination/Pagination.jsx b/vite-project/src/common/Pagination/index.jsx similarity index 100% rename from vite-project/src/common/Pagination/Pagination.jsx rename to vite-project/src/common/Pagination/index.jsx diff --git a/vite-project/src/common/Product-Card/ProductCard.style.css b/vite-project/src/common/ProductCard/ProductCard.style.css similarity index 100% rename from vite-project/src/common/Product-Card/ProductCard.style.css rename to vite-project/src/common/ProductCard/ProductCard.style.css diff --git a/vite-project/src/common/Product-Card/ProductCard.jsx b/vite-project/src/common/ProductCard/index.jsx similarity index 100% rename from vite-project/src/common/Product-Card/ProductCard.jsx rename to vite-project/src/common/ProductCard/index.jsx diff --git a/vite-project/src/common/Product-Card/ProductList.jsx b/vite-project/src/common/ProductList/index.jsx similarity index 69% rename from vite-project/src/common/Product-Card/ProductList.jsx rename to vite-project/src/common/ProductList/index.jsx index 3fe23879..10308393 100644 --- a/vite-project/src/common/Product-Card/ProductList.jsx +++ b/vite-project/src/common/ProductList/index.jsx @@ -1,10 +1,10 @@ import React from "react"; import { Link } from "react-router"; -import ProductCard from "./ProductCard"; -const ProductList = ({ allProducts, className }) => { +import ProductCard from "../ProductCard"; +const ProductList = ({ products, className }) => { return (