diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..78e93558 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6 @@ +{ + "name": "18-Sprint-Mission", + "lockfileVersion": 3, + "requires": true, + "packages": {} +} diff --git a/vite-project/.env b/vite-project/.env new file mode 100644 index 00000000..7700d62d --- /dev/null +++ b/vite-project/.env @@ -0,0 +1 @@ +VITE_BASE_URL = 'https://panda-market-api.vercel.app' \ No newline at end of file diff --git a/vite-project/package-lock.json b/vite-project/package-lock.json index 7cf63a32..3e3374fd 100644 --- a/vite-project/package-lock.json +++ b/vite-project/package-lock.json @@ -8,10 +8,12 @@ "name": "vite-project", "version": "0.0.0", "dependencies": { + "axios": "^1.11.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-responsive": "^10.0.1", - "react-router-dom": "^6.30.1" + "react-router-dom": "^6.30.1", + "styled-components": "^6.1.19" }, "devDependencies": { "@eslint/js": "^9.25.0", @@ -321,6 +323,27 @@ "node": ">=6.9.0" } }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz", + "integrity": "sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.8.1.tgz", + "integrity": "sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.8", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz", @@ -1397,6 +1420,12 @@ "@types/react": "^19.0.0" } }, + "node_modules/@types/stylis": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", + "integrity": "sha512-1Xve+NMN7FWjY14vLoY5tL3BVEQ/n42YLwaqJIPYhotZ9uBHt87VceMwWQpzmdEt2TNXIorIFG+YeCUUW7RInw==", + "license": "MIT" + }, "node_modules/@vitejs/plugin-react": { "version": "4.7.0", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", @@ -1481,6 +1510,23 @@ "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/axios": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz", + "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.4", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -1532,6 +1578,19 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", @@ -1542,6 +1601,15 @@ "node": ">=6" } }, + "node_modules/camelize": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz", + "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001731", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", @@ -1600,6 +1668,18 @@ "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" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1629,17 +1709,36 @@ "node": ">= 8" } }, + "node_modules/css-color-keywords": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz", + "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==", + "license": "ISC", + "engines": { + "node": ">=4" + } + }, "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/css-to-react-native": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz", + "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==", + "license": "MIT", + "dependencies": { + "camelize": "^1.0.0", + "css-color-keywords": "^1.0.0", + "postcss-value-parser": "^4.0.2" + } + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/debug": { @@ -1667,6 +1766,29 @@ "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" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/electron-to-chromium": { "version": "1.5.194", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz", @@ -1674,6 +1796,51 @@ "dev": true, "license": "ISC" }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/esbuild": { "version": "0.25.8", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", @@ -2004,6 +2171,42 @@ "dev": true, "license": "ISC" }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", + "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2019,6 +2222,15 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, + "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==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -2029,6 +2241,43 @@ "node": ">=6.9.0" } }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -2055,6 +2304,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2065,6 +2326,45 @@ "node": ">=8" } }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/hyphenate-style-name": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz", @@ -2282,6 +2582,36 @@ "css-mediaquery": "^0.1.2" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "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" + } + }, + "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" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2306,7 +2636,6 @@ "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, "funding": [ { "type": "github", @@ -2431,7 +2760,6 @@ "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": { @@ -2476,6 +2804,12 @@ "node": "^10 || ^12 || >=14" } }, + "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==", + "license": "MIT" + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -2497,6 +2831,12 @@ "react-is": "^16.13.1" } }, + "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", @@ -2666,6 +3006,12 @@ "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", @@ -2693,7 +3039,6 @@ "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" @@ -2712,6 +3057,68 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/styled-components": { + "version": "6.1.19", + "resolved": "https://registry.npmjs.org/styled-components/-/styled-components-6.1.19.tgz", + "integrity": "sha512-1v/e3Dl1BknC37cXMhwGomhO8AkYmN41CqyX9xhUDxry1ns3BFQy2lLDRQXJRdVVWB9OHemv/53xaStimvWyuA==", + "license": "MIT", + "dependencies": { + "@emotion/is-prop-valid": "1.2.2", + "@emotion/unitless": "0.8.1", + "@types/stylis": "4.2.5", + "css-to-react-native": "3.2.0", + "csstype": "3.1.3", + "postcss": "8.4.49", + "shallowequal": "1.1.0", + "stylis": "4.3.2", + "tslib": "2.6.2" + }, + "engines": { + "node": ">= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/styled-components" + }, + "peerDependencies": { + "react": ">= 16.8.0", + "react-dom": ">= 16.8.0" + } + }, + "node_modules/styled-components/node_modules/postcss": { + "version": "8.4.49", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", + "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/stylis": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.2.tgz", + "integrity": "sha512-bhtUjWd/z6ltJiQwg0dUfxEJ+W+jdqQd8TbWLWyeIJHlnsqmGLRFFd8e5mA0AZi/zx90smXRlN66YMTcaSFifg==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -2742,6 +3149,12 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/vite-project/package.json b/vite-project/package.json index 3bd10b91..6b0d534a 100644 --- a/vite-project/package.json +++ b/vite-project/package.json @@ -10,10 +10,12 @@ "preview": "vite preview" }, "dependencies": { + "axios": "^1.11.0", "react": "^19.1.0", "react-dom": "^19.1.0", "react-responsive": "^10.0.1", - "react-router-dom": "^6.30.1" + "react-router-dom": "^6.30.1", + "styled-components": "^6.1.19" }, "devDependencies": { "@eslint/js": "^9.25.0", diff --git a/vite-project/src/App.jsx b/vite-project/src/App.jsx index 32dd4956..929e1dc6 100644 --- a/vite-project/src/App.jsx +++ b/vite-project/src/App.jsx @@ -1,7 +1,7 @@ import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom"; import Nav from "./components/Nav"; -import ItemsPage from "./components/ItemsPage"; -import AddItemPage from "./components/AddItemPage"; +import ItemsPage from "./pages/ItemsPage/ItemsPage"; +import AddItemPage from "./pages/AddItemPage/AddItemPage"; function App() { return ( diff --git a/vite-project/src/api.jsx b/vite-project/src/api.jsx index 3a1a17a5..7a383b6d 100644 --- a/vite-project/src/api.jsx +++ b/vite-project/src/api.jsx @@ -1,16 +1,16 @@ +import instance from "./axiosInstance"; + export async function getProducts({ page = 1, pageSize = 10, orderBy = "recent", keyword = "", }) { - const params = new URLSearchParams({ page, pageSize, orderBy, keyword }); - const response = await fetch( - `https://panda-market-api.vercel.app/products?${params}` - ); - if (!response.ok) { - throw new Error("상품을 불러오는데 실패했습니다"); + try { + const params = new URLSearchParams({ page, pageSize, orderBy, keyword }); + const response = await instance.get("/products", { params }); + return response.data; + } catch (error) { + throw new Error(`상품을 불러오는데 실패했습니다 : ${error.message}`); } - const data = await response.json(); - return [data.list, data.totalCount]; } diff --git a/vite-project/src/assets/ic-plus.svg b/vite-project/src/assets/ic-plus.svg new file mode 100644 index 00000000..5bb9abf5 --- /dev/null +++ b/vite-project/src/assets/ic-plus.svg @@ -0,0 +1,4 @@ + + + + diff --git a/vite-project/src/assets/ic-x.svg b/vite-project/src/assets/ic-x.svg new file mode 100644 index 00000000..a85baced --- /dev/null +++ b/vite-project/src/assets/ic-x.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/vite-project/src/axiosInstance.jsx b/vite-project/src/axiosInstance.jsx new file mode 100644 index 00000000..7ad33f1e --- /dev/null +++ b/vite-project/src/axiosInstance.jsx @@ -0,0 +1,33 @@ +import axios from "axios"; + +const VITE_BASE_URL = import.meta.env.VITE_BASE_URL; + +const instance = axios.create({ + baseURL: VITE_BASE_URL, + headers: { + "Content-Type": "application/json", + }, +}); + +instance.interceptors.response.use( + (response) => { + return response; + }, + (error) => { + if (error.response) { + const status = error.response.status; + + if (status === 401) { + alert("인증이 필요합니다. 로그인 해주세요."); + } else if (status === 500) { + alert("서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요."); + } + } else { + alert("네트워크 오류가 발생했습니다."); + } + + return Promise.reject(error); + } +); + +export default instance; diff --git a/vite-project/src/components/AddItemPage.jsx b/vite-project/src/components/AddItemPage.jsx deleted file mode 100644 index ff249ac4..00000000 --- a/vite-project/src/components/AddItemPage.jsx +++ /dev/null @@ -1,5 +0,0 @@ -function AddItemPage() { - return
상품 추가 페이지
; -} - -export default AddItemPage; diff --git a/vite-project/src/components/Nav.css b/vite-project/src/components/Nav.css index b58c1f49..147faf72 100644 --- a/vite-project/src/components/Nav.css +++ b/vite-project/src/components/Nav.css @@ -1,9 +1,4 @@ @import url("./reset.css"); -@import url("./variable.css"); - -html { - font-size: 62.5%; -} .nav-container { border-bottom: 0.1rem solid #dfdfdf; diff --git a/vite-project/src/components/Nav.jsx b/vite-project/src/components/Nav.jsx index ff48a846..1e743fd3 100644 --- a/vite-project/src/components/Nav.jsx +++ b/vite-project/src/components/Nav.jsx @@ -6,6 +6,8 @@ import { Link, useLocation } from "react-router-dom"; function Nav() { const location = useLocation(); + const navActive = ["/items", "/additem"].includes(location.pathname); + return (
@@ -18,9 +20,7 @@ function Nav() {
  • 중고마켓 diff --git a/vite-project/src/components/SelectDropdown.jsx b/vite-project/src/components/SelectDropdown.jsx new file mode 100644 index 00000000..203b3093 --- /dev/null +++ b/vite-project/src/components/SelectDropdown.jsx @@ -0,0 +1,49 @@ +import { useEffect, useRef, useState } from "react"; +import selectIcon from "../assets/ic-sort.svg"; + +export default function SelectDropdown({ onChange, value }) { + const [isOpen, setIsOpen] = useState(false); + const dropdownRef = useRef(null); + + const options = [ + { label: "최신순", value: "recent" }, + { label: "좋아요순", value: "favorite" }, + ]; + + const selected = options.find((opt) => opt.value === value); + + const handleSelect = (option) => { + onChange({ target: { value: option.value } }); + setIsOpen(false); + }; + + useEffect(() => { + const handleClickOutside = (e) => { + if (dropdownRef.current && !dropdownRef.current.contains(e.target)) { + setIsOpen(false); + } + }; + document.addEventListener("mousedown", handleClickOutside); + return () => document.removeEventListener("mousedown", handleClickOutside); + }, []); + + return ( + <> +
    +
    setIsOpen(!isOpen)}> + 드롭다운 아이콘 +
    + + {isOpen && ( +
      + {options.map((option) => ( +
    • handleSelect(option)}> + {option.label} +
    • + ))} +
    + )} +
    + + ); +} diff --git a/vite-project/src/components/reset.css b/vite-project/src/components/reset.css index 3a8bf972..ea8c85ef 100644 --- a/vite-project/src/components/reset.css +++ b/vite-project/src/components/reset.css @@ -4,50 +4,148 @@ */ * { - box-sizing: border-box; + box-sizing: border-box; } - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font-size: 100%; - font: inherit; - vertical-align: baseline; +html, +body, +div, +span, +applet, +object, +iframe, +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +a, +abbr, +acronym, +address, +big, +cite, +code, +del, +dfn, +em, +img, +ins, +kbd, +q, +s, +samp, +small, +strike, +strong, +sub, +sup, +tt, +var, +b, +u, +i, +center, +dl, +dt, +dd, +ol, +ul, +li, +fieldset, +form, +label, +legend, +table, +caption, +tbody, +tfoot, +thead, +tr, +th, +td, +article, +aside, +canvas, +details, +embed, +figure, +figcaption, +footer, +header, +hgroup, +menu, +nav, +output, +ruby, +section, +summary, +time, +mark, +audio, +video { + margin: 0; + padding: 0; + border: 0; + font-size: 100%; + font: inherit; + vertical-align: baseline; } /* HTML5 display-role reset for older browsers */ -article, aside, details, figcaption, figure, -footer, header, hgroup, menu, nav, section { - display: block; +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; } body { - line-height: 1; + line-height: 1; } -ol, ul { - list-style: none; +ol, +ul { + list-style: none; } -blockquote, q { - quotes: none; +blockquote, +q { + quotes: none; } -blockquote:before, blockquote:after, -q:before, q:after { - content: ''; - content: none; +blockquote:before, +blockquote:after, +q:before, +q:after { + content: ""; + content: none; } table { - border-collapse: collapse; - border-spacing: 0; -} \ No newline at end of file + border-collapse: collapse; + border-spacing: 0; +} + +:root { + --gray-900: #111827; + --gray-800: #1f2937; + --gray-700: #374151; + --gray-600: #4b5563; + --gray-500: #6b7280; + --gray-400: #9ca3af; + --gray-200: #e5e7eb; + --gray-100: #f3f4f6; + --gray-50: #f9fafb; + + --blue: #3692ff; +} + +html { + font-size: 62.5%; +} diff --git a/vite-project/src/components/variable.css b/vite-project/src/components/variable.css deleted file mode 100644 index 20d88549..00000000 --- a/vite-project/src/components/variable.css +++ /dev/null @@ -1,13 +0,0 @@ -:root { - --gray-900: #111827; - --gray-800: #1F2937; - --gray-700: #374151; - --gray-600: #4B5563; - --gray-500: #6B7280; - --gray-400: #9CA3AF; - --gray-200: #E5E7EB; - --gray-100: #F3F4F6; - --gray-50: #F9FAFB; - - --blue: #3692FF; -} \ No newline at end of file diff --git a/vite-project/src/pages/AddItemPage/AddItemPage.jsx b/vite-project/src/pages/AddItemPage/AddItemPage.jsx new file mode 100644 index 00000000..1789a183 --- /dev/null +++ b/vite-project/src/pages/AddItemPage/AddItemPage.jsx @@ -0,0 +1,75 @@ +import "../../components/reset.css"; +import Styled from "styled-components"; +import ProductAddHeader from "./ProducutAddHeader"; +import ProductAddImg from "./ProductAddImg.jsx"; +import ProductAddName from "./ProductAddName.jsx"; +import ProductAddInt from "./ProductAddInt.jsx"; +import ProductAddPrice from "./ProductAddPrice.jsx"; +import ProductAddTag from "./ProductAddTag.jsx"; +import { useState } from "react"; + +const FormContainer = Styled.form` + display: flex; + flex-direction: column; + margin: 3rem auto; + width: 120.6rem; + gap: 2.4rem; + + @media (max-width: 1199px) { + width: 69.6rem; + } + + @media (max-width: 767px) { + width: 34.6rem; + } + `; + +function AddItemPage() { + const [formValues, setFormValues] = useState({ + name: "", + description: "", + price: "", + tags: [], + }); + + const handleChange = (field, value) => { + setFormValues((prev) => ({ ...prev, [field]: value })); + }; + + const isFormValid = + formValues.name.trim() !== "" && + formValues.description.trim() !== "" && + formValues.price.trim() !== "" && + formValues.tags.length > 0; + + const handleSubmit = (e) => { + e.preventDefault(); + if (!isFormValid) return; + + console.log("등록 데이터:", formValues); //submit 확인용 + }; + + return ( + <> + + + handleChange("image", img)} /> + handleChange("name", val)} + /> + handleChange("description", val)} + /> + handleChange("price", val)} + /> + handleChange("tags", tags)} /> + + + ); +} + +export default AddItemPage; diff --git a/vite-project/src/pages/AddItemPage/ProductAddImg.jsx b/vite-project/src/pages/AddItemPage/ProductAddImg.jsx new file mode 100644 index 00000000..dc591158 --- /dev/null +++ b/vite-project/src/pages/AddItemPage/ProductAddImg.jsx @@ -0,0 +1,153 @@ +import styled from "styled-components"; +import plusIcon from "../../assets/ic-plus.svg"; +import xIcon from "../../assets/ic-x.svg"; +import { useState, useRef } from "react"; + +const ProductAddImgDiv = styled.div` + display: flex; + flex-direction: column; + gap: 1.6rem; +`; +const ProductAddImgTitle = styled.h1` + font-weight: 700; + font-size: 1.8rem; + color: var(--gray-800); +`; +const ProductAddImgFile = styled.label` + width: 28.2rem; + height: 28.2rem; + border-radius: 1.2rem; + background-color: var(--gray-100); + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + font-weight: 400; + font-size: 1.6rem; + color: var(--gray-400); + gap: 1rem; + cursor: pointer; + img { + width: 4.8rem; + height: 4.8rem; + } + input { + display: none; + } + + @media (max-width: 767px) { + width: 16.8rem; + height: 16.8rem; + } +`; + +const ProductAddImgFileDiv = styled.div` + display: flex; + gap: 2.4rem; + + @media (max-width: 767px) { + gap: 1rem; + } +`; + +const PreviewWrapper = styled.div` + position: relative; + + +`; + +const PreviewImg = styled.img` + width: 28.2rem; + height: 28.2rem; + border-radius: 1.2rem; + border: 0.1rem solid var(--gray-50); + + @media (max-width: 767px) { + width: 16.8rem; + height: 16.8rem; + } +`; + +const ClearBtn = styled.button` + all: unset; + position: absolute; + top: 0.8rem; + right: 0.8rem; + cursor: pointer; + + img { + width: 2.2rem; + height: 2.4rem; + } +`; + +export default function ProductAddImg() { + const [previewImg, setPreviewImg] = useState(null); + const [showError, SetShowError] = useState(false); + const inputRef = useRef(); + + const handleFileChange = (e) => { + const file = e.target.files[0]; + if (!file) return; + + if (previewImg) { + SetShowError(true); + inputRef.current.value = ""; + return; + } + + const reader = new FileReader(); + reader.onloadend = () => { + setPreviewImg(reader.result); + }; + reader.readAsDataURL(file); + }; + + const handleClearClick = () => { + if (inputRef.current) { + inputRef.current.value = ""; + } + setPreviewImg(null); + SetShowError(false); + }; + + const handleInputClick = (e) => { + if (previewImg) { + e.preventDefault(); + SetShowError(true); + } + }; + + return ( + + 상품 이미지 + + + 추가 아이콘 + 이미지등록 + + + {previewImg && ( + + + + X 아이콘 + + + )} + + {showError && ( +

    + *이미지 등록은 최대 1개까지 가능합니다. +

    + )} +
    + ); +} diff --git a/vite-project/src/pages/AddItemPage/ProductAddInt.jsx b/vite-project/src/pages/AddItemPage/ProductAddInt.jsx new file mode 100644 index 00000000..4907f3df --- /dev/null +++ b/vite-project/src/pages/AddItemPage/ProductAddInt.jsx @@ -0,0 +1,43 @@ +import styled from "styled-components"; + +const ProductAddIntDiv = styled.div` + display: flex; + flex-direction: column; + gap: 1.6rem; +`; + +const ProductAddIntTitle = styled.h1` + font-weight: 700; + font-size: 1.8rem; + color: var(--gray-800); +`; + +const ProductAddIntInput = styled.textarea` + border-radius: 1.2rem; + padding: 1.6rem 2.4rem; + height: 28.2rem; + background-color: var(--gray-100); + border: 0.1rem solid var(--gray-100); + font-weight: 400; + font-size: 1.6rem; + color: var(--gray-800); + font-family: Noto Sans KR; + + &::placeholder { + color: var(--gray-400); + } +`; + +export default function ProductAddInt({ value, onChange }) { + return ( + + 상품 소개 + onChange(e.target.value)} + /> + + ); +} diff --git a/vite-project/src/pages/AddItemPage/ProductAddName.jsx b/vite-project/src/pages/AddItemPage/ProductAddName.jsx new file mode 100644 index 00000000..0c00456b --- /dev/null +++ b/vite-project/src/pages/AddItemPage/ProductAddName.jsx @@ -0,0 +1,42 @@ +import styled from "styled-components"; + +const ProductAddNameDiv = styled.div` + display: flex; + flex-direction: column; + gap: 1.6rem; +`; + +const ProductAddNameTitle = styled.h1` + font-weight: 700; + font-size: 1.8rem; + color: var(--gray-800); +`; + +const ProductAddNameInput = styled.input` + border-radius: 1.2rem; + padding: 1.6rem 2.4rem; + height: 5.6rem; + background-color: var(--gray-100); + border: 0.1rem solid var(--gray-100); + font-weight: 400; + font-size: 1.6rem; + color: var(--gray-800); + + &::placeholder { + color: var(--gray-400); + } +`; + +export default function ProductAddName({ value, onChange }) { + return ( + + 상품명 + onChange(e.target.value)} + /> + + ); +} diff --git a/vite-project/src/pages/AddItemPage/ProductAddPrice.jsx b/vite-project/src/pages/AddItemPage/ProductAddPrice.jsx new file mode 100644 index 00000000..7a36d3a7 --- /dev/null +++ b/vite-project/src/pages/AddItemPage/ProductAddPrice.jsx @@ -0,0 +1,42 @@ +import styled from "styled-components"; + +const ProductAddPriceDiv = styled.div` + display: flex; + flex-direction: column; + gap: 1.6rem; +`; + +const ProductAddPriceTitle = styled.h1` + font-weight: 700; + font-size: 1.8rem; + color: var(--gray-800); +`; + +const ProductAddPriceInput = styled.input` + border-radius: 1.2rem; + padding: 1.6rem 2.4rem; + height: 5.6rem; + background-color: var(--gray-100); + border: 0.1rem solid var(--gray-100); + font-weight: 400; + font-size: 1.6rem; + color: var(--gray-800); + + &::placeholder { + color: var(--gray-400); + } +`; + +export default function ProductAddPrice({ value, onChange }) { + return ( + + 판매가격 + onChange(e.target.value)} + /> + + ); +} diff --git a/vite-project/src/pages/AddItemPage/ProductAddTag.jsx b/vite-project/src/pages/AddItemPage/ProductAddTag.jsx new file mode 100644 index 00000000..99114bde --- /dev/null +++ b/vite-project/src/pages/AddItemPage/ProductAddTag.jsx @@ -0,0 +1,100 @@ +import { useState } from "react"; +import styled from "styled-components"; +import xIcon from "../../assets/ic-x.svg"; + +const ProductAddTagDiv = styled.div` + display: flex; + flex-direction: column; + gap: 1.6rem; +`; + +const ProductAddTagTitle = styled.h1` + font-weight: 700; + font-size: 1.8rem; + color: var(--gray-800); +`; + +const ProductAddTagInput = styled.input` + border-radius: 1.2rem; + padding: 1.6rem 2.4rem; + height: 5.6rem; + background-color: var(--gray-100); + border: 0.1rem solid var(--gray-100); + font-weight: 400; + font-size: 1.6rem; + color: var(--gray-800); + + &::placeholder { + color: var(--gray-400); + } +`; + +const TagList = styled.div` + display: flex; + gap: 1.2rem; +`; + +const TagSpan = styled.span` + border-radius: 2.6rem; + border: 0.1rem solid var(--gray-100); + background-color: var(--gray-100); + display: flex; + justify-content: center; + align-items: center; + width: auto; + height: 3.6rem; + font-weight: 400; + font-size: 1.6rem; + color: var(--gray-800); + padding: 0.6rem 1.2rem; + gap: 1rem; + img { + cursor: pointer; + } +`; + +export default function ProductAddTag({ onTagsChange }) { + const [input, setInput] = useState(""); + const [tags, setTags] = useState([]); + + const handleKeyDown = (e) => { + if (e.key === "Enter" && input.trim()) { + e.preventDefault(); + const newTags = [...tags, input.trim()]; + setTags(newTags); + onTagsChange(newTags); + setInput(""); + } + }; + + const handleDeleteClick = (deletespan) => { + const newTags = tags.filter((_, id) => id !== deletespan); + setTags(newTags); + onTagsChange(newTags); + }; + + return ( + + 태그 + setInput(e.target.value)} + placeholder="태그를 입력해주세요" + onKeyDown={handleKeyDown} + /> + + {tags.map((tag, id) => ( + + #{tag} + X 아이콘 handleDeleteClick(id)} + /> + + ))} + + + ); +} diff --git a/vite-project/src/pages/AddItemPage/ProducutAddHeader.jsx b/vite-project/src/pages/AddItemPage/ProducutAddHeader.jsx new file mode 100644 index 00000000..a07b9068 --- /dev/null +++ b/vite-project/src/pages/AddItemPage/ProducutAddHeader.jsx @@ -0,0 +1,37 @@ +import styled from "styled-components"; + +const ProductAddHeaderDiv = styled.div` + display: flex; + justify-content: space-between; + align-items: center; +`; + +const ProductAddHeaderTitle = styled.h1` + font-weight: 700; + font-size: 2rem; + color: var(--gray-800); +`; + +const ProductAddHeaderButton = styled.button` + font-weight: 600; + font-size: 1.6rem; + color: var(--gray-100); + background-color: ${({ disabled }) => + disabled ? "var(--gray-400)" : "var(--blue)"}; + border-radius: 0.8rem; + width: 7.4rem; + height: 4.2rem; + border: 0.1rem solid var(--gray-400); + cursor: ${({ disabled }) => (disabled ? "not-allowed" : "pointer")}; +`; + +export default function ProductAddHeader({ isFormValid }) { + return ( + + 상품 등록하기 + + 등록 + + + ); +} diff --git a/vite-project/src/components/BestProducts.jsx b/vite-project/src/pages/ItemsPage/BestProducts.jsx similarity index 77% rename from vite-project/src/components/BestProducts.jsx rename to vite-project/src/pages/ItemsPage/BestProducts.jsx index dc02cdf0..19733703 100644 --- a/vite-project/src/components/BestProducts.jsx +++ b/vite-project/src/pages/ItemsPage/BestProducts.jsx @@ -1,4 +1,4 @@ -import likeIcon from "../assets/ic-heart.svg"; +import likeIcon from "../../assets/ic-heart.svg"; function BestProducts({ bestProducts }) { return ( @@ -15,13 +15,15 @@ function BestProducts({ bestProducts }) { alt={product.name} />

    {product.name}

    -

    {product.price.toLocaleString()}원

    -

    + + {product.price.toLocaleString()}원 + + {product.favoriteCount} -

    +
  • ))}
    diff --git a/vite-project/src/components/ItemsPage.css b/vite-project/src/pages/ItemsPage/ItemsPage.css similarity index 81% rename from vite-project/src/components/ItemsPage.css rename to vite-project/src/pages/ItemsPage/ItemsPage.css index 4eaa75fc..419ebe7f 100644 --- a/vite-project/src/components/ItemsPage.css +++ b/vite-project/src/pages/ItemsPage/ItemsPage.css @@ -1,9 +1,4 @@ -@import url("../components/reset.css"); -@import url("../components/variable.css"); - -html { - font-size: 62.5%; -} +@import url("../../components/reset.css"); .products-container { display: flex; @@ -209,6 +204,7 @@ html { .total-products-card { grid-template-columns: repeat(2, 1fr); + gap: 0.8rem; } .total-product-card-img { @@ -237,7 +233,47 @@ html { gap: 0; } - .total-products-content select { - padding: 0; + .total-products-content input { + display: flex; + width: 29rem; + } + + .select-dropdown { + position: relative; + } + + .selected-option { + border: 0.1rem solid var(--gray-200); + width: 4.2rem; + height: 4.2rem; + border-radius: 1.2rem; + padding: 0.9rem; + cursor: pointer; + } + + .option-list { + position: absolute; + font-weight: 400; + font-size: 1.6rem; + color: var(--gray-800); + border: 0.1rem solid var(--gray-200); + right: 0; + background-color: white; + border-radius: 1.2rem; + text-align: center; + cursor: pointer; + margin-top: 0.5rem; + } + + .option-list li { + width: 13rem; + height: 4.2rem; + display: flex; + justify-content: center; + align-items: center; + } + + .option-list li:first-child { + border-bottom: 0.1rem solid var(--gray-200); } } diff --git a/vite-project/src/components/ItemsPage.jsx b/vite-project/src/pages/ItemsPage/ItemsPage.jsx similarity index 81% rename from vite-project/src/components/ItemsPage.jsx rename to vite-project/src/pages/ItemsPage/ItemsPage.jsx index ca76509b..1bec452f 100644 --- a/vite-project/src/components/ItemsPage.jsx +++ b/vite-project/src/pages/ItemsPage/ItemsPage.jsx @@ -1,10 +1,10 @@ import { useEffect, useState } from "react"; -import { getProducts } from "../api"; +import { getProducts } from "../../api"; import "./ItemsPage.css"; -import { useResponsive } from "./Responsive"; -import BestProducts from "../components/BestProducts"; -import TotalProducts from "../components/TotalProducts"; -import Pagination from "../components/Pagination"; +import { useResponsive } from "../../components/Responsive"; +import BestProducts from "./BestProducts"; +import TotalProducts from "./TotalProducts"; +import Pagination from "../../components/Pagination"; function ItemsPage() { const [orderBy, setOrderBy] = useState("recent"); @@ -20,12 +20,12 @@ function ItemsPage() { useEffect(() => { async function fetchBestProducts() { try { - const [list] = await getProducts({ + const res = await getProducts({ page: 1, pageSize: bestCount, orderBy: "favorite", }); - setBestProducts(list); + setBestProducts(res.list); } catch (error) { setError(error.message); } @@ -37,14 +37,14 @@ function ItemsPage() { useEffect(() => { async function fetchTotalProducts() { try { - const [list, count] = await getProducts({ + const res = await getProducts({ page, pageSize: totalCountPerPage, orderBy, keyword, }); - setTotalProducts(list); - setTotalCount(count); + setTotalProducts(res.list); + setTotalCount(res.totalCount); } catch (error) { setError(error.message); } diff --git a/vite-project/src/components/TotalProducts.jsx b/vite-project/src/pages/ItemsPage/TotalProducts.jsx similarity index 85% rename from vite-project/src/components/TotalProducts.jsx rename to vite-project/src/pages/ItemsPage/TotalProducts.jsx index d3b8d3dc..f9c85447 100644 --- a/vite-project/src/components/TotalProducts.jsx +++ b/vite-project/src/pages/ItemsPage/TotalProducts.jsx @@ -1,7 +1,8 @@ -import likeIcon from "../assets/ic-heart.svg"; -import searchIcon from "../assets/ic-search.svg"; +import likeIcon from "../../assets/ic-heart.svg"; +import searchIcon from "../../assets/ic-search.svg"; import { Link } from "react-router-dom"; import { useMediaQuery } from "react-responsive"; +import SelectDropdown from "../../components/SelectDropdown"; function TotalProducts({ totalProducts, @@ -55,10 +56,7 @@ function TotalProducts({ onChange={onKeywordChange} /> - + ) : null} @@ -72,13 +70,15 @@ function TotalProducts({ alt={product.name} />

    {product.name}

    -

    {product.price.toLocaleString()}원

    -

    + + {product.price.toLocaleString()}원 + + {product.favoriteCount} -

    + ))}