socket.io 추가
This commit is contained in:
parent
e5c206c11e
commit
3a724936a1
@ -7,4 +7,4 @@ PAYPAL_CLIENT_ID=
|
||||
CLOUDINARY_CLOUD_NAME="dmjztlmj4"
|
||||
BASE_CURRENCY=KRW
|
||||
SHIPPING_FEE=
|
||||
JWT_SECRET="123123"
|
||||
JWT_SECRET=
|
||||
|
@ -16,7 +16,10 @@ const nextConfig = {
|
||||
},
|
||||
images: {
|
||||
domains: ['nextall.vercel.app"', 'res.cloudinary.com']
|
||||
}
|
||||
},
|
||||
// experimental: {
|
||||
// appDir: true,
|
||||
// }
|
||||
};
|
||||
|
||||
module.exports = nextConfig;
|
||||
|
255
package-lock.json
generated
255
package-lock.json
generated
@ -59,6 +59,8 @@
|
||||
"redux-persist": "^6.0.0",
|
||||
"server-only": "^0.0.1",
|
||||
"simplebar-react": "^3.2.4",
|
||||
"socket.io": "^4.8.1",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"stripe": "^14.9.0",
|
||||
"stylis": "^4.3.0",
|
||||
"stylis-plugin-rtl": "^2.1.1",
|
||||
@ -1881,6 +1883,12 @@
|
||||
"integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@socket.io/component-emitter": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz",
|
||||
"integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@stripe/react-stripe-js": {
|
||||
"version": "2.9.0",
|
||||
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-2.9.0.tgz",
|
||||
@ -1977,6 +1985,21 @@
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/cookie": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz",
|
||||
"integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/cors": {
|
||||
"version": "2.8.17",
|
||||
"resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz",
|
||||
"integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz",
|
||||
@ -2323,6 +2346,28 @@
|
||||
"integrity": "sha512-d8XPSGjfyzlXC3Xx891DJRyZfqk5JU0BJrDQcsWomFIV1/BIzPW5HDH5iDdWpqWaav0YVIEzT1RHTwWr0FFshA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-types": "~2.1.34",
|
||||
"negotiator": "0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts/node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||
@ -2718,6 +2763,15 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/base64id": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz",
|
||||
"integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "^4.5.0 || >= 5.9"
|
||||
}
|
||||
},
|
||||
"node_modules/bcrypt": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/bcrypt/-/bcrypt-5.1.1.tgz",
|
||||
@ -3054,6 +3108,15 @@
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.7.2",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz",
|
||||
"integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.39.0",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.39.0.tgz",
|
||||
@ -3065,6 +3128,19 @@
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/cors": {
|
||||
"version": "2.8.5",
|
||||
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object-assign": "^4",
|
||||
"vary": "^1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||
@ -3360,6 +3436,91 @@
|
||||
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/engine.io": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz",
|
||||
"integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/cookie": "^0.4.1",
|
||||
"@types/cors": "^2.8.12",
|
||||
"@types/node": ">=10.0.0",
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "2.0.0",
|
||||
"cookie": "~0.7.2",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client": {
|
||||
"version": "6.6.2",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.6.2.tgz",
|
||||
"integrity": "sha512-TAr+NKeoVTjEVW8P3iHguO1LO6RlUz9O5Y8o7EY0fU+gY1NYqas7NN3slpFtbXEsLMHk0h90fJMfKjRkQ0qUIw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1",
|
||||
"engine.io-parser": "~5.2.1",
|
||||
"ws": "~8.17.1",
|
||||
"xmlhttprequest-ssl": "~2.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-client/node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io-parser": {
|
||||
"version": "5.2.3",
|
||||
"resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz",
|
||||
"integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/engine.io/node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/enhanced-resolve": {
|
||||
"version": "5.17.1",
|
||||
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
|
||||
@ -7164,6 +7325,83 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
|
||||
"integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.4",
|
||||
"base64id": "~2.0.0",
|
||||
"cors": "~2.8.5",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io": "~6.6.0",
|
||||
"socket.io-adapter": "~2.5.2",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter": {
|
||||
"version": "2.5.5",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz",
|
||||
"integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "~4.3.4",
|
||||
"ws": "~8.17.1"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-adapter/node_modules/ws": {
|
||||
"version": "8.17.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz",
|
||||
"integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-client": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
|
||||
"integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.2",
|
||||
"engine.io-client": "~6.6.1",
|
||||
"socket.io-parser": "~4.2.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socket.io-parser": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz",
|
||||
"integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@socket.io/component-emitter": "~3.1.0",
|
||||
"debug": "~4.3.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.5.7",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
|
||||
@ -7916,6 +8154,15 @@
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/vite-compatible-readable-stream": {
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/vite-compatible-readable-stream/-/vite-compatible-readable-stream-3.6.1.tgz",
|
||||
@ -8252,6 +8499,14 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xmlhttprequest-ssl": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.1.2.tgz",
|
||||
"integrity": "sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||
|
@ -61,6 +61,8 @@
|
||||
"redux-persist": "^6.0.0",
|
||||
"server-only": "^0.0.1",
|
||||
"simplebar-react": "^3.2.4",
|
||||
"socket.io": "^4.8.1",
|
||||
"socket.io-client": "^4.8.1",
|
||||
"stripe": "^14.9.0",
|
||||
"stylis": "^4.3.0",
|
||||
"stylis-plugin-rtl": "^2.1.1",
|
||||
|
72
src/app/admin/chat/page.jsx
Normal file
72
src/app/admin/chat/page.jsx
Normal file
@ -0,0 +1,72 @@
|
||||
'use client';
|
||||
|
||||
import { Button } from '@mui/material';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import io from 'socket.io-client';
|
||||
|
||||
let socket;
|
||||
|
||||
export default function Chat() {
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [input, setInput] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
// Socket.io 클라이언트 초기화
|
||||
socket = io({ path: '/api/socketio' });
|
||||
|
||||
// 서버와 연결 확인
|
||||
socket.on('connect', () => {
|
||||
console.log('Connected to server');
|
||||
});
|
||||
|
||||
// 서버에서 메시지를 받는 이벤트 처리
|
||||
socket.on('message', (data) => {
|
||||
setMessages((prevMessages) => [...prevMessages, data]);
|
||||
});
|
||||
|
||||
// 컴포넌트 언마운트 시 소켓 연결 종료
|
||||
return () => {
|
||||
if (socket) {
|
||||
socket.disconnect();
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const sendMessage = () => {
|
||||
if (!socket) {
|
||||
console.error('Socket not initialized');
|
||||
return;
|
||||
}
|
||||
|
||||
if (input.trim()) {
|
||||
const message = { user: '셀러테스트', text: input };
|
||||
|
||||
// 메시지 서버로 전송
|
||||
socket.emit('message', message);
|
||||
setMessages((prevMessages) => [...prevMessages, message]);
|
||||
setInput('');
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div style={{ width:'320px', height: '400px', overflowY: 'scroll', border: '1px solid #ccc', padding: '10px', margin:'auto', borderRadius:'12px'}}>
|
||||
{messages.map((msg, index) => (
|
||||
<div key={index}>
|
||||
<strong>{msg.user}:</strong> {msg.text}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div style={{display:'flex', alignItems:'center', justifyContent:'center', marginTop:'10px'}}>
|
||||
<input
|
||||
type="text"
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
placeholder="입력"
|
||||
style={{height:'32px', borderRadius:'8px', width:'250px'}}
|
||||
/>
|
||||
<Button onClick={sendMessage}>Send</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
34
src/app/api/socket.js
Normal file
34
src/app/api/socket.js
Normal file
@ -0,0 +1,34 @@
|
||||
import { Server } from 'socket.io';
|
||||
|
||||
export default function handler(req, res) {
|
||||
if (!res.socket.server.io) {
|
||||
console.log('Initializing Socket.io...');
|
||||
|
||||
const io = new Server(res.socket.server, {
|
||||
path: '/api/socketio',
|
||||
cors: {
|
||||
origin: '*',
|
||||
methods: ['GET', 'POST'],
|
||||
},
|
||||
});
|
||||
|
||||
res.socket.server.io = io;
|
||||
|
||||
io.on('connection', (socket) => {
|
||||
console.log('Client connected:', socket.id);
|
||||
|
||||
socket.on('message', (data) => {
|
||||
console.log('Message received:', data);
|
||||
socket.broadcast.emit('message', data);
|
||||
});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log('Client disconnected:', socket.id);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
console.log('Socket.io is already initialized.');
|
||||
}
|
||||
|
||||
res.end();
|
||||
}
|
5
src/app/socket.js
Normal file
5
src/app/socket.js
Normal file
@ -0,0 +1,5 @@
|
||||
"use client";
|
||||
|
||||
import { io } from "socket.io-client";
|
||||
|
||||
export const socket = io();
|
@ -38,7 +38,6 @@ export default function UserProfile({ id }) {
|
||||
if (isLoading) {
|
||||
return null;
|
||||
} else {
|
||||
console.log(data, 'dadsasdas');
|
||||
const { user } = data;
|
||||
return user;
|
||||
}
|
||||
|
@ -19,7 +19,6 @@ const TABLE_HEAD = [
|
||||
{ id: 'orders', label: 'Orders', alignRight: false, sort: true },
|
||||
{ id: 'role', label: 'Role', alignRight: false, sort: true },
|
||||
{ id: 'joined', label: 'Joined', alignRight: false, sort: true },
|
||||
|
||||
{ id: '', label: 'Actions', alignRight: true }
|
||||
];
|
||||
|
||||
|
@ -55,7 +55,7 @@ export default function LoginForm() {
|
||||
onSuccess: async (data) => {
|
||||
dispatch(setLogin(data.user));
|
||||
dispatch(setWishlist(data.user.wishlist));
|
||||
// await createCookies('token', data.token);
|
||||
await createCookies('token', data.token);
|
||||
setloading(false);
|
||||
toast.success(lang['Logged in successfully!']);
|
||||
const isAdmin = data.user.role.includes('admin');
|
||||
@ -95,9 +95,11 @@ export default function LoginForm() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<FormControl fullWidth>
|
||||
<InputLabel id="demo-simple-select-label">SELECT LANGUAGE</InputLabel>
|
||||
<Select
|
||||
<FormControl fullWidth sx={{ mb: '10px' }}>
|
||||
<Typography variant="overline" color="text.primary" htmlFor="email" component={'label'}>
|
||||
Select Language
|
||||
</Typography>
|
||||
<Select
|
||||
onChange={(e) => setLangState(e.target.value)}
|
||||
value={langIs}
|
||||
>
|
||||
|
@ -413,7 +413,7 @@ export default function ProductForm({
|
||||
/>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={12} md={6}>
|
||||
<Grid item xs={12} md={6} sx={{display:'none'}}>
|
||||
<FormControl fullWidth>
|
||||
{isInitialized ? (
|
||||
<Skeleton variant="text" width={80} />
|
||||
@ -443,7 +443,7 @@ export default function ProductForm({
|
||||
)}
|
||||
</FormControl>
|
||||
</Grid>
|
||||
<Grid item xs={12} md={4}>
|
||||
<Grid item xs={12} md={4} sx={{display:'none'}}>
|
||||
<FormControl fullWidth>
|
||||
{isInitialized ? (
|
||||
<Skeleton variant="text" width={80} />
|
||||
@ -671,7 +671,7 @@ export default function ProductForm({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div style={{display:'none'}}>
|
||||
<LabelStyle component={'label'} htmlFor="quantity">
|
||||
{'Quantity'}
|
||||
</LabelStyle>
|
||||
@ -685,7 +685,7 @@ export default function ProductForm({
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div style={{display:'none'}}>
|
||||
<LabelStyle component={'label'} htmlFor="regular-price">
|
||||
{'Regular Price'}
|
||||
</LabelStyle>
|
||||
@ -702,7 +702,7 @@ export default function ProductForm({
|
||||
helperText={touched.price && errors.price}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{display:'none'}}>
|
||||
<LabelStyle component={'label'} htmlFor="sale-price">
|
||||
{'Sale Price'}
|
||||
</LabelStyle>
|
||||
|
@ -519,7 +519,7 @@ export default function ShopSettingFrom({ data: currentShop, isLoading: category
|
||||
{categoryLoading ? (
|
||||
<Skeleton variant="text" width={150} />
|
||||
) : (
|
||||
<LabelStyle component={'label'} htmlFor="country">
|
||||
<LabelStyle component={'label'} htmlFor="country" sx={{display:'none'}}>
|
||||
Country
|
||||
</LabelStyle>
|
||||
)}
|
||||
|
@ -422,7 +422,7 @@ export default function CreateShopSettingFrom() {
|
||||
helperText={touched.phone && errors.phone}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{display:'none'}}>
|
||||
<LabelStyle component={'label'} htmlFor="country">
|
||||
Country
|
||||
</LabelStyle>
|
||||
@ -444,7 +444,7 @@ export default function CreateShopSettingFrom() {
|
||||
))}
|
||||
</TextField>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{display:'none'}}>
|
||||
<LabelStyle component={'label'} htmlFor="city">
|
||||
City
|
||||
</LabelStyle>
|
||||
@ -457,7 +457,7 @@ export default function CreateShopSettingFrom() {
|
||||
helperText={touched.address?.city && errors.address?.city}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{display:'none'}}>
|
||||
<LabelStyle component={'label'} htmlFor="state">
|
||||
State
|
||||
</LabelStyle>
|
||||
@ -472,7 +472,7 @@ export default function CreateShopSettingFrom() {
|
||||
</div>
|
||||
<div>
|
||||
<LabelStyle component={'label'} htmlFor="streetAddress">
|
||||
Street Address
|
||||
Address
|
||||
</LabelStyle>
|
||||
|
||||
<TextField
|
||||
|
@ -4,7 +4,7 @@ import { useRouter } from 'next-nprogress-bar';
|
||||
|
||||
// mui
|
||||
import { styled } from '@mui/material/styles';
|
||||
import { Box, TableRow, Skeleton, TableCell, Typography, Stack, IconButton, Avatar, Tooltip } from '@mui/material';
|
||||
import { Box, TableRow, Skeleton, TableCell, Typography, Stack, IconButton, Avatar, Tooltip, Select, MenuItem } from '@mui/material';
|
||||
|
||||
// utils
|
||||
import { fDateShort } from 'src/utils/formatTime';
|
||||
@ -75,7 +75,7 @@ export default function UserRow({ isLoading, row, setId }) {
|
||||
<TableCell style={{ minWidth: 80 }}>{isLoading ? <Skeleton variant="text" /> : row?.phone}</TableCell>
|
||||
<TableCell style={{ minWidth: 40 }}>{isLoading ? <Skeleton variant="text" /> : row?.totalOrders || 0}</TableCell>
|
||||
<TableCell style={{ minWidth: 40, textTransform: 'capitalize' }}>
|
||||
{isLoading ? <Skeleton variant="text" /> : row.role}
|
||||
{isLoading ? <Skeleton variant="text" /> : <Select defaultValue={row.role}><MenuItem value="user">Buyer</MenuItem><MenuItem value="seller">Seller</MenuItem><MenuItem value="super admin">Admin</MenuItem></Select>}
|
||||
</TableCell>
|
||||
<TableCell style={{ minWidth: 40 }}>
|
||||
{isLoading ? <Skeleton variant="text" /> : fDateShort(row.createdAt, enUS)}
|
||||
|
@ -44,6 +44,14 @@ UploadMultiFile.propTypes = {
|
||||
export default function UploadMultiFile({ ...props }) {
|
||||
const { error, files, onRemove, blob, isEdit, onRemoveAll, loading, sx, ...other } = props;
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
|
||||
const [priceModalOpen, setPriceModalOpen] = useState(false); // 금액 입력 모달 열기 상태
|
||||
const [clientPosition, setClientPosition] = useState({ x: 0, y: 0 }); // 클릭 위치
|
||||
const [price, setPrice] = useState(''); // 금액 입력 상태
|
||||
const [annotations, setAnnotations] = useState([]); // 입력된 금액 및 위치 저장
|
||||
|
||||
|
||||
const [image, setImage] = useState('');
|
||||
const [predictions, setPredictions] = useState([]); // Roboflow 결과 저장
|
||||
const canvasRef = useRef(null); // 캔버스 참조
|
||||
@ -116,6 +124,22 @@ export default function UploadMultiFile({ ...props }) {
|
||||
detectWithRoboflow();
|
||||
};
|
||||
|
||||
// 캔버스 클릭 시 실행되는 핸들러
|
||||
const priceTagHandler = (event) => {
|
||||
const rect = event.target.getBoundingClientRect();
|
||||
const x = event.clientX - rect.left; // 캔버스 내 X 좌표
|
||||
const y = event.clientY - rect.top; // 캔버스 내 Y 좌표
|
||||
setClientPosition({ x, y });
|
||||
setPriceModalOpen(true); // 금액 입력 모달 열기
|
||||
};
|
||||
|
||||
// 금액 입력 후 저장
|
||||
const handleSavePrice = () => {
|
||||
setAnnotations([...annotations, { x: clientPosition.x, y: clientPosition.y, price }]);
|
||||
setPriceModalOpen(false); // 모달 닫기
|
||||
setPrice(''); // 입력 초기화
|
||||
};
|
||||
|
||||
return (
|
||||
<Box sx={{ width: '100%', ...sx }}>
|
||||
<DropZoneStyle
|
||||
@ -232,7 +256,52 @@ export default function UploadMultiFile({ ...props }) {
|
||||
>
|
||||
AI 상품 검출
|
||||
</Button>
|
||||
<canvas ref={canvasRef} style={{ width: '100%' }} />
|
||||
{/* 금액 입력 모달 */}
|
||||
<Modal open={priceModalOpen} onClose={() => setPriceModalOpen(false)}>
|
||||
<Stack
|
||||
spacing={2}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: '50%',
|
||||
left: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
background: '#fff',
|
||||
padding: 3,
|
||||
borderRadius: 1,
|
||||
boxShadow: 24,
|
||||
}}
|
||||
>
|
||||
<Typography variant="h6">Enter Price</Typography>
|
||||
<input
|
||||
type="text"
|
||||
value={price}
|
||||
onChange={(e) => setPrice(e.target.value)}
|
||||
placeholder="Enter price"
|
||||
style={{ padding: '8px', borderRadius: '4px', border: '1px solid #ddd' }}
|
||||
/>
|
||||
<Button variant="contained" onClick={handleSavePrice}>
|
||||
Save
|
||||
</Button>
|
||||
</Stack>
|
||||
</Modal>
|
||||
<canvas ref={canvasRef} style={{ width: '100%' }} onClick={(event) => priceTagHandler(event)} />
|
||||
{/* 저장된 금액 표시 */}
|
||||
{annotations.map((annotation, idx) => (
|
||||
<Typography
|
||||
key={idx}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
top: annotation.y,
|
||||
left: annotation.x,
|
||||
backgroundColor: 'rgba(0,0,0,0.7)',
|
||||
color: '#fff',
|
||||
padding: '2px 5px',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
>
|
||||
{annotation.price}
|
||||
</Typography>
|
||||
))}
|
||||
</Stack>
|
||||
</Modal>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user