diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md deleted file mode 100644 index 7df7432..0000000 --- a/.github/pull_request_template.md +++ /dev/null @@ -1,25 +0,0 @@ -**변경 내용 요약** - -- ex) 로그인 시, 네이버 소셜 로그인 기능을 추가했습니다. - -**변경 유형** - -어떤 변경 사항이 있나요? - -- [ ] 새로운 기능 추가 -- [ ] 버그 수정 -- [ ] CSS 등 사용자 UI 디자인 변경 -- [ ] 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경) -- [ ] 코드 리팩토링 -- [ ] 테스트 추가, 테스트 리팩토링 -- [ ] 빌드 부분 혹은 패키지 매니저 수정 -- [ ] 파일 혹은 폴더명 수정 -- [ ] 파일 혹은 폴더 삭제 - -**스크린샷/GIF (Optional)** - -- [UI 변경 사항이 있다면 스크린샷 또는 GIF를 첨부합니다.] - -**리뷰어에게 전달할 말 (Optional)** - -- [리뷰 시 특별히 확인해야 할 부분이 있다면 알려주세요.] diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml deleted file mode 100644 index eca5455..0000000 --- a/.github/workflows/deploy.yml +++ /dev/null @@ -1,52 +0,0 @@ -# name: Deploy to S3 And Invalidate Cloudfront - -# on: -# push: -# branches: -# - develop -# - main - -# jobs: -# deploy: -# runs-on: ubuntu-latest -# steps: -# - name: Github Repository Checkout -# uses: actions/checkout@v4 - -# - name: 의존성 패키지 설치 -# run: npm install - -# - name: 빌드 -# env: -# VITE_PUBLIC_BASE_URL: ${{ secrets.VITE_PUBLIC_BASE_URL }} -# VITE_KAKAO_BASE_URL: ${{ secrets.VITE_KAKAO_BASE_URL }} -# VITE_KAKAO_CLIENT_ID: ${{ secrets.VITE_KAKAO_CLIENT_ID }} -# VITE_KAKAO_REDIRECT_URI: ${{ secrets.VITE_KAKAO_REDIRECT_URI }} -# VITE_TOSS_CLIENTKEY: ${{ secrets.VITE_TOSS_CLIENTKEY }} -# run: npm run build - -# - name: 빌드 파일 디버깅 -# run: | -# ls -# echo "---------------------------------" -# cd dist -# ls - -# - name: AWS Resource 접근 권한 AWS 인증 설정 -# uses: aws-actions/configure-aws-credentials@v4 -# with: -# aws-region: ap-northeast-2 -# aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} -# aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} - -# - name: AWS S3 기존 파일 삭제 -# if: github.ref == 'refs/heads/main' -# run: aws s3 rm --recursive s3://oz-main-vita-front - -# - name: AWS S3 빌드 파일 재배포 -# if: github.ref == 'refs/heads/main' -# run: aws s3 cp ./dist s3://oz-main-vita-front/ --recursive - -# - name: Cloudfront 캐시 무효화 -# if: github.ref == 'refs/heads/main' -# run: aws cloudfront create-invalidation --distribution-id EQEIPG9IJRV5K --paths "/*" diff --git a/.gitignore b/.gitignore index 7cab059..e274906 100644 --- a/.gitignore +++ b/.gitignore @@ -24,4 +24,7 @@ dist-ssr # env .env -.env.* \ No newline at end of file +.env.* + +# md +troubleShooting.md \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000..9aef5aa --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20.17.0 \ No newline at end of file diff --git a/README.md b/README.md index 74872fd..a4c2e6f 100644 --- a/README.md +++ b/README.md @@ -1,50 +1,186 @@ -# React + TypeScript + Vite +# 🏌️ MIC Golf -This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. +골프 용품 쇼핑몰 웹 애플리케이션 -Currently, two official plugins are available: +## 📋 프로젝트 개요 -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh -- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh +MIC Golf는 React 18과 TypeScript를 기반으로 한 현대적인 골프 용품 이커머스 플랫폼입니다. 사용자들이 골프 관련 상품을 +쇼핑하고, 이벤트에 참여하며, 개인 정보를 관리할 수 있는 통합 솔루션을 제공합니다. -## Expanding the ESLint configuration +## ✨ 주요 기능 -If you are developing a production application, we recommend updating the configuration to enable type aware lint rules: +### 🛍️ 쇼핑 기능 -- Configure the top-level `parserOptions` property like this: +- **상품 카탈로그**: 카테고리별 골프 용품 브라우징 +- **상품 상세 페이지**: 자세한 상품 정보 및 이미지 +- **장바구니**: 상품 담기 및 수량 관리 +- **주문 처리**: 결제 및 주문 관리 + +### 👥 사용자 기능 + +- **회원가입/로그인**: 사용자 계정 관리 +- **비밀번호 재설정**: 계정 보안 관리 +- **마이페이지**: 개인정보 및 주문 내역 관리 + +### 🎯 이벤트 기능 + +- **이벤트 목록**: 진행 중인 골프 이벤트 확인 +- **이벤트 상세**: 이벤트 정보 및 참여 기능 + +### 🔧 관리자 기능 + +- **관리자 대시보드**: 전체 시스템 관리 +- **상품 관리**: 상품 등록, 수정, 삭제 +- **사용자 관리**: 회원 정보 관리 + +## 🛠️ 기술 스택 + +### Frontend Framework + +- **React 18** - 최신 React 기능 활용 +- **TypeScript** - 타입 안전성 보장 +- **Vite** - 빠른 개발 서버 및 빌드 + +### 상태 관리 & API + +- **Zustand** - 경량 상태 관리 +- **TanStack Query** - 서버 상태 관리 및 캐싱 +- **Axios** - HTTP 클라이언트 + +### 라우팅 & 폼 + +- **React Router v6** - 클라이언트 사이드 라우팅 +- **React Hook Form** - 효율적인 폼 관리 + +### UI & 스타일링 + +- **Tailwind CSS** - 유틸리티 기반 CSS 프레임워크 +- **React Slick** - 캐러셀 컴포넌트 +- **React Helmet Async** - 메타 태그 관리 + +### 개발 도구 + +- **ESLint** - 코드 품질 관리 +- **Prettier** - 코드 포맷팅 +- **PostCSS** - CSS 후처리 + +## 📁 프로젝트 구조 -```js -export default tseslint.config({ - languageOptions: { - // other options... - parserOptions: { - project: ['./tsconfig.node.json', './tsconfig.app.json'], - tsconfigRootDir: import.meta.dirname, - }, - }, -}) ``` +src/ +├── api/ # API 클라이언트 설정 +├── assets/ # 정적 자원 (이미지, 아이콘) +├── components/ # 재사용 가능한 컴포넌트 +├── config/ # 설정 파일들 +│ ├── constants.ts # 상수 정의 +│ ├── store.ts # 전역 상태 관리 +│ └── types.ts # TypeScript 타입 정의 +├── hooks/ # 커스텀 React 훅 +├── layouts/ # 레이아웃 컴포넌트 +│ ├── adminLayout/ # 관리자 레이아웃 +│ └── commonLayout/ # 일반 사용자 레이아웃 +├── pages/ # 페이지 컴포넌트 +│ ├── admin/ # 관리자 페이지 +│ ├── auth/ # 인증 관련 페이지 +│ ├── cart/ # 장바구니 페이지 +│ ├── event/ # 이벤트 페이지 +│ ├── home/ # 홈페이지 +│ ├── mypage/ # 마이페이지 +│ ├── order/ # 주문 페이지 +│ └── shop/ # 쇼핑 페이지 +├── routes/ # 라우트 보호 컴포넌트 +└── utils/ # 유틸리티 함수 +``` + +## 🚀 시작하기 + +### 사전 요구사항 + +- Node.js (v18 이상) +- npm 또는 yarn + +### 설치 및 실행 + +1. **의존성 설치** -- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked` -- Optionally add `...tseslint.configs.stylisticTypeChecked` -- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config: - -```js -// eslint.config.js -import react from 'eslint-plugin-react' - -export default tseslint.config({ - // Set the react version - settings: { react: { version: '18.3' } }, - plugins: { - // Add the react plugin - react, - }, - rules: { - // other rules... - // Enable its recommended rules - ...react.configs.recommended.rules, - ...react.configs['jsx-runtime'].rules, - }, -}) + ```bash + npm install + ``` + +2. **개발 서버 실행** + + ```bash + npm run dev + ``` + +3. **프로덕션 빌드** + + ```bash + npm run build + ``` + +4. **빌드 미리보기** + + ```bash + npm run preview + ``` + +5. **코드 린팅** + ```bash + npm run lint + ``` + +## 🔧 환경 설정 + +프로젝트 루트에 `.env` 파일을 생성하고 필요한 환경 변수를 설정하세요: + +```env +VITE_PUBLIC_BASE_URL=your_api_base_url ``` + +## 📱 주요 라우트 + +| 경로 | 설명 | 접근 권한 | +| --------------------- | --------------- | ----------- | +| `/` | 홈페이지 | 공개 | +| `/shop` | 상품 목록 | 공개 | +| `/shop/:category` | 카테고리별 상품 | 공개 | +| `/shop/:category/:id` | 상품 상세 | 공개 | +| `/event` | 이벤트 목록 | 공개 | +| `/event/:id` | 이벤트 상세 | 공개 | +| `/cart` | 장바구니 | 공개 | +| `/signin` | 로그인 | 공개 | +| `/signup` | 회원가입 | 공개 | +| `/mypage` | 마이페이지 | 로그인 필요 | +| `/admin` | 관리자 대시보드 | 관리자 권한 | + +## 🧪 개발 현황 + +현재 프로젝트는 초기 개발 단계에 있으며, 다음과 같은 상태입니다: + +- ✅ 프로젝트 구조 설정 완료 +- ✅ 라우팅 설정 완료 +- ✅ 기본 페이지 컴포넌트 생성 +- 🔄 UI 컴포넌트 개발 진행 중 +- ⏳ API 연동 대기 +- ⏳ 인증 시스템 구현 예정 + +## 🤝 기여하기 + +1. 이 저장소를 포크합니다 +2. 새로운 기능 브랜치를 생성합니다 (`git checkout -b feature/amazing-feature`) +3. 변경사항을 커밋합니다 (`git commit -m 'Add some amazing feature'`) +4. 브랜치에 푸시합니다 (`git push origin feature/amazing-feature`) +5. Pull Request를 생성합니다 + +## 📄 라이선스 + +이 프로젝트는 MIT 라이선스 하에 배포됩니다. + +## 📞 연락처 + +프로젝트에 대한 문의사항이 있으시면 이슈를 생성해 주세요. + +--- + +**MIC Golf** - 골프를 사랑하는 모든 이들을 위한 프리미엄 쇼핑 경험을 제공합니다. ⛳ diff --git a/eslint.config.js b/eslint.config.js index 0548102..14c9f72 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -3,19 +3,23 @@ import globals from 'globals'; import react from 'eslint-plugin-react'; import reactHooks from 'eslint-plugin-react-hooks'; import reactRefresh from 'eslint-plugin-react-refresh'; -import prettierPlugin from 'eslint-plugin-prettier'; // Prettier 플러그인 추가 +import prettierPlugin from 'eslint-plugin-prettier'; +import typescript from '@typescript-eslint/eslint-plugin'; +import tsParser from '@typescript-eslint/parser'; export default [ { ignores: ['dist'] }, // 'dist' 디렉토리는 ESLint 검사를 무시 { - files: ['**/*.{js,jsx}'], // ESLint가 검사할 파일 확장자 설정 + files: ['**/*.{js,jsx,ts,tsx}'], // ESLint가 검사할 파일 확장자 설정 languageOptions: { ecmaVersion: 2020, // ECMAScript 2020 지원 globals: globals.browser, // 브라우저 전역 변수 허용 + parser: tsParser, // TypeScript 파서 사용 parserOptions: { ecmaVersion: 'latest', // 최신 ECMAScript 버전 지원 ecmaFeatures: { jsx: true }, // JSX 지원 sourceType: 'module', // ECMAScript 모듈 사용 + project: './tsconfig.json', // tsconfig.json 경로 설정 }, }, settings: { @@ -26,15 +30,20 @@ export default [ 'react-hooks': reactHooks, // React Hooks 플러그인 'react-refresh': reactRefresh, // React Fast Refresh 플러그인 prettier: prettierPlugin, // Prettier 플러그인 추가 + '@typescript-eslint': typescript, // TypeScript ESLint 플러그인 추가 }, rules: { ...js.configs.recommended.rules, // ESLint 추천 규칙 적용 ...react.configs.recommended.rules, // React 추천 규칙 적용 ...react.configs['jsx-runtime'].rules, // JSX 런타임 관련 규칙 ...reactHooks.configs.recommended.rules, // React Hooks 추천 규칙 적용 + ...typescript.configs.recommended.rules, // TypeScript 추천 규칙 적용 + ...typescript.configs['recommended-requiring-type-checking'].rules, // 타입 체크가 필요한 규칙 적용 'react/jsx-no-target-blank': 'off', // target="_blank" 보안 경고 비활성화 'react-refresh/only-export-components': ['warn', { allowConstantExport: true }], 'prettier/prettier': 'error', // Prettier 규칙을 위반하면 ESLint에서 에러로 처리 + '@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }], // 사용되지 않는 변수 경고 + '@typescript-eslint/explicit-module-boundary-types': 'off', // 함수 반환 타입 강제 비활성화 }, }, -]; +]; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index af84a5c..70d67d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,24 +8,39 @@ "name": "mic-golf", "version": "0.0.0", "dependencies": { + "@portone/browser-sdk": "^0.0.10", + "@tailwindcss/aspect-ratio": "^0.4.2", "@tanstack/react-query": "^5.59.20", "@tanstack/react-query-devtools": "^5.59.15", + "@types/react-beautiful-dnd": "^13.1.8", "axios": "^1.7.7", + "chart.js": "^4.4.6", + "framer-motion": "^11.11.17", + "js-cookie": "^3.0.5", + "lucide-react": "^0.456.0", "nanoid": "^5.0.8", "react": "^18.3.1", + "react-beautiful-dnd": "^13.1.1", + "react-chartjs-2": "^5.2.0", + "react-daum-postcode": "^3.1.3", "react-dom": "^18.3.1", "react-helmet-async": "^2.0.5", "react-hook-form": "^7.53.0", + "react-intersection-observer": "^9.13.1", + "react-responsive": "^10.0.0", "react-router-dom": "^6.28.0", "react-slick": "^0.30.2", "slick-carousel": "^1.8.1", + "swiper": "^11.1.14", "zustand": "^5.0.1" }, "devDependencies": { "@eslint/js": "^9.13.0", + "@types/js-cookie": "^3.0.6", "@types/node": "^22.9.0", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", + "@types/react-slick": "^0.23.13", "@vitejs/plugin-react-swc": "^3.5.0", "autoprefixer": "^10.4.20", "eslint": "^9.13.0", @@ -43,9 +58,6 @@ }, "node_modules/@alloc/quick-lru": { "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", - "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -54,10 +66,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@babel/runtime": { + "version": "7.26.0", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@esbuild/darwin-arm64": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", "cpu": [ "arm64" ], @@ -73,8 +93,6 @@ }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "license": "MIT", "dependencies": { @@ -92,8 +110,6 @@ }, "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { @@ -105,8 +121,6 @@ }, "node_modules/@eslint-community/regexpp": { "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", "engines": { @@ -115,8 +129,6 @@ }, "node_modules/@eslint/config-array": { "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -130,8 +142,6 @@ }, "node_modules/@eslint/core": { "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -140,8 +150,6 @@ }, "node_modules/@eslint/eslintrc": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", "dev": true, "license": "MIT", "dependencies": { @@ -164,8 +172,6 @@ }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, "license": "MIT", "engines": { @@ -177,8 +183,6 @@ }, "node_modules/@eslint/js": { "version": "9.14.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.14.0.tgz", - "integrity": "sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==", "dev": true, "license": "MIT", "engines": { @@ -187,8 +191,6 @@ }, "node_modules/@eslint/object-schema": { "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -196,9 +198,9 @@ } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.2.tgz", - "integrity": "sha512-CXtq5nR4Su+2I47WPOlWud98Y5Lv8Kyxp2ukhgFx/eW6Blm18VXJO5WuQylPugRo8nbluoi6GvvxBLqHcvqUUw==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", + "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -210,8 +212,6 @@ }, "node_modules/@humanfs/core": { "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -220,8 +220,6 @@ }, "node_modules/@humanfs/node": { "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -234,8 +232,6 @@ }, "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -248,8 +244,6 @@ }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -262,8 +256,6 @@ }, "node_modules/@humanwhocodes/retry": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.1.tgz", - "integrity": "sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -276,9 +268,6 @@ }, "node_modules/@isaacs/cliui": { "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "license": "ISC", "dependencies": { "string-width": "^5.1.2", @@ -294,9 +283,6 @@ }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/set-array": "^1.2.1", @@ -309,9 +295,6 @@ }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -319,9 +302,6 @@ }, "node_modules/@jridgewell/set-array": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -329,27 +309,22 @@ }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@kurkle/color": { + "version": "0.3.2", + "license": "MIT" + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", @@ -361,9 +336,6 @@ }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -371,9 +343,6 @@ }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -385,19 +354,19 @@ }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "license": "MIT", "optional": true, "engines": { "node": ">=14" } }, + "node_modules/@portone/browser-sdk": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/@portone/browser-sdk/-/browser-sdk-0.0.10.tgz", + "integrity": "sha512-AylNhel3iWZuq632Axfgg5CLTVgv5xhjxJb0Umfy4chi/PV0K2R5ry/9ywOrKTPdSWqo3KwKVZGgv4X46Gvz+g==" + }, "node_modules/@remix-run/router": { "version": "1.21.0", - "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.21.0.tgz", - "integrity": "sha512-xfSkCAchbdG5PnbrKqFWwia4Bi61nH+wm8wLEqfHDyp7Y3dZzgqS2itV8i4gAq9pC2HsTpwyBC6Ds8VHZ96JlA==", "license": "MIT", "engines": { "node": ">=14.0.0" @@ -405,8 +374,6 @@ }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.24.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.4.tgz", - "integrity": "sha512-GmU/QgGtBTeraKyldC7cDVVvAJEOr3dFLKneez/n7BvX57UdhOqDsVwzU7UOnYA7AAOt+Xb26lk79PldDHgMIQ==", "cpu": [ "arm64" ], @@ -419,8 +386,6 @@ }, "node_modules/@swc/core": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.9.1.tgz", - "integrity": "sha512-OnPc+Kt5oy3xTvr/KCUOqE9ptJcWbyQgAUr1ydh9EmbBcmJTaO1kfQCxm/axzJi6sKeDTxL9rX5zvLOhoYIaQw==", "dev": true, "hasInstallScript": true, "license": "Apache-2.0", @@ -458,8 +423,6 @@ }, "node_modules/@swc/core-darwin-arm64": { "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.9.1.tgz", - "integrity": "sha512-2/ncHSCdAh5OHem1fMITrWEzzl97OdMK1PHc9CkxSJnphLjRubfxB5sbc5tDhcO68a5tVy+DxwaBgDec3PXnOg==", "cpu": [ "arm64" ], @@ -475,25 +438,26 @@ }, "node_modules/@swc/counter": { "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", - "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", "dev": true, "license": "Apache-2.0" }, "node_modules/@swc/types": { "version": "0.1.14", - "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.14.tgz", - "integrity": "sha512-PbSmTiYCN+GMrvfjrMo9bdY+f2COnwbdnoMw7rqU/PI5jXpKjxOGZ0qqZCImxnT81NkNsKnmEpvu+hRXLBeCJg==", "dev": true, "license": "Apache-2.0", "dependencies": { "@swc/counter": "^0.1.3" } }, + "node_modules/@tailwindcss/aspect-ratio": { + "version": "0.4.2", + "license": "MIT", + "peerDependencies": { + "tailwindcss": ">=2.0.0 || >=3.0.0 || >=3.0.0-alpha.1" + } + }, "node_modules/@tanstack/query-core": { "version": "5.59.20", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.20.tgz", - "integrity": "sha512-e8vw0lf7KwfGe1if4uPFhvZRWULqHjFcz3K8AebtieXvnMOz5FSzlZe3mTLlPuUBcydCnBRqYs2YJ5ys68wwLg==", "license": "MIT", "funding": { "type": "github", @@ -502,8 +466,6 @@ }, "node_modules/@tanstack/query-devtools": { "version": "5.59.20", - "resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.59.20.tgz", - "integrity": "sha512-vxhuQ+8VV4YWQSFxQLsuM+dnEKRY7VeRzpNabFXdhEwsBYLrjXlF1pM38A8WyKNLqZy8JjyRO8oP4Wd/oKHwuQ==", "license": "MIT", "funding": { "type": "github", @@ -512,8 +474,6 @@ }, "node_modules/@tanstack/react-query": { "version": "5.59.20", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.20.tgz", - "integrity": "sha512-Zly0egsK0tFdfSbh5/mapSa+Zfc3Et0Zkar7Wo5sQkFzWyB3p3uZWOHR2wrlAEEV2L953eLuDBtbgFvMYiLvUw==", "license": "MIT", "dependencies": { "@tanstack/query-core": "5.59.20" @@ -528,8 +488,6 @@ }, "node_modules/@tanstack/react-query-devtools": { "version": "5.59.20", - "resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.59.20.tgz", - "integrity": "sha512-AL/eQS1NFZhwwzq2Bq9Gd8wTTH+XhPNOJlDFpzPMu9NC5CQVgA0J8lWrte/sXpdWNo5KA4hgHnEdImZsF4h6Lw==", "license": "MIT", "dependencies": { "@tanstack/query-devtools": "5.59.20" @@ -545,22 +503,31 @@ }, "node_modules/@types/estree": { "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.5", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, + "node_modules/@types/js-cookie": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", + "integrity": "sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==", "dev": true, "license": "MIT" }, "node_modules/@types/json-schema": { "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "22.9.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.0.tgz", - "integrity": "sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -569,26 +536,43 @@ }, "node_modules/@types/prop-types": { "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==", - "devOptional": true, "license": "MIT" }, "node_modules/@types/react": { "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", - "devOptional": true, "license": "MIT", "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" } }, + "node_modules/@types/react-beautiful-dnd": { + "version": "13.1.8", + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/react-dom": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/react": "*" + } + }, + "node_modules/@types/react-redux": { + "version": "7.1.34", + "license": "MIT", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/react-slick": { + "version": "0.23.13", "dev": true, "license": "MIT", "dependencies": { @@ -597,8 +581,6 @@ }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.13.0.tgz", - "integrity": "sha512-nQtBLiZYMUPkclSeC3id+x4uVd1SGtHuElTxL++SfP47jR0zfkZBJHc+gL4qPsgTuypz0k8Y2GheaDYn6Gy3rg==", "dev": true, "license": "MIT", "dependencies": { @@ -631,8 +613,6 @@ }, "node_modules/@typescript-eslint/parser": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.13.0.tgz", - "integrity": "sha512-w0xp+xGg8u/nONcGw1UXAr6cjCPU1w0XVyBs6Zqaj5eLmxkKQAByTdV/uGgNN5tVvN/kKpoQlP2cL7R+ajZZIQ==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -660,8 +640,6 @@ }, "node_modules/@typescript-eslint/scope-manager": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.13.0.tgz", - "integrity": "sha512-XsGWww0odcUT0gJoBZ1DeulY1+jkaHUciUq4jKNv4cpInbvvrtDoyBH9rE/n2V29wQJPk8iCH1wipra9BhmiMA==", "dev": true, "license": "MIT", "dependencies": { @@ -678,8 +656,6 @@ }, "node_modules/@typescript-eslint/type-utils": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.13.0.tgz", - "integrity": "sha512-Rqnn6xXTR316fP4D2pohZenJnp+NwQ1mo7/JM+J1LWZENSLkJI8ID8QNtlvFeb0HnFSK94D6q0cnMX6SbE5/vA==", "dev": true, "license": "MIT", "dependencies": { @@ -703,8 +679,6 @@ }, "node_modules/@typescript-eslint/types": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.13.0.tgz", - "integrity": "sha512-4cyFErJetFLckcThRUFdReWJjVsPCqyBlJTi6IDEpc1GWCIIZRFxVppjWLIMcQhNGhdWJJRYFHpHoDWvMlDzng==", "dev": true, "license": "MIT", "engines": { @@ -717,8 +691,6 @@ }, "node_modules/@typescript-eslint/typescript-estree": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.13.0.tgz", - "integrity": "sha512-v7SCIGmVsRK2Cy/LTLGN22uea6SaUIlpBcO/gnMGT/7zPtxp90bphcGf4fyrCQl3ZtiBKqVTG32hb668oIYy1g==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -746,8 +718,6 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { @@ -756,8 +726,6 @@ }, "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dev": true, "license": "ISC", "dependencies": { @@ -772,8 +740,6 @@ }, "node_modules/@typescript-eslint/utils": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.13.0.tgz", - "integrity": "sha512-A1EeYOND6Uv250nybnLZapeXpYMl8tkzYUxqmoKAWnI4sei3ihf2XdZVd+vVOmHGcp3t+P7yRrNsyyiXTvShFQ==", "dev": true, "license": "MIT", "dependencies": { @@ -795,8 +761,6 @@ }, "node_modules/@typescript-eslint/visitor-keys": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.13.0.tgz", - "integrity": "sha512-7N/+lztJqH4Mrf0lb10R/CbI1EaAMMGyF5y0oJvFoAhafwgiRA7TXyd8TFn8FC8k5y2dTsYogg238qavRGNnlw==", "dev": true, "license": "MIT", "dependencies": { @@ -813,8 +777,6 @@ }, "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, "license": "Apache-2.0", "engines": { @@ -826,8 +788,6 @@ }, "node_modules/@vitejs/plugin-react-swc": { "version": "3.7.1", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react-swc/-/plugin-react-swc-3.7.1.tgz", - "integrity": "sha512-vgWOY0i1EROUK0Ctg1hwhtC3SdcDjZcdit4Ups4aPkDcB1jYhmo+RMYWY87cmXMhvtD5uf8lV89j2w16vkdSVg==", "dev": true, "license": "MIT", "dependencies": { @@ -839,8 +799,6 @@ }, "node_modules/acorn": { "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "dev": true, "license": "MIT", "bin": { @@ -852,8 +810,6 @@ }, "node_modules/acorn-jsx": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -862,8 +818,6 @@ }, "node_modules/ajv": { "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "license": "MIT", "dependencies": { @@ -879,9 +833,6 @@ }, "node_modules/ansi-regex": { "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -892,9 +843,6 @@ }, "node_modules/ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" @@ -908,16 +856,10 @@ }, "node_modules/any-promise": { "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, "license": "MIT" }, "node_modules/anymatch": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -929,28 +871,19 @@ }, "node_modules/arg": { "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true, "license": "Python-2.0" }, "node_modules/asynckit": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, "node_modules/autoprefixer": { "version": "10.4.20", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz", - "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==", "dev": true, "funding": [ { @@ -987,8 +920,6 @@ }, "node_modules/axios": { "version": "1.7.7", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", - "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "license": "MIT", "dependencies": { "follow-redirects": "^1.15.6", @@ -998,16 +929,10 @@ }, "node_modules/balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, "license": "MIT" }, "node_modules/binary-extensions": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1018,8 +943,6 @@ }, "node_modules/brace-expansion": { "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { @@ -1029,9 +952,6 @@ }, "node_modules/braces": { "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" @@ -1042,8 +962,6 @@ }, "node_modules/browserslist": { "version": "4.24.2", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", - "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "dev": true, "funding": [ { @@ -1075,8 +993,6 @@ }, "node_modules/callsites": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "license": "MIT", "engines": { @@ -1085,9 +1001,6 @@ }, "node_modules/camelcase-css": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -1095,8 +1008,6 @@ }, "node_modules/caniuse-lite": { "version": "1.0.30001677", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001677.tgz", - "integrity": "sha512-fmfjsOlJUpMWu+mAAtZZZHz7UEwsUxIIvu1TJfO1HqFQvB/B+ii0xr9B5HpbZY/mC4XZ8SvjHJqtAY6pDPQEog==", "dev": true, "funding": [ { @@ -1116,8 +1027,6 @@ }, "node_modules/chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { @@ -1131,11 +1040,20 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chart.js": { + "version": "4.4.6", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-4.4.6.tgz", + "integrity": "sha512-8Y406zevUPbbIBA/HRk33khEmQPk5+cxeflWE/2rx1NJsjVWMPw/9mSP9rxHP5eqi6LNoPBVMfZHxbwLSgldYA==", + "license": "MIT", + "dependencies": { + "@kurkle/color": "^0.3.0" + }, + "engines": { + "pnpm": ">=8" + } + }, "node_modules/chokidar": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", @@ -1158,9 +1076,6 @@ }, "node_modules/chokidar/node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -1177,9 +1092,6 @@ }, "node_modules/color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -1190,15 +1102,10 @@ }, "node_modules/color-name": { "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, "license": "MIT" }, "node_modules/combined-stream": { "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "license": "MIT", "dependencies": { "delayed-stream": "~1.0.0" @@ -1209,9 +1116,6 @@ }, "node_modules/commander": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -1219,16 +1123,13 @@ }, "node_modules/concat-map": { "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -1239,11 +1140,21 @@ "node": ">= 8" } }, + "node_modules/css-box-model": { + "version": "1.2.1", + "license": "MIT", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, + "node_modules/css-mediaquery": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/css-mediaquery/-/css-mediaquery-0.1.2.tgz", + "integrity": "sha512-COtn4EROW5dBGlE/4PiKnh6rZpAPxDeFLaEEwt4i10jpDMFt2EhQGS79QmmrO+iKCHv0PU/HrOWEhijFd1x99Q==", + "license": "BSD" + }, "node_modules/cssesc": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, "license": "MIT", "bin": { "cssesc": "bin/cssesc" @@ -1254,15 +1165,10 @@ }, "node_modules/csstype": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "devOptional": true, "license": "MIT" }, "node_modules/debug": { "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1279,15 +1185,11 @@ }, "node_modules/deep-is": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true, "license": "MIT" }, "node_modules/delayed-stream": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "license": "MIT", "engines": { "node": ">=0.4.0" @@ -1295,37 +1197,23 @@ }, "node_modules/didyoumean": { "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, "license": "Apache-2.0" }, "node_modules/dlv": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, "license": "MIT" }, "node_modules/eastasianwidth": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { "version": "1.5.52", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.52.tgz", - "integrity": "sha512-xtoijJTZ+qeucLBDNztDOuQBE1ksqjvNjvqFoST3nGC7fSpqJ+X6BdTBaY5BHG+IhWWmpc6b/KfpeuEDupEPOQ==", "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, "license": "MIT" }, "node_modules/enquire.js": { @@ -1336,8 +1224,6 @@ }, "node_modules/esbuild": { "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -1375,8 +1261,6 @@ }, "node_modules/escalade": { "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -1385,8 +1269,6 @@ }, "node_modules/escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, "license": "MIT", "engines": { @@ -1398,8 +1280,6 @@ }, "node_modules/eslint": { "version": "9.14.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.14.0.tgz", - "integrity": "sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==", "dev": true, "license": "MIT", "dependencies": { @@ -1459,8 +1339,6 @@ }, "node_modules/eslint-plugin-react-hooks": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.0.0.tgz", - "integrity": "sha512-hIOwI+5hYGpJEc4uPRmz2ulCjAGD/N13Lukkh8cLV0i2IRk/bdZDYjgLVHj+U9Z704kLIdIO6iueGvxNur0sgw==", "dev": true, "license": "MIT", "engines": { @@ -1472,8 +1350,6 @@ }, "node_modules/eslint-plugin-react-refresh": { "version": "0.4.14", - "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.14.tgz", - "integrity": "sha512-aXvzCTK7ZBv1e7fahFuR3Z/fyQQSIQ711yPgYRj+Oj64tyTgO4iQIDmYXDBqvSWQ/FA4OSCsXOStlF+noU0/NA==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1482,8 +1358,6 @@ }, "node_modules/eslint-scope": { "version": "8.2.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", - "integrity": "sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -1499,8 +1373,6 @@ }, "node_modules/eslint-visitor-keys": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", - "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -1512,8 +1384,6 @@ }, "node_modules/espree": { "version": "10.3.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", - "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -1530,8 +1400,6 @@ }, "node_modules/esquery": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -1543,8 +1411,6 @@ }, "node_modules/esrecurse": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -1556,8 +1422,6 @@ }, "node_modules/estraverse": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -1566,8 +1430,6 @@ }, "node_modules/esutils": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, "license": "BSD-2-Clause", "engines": { @@ -1576,16 +1438,11 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true, "license": "MIT" }, "node_modules/fast-glob": { "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", @@ -1600,9 +1457,6 @@ }, "node_modules/fast-glob/node_modules/glob-parent": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -1613,23 +1467,16 @@ }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true, "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true, "license": "MIT" }, "node_modules/fastq": { "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" @@ -1637,8 +1484,6 @@ }, "node_modules/file-entry-cache": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1650,9 +1495,6 @@ }, "node_modules/fill-range": { "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -1663,8 +1505,6 @@ }, "node_modules/find-up": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "dev": true, "license": "MIT", "dependencies": { @@ -1680,8 +1520,6 @@ }, "node_modules/flat-cache": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, "license": "MIT", "dependencies": { @@ -1694,15 +1532,11 @@ }, "node_modules/flatted": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", "dev": true, "license": "ISC" }, "node_modules/follow-redirects": { "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "funding": [ { "type": "individual", @@ -1721,9 +1555,6 @@ }, "node_modules/foreground-child": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, "license": "ISC", "dependencies": { "cross-spawn": "^7.0.0", @@ -1738,8 +1569,6 @@ }, "node_modules/form-data": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "license": "MIT", "dependencies": { "asynckit": "^0.4.0", @@ -1752,8 +1581,6 @@ }, "node_modules/fraction.js": { "version": "4.3.7", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", - "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", "dev": true, "license": "MIT", "engines": { @@ -1764,12 +1591,33 @@ "url": "https://github.com/sponsors/rawify" } }, + "node_modules/framer-motion": { + "version": "11.11.17", + "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.11.17.tgz", + "integrity": "sha512-O8QzvoKiuzI5HSAHbcYuL6xU+ZLXbrH7C8Akaato4JzQbX2ULNeniqC2Vo5eiCtFktX9XsJ+7nUhxcl2E2IjpA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.4.0" + }, + "peerDependencies": { + "@emotion/is-prop-valid": "*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "peerDependenciesMeta": { + "@emotion/is-prop-valid": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, "node_modules/fsevents": { "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, "license": "MIT", "optional": true, "os": [ @@ -1781,9 +1629,6 @@ }, "node_modules/function-bind": { "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -1791,9 +1636,6 @@ }, "node_modules/glob": { "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, "license": "ISC", "dependencies": { "foreground-child": "^3.1.0", @@ -1812,9 +1654,6 @@ }, "node_modules/glob-parent": { "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.3" @@ -1825,9 +1664,6 @@ }, "node_modules/glob/node_modules/brace-expansion": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0" @@ -1835,9 +1671,6 @@ }, "node_modules/glob/node_modules/minimatch": { "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" @@ -1851,8 +1684,6 @@ }, "node_modules/globals": { "version": "15.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.12.0.tgz", - "integrity": "sha512-1+gLErljJFhbOVyaetcwJiJ4+eLe45S2E7P5UiZ9xGfeq3ATQf5DOv9G7MH3gGbKQLkzmNh2DxfZwLdw+j6oTQ==", "dev": true, "license": "MIT", "engines": { @@ -1864,15 +1695,11 @@ }, "node_modules/graphemer": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, "license": "MIT" }, "node_modules/has-flag": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { @@ -1881,9 +1708,6 @@ }, "node_modules/hasown": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -1892,10 +1716,25 @@ "node": ">= 0.4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, + "node_modules/hyphenate-style-name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", + "integrity": "sha512-WDC/ui2VVRrz3jOVi+XtjqkDjiVjTtFaAGiW37k6b+ohyQ5wYDOGkvCZa8+H0nx3gyvv0+BST9xuOgIyGQ00gw==", + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, "license": "MIT", "engines": { @@ -1904,8 +1743,6 @@ }, "node_modules/import-fresh": { "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "license": "MIT", "dependencies": { @@ -1921,8 +1758,6 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true, "license": "MIT", "engines": { @@ -1931,8 +1766,6 @@ }, "node_modules/invariant": { "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", "license": "MIT", "dependencies": { "loose-envify": "^1.0.0" @@ -1940,9 +1773,6 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -1953,9 +1783,6 @@ }, "node_modules/is-core-module": { "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -1969,9 +1796,6 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -1979,9 +1803,6 @@ }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -1989,9 +1810,6 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -2002,9 +1820,6 @@ }, "node_modules/is-number": { "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -2012,16 +1827,10 @@ }, "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/jackspeak": { "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "@isaacs/cliui": "^8.0.2" @@ -2035,9 +1844,6 @@ }, "node_modules/jiti": { "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", - "dev": true, "license": "MIT", "bin": { "jiti": "bin/jiti.js" @@ -2050,16 +1856,21 @@ "license": "MIT", "peer": true }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/js-tokens": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "license": "MIT", "dependencies": { @@ -2071,22 +1882,16 @@ }, "node_modules/json-buffer": { "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", "dev": true, "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true, "license": "MIT" }, @@ -2101,8 +1906,6 @@ }, "node_modules/keyv": { "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, "license": "MIT", "dependencies": { @@ -2111,8 +1914,6 @@ }, "node_modules/levn": { "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2125,9 +1926,6 @@ }, "node_modules/lilconfig": { "version": "2.1.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", - "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -2135,15 +1933,10 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, "license": "MIT", "dependencies": { @@ -2164,15 +1957,11 @@ }, "node_modules/lodash.merge": { "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true, "license": "MIT" }, "node_modules/loose-envify": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -2183,16 +1972,32 @@ }, "node_modules/lru-cache": { "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, "license": "ISC" }, + "node_modules/lucide-react": { + "version": "0.456.0", + "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.456.0.tgz", + "integrity": "sha512-DIIGJqTT5X05sbAsQ+OhA8OtJYyD4NsEMCA/HQW/Y6ToPQ7gwbtujIoeAaup4HpHzV35SQOarKAWH8LYglB6eA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc" + } + }, + "node_modules/matchmediaquery": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/matchmediaquery/-/matchmediaquery-0.4.2.tgz", + "integrity": "sha512-wrZpoT50ehYOudhDjt/YvUJc6eUzcdFPdmbizfgvswCKNHD1/OBOHYJpHie+HXpu6bSkEGieFMYk6VuutaiRfA==", + "license": "MIT", + "dependencies": { + "css-mediaquery": "^0.1.2" + } + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 8" @@ -2200,9 +2005,6 @@ }, "node_modules/micromatch": { "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", @@ -2214,8 +2016,6 @@ }, "node_modules/mime-db": { "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "license": "MIT", "engines": { "node": ">= 0.6" @@ -2223,8 +2023,6 @@ }, "node_modules/mime-types": { "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "license": "MIT", "dependencies": { "mime-db": "1.52.0" @@ -2235,8 +2033,6 @@ }, "node_modules/minimatch": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { @@ -2248,9 +2044,6 @@ }, "node_modules/minipass": { "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -2258,16 +2051,11 @@ }, "node_modules/ms": { "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, "node_modules/mz": { "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0", @@ -2277,8 +2065,6 @@ }, "node_modules/nanoid": { "version": "5.0.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-5.0.8.tgz", - "integrity": "sha512-TcJPw+9RV9dibz1hHUzlLVy8N4X9TnwirAjrU08Juo6BNKggzVfP2ZJ/3ZUSq15Xl5i85i+Z89XBO90pB2PghQ==", "funding": [ { "type": "github", @@ -2295,23 +2081,16 @@ }, "node_modules/natural-compare": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, "license": "MIT" }, "node_modules/node-releases": { "version": "2.0.18", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", - "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true, "license": "MIT" }, "node_modules/normalize-path": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2319,8 +2098,6 @@ }, "node_modules/normalize-range": { "version": "0.1.2", - "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", - "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, "license": "MIT", "engines": { @@ -2329,9 +2106,6 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2339,9 +2113,6 @@ }, "node_modules/object-hash": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -2349,8 +2120,6 @@ }, "node_modules/optionator": { "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, "license": "MIT", "dependencies": { @@ -2367,8 +2136,6 @@ }, "node_modules/p-limit": { "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2383,8 +2150,6 @@ }, "node_modules/p-locate": { "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, "license": "MIT", "dependencies": { @@ -2399,15 +2164,10 @@ }, "node_modules/package-json-from-dist": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, "license": "BlueOak-1.0.0" }, "node_modules/parent-module": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "license": "MIT", "dependencies": { @@ -2419,8 +2179,6 @@ }, "node_modules/path-exists": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, "license": "MIT", "engines": { @@ -2429,9 +2187,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -2439,16 +2194,10 @@ }, "node_modules/path-parse": { "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-scurry": { "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^10.2.0", @@ -2463,16 +2212,10 @@ }, "node_modules/picocolors": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -2483,9 +2226,6 @@ }, "node_modules/pify": { "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -2493,9 +2233,6 @@ }, "node_modules/pirates": { "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 6" @@ -2503,9 +2240,6 @@ }, "node_modules/postcss": { "version": "8.4.47", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz", - "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2532,9 +2266,6 @@ }, "node_modules/postcss-import": { "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, "license": "MIT", "dependencies": { "postcss-value-parser": "^4.0.0", @@ -2550,9 +2281,6 @@ }, "node_modules/postcss-js": { "version": "4.0.1", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", - "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", - "dev": true, "license": "MIT", "dependencies": { "camelcase-css": "^2.0.1" @@ -2570,9 +2298,6 @@ }, "node_modules/postcss-load-config": { "version": "4.0.2", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", - "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2606,9 +2331,6 @@ }, "node_modules/postcss-load-config/node_modules/lilconfig": { "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, "license": "MIT", "engines": { "node": ">=14" @@ -2619,9 +2341,6 @@ }, "node_modules/postcss-nested": { "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, "funding": [ { "type": "opencollective", @@ -2645,9 +2364,6 @@ }, "node_modules/postcss-selector-parser": { "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, "license": "MIT", "dependencies": { "cssesc": "^3.0.0", @@ -2659,16 +2375,10 @@ }, "node_modules/postcss-value-parser": { "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true, "license": "MIT" }, "node_modules/postcss/node_modules/nanoid": { "version": "3.3.7", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", - "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", - "dev": true, "funding": [ { "type": "github", @@ -2685,8 +2395,6 @@ }, "node_modules/prelude-ls": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, "license": "MIT", "engines": { @@ -2695,8 +2403,6 @@ }, "node_modules/prettier": { "version": "3.3.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz", - "integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==", "dev": true, "license": "MIT", "bin": { @@ -2711,8 +2417,6 @@ }, "node_modules/prettier-plugin-tailwindcss": { "version": "0.6.8", - "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.8.tgz", - "integrity": "sha512-dGu3kdm7SXPkiW4nzeWKCl3uoImdd5CTZEJGxyypEPL37Wj0HT2pLqjrvSei1nTeuQfO4PUfjeW5cTUNRLZ4sA==", "dev": true, "license": "MIT", "engines": { @@ -2788,16 +2492,25 @@ } } }, + "node_modules/prop-types": { + "version": "15.8.1", + "license": "MIT", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/prop-types/node_modules/react-is": { + "version": "16.13.1", + "license": "MIT" + }, "node_modules/proxy-from-env": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", "license": "MIT" }, "node_modules/punycode": { "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { @@ -2806,9 +2519,6 @@ }, "node_modules/queue-microtask": { "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -2825,10 +2535,12 @@ ], "license": "MIT" }, + "node_modules/raf-schd": { + "version": "4.0.3", + "license": "MIT" + }, "node_modules/react": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", - "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -2837,10 +2549,42 @@ "node": ">=0.10.0" } }, + "node_modules/react-beautiful-dnd": { + "version": "13.1.1", + "license": "Apache-2.0", + "dependencies": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.5 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.5 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-chartjs-2": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-5.2.0.tgz", + "integrity": "sha512-98iN5aguJyVSxp5U3CblRLH67J8gkfyGNbiK3c+l1QI/G4irHMPQw44aEPmjVag+YKTyQ260NcF82GTQ3bdscA==", + "license": "MIT", + "peerDependencies": { + "chart.js": "^4.1.1", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, + "node_modules/react-daum-postcode": { + "version": "3.1.3", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/react-dom": { "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0", @@ -2852,14 +2596,10 @@ }, "node_modules/react-fast-compare": { "version": "3.2.2", - "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.2.tgz", - "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==", "license": "MIT" }, "node_modules/react-helmet-async": { "version": "2.0.5", - "resolved": "https://registry.npmjs.org/react-helmet-async/-/react-helmet-async-2.0.5.tgz", - "integrity": "sha512-rYUYHeus+i27MvFE+Jaa4WsyBKGkL6qVgbJvSBoX8mbsWoABJXdEO0bZyi0F6i+4f0NuIb8AvqPMj3iXFHkMwg==", "license": "Apache-2.0", "dependencies": { "invariant": "^2.2.4", @@ -2872,8 +2612,6 @@ }, "node_modules/react-hook-form": { "version": "7.53.1", - "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.53.1.tgz", - "integrity": "sha512-6aiQeBda4zjcuaugWvim9WsGqisoUk+etmFEsSUMm451/Ic8L/UAb7sRtMj3V+Hdzm6mMjU1VhiSzYUZeBm0Vg==", "license": "MIT", "engines": { "node": ">=18.0.0" @@ -2886,10 +2624,68 @@ "react": "^16.8.0 || ^17 || ^18 || ^19" } }, + "node_modules/react-intersection-observer": { + "version": "9.13.1", + "resolved": "https://registry.npmjs.org/react-intersection-observer/-/react-intersection-observer-9.13.1.tgz", + "integrity": "sha512-tSzDaTy0qwNPLJHg8XZhlyHTgGW6drFKTtvjdL+p6um12rcnp8Z5XstE+QNBJ7c64n5o0Lj4ilUleA41bmDoMw==", + "license": "MIT", + "peerDependencies": { + "react": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "license": "MIT" + }, + "node_modules/react-redux": { + "version": "7.2.9", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-responsive": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/react-responsive/-/react-responsive-10.0.0.tgz", + "integrity": "sha512-N6/UiRLGQyGUqrarhBZmrSmHi2FXSD++N5VbSKsBBvWfG0ZV7asvUBluSv5lSzdMyEVjzZ6Y8DL4OHABiztDOg==", + "license": "MIT", + "dependencies": { + "hyphenate-style-name": "^1.0.0", + "matchmediaquery": "^0.4.2", + "prop-types": "^15.6.1", + "shallow-equal": "^3.1.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "react": ">=16.8.0" + } + }, "node_modules/react-router": { "version": "6.28.0", - "resolved": "https://registry.npmjs.org/react-router/-/react-router-6.28.0.tgz", - "integrity": "sha512-HrYdIFqdrnhDw0PqG/AKjAqEqM7AvxCz0DQ4h2W8k6nqmc5uRBYDag0SBxx9iYz5G8gnuNVLzUe13wl9eAsXXg==", "license": "MIT", "dependencies": { "@remix-run/router": "1.21.0" @@ -2903,8 +2699,6 @@ }, "node_modules/react-router-dom": { "version": "6.28.0", - "resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.28.0.tgz", - "integrity": "sha512-kQ7Unsl5YdyOltsPGl31zOjLrDv+m2VcIEcIHqYYD3Lp0UppLjrzcfJqDJwXxFw3TH/yvapbnUvPlAj7Kx5nbg==", "license": "MIT", "dependencies": { "@remix-run/router": "1.21.0", @@ -2937,9 +2731,6 @@ }, "node_modules/read-cache": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, "license": "MIT", "dependencies": { "pify": "^2.3.0" @@ -2947,9 +2738,6 @@ }, "node_modules/readdirp": { "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" @@ -2958,6 +2746,17 @@ "node": ">=8.10.0" } }, + "node_modules/redux": { + "version": "4.2.1", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "license": "MIT" + }, "node_modules/resize-observer-polyfill": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", @@ -2966,9 +2765,6 @@ }, "node_modules/resolve": { "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.13.0", @@ -2984,8 +2780,6 @@ }, "node_modules/resolve-from": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, "license": "MIT", "engines": { @@ -2994,9 +2788,6 @@ }, "node_modules/reusify": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", @@ -3005,8 +2796,6 @@ }, "node_modules/rollup": { "version": "4.24.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.4.tgz", - "integrity": "sha512-vGorVWIsWfX3xbcyAS+I047kFKapHYivmkaT63Smj77XwvLSJos6M1xGqZnBPFQFBRZDOcG1QnYEIxAvTr/HjA==", "dev": true, "license": "MIT", "dependencies": { @@ -3043,9 +2832,6 @@ }, "node_modules/run-parallel": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -3067,8 +2853,6 @@ }, "node_modules/scheduler": { "version": "0.23.2", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", - "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", "license": "MIT", "dependencies": { "loose-envify": "^1.1.0" @@ -3076,8 +2860,6 @@ }, "node_modules/semver": { "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, "license": "ISC", "bin": { @@ -3087,17 +2869,18 @@ "node": ">=10" } }, + "node_modules/shallow-equal": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/shallow-equal/-/shallow-equal-3.1.0.tgz", + "integrity": "sha512-pfVOw8QZIXpMbhBWvzBISicvToTiM5WBF1EeAUZDDSb5Dt29yl4AYbyywbJFSEsRUMr7gJaxqCdr4L3tQf9wVg==", + "license": "MIT" + }, "node_modules/shallowequal": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/shallowequal/-/shallowequal-1.1.0.tgz", - "integrity": "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==", "license": "MIT" }, "node_modules/shebang-command": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -3108,9 +2891,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3118,9 +2898,6 @@ }, "node_modules/signal-exit": { "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "license": "ISC", "engines": { "node": ">=14" @@ -3140,9 +2917,6 @@ }, "node_modules/source-map-js": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -3156,9 +2930,6 @@ }, "node_modules/string-width": { "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "license": "MIT", "dependencies": { "eastasianwidth": "^0.2.0", @@ -3175,9 +2946,6 @@ "node_modules/string-width-cjs": { "name": "string-width", "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3190,9 +2958,6 @@ }, "node_modules/string-width-cjs/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3200,16 +2965,10 @@ }, "node_modules/string-width-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/string-width-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3220,9 +2979,6 @@ }, "node_modules/strip-ansi": { "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" @@ -3237,9 +2993,6 @@ "node_modules/strip-ansi-cjs": { "name": "strip-ansi", "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3250,9 +3003,6 @@ }, "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3260,8 +3010,6 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, "license": "MIT", "engines": { @@ -3273,9 +3021,6 @@ }, "node_modules/sucrase": { "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.2", @@ -3296,8 +3041,6 @@ }, "node_modules/supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { @@ -3309,9 +3052,6 @@ }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3320,11 +3060,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/swiper": { + "version": "11.1.14", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-11.1.14.tgz", + "integrity": "sha512-VbQLQXC04io6AoAjIUWuZwW4MSYozkcP9KjLdrsG/00Q/yiwvhz9RQyt0nHXV10hi9NVnDNy1/wv7Dzq1lkOCQ==", + "funding": [ + { + "type": "patreon", + "url": "https://www.patreon.com/swiperjs" + }, + { + "type": "open_collective", + "url": "http://opencollective.com/swiper" + } + ], + "license": "MIT", + "engines": { + "node": ">= 4.7.0" + } + }, "node_modules/tailwindcss": { "version": "3.4.14", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.14.tgz", - "integrity": "sha512-IcSvOcTRcUtQQ7ILQL5quRDg7Xs93PdJEk1ZLbhhvJc7uj/OAhYOnruEiwnGgBvUtaUAJ8/mhSw1o8L2jCiENA==", - "dev": true, "license": "MIT", "dependencies": { "@alloc/quick-lru": "^5.2.0", @@ -3360,16 +3116,11 @@ }, "node_modules/text-table": { "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true, "license": "MIT" }, "node_modules/thenify": { "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, "license": "MIT", "dependencies": { "any-promise": "^1.0.0" @@ -3377,9 +3128,6 @@ }, "node_modules/thenify-all": { "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, "license": "MIT", "dependencies": { "thenify": ">= 3.1.0 < 4" @@ -3388,11 +3136,12 @@ "node": ">=0.8" } }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" @@ -3403,8 +3152,6 @@ }, "node_modules/ts-api-utils": { "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.0.tgz", - "integrity": "sha512-032cPxaEKwM+GT3vA5JXNzIaizx388rhsSW79vGRNGXfRRAdEAn2mvk36PvK5HnOchyWZ7afLEXqYCvPCrzuzQ==", "dev": true, "license": "MIT", "engines": { @@ -3416,15 +3163,16 @@ }, "node_modules/ts-interface-checker": { "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, "license": "Apache-2.0" }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "license": "MIT", "dependencies": { @@ -3436,8 +3184,6 @@ }, "node_modules/typescript": { "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -3450,8 +3196,6 @@ }, "node_modules/typescript-eslint": { "version": "8.13.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.13.0.tgz", - "integrity": "sha512-vIMpDRJrQd70au2G8w34mPps0ezFSPMEX4pXkTzUkrNbRX+36ais2ksGWN0esZL+ZMaFJEneOBHzCgSqle7DHw==", "dev": true, "license": "MIT", "dependencies": { @@ -3474,15 +3218,11 @@ }, "node_modules/undici-types": { "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", "dev": true, "license": "MIT" }, "node_modules/update-browserslist-db": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", - "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "dev": true, "funding": [ { @@ -3512,25 +3252,25 @@ }, "node_modules/uri-js": { "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" } }, + "node_modules/use-memo-one": { + "version": "1.1.3", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, "license": "MIT" }, "node_modules/vite": { "version": "5.4.10", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.10.tgz", - "integrity": "sha512-1hvaPshuPUtxeQ0hsVH3Mud0ZanOLwVTneA1EgbAM5LhaZEqyPWGRQ7BtaMvUrTDeEaC8pxtj6a6jku3x4z6SQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3589,9 +3329,6 @@ }, "node_modules/which": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -3605,8 +3342,6 @@ }, "node_modules/word-wrap": { "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "dev": true, "license": "MIT", "engines": { @@ -3615,9 +3350,6 @@ }, "node_modules/wrap-ansi": { "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^6.1.0", @@ -3634,9 +3366,6 @@ "node_modules/wrap-ansi-cjs": { "name": "wrap-ansi", "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -3652,9 +3381,6 @@ }, "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -3662,16 +3388,10 @@ }, "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, "license": "MIT" }, "node_modules/wrap-ansi-cjs/node_modules/string-width": { "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "license": "MIT", "dependencies": { "emoji-regex": "^8.0.0", @@ -3684,9 +3404,6 @@ }, "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -3697,9 +3414,6 @@ }, "node_modules/wrap-ansi/node_modules/ansi-styles": { "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -3710,9 +3424,6 @@ }, "node_modules/yaml": { "version": "2.6.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.0.tgz", - "integrity": "sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==", - "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" @@ -3723,8 +3434,6 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "license": "MIT", "engines": { @@ -3736,8 +3445,6 @@ }, "node_modules/zustand": { "version": "5.0.1", - "resolved": "https://registry.npmjs.org/zustand/-/zustand-5.0.1.tgz", - "integrity": "sha512-pRET7Lao2z+n5R/HduXMio35TncTlSW68WsYBq2Lg1ASspsNGjpwLAsij3RpouyV6+kHMwwwzP0bZPD70/Jx/w==", "license": "MIT", "engines": { "node": ">=12.20.0" diff --git a/package.json b/package.json index 1755ae8..d8f30d1 100644 --- a/package.json +++ b/package.json @@ -10,24 +10,39 @@ "preview": "vite preview" }, "dependencies": { + "@portone/browser-sdk": "^0.0.10", + "@tailwindcss/aspect-ratio": "^0.4.2", "@tanstack/react-query": "^5.59.20", "@tanstack/react-query-devtools": "^5.59.15", + "@types/react-beautiful-dnd": "^13.1.8", "axios": "^1.7.7", + "chart.js": "^4.4.6", + "framer-motion": "^11.11.17", + "js-cookie": "^3.0.5", + "lucide-react": "^0.456.0", "nanoid": "^5.0.8", "react": "^18.3.1", + "react-beautiful-dnd": "^13.1.1", + "react-chartjs-2": "^5.2.0", + "react-daum-postcode": "^3.1.3", + "react-dom": "^18.3.1", "react-helmet-async": "^2.0.5", "react-hook-form": "^7.53.0", + "react-intersection-observer": "^9.13.1", + "react-responsive": "^10.0.0", + "react-router-dom": "^6.28.0", "react-slick": "^0.30.2", "slick-carousel": "^1.8.1", - "zustand": "^5.0.1", - "react-dom": "^18.3.1", - "react-router-dom": "^6.28.0" + "swiper": "^11.1.14", + "zustand": "^5.0.1" }, "devDependencies": { "@eslint/js": "^9.13.0", + "@types/js-cookie": "^3.0.6", "@types/node": "^22.9.0", "@types/react": "^18.3.12", "@types/react-dom": "^18.3.1", + "@types/react-slick": "^0.23.13", "@vitejs/plugin-react-swc": "^3.5.0", "autoprefixer": "^10.4.20", "eslint": "^9.13.0", diff --git a/src/App.tsx b/src/App.tsx index 888e212..6d2f541 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,58 +1,12 @@ import { Route, Routes } from 'react-router-dom'; -import HomePage from './pages/home/HomePage'; -import ShopPage from './pages/shop/ShopPage'; -import EventMainPage from './pages/event/EventMainPage'; -import EventDetailPage from './pages/event/EventDetailPage'; -import SignInPage from './pages/auth/SignInPage'; -import SignUpPage from './pages/auth/SignUpPage'; -import SignUpCompletePage from './pages/auth/SignUpCompletePage'; -import PasswordResetPage from './pages/auth/PasswordResetPage'; -import MyPage from './pages/mypage/MyPage'; -import AdminPage from './pages/admin/AdminPage'; -import AdminLoginPage from './pages/admin/AdminLoginPage'; -import DetailPage from './pages/shop/DetailPage'; -import CategoryPage from './pages/shop/CategoryPage'; -import CartPage from './pages/cart/CartPage'; -import PrivateRoute from './routes/PrivateRoute'; -import AdminRoute from './routes/AdminRoute'; +import PublicRoutes from './routes/PublicRoutes'; +import AdminRoutes from './routes/AdminRoutes'; function App() { return ( - {/* PrivateRoute */} - {/* 마이페이지 */} - }> - } /> - - - {/* PublicRoute */} - {/* 쇼핑 */} - } /> - } /> - } /> - - {/* 이벤트 */} - } /> - } /> - - {/* 인증 */} - } /> - } /> - } /> - } /> - - {/* 장바구니 */} - } /> - - {/* 메인 */} - } /> - - {/* AdminRoute */} - {/* 관리자 */} - }> - } /> - } /> - + } /> + } /> ); } diff --git a/src/api/admin.ts b/src/api/admin.ts new file mode 100644 index 0000000..8c7d0cf --- /dev/null +++ b/src/api/admin.ts @@ -0,0 +1,36 @@ +import { client } from './client'; + +export const getAdminProducts = async (params?: any) => { + return client + .get(`products`, { params: params }) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; +export const patchProductsStatus = async (id?: number[], status?: string) => { + return client + .patch(`products/products/status`, { product_ids: id, status: status?.toUpperCase() }) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; + +export const deleteProduct = async (params: number) => { + return client + .delete(`products/${params}`) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; + +export const getOrder = async () => { + return client + .get(`order`) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; diff --git a/src/api/category.ts b/src/api/category.ts new file mode 100644 index 0000000..ec52bfe --- /dev/null +++ b/src/api/category.ts @@ -0,0 +1,38 @@ +import { client } from './client'; + +export const getCategory = (parent_id?: number, page?: number, limit?: number) => { + const params: any = {}; + if (page !== undefined) params.page = page; + if (limit !== undefined) params.limit = limit; + if (parent_id !== undefined) params.parent_id = parent_id; + return client.get('/category', { params }); +}; + +export const postCategory = (parent_id?: number, name?: string) => { + const params: any = {}; + if (name !== undefined) params.name = name; + if (parent_id !== undefined && parent_id > 0) params.parent_id = parent_id; + + return client.post('/category', params); +}; +export const putCategory = async (category_id: number, parent_id?: number, name?: string) => { + const params: any = {}; + if (parent_id !== undefined) params.parent_id = parent_id; + if (name !== undefined) params.name = name; + + return client + .put(`category/${category_id}`, params) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; + +export const deleteCategory = async (id: number) => { + return client + .delete(`category/${id}`) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; diff --git a/src/api/client.ts b/src/api/client.ts index a67a8ba..7f0dd5f 100644 --- a/src/api/client.ts +++ b/src/api/client.ts @@ -3,8 +3,9 @@ import axios from 'axios'; axios.defaults.withCredentials = true; export const client = axios.create({ - baseURL: import.meta.env.VITE_PUBLIC_BASE_URL, + baseURL: import.meta.env.VITE_PUBLIC_BASEURL, headers: { 'Content-Type': 'application/json', }, + withCredentials: true, }); diff --git a/src/api/home.ts b/src/api/home.ts new file mode 100644 index 0000000..88d3548 --- /dev/null +++ b/src/api/home.ts @@ -0,0 +1,30 @@ +import { client } from './client'; + +type BannersOrPromotionsType = { + type: 'banner' | 'promotion'; +}; + +export const getBannersOrPromotions = async ({ type }: BannersOrPromotionsType) => { + return client.get('/banners', { params: { query: type } }); +}; + +interface BannerFormData { + title: string; + sub_title: string; + event_url: string; + banner_type: string; + is_active?: boolean; + image_url: File; +} + +export const postBannersOrPromotions = async (formData: BannerFormData) => { + return client.post('/banners', { formData }); +}; + +type PromotionOrMdsChoiceType = { + type: 'best' | 'md_pick'; +}; + +export const getBestProductOrMdsChoice = async ({ type }: PromotionOrMdsChoiceType) => { + return client.get('/promotion-products/get-list', { params: { promotion_type: type } }); +}; diff --git a/src/api/index.ts b/src/api/index.ts new file mode 100644 index 0000000..434505a --- /dev/null +++ b/src/api/index.ts @@ -0,0 +1,9 @@ +import * as productsApi from './products'; +import * as homeApi from './home'; +import * as categoryApi from './category'; +import * as promotionApi from './promotion'; +import * as userApi from './user'; +import * as orderApi from './order'; +import * as adminApi from './admin'; + +export { productsApi, homeApi, categoryApi, promotionApi, userApi, orderApi, adminApi }; diff --git a/src/api/order.ts b/src/api/order.ts new file mode 100644 index 0000000..effd06a --- /dev/null +++ b/src/api/order.ts @@ -0,0 +1,44 @@ +import { client } from './client'; + +export const getPageType = async (pageType: string) => { + return client + .get(`order/page/${pageType}`) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; +export const getOrderSearch = async (params?: any) => { + return client + .get(`order/search`, { params: params }) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; +export const getOrderStatistics = async () => { + return client + .get(`order/statistics`) + .then((response) => response) + .catch((error) => { + console.log(error); + }); +}; +export const postOrderPurchase = async ( + order_id: number, + purchase_number: number, + purchase_date: string, + status: string +) => { + const params: any = {}; + if (order_id !== undefined) params.order_id = order_id; + if (purchase_number !== undefined) params.purchase_number = purchase_number; + if (purchase_date !== undefined) params.purchase_date = purchase_date; + if (status !== undefined) params.status = status; + return client + .post(`order/purchase`) + .then((response) => response, params) + .catch((error) => { + console.log(error); + }); +}; diff --git a/src/api/products.ts b/src/api/products.ts new file mode 100644 index 0000000..8372642 --- /dev/null +++ b/src/api/products.ts @@ -0,0 +1,39 @@ +import { client } from './client'; +import { getAllProductsParams } from './type'; + +/** + * 인자가 필요하다면 인자를 받고 api를 return 하세요 + * index.ts 에서 모든 API를 return 하고있으니 + * 여기서는 API 하나만 return 하면 됩니다. + * + * { productsApi, bannersApi, categoryApi, promotionApi, userApi, cartApi, orderApi } + * 본인 API 위치에서 productsApi.예시(인자) 이런식으로 사용하세요 + * @param id + * @returns + */ + +export const createProduct = (data: FormData) => { + return client.post('/products', data, { headers: { 'Content-Type': 'multipart/form-data' } }); +}; + +export const getSingleProduct = (id: number) => { + return client.get(`/products/${id}`); +}; + +export const getProductsData = async ({ + page = 1, + pageSize = 20, + sort = 'created_at', + order = 'desc', + categoryId, +}: getAllProductsParams) => { + return await client.get(`/products`, { + params: { + page, + page_size: pageSize, + sort, + order, + ...(categoryId && { category_id: categoryId }), + }, + }); +}; diff --git a/src/api/promotion.ts b/src/api/promotion.ts new file mode 100644 index 0000000..ab4dddc --- /dev/null +++ b/src/api/promotion.ts @@ -0,0 +1,15 @@ +import { client } from './client'; + +/** + * 인자가 필요하다면 인자를 받고 api를 return 하세요 + * index.ts 에서 모든 API를 return 하고있으니 + * 여기서는 API 하나만 return 하면 됩니다. + * + * { productsApi, bannersApi, categoryApi, promotionApi, userApi, cartApi, orderApi } + * 본인 API 위치에서 productsApi.예시(인자) 이런식으로 사용하세요 + * @param id + * @returns + */ +export const 예시 = async (id: number) => { + return client.get(`/API 주소 적으세요/${id}`); +}; diff --git a/src/api/type.ts b/src/api/type.ts new file mode 100644 index 0000000..f50eb68 --- /dev/null +++ b/src/api/type.ts @@ -0,0 +1,59 @@ +// 상품의 기본 정보 타입 +export interface ProductDetail2 { + id: number; + product_code: string; + name: string; + price: number; + discount: number; + discount_option: 'percent' | 'amount'; + origin_price: number; + description: string; + detail: string; + brand: string; + status: 'Y' | 'N'; // 상품 활성화 여부 +} + +// 상품 이미지 타입 +export interface ProductImage { + id: number; + image_url: string; +} + +// 상품 옵션 사이즈 타입 +export interface ProductSize { + size: string; + stock: number; +} + +export interface ProductColor { + color: string; + color_code: string; +} + +// 상품 옵션 타입 +export interface ProductOption { + id: number; + color: string; + color_code: string; // 색상 코드 (e.g., #FF0000) + images: ProductImage[]; + sizes: ProductSize[]; +} + +export interface ProductData { + product: ProductDetail2; + options: ProductOption[]; +} + +// 전체 상품 데이터 타입 +export interface ProductDatas { + products: ProductData[]; + total_count: number; +} + +export interface getAllProductsParams { + page?: number; + pageSize?: number; + sort?: 'created_at' | 'price'; + order?: 'desc' | 'asc'; + categoryId?: number; +} diff --git a/src/api/user.ts b/src/api/user.ts new file mode 100644 index 0000000..ab4dddc --- /dev/null +++ b/src/api/user.ts @@ -0,0 +1,15 @@ +import { client } from './client'; + +/** + * 인자가 필요하다면 인자를 받고 api를 return 하세요 + * index.ts 에서 모든 API를 return 하고있으니 + * 여기서는 API 하나만 return 하면 됩니다. + * + * { productsApi, bannersApi, categoryApi, promotionApi, userApi, cartApi, orderApi } + * 본인 API 위치에서 productsApi.예시(인자) 이런식으로 사용하세요 + * @param id + * @returns + */ +export const 예시 = async (id: number) => { + return client.get(`/API 주소 적으세요/${id}`); +}; diff --git a/src/assets/arrow_L.svg b/src/assets/arrow_L.svg new file mode 100644 index 0000000..9b43715 --- /dev/null +++ b/src/assets/arrow_L.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/arrow_R.svg b/src/assets/arrow_R.svg new file mode 100644 index 0000000..9bf43ce --- /dev/null +++ b/src/assets/arrow_R.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/dropdown.svg b/src/assets/dropdown.svg new file mode 100644 index 0000000..a1155ff --- /dev/null +++ b/src/assets/dropdown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/dummys/categoryDatas.ts b/src/assets/dummys/categoryDatas.ts new file mode 100644 index 0000000..7b67d82 --- /dev/null +++ b/src/assets/dummys/categoryDatas.ts @@ -0,0 +1,97 @@ +import { MajorCategory } from './types'; + +export const shopCategoryData: MajorCategory[] = [ + { + id: 1, + majorCategory: 'Outstand', + middleCategories: [ + { + id: 1, + category: 'Best', + }, + { + id: 2, + category: 'Promotion', + }, + { + id: 3, + category: 'New', + }, + ], + }, + { + id: 2, + majorCategory: 'Bag', + middleCategories: [ + { id: 1, category: '1st Gen' }, + { + id: 2, + category: '2st Gen', + }, + ], + }, +]; + +export const eventCategoryData: MajorCategory[] = [ + { + id: 1, + majorCategory: '이벤트1', + middleCategories: [ + { + id: 1, + category: '뭐적을까', + }, + { + id: 2, + category: '잘모르겠다', + }, + { + id: 3, + category: '그러하다', + }, + ], + }, + { + id: 2, + majorCategory: '이벤트2', + middleCategories: [ + { id: 1, category: '뭐적지진짜' }, + { + id: 2, + category: '배고프다', + }, + ], + }, +]; + +export const noticeCategoryData: MajorCategory[] = [ + { + id: 1, + majorCategory: '11월 공지', + middleCategories: [ + { + id: 1, + category: '그러하다', + }, + { + id: 2, + category: '모르겠다', + }, + { + id: 3, + category: '너무어렵다', + }, + ], + }, + { + id: 2, + majorCategory: '12월 공지', + middleCategories: [ + { id: 1, category: '뭐적지' }, + { + id: 2, + category: '배고파요', + }, + ], + }, +]; diff --git a/src/assets/dummys/navigationData.ts b/src/assets/dummys/navigationData.ts new file mode 100644 index 0000000..182cddc --- /dev/null +++ b/src/assets/dummys/navigationData.ts @@ -0,0 +1 @@ +export const navigations: string[] = ['shop', 'event', 'notice']; diff --git a/src/assets/dummys/productListDatas.ts b/src/assets/dummys/productListDatas.ts new file mode 100644 index 0000000..5a0399d --- /dev/null +++ b/src/assets/dummys/productListDatas.ts @@ -0,0 +1,63 @@ +import b_001 from '@/assets/imgs/b_001.jpg'; +import b_002 from '@/assets/imgs/b_002.jpg'; +import b_004 from '@/assets/imgs/b_004.jpg'; +import pouch1_001 from '@/assets/imgs/pouch1_001.jpg'; +import pouch1_002 from '@/assets/imgs/pouch1_002.jpg'; +import pouch1_003 from '@/assets/imgs/pouch1_003.jpg'; +import pouch1_004 from '@/assets/imgs/pouch1_004.jpg'; +import pouch1_005 from '@/assets/imgs/pouch1_005.jpg'; +import pouch1_006 from '@/assets/imgs/pouch1_006.jpg'; +import pouch1_007 from '@/assets/imgs/pouch1_007.jpg'; +import pouch2_001 from '@/assets/imgs/pouch2_001.jpg'; +import pouch2_002 from '@/assets/imgs/pouch2_002.jpg'; +import pouch2_003 from '@/assets/imgs/pouch2_003.jpg'; +import pouch2_004 from '@/assets/imgs/pouch2_004.jpg'; +import pouch2_005 from '@/assets/imgs/pouch2_005.jpg'; +import pouch2_006 from '@/assets/imgs/pouch2_006.jpg'; +import pouch2_007 from '@/assets/imgs/pouch2_007.jpg'; +import banner1 from '@/assets/imgs/image_section-1.jpg'; +import banner2 from '@/assets/imgs/image_section-2.jpg'; +import banner3 from '@/assets/imgs/image_section-3.jpg'; +import banner4 from '@/assets/imgs/image_section-4.jpg'; +import banner5 from '@/assets/imgs/image_section-5.jpg'; + +export const bannerImage = [banner1, banner2, banner3, banner4, banner5]; +export const promotionImage = [banner3, banner4, banner5, banner1, banner1]; +export const Homeimages1 = [ + pouch1_001, + pouch1_002, + pouch1_003, + pouch1_004, + pouch1_005, + pouch1_006, + pouch1_007, + pouch2_001, + pouch2_002, + pouch2_003, + pouch2_004, + pouch2_005, + pouch2_006, + pouch2_007, + b_001, + b_002, + b_004, +]; +export const Homeimages2 = [ + b_004, + pouch2_004, + b_001, + pouch1_003, + pouch2_005, + pouch1_002, + pouch1_004, + pouch1_007, + pouch2_001, + pouch1_001, + pouch2_007, + pouch1_005, + pouch1_006, + pouch2_002, + b_002, + pouch2_003, + pouch2_006, +]; diff --git a/src/assets/dummys/reviewData.ts b/src/assets/dummys/reviewData.ts new file mode 100644 index 0000000..a048005 --- /dev/null +++ b/src/assets/dummys/reviewData.ts @@ -0,0 +1,38 @@ +import b_001 from '@/assets/imgs/b_001.jpg'; +import b_002 from '@/assets/imgs/b_002.jpg'; +import b_004 from '@/assets/imgs/b_004.jpg'; +import b_005 from '@/assets/imgs/b_005.jpg'; +import b_011 from '@/assets/imgs/b_011.jpg'; +import b_012 from '@/assets/imgs/b_012.jpg'; +import b_015 from '@/assets/imgs/b_015.jpg'; + +export const reviewImgs = [ + { + id: 1, + image: b_001, + }, + { + id: 2, + image: b_002, + }, + { + id: 3, + image: b_004, + }, + { + id: 3, + image: b_005, + }, + { + id: 4, + image: b_011, + }, + { + id: 5, + image: b_012, + }, + { + id: 6, + image: b_015, + }, +]; diff --git a/src/assets/dummys/types.ts b/src/assets/dummys/types.ts new file mode 100644 index 0000000..1dc39d2 --- /dev/null +++ b/src/assets/dummys/types.ts @@ -0,0 +1,38 @@ +export interface UserData { + name: string; + email: string; +} + +export type CartItemData = { + id: number; // 장바구니 id + productId: number; // 상품 id + optionId: number | undefined; + productCode: string; // 상품 코드 + name: string; // 상품 이름 + image: string | undefined; // 썸네일 이미지 url + color: string | undefined; + size: string | undefined; + amount: number; // 선택 갯수 + stock: number | undefined; // 상품 재고량 + originPrice: number; // 상품 원가 + price: number; // 최종가 + discount: number; // 할인률 또는 할인금액 + discountOption: 'percent' | 'amount'; +}; + +export type CartItemDatas = { + items: CartItemData[]; +}; + +// 중분류 타입 정의 +export interface MiddleCategory { + id: number; + category: string; +} + +// 대분류 타입 정의 +export interface MajorCategory { + id: number; + majorCategory: string; + middleCategories: MiddleCategory[]; +} diff --git a/src/assets/dummys/user.ts b/src/assets/dummys/user.ts new file mode 100644 index 0000000..ba681b7 --- /dev/null +++ b/src/assets/dummys/user.ts @@ -0,0 +1,6 @@ +import { UserData } from './types'; + +export const user: UserData = { + name: '미낙', + email: 'afs_style@naver.com', +}; diff --git a/src/assets/icons/CartIco.tsx b/src/assets/icons/CartIco.tsx new file mode 100644 index 0000000..5f3490f --- /dev/null +++ b/src/assets/icons/CartIco.tsx @@ -0,0 +1,18 @@ +interface CartIcoProps { + color?: 'black' | 'white'; +} + +const CartIco = ({ color = 'black' }: CartIcoProps) => { + const fillColor = color === 'black' ? '#000000' : '#FFFFFF'; + + return ( + + + + ); +}; + +export default CartIco; diff --git a/src/assets/icons/CheckIco.tsx b/src/assets/icons/CheckIco.tsx new file mode 100644 index 0000000..0b34910 --- /dev/null +++ b/src/assets/icons/CheckIco.tsx @@ -0,0 +1,18 @@ +interface CheckIcoProps { + color?: string; + size?: string | number; +} + +const CheckIco = ({ color = 'black', size = '21' }: CheckIcoProps) => { + const iconSize = typeof size === 'number' ? size.toString() : size; + return ( + + + + ); +}; + +export default CheckIco; diff --git a/src/assets/icons/CloseIco.tsx b/src/assets/icons/CloseIco.tsx new file mode 100644 index 0000000..a41e3de --- /dev/null +++ b/src/assets/icons/CloseIco.tsx @@ -0,0 +1,19 @@ +interface CloseIcoProps { + size?: number | string; + color?: string; +} + +const CloseIco = ({ size = '16', color = 'black' }: CloseIcoProps) => { + const iconSize = typeof size === 'number' ? size.toString() : size; + + return ( + + + + ); +}; + +export default CloseIco; diff --git a/src/assets/icons/LensIco.tsx b/src/assets/icons/LensIco.tsx new file mode 100644 index 0000000..f075595 --- /dev/null +++ b/src/assets/icons/LensIco.tsx @@ -0,0 +1,18 @@ +interface LensIcoProps { + color?: 'black' | 'white'; +} + +const LensIco = ({ color = 'black' }: LensIcoProps) => { + const fillColor = color === 'black' ? '#000000' : '#FFFFFF'; + + return ( + + + + ); +}; + +export default LensIco; diff --git a/src/assets/icons/LikeIco.tsx b/src/assets/icons/LikeIco.tsx new file mode 100644 index 0000000..a41b62e --- /dev/null +++ b/src/assets/icons/LikeIco.tsx @@ -0,0 +1,18 @@ +interface LikeIcoProps { + color?: 'black' | 'white'; +} + +const LikeIco = ({ color = 'black' }: LikeIcoProps) => { + return ( + + + + ); +}; + +export default LikeIco; diff --git a/src/assets/icons/PlusBtnIco.tsx b/src/assets/icons/PlusBtnIco.tsx new file mode 100644 index 0000000..c7a215e --- /dev/null +++ b/src/assets/icons/PlusBtnIco.tsx @@ -0,0 +1,9 @@ +const PlusBtnIco = () => { + return ( + + + + ); +}; + +export default PlusBtnIco; diff --git a/src/assets/icons/UserIco.tsx b/src/assets/icons/UserIco.tsx new file mode 100644 index 0000000..09cadaa --- /dev/null +++ b/src/assets/icons/UserIco.tsx @@ -0,0 +1,18 @@ +interface UserIcoProps { + color?: 'black' | 'white'; +} + +const UserIco = ({ color = 'black' }: UserIcoProps) => { + return ( + + + + ); +}; + +export default UserIco; diff --git a/src/assets/icons/arrowDropDown.svg b/src/assets/icons/arrowDropDown.svg new file mode 100644 index 0000000..19af8b0 --- /dev/null +++ b/src/assets/icons/arrowDropDown.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/arrowDropUp.svg b/src/assets/icons/arrowDropUp.svg new file mode 100644 index 0000000..d817384 --- /dev/null +++ b/src/assets/icons/arrowDropUp.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/arrowRight.svg b/src/assets/icons/arrowRight.svg new file mode 100644 index 0000000..58f3704 --- /dev/null +++ b/src/assets/icons/arrowRight.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/cart.svg b/src/assets/icons/cart.svg new file mode 100644 index 0000000..dfce060 --- /dev/null +++ b/src/assets/icons/cart.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/checkIco.svg b/src/assets/icons/checkIco.svg new file mode 100644 index 0000000..5f81045 --- /dev/null +++ b/src/assets/icons/checkIco.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/closeIco.svg b/src/assets/icons/closeIco.svg new file mode 100644 index 0000000..56b5d8c --- /dev/null +++ b/src/assets/icons/closeIco.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/completeCheck.svg b/src/assets/icons/completeCheck.svg new file mode 100644 index 0000000..581df9a --- /dev/null +++ b/src/assets/icons/completeCheck.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/assets/icons/dropDownIco.svg b/src/assets/icons/dropDownIco.svg new file mode 100644 index 0000000..91c77b8 --- /dev/null +++ b/src/assets/icons/dropDownIco.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/facebook.svg b/src/assets/icons/facebook.svg new file mode 100644 index 0000000..6bd1d35 --- /dev/null +++ b/src/assets/icons/facebook.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/instagram.svg b/src/assets/icons/instagram.svg new file mode 100644 index 0000000..f0d0e0d --- /dev/null +++ b/src/assets/icons/instagram.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/kakao.svg b/src/assets/icons/kakao.svg new file mode 100644 index 0000000..d1e4274 --- /dev/null +++ b/src/assets/icons/kakao.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/kakaopay.svg b/src/assets/icons/kakaopay.svg new file mode 100644 index 0000000..5a0d2b4 --- /dev/null +++ b/src/assets/icons/kakaopay.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/icons/lens.svg b/src/assets/icons/lens.svg new file mode 100644 index 0000000..7e64eb6 --- /dev/null +++ b/src/assets/icons/lens.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/like.svg b/src/assets/icons/like.svg new file mode 100644 index 0000000..299d4b5 --- /dev/null +++ b/src/assets/icons/like.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/minus.svg b/src/assets/icons/minus.svg new file mode 100644 index 0000000..8578f6d --- /dev/null +++ b/src/assets/icons/minus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/naver.svg b/src/assets/icons/naver.svg new file mode 100644 index 0000000..8bec0c1 --- /dev/null +++ b/src/assets/icons/naver.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/naverPayLogo.svg b/src/assets/icons/naverPayLogo.svg new file mode 100644 index 0000000..cfc6807 --- /dev/null +++ b/src/assets/icons/naverPayLogo.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/naverPayText.svg b/src/assets/icons/naverPayText.svg new file mode 100644 index 0000000..41d5489 --- /dev/null +++ b/src/assets/icons/naverPayText.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/plus.svg b/src/assets/icons/plus.svg new file mode 100644 index 0000000..0cbf603 --- /dev/null +++ b/src/assets/icons/plus.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/setting.svg b/src/assets/icons/setting.svg new file mode 100644 index 0000000..0ee07a7 --- /dev/null +++ b/src/assets/icons/setting.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/user.svg b/src/assets/icons/user.svg new file mode 100644 index 0000000..fbfb6c1 --- /dev/null +++ b/src/assets/icons/user.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/youTube.svg b/src/assets/icons/youTube.svg new file mode 100644 index 0000000..f79e532 --- /dev/null +++ b/src/assets/icons/youTube.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/imgs/LogoWhite.tsx b/src/assets/imgs/LogoWhite.tsx new file mode 100644 index 0000000..a810a3e --- /dev/null +++ b/src/assets/imgs/LogoWhite.tsx @@ -0,0 +1,40 @@ +const LogoWhite = ({ size = 'm' }: { size?: 'xs' | 's' | 'm' | 'l' }) => { + const matchedSize = { + xs: 50, // Small size width + s: 70, + m: 100, // Medium size width + l: 150, // Large size width + }; + + const width = matchedSize[size]; + const height = (width / 100) * 37; // Maintain original aspect ratio (width: 100, height: 37) + + return ( + + + + + + + + + + + + ); +}; + +export default LogoWhite; diff --git a/src/assets/imgs/b_001.jpg b/src/assets/imgs/b_001.jpg new file mode 100644 index 0000000..1e9502d Binary files /dev/null and b/src/assets/imgs/b_001.jpg differ diff --git a/src/assets/imgs/b_002.jpg b/src/assets/imgs/b_002.jpg new file mode 100644 index 0000000..09c145a Binary files /dev/null and b/src/assets/imgs/b_002.jpg differ diff --git a/src/assets/imgs/b_004.jpg b/src/assets/imgs/b_004.jpg new file mode 100644 index 0000000..cdfecb0 Binary files /dev/null and b/src/assets/imgs/b_004.jpg differ diff --git a/src/assets/imgs/b_005.jpg b/src/assets/imgs/b_005.jpg new file mode 100644 index 0000000..44fc45c Binary files /dev/null and b/src/assets/imgs/b_005.jpg differ diff --git a/src/assets/imgs/b_011.jpg b/src/assets/imgs/b_011.jpg new file mode 100644 index 0000000..e988bfa Binary files /dev/null and b/src/assets/imgs/b_011.jpg differ diff --git a/src/assets/imgs/b_012.jpg b/src/assets/imgs/b_012.jpg new file mode 100644 index 0000000..920115c Binary files /dev/null and b/src/assets/imgs/b_012.jpg differ diff --git a/src/assets/imgs/b_015.jpg b/src/assets/imgs/b_015.jpg new file mode 100644 index 0000000..238a8a3 Binary files /dev/null and b/src/assets/imgs/b_015.jpg differ diff --git a/src/assets/imgs/image_section-1.jpg b/src/assets/imgs/image_section-1.jpg new file mode 100644 index 0000000..3703b73 Binary files /dev/null and b/src/assets/imgs/image_section-1.jpg differ diff --git a/src/assets/imgs/image_section-2.jpg b/src/assets/imgs/image_section-2.jpg new file mode 100644 index 0000000..7aa2570 Binary files /dev/null and b/src/assets/imgs/image_section-2.jpg differ diff --git a/src/assets/imgs/image_section-3.jpg b/src/assets/imgs/image_section-3.jpg new file mode 100644 index 0000000..675061a Binary files /dev/null and b/src/assets/imgs/image_section-3.jpg differ diff --git a/src/assets/imgs/image_section-4.jpg b/src/assets/imgs/image_section-4.jpg new file mode 100644 index 0000000..1da80a7 Binary files /dev/null and b/src/assets/imgs/image_section-4.jpg differ diff --git a/src/assets/imgs/image_section-5.jpg b/src/assets/imgs/image_section-5.jpg new file mode 100644 index 0000000..31abda4 Binary files /dev/null and b/src/assets/imgs/image_section-5.jpg differ diff --git a/src/assets/imgs/logoBlack.svg b/src/assets/imgs/logoBlack.svg new file mode 100644 index 0000000..7695ab9 --- /dev/null +++ b/src/assets/imgs/logoBlack.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/imgs/logoText.svg b/src/assets/imgs/logoText.svg new file mode 100644 index 0000000..b5d4c4e --- /dev/null +++ b/src/assets/imgs/logoText.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/imgs/logoWhite.svg b/src/assets/imgs/logoWhite.svg new file mode 100644 index 0000000..7bd02b0 --- /dev/null +++ b/src/assets/imgs/logoWhite.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/assets/imgs/pouch.svg b/src/assets/imgs/pouch.svg new file mode 100644 index 0000000..a96a66a --- /dev/null +++ b/src/assets/imgs/pouch.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/assets/imgs/pouch1_001.jpg b/src/assets/imgs/pouch1_001.jpg new file mode 100644 index 0000000..e172deb Binary files /dev/null and b/src/assets/imgs/pouch1_001.jpg differ diff --git a/src/assets/imgs/pouch1_002.jpg b/src/assets/imgs/pouch1_002.jpg new file mode 100644 index 0000000..805ef9a Binary files /dev/null and b/src/assets/imgs/pouch1_002.jpg differ diff --git a/src/assets/imgs/pouch1_003.jpg b/src/assets/imgs/pouch1_003.jpg new file mode 100644 index 0000000..fa61f11 Binary files /dev/null and b/src/assets/imgs/pouch1_003.jpg differ diff --git a/src/assets/imgs/pouch1_004.jpg b/src/assets/imgs/pouch1_004.jpg new file mode 100644 index 0000000..d596abf Binary files /dev/null and b/src/assets/imgs/pouch1_004.jpg differ diff --git a/src/assets/imgs/pouch1_005.jpg b/src/assets/imgs/pouch1_005.jpg new file mode 100644 index 0000000..8654a15 Binary files /dev/null and b/src/assets/imgs/pouch1_005.jpg differ diff --git a/src/assets/imgs/pouch1_006.jpg b/src/assets/imgs/pouch1_006.jpg new file mode 100644 index 0000000..00124f8 Binary files /dev/null and b/src/assets/imgs/pouch1_006.jpg differ diff --git a/src/assets/imgs/pouch1_007.jpg b/src/assets/imgs/pouch1_007.jpg new file mode 100644 index 0000000..1a25222 Binary files /dev/null and b/src/assets/imgs/pouch1_007.jpg differ diff --git a/src/assets/imgs/pouch2_001.jpg b/src/assets/imgs/pouch2_001.jpg new file mode 100644 index 0000000..ecce2bd Binary files /dev/null and b/src/assets/imgs/pouch2_001.jpg differ diff --git a/src/assets/imgs/pouch2_002.jpg b/src/assets/imgs/pouch2_002.jpg new file mode 100644 index 0000000..61d217a Binary files /dev/null and b/src/assets/imgs/pouch2_002.jpg differ diff --git a/src/assets/imgs/pouch2_003.jpg b/src/assets/imgs/pouch2_003.jpg new file mode 100644 index 0000000..0be7d54 Binary files /dev/null and b/src/assets/imgs/pouch2_003.jpg differ diff --git a/src/assets/imgs/pouch2_004.jpg b/src/assets/imgs/pouch2_004.jpg new file mode 100644 index 0000000..9717a1e Binary files /dev/null and b/src/assets/imgs/pouch2_004.jpg differ diff --git a/src/assets/imgs/pouch2_005.jpg b/src/assets/imgs/pouch2_005.jpg new file mode 100644 index 0000000..e646cdf Binary files /dev/null and b/src/assets/imgs/pouch2_005.jpg differ diff --git a/src/assets/imgs/pouch2_006.jpg b/src/assets/imgs/pouch2_006.jpg new file mode 100644 index 0000000..cda8108 Binary files /dev/null and b/src/assets/imgs/pouch2_006.jpg differ diff --git a/src/assets/imgs/pouch2_007.jpg b/src/assets/imgs/pouch2_007.jpg new file mode 100644 index 0000000..bd2ba78 Binary files /dev/null and b/src/assets/imgs/pouch2_007.jpg differ diff --git a/src/assets/mic_golf_logo.svg b/src/assets/mic_golf_logo.svg deleted file mode 100644 index 45f0189..0000000 --- a/src/assets/mic_golf_logo.svg +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/components/Button.tsx b/src/components/Button.tsx new file mode 100644 index 0000000..1cbd7a7 --- /dev/null +++ b/src/components/Button.tsx @@ -0,0 +1,21 @@ +type ButtonProps = { + type?: 'button' | 'submit'; + title: string; + onClick?: () => void; + className?: string; + color?: string; +}; + +const Button = ({ type = 'button', title, onClick, className, color = 'bg-primary text-white' }: ButtonProps) => { + return ( + + ); +}; + +export default Button; diff --git a/src/components/CounterMessage.tsx b/src/components/CounterMessage.tsx new file mode 100644 index 0000000..b470af9 --- /dev/null +++ b/src/components/CounterMessage.tsx @@ -0,0 +1,49 @@ +import { AnimatePresence, motion } from 'framer-motion'; + +interface CounterMessageProps { + isOpen: boolean; + isMobile?: boolean; + position?: 'row' | 'col'; +} + +const CounterMessage = ({ isOpen, isMobile, position = 'row' }: CounterMessageProps) => { + const pos = position === 'row' ? '-right-[120px]' : isMobile ? '-top-[30px]' : '-top-[40px]'; + + return ( + + {isOpen && ( + + 최대수량입니다. + + )} + + ); +}; + +export default CounterMessage; diff --git a/src/components/GlobalCounterBtn.tsx b/src/components/GlobalCounterBtn.tsx new file mode 100644 index 0000000..b40c440 --- /dev/null +++ b/src/components/GlobalCounterBtn.tsx @@ -0,0 +1,95 @@ +import minus from '@/assets/icons/minus.svg'; +import plus from '@/assets/icons/plus.svg'; +import { useEffect, useState } from 'react'; +import { AnimatePresence, motion } from 'framer-motion'; +import CounterMessage from './CounterMessage'; +import { CartItemData } from '@/assets/dummys/types'; + +interface CounterBtnProps { + data: CartItemData; + isMobile: boolean; + stock: number | undefined; + size?: 's' | 'm' | 'l'; + handleUpdateCount: (id: number, newCount: number) => void; +} + +const GlobalCounterBtn = ({ data, isMobile, stock, size = 'l', handleUpdateCount }: CounterBtnProps) => { + const maxCount = stock ?? 0; + const [isMaxStock, setIsMaxStock] = useState(false); + const [count, setCount] = useState(data.amount || 1); + + useEffect(() => { + if (count >= maxCount) { + setIsMaxStock(true); + } else { + setIsMaxStock(false); + } + }, [count, maxCount]); + + const handleDecrease = () => { + if (count > 1) { + const newCount = count - 1; + setCount(newCount); + handleUpdateCount(data.id, newCount); + } + }; + + const handleIncrease = () => { + if (!maxCount) return; + if (count < maxCount) { + const newCount = count + 1; + setCount(newCount); + handleUpdateCount(data.id, newCount); + } + }; + + // 버튼 크기 클래스 매핑 + const sizeClasses = { + s: 'h-[30px] w-[80px]', + m: 'h-[40px] w-[130px]', + l: 'h-[50px] w-[170px]', + }; + + return ( +
+
+ + +

+ + + {count} + + +

+ + + + +
+
+ ); +}; + +export default GlobalCounterBtn; diff --git a/src/components/Input.tsx b/src/components/Input.tsx new file mode 100644 index 0000000..0bac1fb --- /dev/null +++ b/src/components/Input.tsx @@ -0,0 +1,75 @@ +import { InputHTMLAttributes } from 'react'; +import { RegisterOptions, UseFormRegister } from 'react-hook-form'; + +export interface InputProps extends InputHTMLAttributes { + label: string; + name: string; + type: string; + register: UseFormRegister; + registerOptions?: RegisterOptions; + onChange?: (e: React.ChangeEvent) => void; + error?: string; + className?: string; +} + +/** + * react-hook-form 사용을 바탕으로 만들어진 Floating Label Input 컴포넌트 + * + * @component + * @example + * ```jsx + * + * ``` + * + * @param {Object} props - 컴포넌트의 props + * @param {string} props.label - input의 라벨 텍스트 + * @param {string} props.name - input 필드의 이름 + * @param {string} props.type - input 필드의 타입 (기본값은 'text') + * @param {UseFormRegister} props.register - react-hook-form의 register 함수 + * @param {RegisterOptions} props.registerOptions - react-hook-form의 register 함수의 옵션 + * @param {(e: React.ChangeEvent) => void} props.onChange - input 필드의 onChange 이벤트 핸들러 + * @param {string} props.error - input 필드의 에러 메시지 + * @param {string} props.className - 추가적인 CSS 클래스 (tailwindcss) + * @returns + */ +export const Input = ({ className, label, name, register, registerOptions, error, onChange, type }: InputProps) => { + const { onChange: registerOnChange, ...registerRest } = register(name, registerOptions); + + const inputStyle = `${className} ${ + error ? 'border-red-500 focus:ring-red-500' : 'border-gray-300 focus:ring-primary' + } peer w-full border border-neutral-300 px-4 py-3 placeholder-transparent focus:outline-none focus:ring-1 focus:ring-inset `; + + const FloatinglabelStyle = `${error ? 'text-red-500 peer-focus:text-red-500 peer-placeholder-shown:text-red-500' : 'text-gray-600 peer-focus:text-gray-600 peer-placeholder-shown:text-gray-400'} absolute left-3 -top-3 bg-white px-1 text-sm transition-all peer-placeholder-shown:top-3 peer-placeholder-shown:text-base peer-focus:-top-3 peer-focus:text-sm`; + + const handleChange = (event: React.ChangeEvent) => { + if (onChange) { + return onChange(event); + } + + return registerOnChange(event); + }; + + return ( +
+ + + {error &&

{error}

} +
+ ); +}; diff --git a/src/components/LoadingSpinner.tsx b/src/components/LoadingSpinner.tsx new file mode 100644 index 0000000..399670e --- /dev/null +++ b/src/components/LoadingSpinner.tsx @@ -0,0 +1,24 @@ +interface LoadingSpinnerProps { + size?: 's' | 'm' | 'l'; +} + +const LoadingSpinner = ({ size = 'm' }: LoadingSpinnerProps) => { + const matchedSize = { + s: 'w-4 h-4', + m: 'w-8 h-8', + l: 'w-14 h-14', + }; + + const sizeClass = matchedSize[size]; + + return ( +
+
+
+
+
+
+ ); +}; + +export default LoadingSpinner; diff --git a/src/components/SaleLabel.tsx b/src/components/SaleLabel.tsx new file mode 100644 index 0000000..03a76ba --- /dev/null +++ b/src/components/SaleLabel.tsx @@ -0,0 +1,22 @@ +import { useSaleContext } from './SaleProvider'; + +interface SaleLabelProps { + classString?: string; // 선택적으로 추가 클래스 제공 + text?: string; // 선택적으로 텍스트 제공 (기본값은 saleLabelText 사용) +} + +const SaleLabel = ({ classString = '', text }: SaleLabelProps) => { + const { isSale, saleLabelText, labelClassNames } = useSaleContext(); + + if (!isSale) return null; + + return ( +

+ {text || saleLabelText} +

+ ); +}; + +export default SaleLabel; diff --git a/src/components/SalePrice.tsx b/src/components/SalePrice.tsx new file mode 100644 index 0000000..6a9486d --- /dev/null +++ b/src/components/SalePrice.tsx @@ -0,0 +1,52 @@ +interface SalePriceProps { + price: number; + originPrice: number; + originalSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl'; + saleSize?: 'sm' | 'md' | 'lg' | 'xl' | '2xl'; + flex?: 'row' | 'col'; + align?: 'start' | 'center' | 'between'; +} + +const SalePrice = ({ + price, + originPrice, + originalSize = 'lg', + saleSize = 'xl', + flex = 'col', + align = 'start', +}: SalePriceProps) => { + // Tailwind CSS의 텍스트 크기 클래스 매핑 + const sizeClasses = { + xs: 'text-xs', + sm: 'text-sm', + md: 'text-md', + lg: 'text-lg', + xl: 'text-xl', + '2xl': 'text-2xl', + }; + + // Flex 방향 및 정렬 클래스 매핑 + const flexClasses = { + row: `flex flex-row items-center gap-2`, + col: `flex flex-col`, + }; + + const alignClasses = { + start: 'items-start', // 시작 정렬 + center: 'items-center', // 중앙 정렬 + between: 'justify-between items-center', // 양쪽 정렬 + }; + + return ( +
+ {/* 취소선 가격 */} +

+ ₩{originPrice.toLocaleString()} +

+ {/* 할인 가격 */} +

₩{price.toLocaleString()}

+
+ ); +}; + +export default SalePrice; diff --git a/src/components/SaleProvider.tsx b/src/components/SaleProvider.tsx new file mode 100644 index 0000000..3e0b35b --- /dev/null +++ b/src/components/SaleProvider.tsx @@ -0,0 +1,34 @@ +import { createContext, useContext, ReactNode } from 'react'; +import useSaleState from '@/hooks/useSaleState'; + +// Sale Context 정의 +interface SaleContextType { + isSale: boolean; + saleLabelText: string; + labelClassNames: string; +} + +// 기본값 설정 (null로 설정 후 타입가드 활용) +const SaleContext = createContext(null); + +// SaleProvider Props 타입 정의 +interface SaleProviderProps { + discount: number; + discountOption: 'percent' | 'amount'; + children?: ReactNode; +} + +export const SaleProvider = ({ discount, discountOption, children }: SaleProviderProps) => { + const saleState = useSaleState({ discount, discountOption }); + + return {children}; +}; + +// SaleContext Hook 정의 +export const useSaleContext = () => { + const context = useContext(SaleContext); + if (!context) { + throw new Error('useSaleContext must be used within a SaleProvider'); + } + return context; +}; diff --git a/src/components/Test.tsx b/src/components/Test.tsx deleted file mode 100644 index ff0170e..0000000 --- a/src/components/Test.tsx +++ /dev/null @@ -1,13 +0,0 @@ -interface IHandlerProps { - handler: () => string; -} - -const Test = ({ handler }: IHandlerProps) => { - return ( - - ); -}; - -export default Test; diff --git a/src/config/store.ts b/src/config/store.ts index e69de29..9214419 100644 --- a/src/config/store.ts +++ b/src/config/store.ts @@ -0,0 +1,32 @@ +import { create } from 'zustand'; +import { HeaderRefStore, MobileStore } from './types'; + +export const useHeaderStore = create((set) => ({ + headerRef: null, + setHeaderRef: (headerRef) => set({ headerRef }), +})); + +export const useMobileScrollStore = create((set) => ({ + isMobileMode: false, + setIsMobileMode: () => set((state) => ({ isMobileMode: !state.isMobileMode })), +})); + +type User = { + isa: string; + iss: string; + user_id: number; + user_name: string; + user_type: 'guest' | 'admin'; +}; + +type AuthState = { + user: User | null; + setUser: (user: User | null) => void; + clearUser: () => void; +}; + +export const useAuthStore = create((set) => ({ + user: null, + setUser: (user) => set({ user }), + clearUser: () => set({ user: null }), +})); diff --git a/src/config/types.ts b/src/config/types.ts index e69de29..c1386f0 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -0,0 +1,9 @@ +export interface HeaderRefStore { + headerRef: HTMLElement | null; + setHeaderRef: (headerRef: HTMLElement | null) => void; +} + +export interface MobileStore { + isMobileMode: boolean; + setIsMobileMode: (state: boolean) => void; +} diff --git a/src/global.css b/src/global.css index b5c61c9..56f8e8e 100644 --- a/src/global.css +++ b/src/global.css @@ -1,3 +1,59 @@ +@import url('https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&display=swap'); + @tailwind base; @tailwind components; @tailwind utilities; + +/* Chrome, Safari, Edge, Opera */ +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +/* 자동완성 input 배경색 제거 */ +input:-webkit-autofill { + box-shadow: 0 0 0px 1000px white inset !important; /* 배경색 제거 */ + -webkit-text-fill-color: black !important; /* 텍스트 색상 설정 */ +} + +/* Firefox */ +input[type='number'] { + -moz-appearance: textfield; +} + +/* 스크롤바 넓이 지정 */ +::-webkit-scrollbar { + width: 4px; +} + +/* 스크롤바 트랙 꾸미기 */ +::-webkit-scrollbar-track { + background: #ececec; + border-radius: 5px; +} + +/* 스크롤바 손잡이 꾸미기 */ +::-webkit-scrollbar-thumb { + background: black; + border-radius: 5px; +} + +/* 스크롤바 손잡이 호버 시 색 */ +::-webkit-scrollbar-thumb:hover { + background: #2f2f2f; +} + +.disable-scroll { + overflow: hidden; + height: 100vh; +} + +.swiper-pagination-bullet-active { + background-color: black; /* 활성화된 점 색상 */ +} + +select:disabled { + z-index: 1; + position: relative; +} diff --git a/src/hooks/useCachedData.ts b/src/hooks/useCachedData.ts new file mode 100644 index 0000000..bcd56b3 --- /dev/null +++ b/src/hooks/useCachedData.ts @@ -0,0 +1,50 @@ +import { ProductData, ProductDatas } from '@/api/type'; +import { useQueryClient } from '@tanstack/react-query'; +import { useLocation, useParams } from 'react-router-dom'; + +interface LocationState { + queryKey?: any[]; +} + +interface UseCachedDataResult { + cachedData: ProductData | null; + id: string | undefined; + hasCachedData: boolean; +} + +export const useCachedData = (): UseCachedDataResult => { + const { id } = useParams<{ id: string }>(); + const location = useLocation(); + const queryClient = useQueryClient(); + + const getQueryData = () => { + const state = location.state as LocationState; + + if (!state?.queryKey || !id) { + console.log('location.state에 queryKey가 없거나 상품 ID가 없습니다.'); + return null; + } + + const queryKey = state.queryKey; + const cachedProducts = queryClient.getQueryData(queryKey)?.products; + + if (!Array.isArray(cachedProducts)) { + console.log('캐싱된 데이터가 Array가 아니므로 find 메서드가 작동하지 않습니다.'); + return null; + } + + const cachedData = cachedProducts.find((item) => item.product.id === Number(id)); + + if (!cachedData) { + console.log(`ID(${id})에 해당하는 캐싱된 데이터가 없습니다.`); + return null; + } + + return cachedData; + }; + + const cachedData = getQueryData(); + const hasCachedData = cachedData !== null; + + return { cachedData, id, hasCachedData }; +}; diff --git a/src/hooks/useCartCalculations.ts b/src/hooks/useCartCalculations.ts new file mode 100644 index 0000000..f075651 --- /dev/null +++ b/src/hooks/useCartCalculations.ts @@ -0,0 +1,18 @@ +import { CartItemData } from '@/assets/dummys/types'; +import { useMemo } from 'react'; + +const useCartCalculations = (selectedProducts: CartItemData[]) => { + const totalPrice = useMemo(() => { + return selectedProducts.reduce((sum, item) => { + const finalPrice = item.discount > 0 ? item.price : item.originPrice; + return sum + finalPrice * item.amount; + }, 0); + }, [selectedProducts]); + + const totalDeliveryFee = useMemo(() => { + return selectedProducts.length === 0 ? 0 : totalPrice >= 50000 ? 0 : 2500; + }, [selectedProducts, totalPrice]); + + return { totalPrice, totalDeliveryFee }; +}; +export default useCartCalculations; diff --git a/src/hooks/useCartSelection.ts b/src/hooks/useCartSelection.ts new file mode 100644 index 0000000..bde0cc6 --- /dev/null +++ b/src/hooks/useCartSelection.ts @@ -0,0 +1,81 @@ +import { CartItemData } from '@/assets/dummys/types'; +import { useEffect, useState } from 'react'; +import useLocalStorage from './useLocalStorage'; + +export const useCartSelection = (cartItems: CartItemData[]) => { + const [_, setValue] = useLocalStorage('cartItems', []); + const [selectedItems, setSelectedItems] = useState([]); + const [cartItemArr, setCartItemArr] = useState(cartItems); // 상태로 cartItems 배열을 관리 + const [selectAll, setSelectAll] = useState(false); // 전체 선택 상태 추적 + + // 전달된 cartItems의 변화를 감지하여 상태 업데이트 + useEffect(() => { + setCartItemArr(cartItems); + }, [cartItems]); + + // 바로구매 기능 + const handleBuyNow = (itemId: number) => { + setSelectedItems([itemId]); + }; + + // 장바구니 아이템 리스트 선택(체크박스) 토글 + const handleCartSelectToggle = (itemId: number) => { + setSelectedItems( + (prev) => + prev.includes(itemId) + ? prev.filter((id) => id !== itemId) // 이미 선택된 아이템이면 제거 + : [...prev, itemId] // 선택되지 않은 아이템이면 추가 + ); + }; + + // 수량 변경 함수 + const handleUpdateCount = (itemId: number, newCount: number) => { + setCartItemArr((prevCart) => prevCart.map((item) => (item.id === itemId ? { ...item, amount: newCount } : item))); + }; + + // 선택된 제품 필터링 + const selectedProducts = cartItemArr.filter((item) => selectedItems.includes(item.id)); + + // 전체 선택/해제 처리 + const handleSelectAll = () => { + if (selectAll) { + setSelectedItems([]); // 선택된 아이템이 있으면 전체 해제 + } else { + setSelectedItems(cartItemArr.map((item) => item.id)); // 모든 아이템을 선택 + } + setSelectAll(!selectAll); // selectAll 상태 반전 + }; + + // 선택된 아이템 삭제 + const handleRemoveSelectedItems = () => { + const updatedCart = cartItemArr.filter((item) => !selectedItems.includes(item.id)); // 선택된 아이템 삭제 + setCartItemArr(updatedCart); // 상태에서 장바구니 업데이트 + setSelectedItems([]); // 선택된 아이템 상태 초기화 + setValue(updatedCart); // 로컬 스토리지에 새로운 장바구니 배열 저장 + }; + + const handleRemoveSingleItem = (itemId: number) => { + const updatedCart = cartItemArr.filter((item) => item.id !== itemId); + setCartItemArr(updatedCart); + setSelectedItems([]); + setValue(updatedCart); + }; + + useEffect(() => { + // 전체 선택 상태 업데이트 (장바구니의 아이템 모두가 선택되면 전체 선택 상태 true) + setSelectAll(selectedItems.length === cartItemArr.length); + }, [selectedItems, cartItemArr, cartItemArr.length]); + + return { + cartItemArr, + selectedItems, + selectedProducts, + selectAll, // 전체 선택 상태 + handleBuyNow, + handleCartSelectToggle, + handleUpdateCount, + handleSelectAll, // 전체 선택/해제 함수 + handleRemoveSelectedItems, // 선택된 아이템 삭제 함수 + handleRemoveSingleItem, // X버튼을 눌렀을때 아이템 하나만 삭제하는 함수 + }; +}; diff --git a/src/hooks/useDebounce.ts b/src/hooks/useDebounce.ts new file mode 100644 index 0000000..6e50026 --- /dev/null +++ b/src/hooks/useDebounce.ts @@ -0,0 +1,18 @@ +import { useCallback, useRef } from 'react'; + +export function useDebounce void>(callback: T, delay: number): T { + const timeoutRef = useRef(null); + + return useCallback( + (...args: Parameters) => { + if (timeoutRef.current) { + clearTimeout(timeoutRef.current); + } + + timeoutRef.current = setTimeout(() => { + callback(...args); + }, delay); + }, + [callback, delay] + ) as T; +} diff --git a/src/hooks/useDefaultImage.ts b/src/hooks/useDefaultImage.ts new file mode 100644 index 0000000..a07bca3 --- /dev/null +++ b/src/hooks/useDefaultImage.ts @@ -0,0 +1,43 @@ +import { useEffect, useState } from 'react'; +import logoWhite from '@/assets/imgs/logoWhite.svg'; + +interface UseDefaultImageReturn { + isImageError: boolean; + handleOnError: (event: React.SyntheticEvent) => void; + isImageLoading: boolean; + handleOnLoad: () => void; +} + +/** + * img 로딩 중 실패하거나 로딩중일때 default이미지 설정해주는 훅 + * @returns isImageError, setDefaultImage + */ +const useDefaultImage = (validation: boolean): UseDefaultImageReturn => { + const [isImageError, setIsImageError] = useState(false); + const [isImageLoading, setIsImageLoading] = useState(true); + + // 만약 이미지URL이 존재하지 않는 경우 => 로딩상태 false => DefaultImage 컴포넌트가 렌더링 됨. + useEffect(() => { + if (!validation) { + setIsImageLoading(false); + } + }, [validation]); + + const setDefaultImage = (event: React.SyntheticEvent) => { + setIsImageError(true); + event.currentTarget.src = logoWhite; // 경로 Optional + }; + + const handleOnError = (event: React.SyntheticEvent) => { + setIsImageLoading(false); + setDefaultImage(event); + }; + + const handleOnLoad = () => { + setIsImageLoading(false); + }; + + return { isImageError, handleOnError, handleOnLoad, isImageLoading }; +}; + +export default useDefaultImage; diff --git a/src/hooks/useDeleteCartItem.ts b/src/hooks/useDeleteCartItem.ts new file mode 100644 index 0000000..602d8f7 --- /dev/null +++ b/src/hooks/useDeleteCartItem.ts @@ -0,0 +1,30 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { client } from '@/api/client'; + +export const deleteCartItem = async (productId: number, optionId: number | undefined, accessToken: string) => { + try { + const response = await client.delete(`/cart?product_id=${productId}&option_id=${optionId}`, { + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + return response.data; + } catch (err) { + throw err; + } +}; + +const useDeleteCartItem = (productId: number, optionId: number | undefined, accessToken: string) => { + const queryClient = useQueryClient(); + + const mutation = useMutation({ + mutationFn: () => deleteCartItem(productId, optionId, accessToken), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: ['cartItems'] }); + }, + }); + + return mutation; +}; + +export default useDeleteCartItem; diff --git a/src/hooks/useGetCartItem.ts b/src/hooks/useGetCartItem.ts new file mode 100644 index 0000000..8e76cf8 --- /dev/null +++ b/src/hooks/useGetCartItem.ts @@ -0,0 +1,96 @@ +import { client } from '@/api/client'; +import { useAuthStore } from '@/config/store'; +import { useQuery } from '@tanstack/react-query'; +import useLocalStorage from './useLocalStorage'; +import { handleApiError } from '@/utils/handleApiError'; + +export type ServerCartItem = { + cart_id: number; // 장바구니 아이템 ID + user_id: number; // 사용자 ID + product_id: number; // 상품 ID + option_id: number; + product_code: string; // 상품 코드 + product_name: string; // 상품 이름 + product_image_url: string; // 상품 이미지 URL + product_color: string; // 상품 색상 + product_size: string; // 상품 사이즈 + product_amount: number; // 상품 수량 + product_stock: number; // 상품 재고 + origin_price: number; // 원래 가격 + price: number; // 가격 + discount: number; // 할인율 + discount_option: 'percent' | 'amount'; // 할인 옵션 ('percent' 또는 'amount') +}; + +export type TransformedCartItems = { + id: number; // 장바구니 아이템 ID + userId: number; // 사용자 ID + productId: number; // 상품 ID + optionId: number; + productCode: string; // 상품 코드 + name: string; // 상품 이름 + image: string; // 상품 이미지 URL + color: string; // 상품 색상 + size: string; // 상품 사이즈 + amount: number; // 상품 수량 + stock: number; // 상품 재고 + originPrice: number; // 원래 가격 + price: number; // 가격 + discount: number; // 할인율 + discountOption: 'percent' | 'amount'; // 할인 옵션 ('percent' 또는 'amount') +}; + +const useGetCartItem = () => { + const { user } = useAuthStore(); + const [guestCartItems] = useLocalStorage('cartItems', []); + const accessToken = localStorage.getItem('accessToken') || ''; + + const { + data: cartItems = [], + isPending, + isError, + error, + } = useQuery({ + queryKey: ['cartItems'], + queryFn: async (): Promise => { + try { + const response = await client.get('/cart', { + headers: { Authorization: `Bearer ${accessToken}` }, + }); + + // 응답을 올바르게 매핑하여 반환 + const transformedCartItems = response.data.items.map((item: ServerCartItem) => { + return { + id: item.cart_id, + userId: item.user_id, + optionId: item.option_id, + productId: item.product_id, + productCode: item.product_code, + name: item.product_name, + image: item.product_image_url, + color: item.product_color, + size: item.product_size, + amount: item.product_amount, + stock: item.product_stock, + originPrice: item.origin_price, + price: item.price, + discount: item.discount, + discountOption: item.discount_option as 'percent' | 'amount', + }; + }); + + return transformedCartItems; + } catch (err: unknown) { + handleApiError(err); + return []; // 실패 시 빈 배열을 반환하여 undefined를 방지 + } + }, + enabled: !!user, + initialData: guestCartItems, // 초기 데이터는 guestCartItems로 설정 + retry: 0, + }); + + return { cartItems, isPending, isError, error }; +}; + +export default useGetCartItem; diff --git a/src/hooks/useHistoryFab.ts b/src/hooks/useHistoryFab.ts new file mode 100644 index 0000000..6068d24 --- /dev/null +++ b/src/hooks/useHistoryFab.ts @@ -0,0 +1,97 @@ +import { ProductData } from '@/api/type'; +import { HistoryType } from '@/layouts/publicLayout/types'; +import { useCallback, useEffect } from 'react'; +import useLocalStorage from './useLocalStorage'; + +const useHistoryFab = (productDetailData: ProductData | null): void => { + // localStorage에서 History 데이터 가져오기 + const [currentHistory, setStoredValue] = useLocalStorage('history', []); + + // 중복 확인 + const isDuplicateEntry = useCallback((history: HistoryType[], today: string, productId: number): boolean => { + return history.some((item: HistoryType) => { + if (item.date === today) { + return item.products.some((product) => product.id === productId); + } + return false; + }); + }, []); + + // 새로운 기록 생성 + const createNewHistoryItem = useCallback((data: ProductData) => { + const today = new Date().toISOString().slice(0, 10); + return { + date: today, + product: { + id: data.product.id, + name: data.product.name, + price: data.product.price, + image: data.options?.[0]?.images?.[0]?.image_url || '', + }, + }; + }, []); + + // 기록 업데이트 + const updateHistory = useCallback((currentHistory: HistoryType[], newItem: { date: string; product: any }) => { + const todayHistoryIndex = currentHistory.findIndex((item) => item.date === newItem.date); + let updatedHistory: HistoryType[]; + + if (todayHistoryIndex !== -1) { + const updatedTodayHistory = { + ...currentHistory[todayHistoryIndex], + products: [newItem.product, ...currentHistory[todayHistoryIndex].products], + }; + updatedHistory = [ + ...currentHistory.slice(0, todayHistoryIndex), + updatedTodayHistory, + ...currentHistory.slice(todayHistoryIndex + 1), + ]; + } else { + updatedHistory = [{ date: newItem.date, products: [newItem.product] }, ...currentHistory]; + } + + return updatedHistory; + }, []); + + // 오래된 기록 삭제 및 최대 100개 제한 + const filterAndLimitHistory = useCallback((history: HistoryType[]) => { + const todayDate = new Date(); + const filteredHistory = history.filter((item) => { + const itemDate = new Date(item.date); + return (todayDate.getTime() - itemDate.getTime()) / (1000 * 60 * 60 * 24) <= 30; + }); + + const flattenedProducts = filteredHistory.flatMap((item) => + item.products.map((product) => ({ ...product, date: item.date })) + ); + const limitedProducts = flattenedProducts.slice(0, 100); + + const finalHistory: HistoryType[] = []; + for (const product of limitedProducts) { + const dateGroup = finalHistory.find((item) => item.date === product.date); + if (dateGroup) { + dateGroup.products.push(product); + } else { + finalHistory.push({ date: product.date, products: [product] }); + } + } + + return finalHistory; + }, []); + + useEffect(() => { + if (!productDetailData) return; + + const today = new Date().toISOString().slice(0, 10); + const isDuplicate = isDuplicateEntry(currentHistory, today, productDetailData.product.id); + + if (isDuplicate) return; + + const newItem = createNewHistoryItem(productDetailData); + const updatedHistory = updateHistory(currentHistory, newItem); + const finalHistory = filterAndLimitHistory(updatedHistory); + setStoredValue(finalHistory); + }, [productDetailData]); +}; + +export default useHistoryFab; diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts new file mode 100644 index 0000000..5498a7e --- /dev/null +++ b/src/hooks/useLocalStorage.ts @@ -0,0 +1,36 @@ +import { useState } from 'react'; + +/** + * 로컬 스토리지(localStorage)와 React 상태를 연결하는 커스텀 훅. + * @param key 로컬 스토리지에 값을 저장하거나 불러올 때 사용할 키 + * @param initialValue 로컬 스토리지에 값이 없을 때 사용할 초기 값 + */ +const useLocalStorage = (key: string, initialValue: T) => { + const [storedValue, setStoredValue] = useState(() => { + try { + const item = localStorage.getItem(key); + return item ? JSON.parse(item) : initialValue; // item에 값이 존재하면 JSON으로 파싱, 없으면 초기값을 사용 + } catch (error) { + console.error(`로컬 스토리지 키 "${key}"를 읽는 중 오류 발생: `, error); + return initialValue; // 에러 메세지 출력 후, 안전하게 초기 값 반환 + } + }); + + /** + * 상태와 로컬 스토리지 값을 동시에 업데이트하는 함수. + * @param value 새로운 값 또는 함수형 업데이트로 기존 값을 기반으로 계산된 값 + */ + const setValue = (value: any) => { + try { + const valueToStore = value instanceof Function ? value(storedValue) : value; + setStoredValue(valueToStore); + localStorage.setItem(key, JSON.stringify(valueToStore)); + } catch (error) { + console.error(`Error setting localStorage key "${key}": `, error); + } + }; + + return [storedValue, setValue] as const; +}; + +export default useLocalStorage; diff --git a/src/hooks/useModalState/AddCartModal.tsx b/src/hooks/useModalState/AddCartModal.tsx new file mode 100644 index 0000000..80c9c30 --- /dev/null +++ b/src/hooks/useModalState/AddCartModal.tsx @@ -0,0 +1,85 @@ +import { useNavigate } from 'react-router-dom'; +import { motion, AnimatePresence } from 'framer-motion'; +import CloseIco from '@/assets/icons/CloseIco'; + +interface AddCartModalProps { + onClose: () => void; + isOpen: boolean; +} + +const AddCartModal = ({ onClose, isOpen }: AddCartModalProps) => { + const navigate = useNavigate(); + const handleOnClick = (path: string) => { + navigate(`/${path}`); + }; + + return ( + + {isOpen && ( + + e.stopPropagation()} + > + +
+

+ 성공적으로 장바구니에 담겼습니다 +

+
+ + +
+
+
+
+ )} +
+ ); +}; + +export default AddCartModal; diff --git a/src/hooks/useModalState/AddUserCartFailedModal.tsx b/src/hooks/useModalState/AddUserCartFailedModal.tsx new file mode 100644 index 0000000..775e09f --- /dev/null +++ b/src/hooks/useModalState/AddUserCartFailedModal.tsx @@ -0,0 +1,79 @@ +import { useNavigate } from 'react-router-dom'; +import { motion, AnimatePresence } from 'framer-motion'; +import CloseIco from '@/assets/icons/CloseIco'; + +interface AddCartFailedModalProps { + onClose: () => void; + isOpen: boolean; + errMsg: string | undefined; +} + +const AddUserCartFailedModal = ({ onClose, isOpen, errMsg }: AddCartFailedModalProps) => { + const navigate = useNavigate(); + const handleOnClick = (path: string) => { + navigate(`/${path}`); + }; + return ( + + {isOpen && ( + + e.stopPropagation()} + > + +
+

+ {errMsg || '장바구니 추가 요청 중 오류가 발생했어요.'} +

+
+ +
+
+
+
+ )} +
+ ); +}; + +export default AddUserCartFailedModal; diff --git a/src/hooks/useModalState/LoginOrPaymentModal.tsx b/src/hooks/useModalState/LoginOrPaymentModal.tsx new file mode 100644 index 0000000..67c5875 --- /dev/null +++ b/src/hooks/useModalState/LoginOrPaymentModal.tsx @@ -0,0 +1,99 @@ +import { CartItemData } from '@/assets/dummys/types'; +import CloseIco from '@/assets/icons/CloseIco'; +import { AnimatePresence, motion } from 'framer-motion'; +import { useNavigate } from 'react-router-dom'; + +type LoginOrPaymentModalProps = { + onClose: () => void; + paymentData: { + items: CartItemData[]; + totalPrice: number; + totalDeliveryFee: number; + }; + isOpen: boolean; +}; + +const LoginOrPaymentModal = ({ isOpen, onClose, paymentData }: LoginOrPaymentModalProps) => { + const navigate = useNavigate(); + + const handleGuestPayment = () => { + onClose; + navigate('/checkout', { state: paymentData }); + }; + + const handleLoginClick = () => { + onClose; + navigate('/auth/signin'); + }; + + return ( + + {isOpen && ( + + e.stopPropagation()} + className='relative w-full max-w-[800px] bg-white p-6 shadow-lg sm:p-8 md:p-10' + > + +
+

+ 로그인이 안돼있어요 !
+ 비회원으로 주문하시겠습니까? +

+
+ + +
+
+
+
+ )} +
+ ); +}; + +export default LoginOrPaymentModal; diff --git a/src/hooks/useModalState/useModalState.tsx b/src/hooks/useModalState/useModalState.tsx new file mode 100644 index 0000000..9b76f2a --- /dev/null +++ b/src/hooks/useModalState/useModalState.tsx @@ -0,0 +1,52 @@ +import { useState } from 'react'; +import LoginOrPaymentModal from './LoginOrPaymentModal'; +import { CartItemData } from '@/assets/dummys/types'; +import AddCartModal from './AddCartModal'; +import AddUserCartFailedModal from './AddUserCartFailedModal'; +import { UseMutationResult } from '@tanstack/react-query'; + +export type SignUpModalType = '개인정보' | '이용약관' | '결제모달' | '장바구니' | '장바구니추가실패'; + +type useModalStateProps = { + paymentData?: { + items: CartItemData[]; + totalPrice: number; + totalDeliveryFee: number; + }; + mutation?: UseMutationResult; // mutation 추가 +}; + +const useModalState = ({ paymentData, mutation }: useModalStateProps) => { + const [currentModal, setCurrentModal] = useState(null); + const [isOpen, setIsOpen] = useState(false); // ADD : 모달 애니메이션 상태관리를 위해 추가 + + const handleModalOpen = (type: SignUpModalType) => { + setCurrentModal(type); + setIsOpen(true); + }; + + const handleModalClose = () => { + setIsOpen(false); + setTimeout(() => setCurrentModal(null), 300); // FIX : 모달 애니메이션을 위한 딜레이 추가 + }; + + const renderModalContent = (): React.ReactNode => { + switch (currentModal) { + case '결제모달': { + if (paymentData) { + return ; + } + return null; + } + case '장바구니': { + return ; + } + case '장바구니추가실패': { + return ; + } + } + }; + return { handleModalOpen, handleModalClose, renderModalContent }; +}; + +export default useModalState; diff --git a/src/hooks/usePostCartItem.ts b/src/hooks/usePostCartItem.ts new file mode 100644 index 0000000..975a286 --- /dev/null +++ b/src/hooks/usePostCartItem.ts @@ -0,0 +1,68 @@ +import { client } from '@/api/client'; +import { useMutation } from '@tanstack/react-query'; +import { useAuthStore } from '@/config/store'; +import axios from 'axios'; + +export interface UserCartItemParam { + productId: number; + color: string | undefined; + size: string | undefined; + amount: number; +} + +const usePostCartItem = () => { + const { user } = useAuthStore(); + const accessToken = localStorage.getItem('accessToken'); + + const postCartItem = async (userCartItem: UserCartItemParam) => { + if (!user) throw new Error('사용자가 인증되지 않았습니다.'); + + try { + const response = await client.post( + `/cart`, + { + product_id: userCartItem.productId, + color: userCartItem.color, + size: userCartItem.size, + product_count: userCartItem.amount, + }, + { + headers: { Authorization: `Bearer ${accessToken}` }, + } + ); + return response.data; + } catch (err: unknown) { + if (axios.isAxiosError(err)) { + const { response, request } = err; + if (response) { + const { status } = response; + switch (status) { + case 400: + throw new Error('재고 부족으로 더이상 담을 수 없어요.'); + case 401: + throw new Error('계정 권한에 오류가 있어요.'); + case 500: + throw new Error('서버 오류가 발생했습니다. 잠시 후 다시 시도하세요.'); + default: + throw new Error(response.data?.error || '알 수 없는 오류가 발생했습니다.'); + } + } + if (request) { + throw new Error('서버와 연결할 수 없습니다. 인터넷 연결을 확인하세요.'); + } + if (typeof err === 'object' && err !== null && 'message' in err) { + throw new Error((err as any).message); + } + throw new Error('요청 중 오류가 발생했습니다.'); + } + } + }; + + const mutation = useMutation({ + mutationFn: postCartItem, + }); + + return mutation; +}; + +export default usePostCartItem; diff --git a/src/hooks/useSaleState.ts b/src/hooks/useSaleState.ts new file mode 100644 index 0000000..ea21490 --- /dev/null +++ b/src/hooks/useSaleState.ts @@ -0,0 +1,38 @@ +import { useEffect, useState } from 'react'; + +interface useSaleStateParams { + discount: number; + discountOption: 'percent' | 'amount'; // 할인 방식 +} + +const useSaleState = ({ discount, discountOption }: useSaleStateParams) => { + const [isSale, setIsSale] = useState(true); + + // 할인 상태의 조건 : discount가 0보다 클때(초과) + useEffect(() => { + if (discount > 0) setIsSale(true); + }, [discount]); + + const renderPriceTextByOption = (discountOption: 'percent' | 'amount', discount: number) => { + switch (discountOption) { + case 'percent': + return `${discount}% 할인`; + case 'amount': + return `${discount}원 할인`; + default: + return ''; + } + }; + + const saleLabelText = renderPriceTextByOption(discountOption, discount); + + // 할인 라벨 조건부 스타일 + const labelClassNames = + discountOption === 'percent' + ? 'bg-primary text-white' // 'percent'일 경우 배경색 + : 'border border-primary text-primary'; // 'amount'일 경우 테두리 색과 글자색 + + return { isSale, saleLabelText, labelClassNames }; +}; + +export default useSaleState; diff --git a/src/hooks/useSearchDebounce.tsx b/src/hooks/useSearchDebounce.tsx new file mode 100644 index 0000000..a6ecfe2 --- /dev/null +++ b/src/hooks/useSearchDebounce.tsx @@ -0,0 +1,16 @@ +import { useEffect, useState } from 'react'; + +const useSearchDebounce = (value: string, delay: number) => { + const [debouncedValue, setDebouncedValue] = useState(value); + + useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delay); + return () => clearTimeout(handler); + }, [value, delay]); + + return debouncedValue; +}; + +export default useSearchDebounce; diff --git a/src/hooks/useSidebarStorage.ts b/src/hooks/useSidebarStorage.ts new file mode 100644 index 0000000..9aca75b --- /dev/null +++ b/src/hooks/useSidebarStorage.ts @@ -0,0 +1,18 @@ +import { useState, useEffect } from 'react'; + +export const useSidebarStorage = () => { + const [selectMenu, setSelectMenu] = useState(() => { + const saved = localStorage.getItem('sidebarState'); + return saved ? JSON.parse(saved) : null; + }); + + useEffect(() => { + localStorage.setItem('sidebarState', JSON.stringify(selectMenu)); + }, [selectMenu]); + + const toggleMenu = (index: number) => { + setSelectMenu((prevIndex) => (prevIndex === index ? null : index)); + }; + + return { selectMenu, toggleMenu }; +}; diff --git a/src/hooks/useSoldoutState.ts b/src/hooks/useSoldoutState.ts new file mode 100644 index 0000000..76b9f6a --- /dev/null +++ b/src/hooks/useSoldoutState.ts @@ -0,0 +1,13 @@ +import { ProductOption } from '@/api/type'; +import { useMemo } from 'react'; + +const useSoldOutState = (optionData: ProductOption | null) => { + const isSoldOut = useMemo(() => { + if (!optionData) return false; + return optionData.sizes.every((size) => size.stock === 0); + }, [optionData]); + + return { isSoldOut }; +}; + +export default useSoldOutState; diff --git a/src/hooks/useSort.ts b/src/hooks/useSort.ts new file mode 100644 index 0000000..d2115cc --- /dev/null +++ b/src/hooks/useSort.ts @@ -0,0 +1,45 @@ +import { useState, useCallback, useEffect } from 'react'; + +export type SortMode = '최신순' | '오래된 순' | '가격 낮은순' | '가격 높은순'; +export type OrderMode = 'desc' | 'asc'; +export type SortModeSync = 'created_at' | 'price'; + +const useSort = () => { + const [currentSort, setCurrentSort] = useState('최신순'); + const [sortResult, setSortResult] = useState('created_at'); + const [currentOrder, setCurrentOrder] = useState('desc'); + + // currentSort 값에 따라 sortResult와 currentOrder를 자동으로 설정하는 함수 + const updateSortSettings = useCallback((sort: SortMode) => { + switch (sort) { + case '최신순': + setSortResult('created_at'); + setCurrentOrder('desc'); + break; + case '오래된 순': + setSortResult('created_at'); + setCurrentOrder('asc'); + break; + case '가격 낮은순': + setSortResult('price'); + setCurrentOrder('asc'); + break; + case '가격 높은순': + setSortResult('price'); + setCurrentOrder('desc'); + break; + default: + setSortResult('created_at'); + setCurrentOrder('desc'); + } + }, []); + + // currentSort 값이 변경될 때마다 updateSortSettings 함수 호출 + useEffect(() => { + updateSortSettings(currentSort); + }, [currentSort, updateSortSettings]); + + return { currentSort, currentOrder, setCurrentSort, sortResult }; +}; + +export default useSort; diff --git a/src/layouts/adminLayout/AdminLayout.tsx b/src/layouts/adminLayout/AdminLayout.tsx index f14e610..2d50de6 100644 --- a/src/layouts/adminLayout/AdminLayout.tsx +++ b/src/layouts/adminLayout/AdminLayout.tsx @@ -1,5 +1,19 @@ +import { Outlet } from 'react-router-dom'; +import { SideBar } from './SideBar'; + const AdminLayout = () => { - return
AdminLayout
; + return ( + <> +
+
+ +
+
+ +
+
+ + ); }; export default AdminLayout; diff --git a/src/layouts/adminLayout/SideBar.tsx b/src/layouts/adminLayout/SideBar.tsx new file mode 100644 index 0000000..7ec7083 --- /dev/null +++ b/src/layouts/adminLayout/SideBar.tsx @@ -0,0 +1,109 @@ +import logoWhite from '@/assets/imgs/logoWhite.svg'; +import arrowDropDown from '@/assets/icons/arrowDropDown.svg'; +import arrowDropUp from '@/assets/icons/arrowDropUp.svg'; +import { useSidebarStorage } from '@/hooks/useSidebarStorage'; +import { Link, useLocation, useNavigate } from 'react-router-dom'; + +const sideBarMenu = [ + { + title: '상품관리', + sibTitle: [ + { title: '상품 조회', link: '/admin/product/search' }, + { title: '상품 등록', link: '/admin/product/add' }, + ], + }, + { + title: '판매관리', + sibTitle: [ + { title: '주문통합검색', link: '/admin/sale/search' }, + { title: '미결제확인', link: '/admin/sale/payment' }, + { title: '발주(주문)확인, 발송관리', link: '/admin/sale/ordering' }, + { title: '배송현황관리', link: '/admin/sale/delivery' }, + { title: '취소관리', link: '/admin/sale/cancel' }, + { title: '반품관리', link: '/admin/sale/return' }, + { title: '교환관리', link: '/admin/sale/exchange' }, + ], + }, + + { + title: '스토어관리', + sibTitle: [ + { title: '배너관리', link: '/admin/store/banner' }, + { title: 'Best Item', link: '/admin/store/bestitem' }, + { title: 'Promotion', link: '/admin/store/promotion' }, + { title: 'MD’s Choice', link: '/admin/store/mdschoice' }, + ], + }, +]; +export const SideBar = () => { + const navigate = useNavigate(); + + const { selectMenu, toggleMenu } = useSidebarStorage(); + const location = useLocation(); + + return ( + + ); +}; diff --git a/src/layouts/commonLayout/CommonLayout.tsx b/src/layouts/commonLayout/CommonLayout.tsx deleted file mode 100644 index aa00f02..0000000 --- a/src/layouts/commonLayout/CommonLayout.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import Header from './Header'; -import Footer from './Footer'; -import { CommonLayoutProps } from './types'; - -const CommonLayout = ({ children }: CommonLayoutProps) => { - return ( - <> -
-
{children}
-