업로드

This commit is contained in:
익희 김 2024-12-23 06:14:41 +09:00
parent dd18322982
commit fc14716bb3
12 changed files with 236 additions and 254 deletions

173
package-lock.json generated
View File

@ -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",

View File

@ -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",

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/logo_blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

View File

@ -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>
);
}

View 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} />
</>
);
}

View 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;

View File

@ -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>
);

View File

@ -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
View 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;

View File

@ -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>
);
};

View File

@ -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,