Skip to content

Commit 020c415

Browse files
authored
Merge pull request #411 from Souf-Project/feat/feed-contest
FEAT : 피드 동영상 썸네일 처리 및 신고 API 수정
2 parents 97f9f55 + f2bda9c commit 020c415

4 files changed

Lines changed: 114 additions & 89 deletions

File tree

src/api/report.js

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
import client from "./client";
22

3-
4-
export const postReport = async (postType, postId, title, reporterId, reportedMemberId, selectedReasons, description) => {
3+
// 원하는 형식에 맞게 reporterId 제거 (백엔드에서 자동 처리 또는 헤더에서 가져옴)
4+
export const postReport = async (postType, postId, title, reportedMemberId, selectedReasons, description) => {
55
try {
6-
const response = await client.post("/api/v1/report", {
7-
postType,
8-
postId,
9-
title,
10-
reporterId,
11-
reportedMemberId,
12-
reasons : selectedReasons,
13-
description,
14-
});
6+
const requestBody = {
7+
postType,
8+
postId: Number(postId),
9+
title,
10+
reportedMemberId: Number(reportedMemberId),
11+
reasons: selectedReasons,
12+
description,
13+
};
14+
15+
16+
const response = await client.post("/api/v1/report", requestBody);
1517
return response.data;
1618
} catch (error) {
1719
console.error("신고 생성 에러:", error);

src/components/declare/declareModal.jsx

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,14 @@ export default function DeclareModal({
5555
return;
5656
}
5757

58-
// 필수 필드 검증
59-
if (!postType || postId === null || postId === undefined || !title || reporterId === null || reportedMemberId === null || reportedMemberId === undefined) {
60-
61-
if (reporterId === null || reporterId === undefined) {
62-
alert("로그인 후 신고해주세요.");
63-
return;
64-
}
58+
// 로그인 체크
59+
if (reporterId === null || reporterId === undefined) {
60+
setShowLoginModal(true);
61+
return;
62+
}
63+
64+
// 필수 필드 검증 (reporterId는 API 호출 시 제외되지만 로그인 체크용으로 필요)
65+
if (!postType || postId === null || postId === undefined || !title || reportedMemberId === null || reportedMemberId === undefined) {
6566
if (!postType) {
6667
alert("신고할 게시물 유형이 없습니다.");
6768
return;
@@ -90,14 +91,14 @@ export default function DeclareModal({
9091
postType,
9192
postId: Number(postId),
9293
title,
93-
reporterId: Number(reporterId),
9494
reportedMemberId: Number(reportedMemberId),
9595
reasons,
9696
description
9797
};
9898

9999
try {
100-
const response = await postReport(postType, postId, title, reporterId, reportedMemberId, reasons, description);
100+
101+
const response = await postReport(postType, postId, title, reportedMemberId, reasons, description);
101102

102103
setIsSubmitted(true);
103104

src/components/feed.jsx

Lines changed: 87 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,13 @@ export default function Feed({ feedData, onFeedClick }) {
6767

6868
useEffect(() => {
6969
setWorksData(feedData);
70-
setMediaData(feedData?.mediaResDtos);
70+
// mediaResDto가 배열인지 단일 객체인지 확인하고 배열로 변환
71+
const mediaArray = Array.isArray(feedData?.mediaResDto)
72+
? feedData.mediaResDto
73+
: feedData?.mediaResDto
74+
? [feedData.mediaResDto]
75+
: [];
76+
setMediaData(mediaArray);
7177
setIsLiked(feedData?.liked || false);
7278
setLikedCount(feedData?.likedCount || 0);
7379
}, [feedData]);
@@ -91,7 +97,7 @@ export default function Feed({ feedData, onFeedClick }) {
9197
setShowDeleteModal(false);
9298
setShowCompleteModal(true);
9399
} catch (err) {
94-
console.log("실패함" , err);
100+
// console.log("실패함" , err);
95101
const errorKey = err?.response?.data?.errorKey;
96102
if (err.response?.status === 403) {
97103
setShowLoginModal(true);
@@ -127,7 +133,7 @@ export default function Feed({ feedData, onFeedClick }) {
127133

128134
const toggleExpand = () => setIsExpanded((prev) => !prev);
129135
const handleDeclareClick = (declareData) => {
130-
console.log('신고 데이터:', declareData);
136+
// console.log('신고 데이터:', declareData);
131137
}
132138

133139
const handleHeartClick = async () => {
@@ -147,7 +153,13 @@ export default function Feed({ feedData, onFeedClick }) {
147153
setWorksData(updatedData.result);
148154
setIsLiked(updatedData.result.liked);
149155
setLikedCount(updatedData.result.likedCount || 0);
150-
setMediaData(updatedData.result.mediaResDtos);
156+
// mediaResDto가 배열인지 단일 객체인지 확인하고 배열로 변환
157+
const mediaArray = Array.isArray(updatedData.result?.mediaResDto)
158+
? updatedData.result.mediaResDto
159+
: updatedData.result?.mediaResDto
160+
? [updatedData.result.mediaResDto]
161+
: [];
162+
setMediaData(mediaArray);
151163

152164
} catch (error) {
153165
console.error("피드 관련 에러:", error);
@@ -228,70 +240,81 @@ export default function Feed({ feedData, onFeedClick }) {
228240
<div
229241
className="flex justify-center w-full overflow-hidden rounded-md mb-2 relative"
230242
>
231-
{feedData?.mediaResDtos && feedData.mediaResDtos.length > 0 ? (
232-
<>
233-
<Swiper
234-
onSwiper={(swiper) => {
235-
swiperRef.current = swiper;
236-
}}
237-
pagination={{
238-
dynamicBullets: true,
239-
}}
240-
modules={[Pagination]}
241-
className="rounded-lg w-full max-w-[800px]"
242-
>
243-
{feedData?.mediaResDtos?.map((data, i) => {
244-
const isVideo = data.fileType?.toLowerCase().startsWith("video") || data.fileUrl?.toLowerCase().endsWith(".mp4");
245-
return (
246-
<SwiperSlide key={i}>
247-
<div className="flex justify-center items-center">
248-
{isVideo ? (
249-
<video
250-
src={`${data.fileUrl}`}
251-
controls
252-
className="w-full h-auto max-h-[500px] object-cover cursor-pointer"
253-
onClick={goToDetail}
254-
/>
255-
) : (
243+
{(() => {
244+
// mediaResDto가 배열인지 단일 객체인지 확인하고 배열로 변환
245+
const mediaArray = Array.isArray(feedData?.mediaResDto)
246+
? feedData.mediaResDto
247+
: feedData?.mediaResDto
248+
? [feedData.mediaResDto]
249+
: [];
250+
251+
if (mediaArray.length === 0) {
252+
return (
253+
<div className="w-full h-48 bg-gray-100 flex items-center justify-center">
254+
<p className="text-gray-400">이미지가 없습니다</p>
255+
</div>
256+
);
257+
}
258+
259+
return (
260+
<>
261+
<Swiper
262+
onSwiper={(swiper) => {
263+
swiperRef.current = swiper;
264+
}}
265+
pagination={{
266+
dynamicBullets: true,
267+
}}
268+
modules={[Pagination]}
269+
className="rounded-lg w-full max-w-[800px]"
270+
>
271+
{mediaArray.map((data, i) => {
272+
// 피드 목록에서는 동영상도 썸네일 이미지(.png)로 표시
273+
// fileUrl이 이미 전체 URL인지 확인 (http:// 또는 https://로 시작하는지)
274+
const isFullUrl = data.fileUrl?.startsWith('http://') || data.fileUrl?.startsWith('https://');
275+
const mediaUrl = isFullUrl ? data.fileUrl : `${BUCKET_URL}${data.fileUrl}`;
276+
277+
return (
278+
<SwiperSlide key={i}>
279+
<div className="flex justify-center items-center">
256280
<img
257-
src={`${BUCKET_URL}${data.fileUrl}`}
258-
alt={data.fileName}
281+
src={mediaUrl}
282+
alt={data.fileName || `미디어 ${i + 1}`}
259283
className="w-full h-auto max-h-[500px] object-cover aspect-[1/1] cursor-pointer"
260284
onClick={goToDetail}
285+
onError={(e) => {
286+
e.target.src = basiclogoimg;
287+
}}
261288
/>
262-
)}
263-
</div>
264-
</SwiperSlide>
265-
)
266-
})}
267-
</Swiper>
268-
{/* 화살표 버튼 */}
269-
{feedData?.mediaResDtos && feedData.mediaResDtos.length > 1 && (
270-
<div className="hidden lg:block">
271-
<button
272-
onClick={(e) => { e.stopPropagation(); swiperRef.current?.slidePrev(); }}
273-
className="absolute left-2 top-1/2 transform -translate-y-1/2 z-10 w-5 h-5 bg-white/80 rounded-full shadow-lg flex items-center justify-center transition-all duration-200"
274-
>
275-
<svg className="w-3 h-3 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
276-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
277-
</svg>
278-
</button>
279-
<button
280-
onClick={(e) => { e.stopPropagation(); swiperRef.current?.slideNext(); }}
281-
className="absolute right-2 top-1/2 transform -translate-y-1/2 z-10 w-5 h-5 bg-white/80 rounded-full shadow-lg flex items-center justify-center transition-all duration-200"
282-
>
283-
<svg className="w-3 h-3 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
284-
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
285-
</svg>
286-
</button>
287-
</div>
288-
)}
289-
</>
290-
) : (
291-
<div className="w-full h-48 bg-gray-100 flex items-center justify-center">
292-
<p className="text-gray-400">이미지가 없습니다</p>
293-
</div>
294-
)}
289+
</div>
290+
</SwiperSlide>
291+
);
292+
})}
293+
</Swiper>
294+
{/* 화살표 버튼 */}
295+
{mediaArray.length > 1 && (
296+
<div className="hidden lg:block">
297+
<button
298+
onClick={(e) => { e.stopPropagation(); swiperRef.current?.slidePrev(); }}
299+
className="absolute left-2 top-1/2 transform -translate-y-1/2 z-10 w-5 h-5 bg-white/80 rounded-full shadow-lg flex items-center justify-center transition-all duration-200"
300+
>
301+
<svg className="w-3 h-3 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
302+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M15 19l-7-7 7-7" />
303+
</svg>
304+
</button>
305+
<button
306+
onClick={(e) => { e.stopPropagation(); swiperRef.current?.slideNext(); }}
307+
className="absolute right-2 top-1/2 transform -translate-y-1/2 z-10 w-5 h-5 bg-white/80 rounded-full shadow-lg flex items-center justify-center transition-all duration-200"
308+
>
309+
<svg className="w-3 h-3 text-gray-700" fill="none" stroke="currentColor" viewBox="0 0 24 24">
310+
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
311+
</svg>
312+
</button>
313+
</div>
314+
)}
315+
</>
316+
);
317+
})()}
295318
</div>
296319
</div>
297320

src/components/studentProfile/postDetail.jsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -152,15 +152,14 @@ const handleDeleteClick = () => {
152152
setShowDeleteModal(false);
153153
setShowCompleteModal(true);
154154
} catch (err) {
155-
//console.log("실패 넘어요", err);
156155
setShowDeleteModal(false);
157156
const errorKey = err?.response?.data?.errorKey;
158157
if (err.response?.status === 403) {
159158
setShowLoginModal(true);
160159
} else {
161160
const errorInfo = FEED_ERRORS[errorKey];
162161
setErrorModal(true);
163-
setErrorDescription(errorInfo?.message || "알 수 없는 오류가 발생했습니다.");
162+
setErrorDescription(errorInfo?.message || "서버 오류가 발생했습니다.");
164163
setErrorAction(errorInfo?.action || "redirect");
165164
}
166165

@@ -215,7 +214,7 @@ const handleDeleteClick = () => {
215214
}else{
216215
const errorInfo = FEED_ERRORS[errorKey];
217216
setErrorModal(true);
218-
setErrorDescription(errorInfo?.message || "알 수 없는 오류가 발생했습니다.");
217+
setErrorDescription(errorInfo?.message || "서버 오류가 발생했습니다.");
219218
setErrorAction(errorInfo?.action || "redirect");
220219
}
221220
}
@@ -241,8 +240,8 @@ const handleDeleteClick = () => {
241240
};
242241

243242
const handleDeclareClick = (declareData) => {
244-
// console.log('프로필 신고 데이터:', declareData);
245-
// 여기에 신고 API 호출
243+
// 신고 API는 declareModal에서 처리하므로 여기서는 데이터만 받아서 로그만 출력
244+
console.log("신고 데이터 수신:", declareData);
246245
};
247246

248247
const shortenUrl = (url) => {

0 commit comments

Comments
 (0)