업로드
This commit is contained in:
parent
dd18322982
commit
fc14716bb3
173
package-lock.json
generated
173
package-lock.json
generated
@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "picshop",
|
||||
"name": "uie",
|
||||
"version": "0.0.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "picshop",
|
||||
"name": "uie",
|
||||
"version": "0.0.2",
|
||||
"dependencies": {
|
||||
"@babel/eslint-parser": "^7.23.10",
|
||||
@ -59,7 +59,6 @@
|
||||
"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",
|
||||
@ -1985,21 +1984,6 @@
|
||||
"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",
|
||||
@ -2346,28 +2330,6 @@
|
||||
"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",
|
||||
@ -2763,15 +2725,6 @@
|
||||
],
|
||||
"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",
|
||||
@ -3108,15 +3061,6 @@
|
||||
"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",
|
||||
@ -3128,19 +3072,6 @@
|
||||
"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",
|
||||
@ -3436,27 +3367,6 @@
|
||||
"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",
|
||||
@ -3500,27 +3410,6 @@
|
||||
"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",
|
||||
@ -7325,55 +7214,6 @@
|
||||
"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",
|
||||
@ -8154,15 +7994,6 @@
|
||||
"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",
|
||||
|
@ -61,7 +61,6 @@
|
||||
"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",
|
||||
|
BIN
public/KakaoTalk_20241222_175154359.jpg
Normal file
BIN
public/KakaoTalk_20241222_175154359.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
public/logo_blue.png
Normal file
BIN
public/logo_blue.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 25 KiB |
@ -1,72 +0,0 @@
|
||||
'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>
|
||||
);
|
||||
}
|
30
src/app/admin/chats/[id]/page.jsx
Normal file
30
src/app/admin/chats/[id]/page.jsx
Normal file
@ -0,0 +1,30 @@
|
||||
import React from 'react';
|
||||
|
||||
// components
|
||||
import HeaderBreadcrumbs from 'src/components/headerBreadcrumbs';
|
||||
import UsersDetails from 'src/components/_admin/users/userDetails';
|
||||
|
||||
export default function page({ params }) {
|
||||
return (
|
||||
<>
|
||||
<HeaderBreadcrumbs
|
||||
admin
|
||||
heading="User Details"
|
||||
links={[
|
||||
{
|
||||
name: 'Dashboard',
|
||||
href: '/admin'
|
||||
},
|
||||
{
|
||||
name: 'Users',
|
||||
href: '/admin/users'
|
||||
},
|
||||
{
|
||||
name: 'Users details'
|
||||
}
|
||||
]}
|
||||
/>
|
||||
<UsersDetails id={params.id} />
|
||||
</>
|
||||
);
|
||||
}
|
82
src/app/admin/chats/page.jsx
Normal file
82
src/app/admin/chats/page.jsx
Normal file
@ -0,0 +1,82 @@
|
||||
'use client'
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Stack, Box, Button } from '@mui/material';
|
||||
import { io } from 'socket.io-client';
|
||||
|
||||
const socket = io('http://localhost:5100'); // 서버 URL
|
||||
|
||||
function AdminChatPage() {
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [filter, setFilter] = useState(''); // 사용자 이메일 필터링
|
||||
const [message, setMessage] = useState(''); // 보낼 메시지
|
||||
const [targetEmail, setTargetEmail] = useState(''); // 대상 이메일
|
||||
|
||||
useEffect(() => {
|
||||
// 관리자 방에 참여
|
||||
socket.emit('joinAdmin');
|
||||
|
||||
// 모든 메시지 가져오기
|
||||
fetch(`${process.env.BASE_URL}/v1/chat/admin/messages`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => setMessages(data));
|
||||
|
||||
// 실시간 메시지 수신
|
||||
socket.on('message', (data) => {
|
||||
setMessages((prev) => [...prev, data]);
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off('message');
|
||||
};
|
||||
}, []);
|
||||
|
||||
|
||||
const sendMessage = () => {
|
||||
if (!targetEmail || !message) {
|
||||
alert('대상 이메일과 메시지를 입력하세요.');
|
||||
return;
|
||||
}
|
||||
|
||||
const msg = { username: 'arkiun@naver.com', message, targetEmail };
|
||||
socket.emit('message', msg);
|
||||
setMessage('');
|
||||
};
|
||||
|
||||
const filteredMessages = filter
|
||||
? messages.filter((msg) => msg.username.includes(filter))
|
||||
: messages;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="이메일로 필터링"
|
||||
value={filter}
|
||||
onChange={(e) => setFilter(e.target.value)}
|
||||
/>
|
||||
<Stack>
|
||||
{filteredMessages.map((msg, idx) => (
|
||||
<div key={idx}>
|
||||
<strong>{msg.username}:</strong> {msg.message}
|
||||
</div>
|
||||
))}
|
||||
</Stack>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="대상 이메일"
|
||||
value={targetEmail}
|
||||
onChange={(e) => setTargetEmail(e.target.value)}
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="메시지를 입력하세요"
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
/>
|
||||
<Button onClick={sendMessage}>전송</Button>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
export default AdminChatPage;
|
@ -27,9 +27,6 @@ export default function RelatedProducts({ ...props }) {
|
||||
<Typography variant="h2" color="text.primary" className="heading">
|
||||
Related Products
|
||||
</Typography>
|
||||
<Typography variant="body1" color="text.secondary" className="description">
|
||||
Lorem Ipsum Is Simply Dummy Text Of The Printing And Typesetting Industry.
|
||||
</Typography>
|
||||
<ProductsCarousel data={data?.data} isLoading={isLoading} />
|
||||
</RootStyled>
|
||||
);
|
||||
|
@ -4,11 +4,14 @@ import PropTypes from 'prop-types';
|
||||
import { useState } from 'react';
|
||||
import BlurImage from 'src/components/blurImage';
|
||||
// mui
|
||||
import { Box, Stack, Typography, Button } from '@mui/material';
|
||||
import { Box, Stack, Typography, Button, Modal, IconButton } from '@mui/material';
|
||||
import { MdClear } from 'react-icons/md';
|
||||
|
||||
// framer motion
|
||||
import { motion, AnimatePresence } from 'framer-motion';
|
||||
// styles
|
||||
import RootStyled from './styled';
|
||||
import ChatApp from 'src/components/chat';
|
||||
|
||||
const variants = {
|
||||
enter: (direction) => {
|
||||
@ -50,9 +53,10 @@ ProductDetailsCarousel.propTypes = {
|
||||
|
||||
function ProductDetailsCarousel({ ...props }) {
|
||||
const { item, meta } = props;
|
||||
const [modal, setModal] = useState();
|
||||
|
||||
// JSON 문자열인 meta를 객체 배열로 파싱
|
||||
const annotations = typeof meta === 'string' ? JSON.parse(meta) : meta;
|
||||
const annotations = meta && typeof meta === 'string' ? JSON.parse(meta) : meta;
|
||||
|
||||
return (
|
||||
<div className="slide-wrapper">
|
||||
@ -69,7 +73,8 @@ function ProductDetailsCarousel({ ...props }) {
|
||||
)}
|
||||
<Box className="bg-overlay" />
|
||||
{/* 저장된 금액 표시 */}
|
||||
{annotations.map((annotation, idx) => (
|
||||
|
||||
{annotations ? annotations.map((annotation, idx) => (
|
||||
<Button
|
||||
key={idx}
|
||||
sx={{
|
||||
@ -82,13 +87,34 @@ function ProductDetailsCarousel({ ...props }) {
|
||||
padding: '2px 5px',
|
||||
borderRadius: '4px',
|
||||
}}
|
||||
onClick={()=>alert('채팅으로 이동')}
|
||||
onClick={()=>setModal(true)}
|
||||
>
|
||||
<Typography>
|
||||
{annotation.price}
|
||||
</Typography>
|
||||
</Button>
|
||||
))}
|
||||
)) : ''}
|
||||
{ modal &&
|
||||
<Modal open={modal}>
|
||||
<Stack direction={'column'} sx={{backgroundColor:'#fff'}}>
|
||||
<Stack direction='row'>
|
||||
<IconButton
|
||||
aria-label="close"
|
||||
onClick={()=>setModal(false)}
|
||||
sx={{
|
||||
position: 'absolute',
|
||||
right: 5,
|
||||
top: 5,
|
||||
zIndex: 111
|
||||
}}
|
||||
>
|
||||
<MdClear />
|
||||
</IconButton>
|
||||
</Stack>
|
||||
<ChatApp />
|
||||
</Stack>
|
||||
</Modal>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
81
src/components/chat.jsx
Normal file
81
src/components/chat.jsx
Normal file
@ -0,0 +1,81 @@
|
||||
import { Stack } from '@mui/material';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { io } from 'socket.io-client';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
const socket = io(process.env.BASE_URL); // 서버 URL
|
||||
|
||||
function ChatApp() {
|
||||
const { user } = useSelector(({ user }) => user);
|
||||
const userEmail = user.email;
|
||||
const adminEmail = 'arkiun@naver.com'; // 관리자 이메일
|
||||
const [messages, setMessages] = useState([]);
|
||||
const [message, setMessage] = useState('');
|
||||
const [username] = useState(userEmail);
|
||||
|
||||
useEffect(() => {
|
||||
// 사용자 방에 참여
|
||||
socket.emit('join', userEmail);
|
||||
|
||||
// 기존 메시지 가져오기
|
||||
fetch(`${process.env.BASE_URL}/v1/chat/messages?email=${username},${adminEmail}`)
|
||||
.then((res) => res.json())
|
||||
.then((data) => setMessages(data));
|
||||
|
||||
// 실시간 메시지 수신
|
||||
socket.on('message', (data) => {
|
||||
setMessages((prev) => [...prev, data]);
|
||||
});
|
||||
|
||||
return () => {
|
||||
socket.off('message');
|
||||
};
|
||||
}, [username, adminEmail]);
|
||||
|
||||
const sendMessage = () => {
|
||||
const msg = { username: username, message, targetEmail: adminEmail }; // 관리자 이메일
|
||||
socket.emit('message', msg);
|
||||
setMessage('');
|
||||
};
|
||||
|
||||
return (
|
||||
<Stack
|
||||
direction={'column'}
|
||||
sx={{
|
||||
position: 'fixed',
|
||||
left: '50%',
|
||||
top: '50%',
|
||||
transform: 'translate(-50%, -50%)',
|
||||
backgroundColor: '#fff',
|
||||
width: '100vw',
|
||||
height: '100vh',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
}}
|
||||
>
|
||||
<Stack width="100%" p="24px" direction={'column'} gap={'10px'}>
|
||||
<Stack>
|
||||
{messages.map((msg, idx) => (
|
||||
<div key={idx}>
|
||||
<strong>{msg.username}:</strong> {msg.message}
|
||||
</div>
|
||||
))}
|
||||
</Stack>
|
||||
<Stack direction={'row'} gap="10px">
|
||||
<input
|
||||
style={{ height: '40px', width: 'calc(100% - 70px)', border: '1px solid #eee' }}
|
||||
type="text"
|
||||
placeholder="여기에 입력"
|
||||
value={message}
|
||||
onChange={(e) => setMessage(e.target.value)}
|
||||
/>
|
||||
<button style={{ width: '70px' }} onClick={sendMessage}>
|
||||
SEND
|
||||
</button>
|
||||
</Stack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
export default ChatApp;
|
@ -15,13 +15,13 @@ export const Logo = () => {
|
||||
width: 150,
|
||||
height: 'auto',
|
||||
'> img': {
|
||||
height:36,
|
||||
height:56,
|
||||
width: 'auto'
|
||||
}
|
||||
}}
|
||||
onClick={() => push('/')}
|
||||
>
|
||||
<img src="/ui_1920.png" alt="logo"/>
|
||||
<img src="/logo_blue.png" alt="logo"/>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
@ -38,6 +38,7 @@ import { BsBuildings } from 'react-icons/bs';
|
||||
|
||||
// components
|
||||
import Scrollbar from 'src/components/Scrollbar';
|
||||
import { ChatBubble, ChatBubbleOutline } from '@mui/icons-material';
|
||||
|
||||
// Dashboard Side NevLinks
|
||||
export const navlinks = [
|
||||
@ -95,6 +96,13 @@ export const navlinks = [
|
||||
slug: 'users',
|
||||
icon: <LuUsers />,
|
||||
isSearch: true
|
||||
},
|
||||
{
|
||||
id: 8,
|
||||
title: 'Chats',
|
||||
slug: 'chats',
|
||||
icon: <ChatBubbleOutline />,
|
||||
isSearch: true
|
||||
}
|
||||
// {
|
||||
// id: 8,
|
||||
|
Loading…
Reference in New Issue
Block a user