그룹채팅 - Part6 방장의 권한(1) - 채팅방 수정 / 삭제
ㆍProject Diary/Next.js + Prisma + MariaDB (KiloFlow)
방장이 채팅방을 수정하고 삭제하는 기능을 구현하는 방법에 대해 설명하겠습니다. 방장은 채팅방의 이름, 이미지, 태그 등을 수정할 수 있으며, 채팅방을 삭제할 수도 있습니다.
프론트엔드
1. 채팅방 정보 불러오기
채팅방 정보를 불러와서 수정 폼에 초기값으로 설정합니다.
useEffect(() => {
const fetchChatroomInfo = async () => {
// 채팅방 정보를 가져오는 API 호출
const res = await fetch(`/api/community/current-chatroom-info?roomId=${roomId}&action=info`);
const data = await res.json();
// 가져온 데이터를 상태에 설정
setChatroomInfo(data);
setName(data.name);
setHashtags(data.tags.split(" "));
setMaxMembers(data.max_members);
setImagePreview(data.image_url || communityThumb.src);
};
if (roomId) {
fetchChatroomInfo(); // roomId가 존재할 때만 함수 호출
}
}, [roomId]);
(설명 : 주석참고)
2. 이미지 변경 핸들러
const handleImageChange = (e: ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
setImage(file); // 이미지 파일을 상태에 저장
setImagePreview(URL.createObjectURL(file)); // 이미지 미리보기를 위한 URL 생성
}
};
(설명 : 주석참고)
3. 해시태그 관리 핸들러
const handleHashtagChange = (index: number, value: string) => {
const newHashtags = [...hashtags]; // 현재 해시태그 목록 복사
newHashtags[index] = value; // 특정 인덱스의 해시태그 변경
setHashtags(newHashtags); // 변경된 해시태그 목록을 상태에 저장
};
const handleAddHashtag = () => {
setHashtags([...hashtags, ""]); // 해시태그 목록에 빈 문자열 추가
};
const handleRemoveHashtag = (index: number) => {
const newHashtags = [...hashtags]; // 현재 해시태그 목록 복사
newHashtags.splice(index, 1); // 특정 인덱스의 해시태그 제거
setHashtags(newHashtags); // 변경된 해시태그 목록을 상태에 저장
};
const handleDefaultImage = () => {
setImage(communityThumb.src); // 기본 이미지 설정
setImagePreview(communityThumb.src); // 이미지 미리보기 설정
};
(설명 : 주석참고)
4. 채팅방 수정 요청 핸들러
const handleSubmit = async (event: FormEvent) => {
event.preventDefault();
const formData = new FormData();
formData.append("name", name); // 채팅방 이름 추가
formData.append("tags", hashtags.join(" ")); // 해시태그 추가
formData.append("max_members", maxMembers.toString()); // 최대 인원 추가
if (image !== communityThumb.src) {
formData.append("image", image); // 이미지가 기본 이미지가 아닐 경우에만 추가
}
try {
const res = await fetch(`/api/modify/chatroom-modify?roomId=${roomId}`, {
method: "POST",
body: formData,
});
if (res.ok) {
const data = await res.json();
setChatroomInfo(data); // 업데이트된 채팅방 정보 상태에 저장
window.alert("채팅방 정보가 업데이트되었습니다.");
router.back(); // 이전 페이지로 이동
} else {
const data = await res.json();
console.log("채팅방 업데이트 데이터 오류", data);
}
} catch (err) {
console.log("채팅방 업데이트 오류", err);
}
};
(설명 : 주석참고)
5. 채팅방 삭제 요청 핸들러
const handleDelete = async () => {
if (confirm("정말로 채팅방을 삭제하시겠습니까?")) {
const res = await fetch(`/api/community/delete?roomId=${roomId}`, {
method: "DELETE",
});
if (res.ok) {
alert("채팅방이 삭제되었습니다.");
router.push("/community/list"); // 채팅방 목록 페이지로 이동
}
}
};
(설명 : 주석참고)
백엔드
1. 채팅방 정보 가져오기 API엔드포인트
import { NextApiRequest, NextApiResponse } from "next";
import prisma from "../../../lib/prisma";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { roomId, action } = req.query;
if (!roomId || !action) {
return res.status(400).json({ message: "Missing roomId or action parameter" }); // roomId 또는 action이 없을 경우 400 상태 코드 응답
}
if (req.method === "GET") {
if (action === "info") {
// 특정 채팅방 정보 가져오기
const chatroom = await prisma.chatrooms.findUnique({
where: { id: Number(roomId) },
});
if (!chatroom) {
return res.status(404).json({ message: "Chatroom not found" }); // 채팅방이 존재하지 않을 경우 404 상태 코드 응답
}
return res.status(200).json(chatroom); // 채팅방 정보 응답
} else if (action === "users") {
// 특정 채팅방의 사용자 목록 가져오기
const users = await prisma.chatroom_members.findMany({
where: { chatroom_id: Number(roomId) },
include: { user: true },
});
const userList = users.map((member) => member.user);
return res.status(200).json(userList); // 사용자 목록 응답
} else {
return res.status(400).json({ message: "Invalid action parameter" }); // action 파라미터가 유효하지 않을 경우 400 상태 코드 응답
}
} else {
res.setHeader("Allow", ["GET"]); // 허용되지 않는 메서드에 대한 응답 설정
res.status(405).end(`Method ${req.method} Not Allowed`); // 405 상태 코드 응답
}
}
(설명 : 주석참고)
2. 채팅방 정보 수정 API엔드포인트
import { NextApiRequest, NextApiResponse } from "next";
import prisma from "../../../lib/prisma";
import upload from "../../../lib/multer";
interface ExtendedRequest extends NextApiRequest {
file: Express.Multer.File;
}
export const config = {
api: {
bodyParser: false, // Multer를 사용하기 위해 bodyParser 비활성화
},
};
// 미들웨어 실행 함수
const runMiddleware = (req: NextApiRequest, res: NextApiResponse, fn: Function) => {
return new Promise((resolve, reject) => {
fn(req, res, (result: any) => {
if (result instanceof Error) {
return reject(result); // 오류 발생 시 reject 호출
}
return resolve(result); // 정상적으로 완료되면 resolve 호출
});
});
};
// 채팅방 수정 핸들러
export default async function handler(req: ExtendedRequest, res: NextApiResponse) {
if (req.method === "POST") {
try {
await runMiddleware(req, res, upload.single("image")); // 이미지 업로드 미들웨어 실행
const { roomId } = req.query;
const { name, tags, max_members, image } = req.body;
const imageUrl = req.file ? `/uploads/${req.file.filename}` : image; // 이미지 경로 설정
const updatedData: any = {
name, // 채팅방 이름
tags, // 해시태그
max_members: Number(max_members), // 최대 인원
};
if (imageUrl) {
updatedData.image_url = imageUrl; // 이미지 URL 추가
}
// Prisma를 사용하여 채팅방 정보 업데이트
const updatedChatroom = await prisma.chatrooms.update({
where: { id: Number(roomId) },
data: updatedData,
});
res.status(200).json(updatedChatroom); // 업데이트된 채팅방 정보 응답
} catch (error) {
console.error("Error updating chatroom:", error);
res.status(500).json({ message: "Internal server error" }); // 오류 발생 시 응답
}
} else {
res.setHeader("Allow", ["POST"]); // 허용되지 않는 메서드에 대한 응답 설정
res.status(405).end(`Method ${req.method} Not Allowed`); // 405 상태 코드 응답
}
}
(설명 : 주석참고)
3. 채팅방 삭제 API엔드포인트
import { NextApiRequest, NextApiResponse } from "next";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { roomId } = req.query;
if (req.method === "DELETE") {
try {
// Prisma 트랜잭션을 사용하여 연관된 모든 데이터를 삭제
await prisma.$transaction([
prisma.chatroom_members.deleteMany({
where: { chatroom_id: Number(roomId) },
}),
prisma.chatMessages.deleteMany({
where: { chatroom_id: Number(roomId) },
}),
prisma.chatrooms.delete({
where: { id: Number(roomId) },
}),
prisma.notices.deleteMany({
where: { chatroom_id: Number(roomId) },
}),
]);
res.status(204).end(); // 성공 시 204 상태 코드 응답
} catch (error) {
console.error("채팅방 삭제 에러", error);
res.status(500).json({ error: "채팅방 삭제 중에 에러가 발생했습니다." }); // 오류 발생 시 응답
}
} else {
res.setHeader("Allow", ["DELETE"]); // 허용되지 않는 메서드에 대한 응답 설정
res.status(405).end(`Method ${req.method} Not Allowed`); // 405 상태 코드 응답
}
}
(설명 : 주석참고)