import React from 'react';
import styled from 'styled-components';
// Styled Components
const MessageInputContainer = styled.div`
display: flex;
align-items: center;
padding: 10px;
border-top: 1px solid #e1e1e1;
`;
const MessageInput = styled.input`
flex-grow: 1;
margin-right: 10px;
padding: 8px;
border: 1px solid #ccc;
border-radius: 5px;
font-size: 16px;
`;
const FileInput = styled.input`
display: none;
`;
const ClipButton = styled.button`
background-color: transparent;
border: none;
cursor: pointer;
`;
const MessageBox = styled.div`
max-width: 500px;
word-wrap: break-word;
background-color: #f9f9f9;
padding: 10px;
border-radius: 5px;
margin: 10px 0;
`;
const StyledImage = styled.img`
max-width: 100%;
height: auto;
`;
const ChatInput = ({ onSendMessage }: { onSendMessage: (messageText: string, attachmentUrl: string | null) => void }) => {
const [messageText, setMessageText] = React.useState('');
const [attachmentUrl, setAttachmentUrl] = React.useState<string | null>(null);
const fileInputRef = React.useRef<HTMLInputElement>(null);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (messageText.trim() !== '') {
onSendMessage(messageText, attachmentUrl);
setMessageText('');
setAttachmentUrl(null);
}
};
const handleFileChange = (e: React.ChangeEvent<HTMLInputElement>) => {
// File change handling logic remains the same
};
const handleClipButtonClick = () => {
fileInputRef.current?.click();
};
return (
<form onSubmit={handleSubmit}>
<MessageInputContainer>
<MessageInput
type="text"
placeholder="Type a message..."
value={messageText}
onChange={(e) => setMessageText(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && handleSubmit(e)}
/>
<ClipButton onClick={handleClipButtonClick} type="button">
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M12 5v14M5 12h14"/>
</svg>
</ClipButton>
<FileInput
ref={fileInputRef}
type="file"
accept="image/*, video/*"
onChange={handleFileChange}
/>
</MessageInputContainer>
<button type="submit" style={{ display: 'none' }}>Send</button>
{attachmentUrl && (
<MessageBox>
<StyledImage src={attachmentUrl} alt="attachment" />
</MessageBox>
)}
</form>
);
};
export default ChatInput;
일단 기존의 백엔드 파일을 분리해줬습니다.
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const express_1 = __importDefault(require("express"));
const http_1 = require("http");
const socket_io_1 = require("socket.io");
const cors_1 = __importDefault(require("cors")); // cors import 추가
const app = (0, express_1.default)();
app.use((0, cors_1.default)()); // CORS 미들웨어 적용
const server = (0, http_1.createServer)(app);
const io = new socket_io_1.Server(server, {
cors: {
origin: "https://nbc-pet.vercel.app/", // 클라이언트 주소, 실제 주소로 변경 필요
methods: ["GET", "POST"],
allowedHeaders: ["my-custom-header"],
credentials: true
}
});
io.on('connection', (socket) => {
console.log('New client connected');
socket.on('chat message', (message) => {
io.emit('chat message', message);
});
socket.on('disconnect', () => {
console.log('Client disconnected');
});
});
const port = process.env.PORT || 4000;
server.listen(port, () => console.log(`Listening on port ${port}`));
와
{
"compilerOptions": {
"target": "es2018",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*"] // 'server/**/*' 대신 'src/**/*' 사용
}
그리고 koyeb을 통해 배포하였고, 이제는 배포한 프론트엔드 링크와 연결을 테스트해야합니다.