juni
게시글 고정 본문
이전 게시글 관련글과 연계
모달
페이지
커스텀 DropDownMenu에서 고정 로직 예시
const togglePinFeed = async () => {
const tagKey = item.tags[0]?.tagKey;
if (!tagKey) {
toast({
description: "고정할 유효한 태그 키가 없습니다.",
state: "warning",
});
return;
}
if (item.pinnedTagKey) {
const result = await unpinFeed(params.domain as string, item.id); // 실제 도메인 값 필요
if (result.statusCode === 200) {
item.pinnedTagKey = null;
if (onCompleted) onCompleted();
} else {
toast({ description: "고정 해제 실패", state: "warning" });
}
} else {
const result = await pinFeed(
params.domain as string, // 실제 도메인 값 필요
item.id,
tagKey
);
if (result.statusCode === 200) {
item.pinnedTagKey = tagKey;
if (onCompleted) onCompleted();
} else {
toast({ description: "고정 실패", state: "warning" });
}
}
};
// 적용 코드
{role == "owner" && (
<div
className="px-3 pt-4 pb-3.5 cursor-pointer"
onClick={togglePinFeed}
>
{item.pinnedTagKey ? "상단 고정 해제하기" : "상단 고정하기"}
</div>
)}
게시글 작성/수정 시 Pin아이콘을 통하여 완료 시 고정 예약 on/off 가능
Pin아이콘을 통하여 완료 시 고정 예약 on/off 코드 예시
const onSubmit = async (data: FeedFormValues) => {
setLoading(true);
// const isPinned = Boolean(feed.pinnedTagKey);
const pinnedTagKey = isPinned && tags.length > 0 ? tags[0].tagKey : null;
let result;
// 일반 피드 생성
if (!submissionInfo) {
if (!defaultValue) {
result = await createFeed({
domain: params.domain as string, // 실제 도메인 값 필요
...data,
tags,
pinnedTagKey: pinnedTagKey,
});
if (result.statusCode === 201) {
if (onCompleted) onCompleted(undefined);
form.reset();
setTags([]);
setIsPinned(false);
setOpenDialog(false);
}
} else {
result = await updateFeed({
feedId: defaultValue.id,
domain: params.domain as string, // 실제 도메인 값 필요
...data,
tags,
imageIdsToDelete,
pinnedTagKey: pinnedTagKey,
});
if (result.statusCode === 200) {
if (onCompleted) onCompleted(result.feed);
form.reset();
setTags([]);
setOpenDialog(false);
}
}
toast({ description: result.message });
}
// 클래스용 피드 생성
if (submissionInfo) {
if (!defaultValue) {
result = await submitTask(
params.domain as string, // 실제 도메인 값 필요
submissionInfo.challengeId as number,
submissionInfo.id as number,
{
domain: params.domain as string, // 실제 도메인 값 필요
...data,
tags,
}
);
if (result.statusCode === 200) {
// toast({ description: result.message });
if (onCompleted) onCompleted();
form.reset();
setOpenDialog(false);
}
if (result.statusCode === 409) {
// toast({ description: result.message });
}
toast({ description: result.message });
}
}
setLoading(false);
};
별도로 분리된 고정 게시글 리스트
고정 게시글 리스트 예시
return (
<>
{pinnedFeeds?.length > 0 && (
<div
className="mb-4 md:mb-8 bg-background-base overflow-hidden"
style={{ maxWidth: "635px" }}
>
<Swiper
spaceBetween={12}
slidesPerView="auto"
freeMode
centeredSlides={false}
>
{pinnedFeeds.map((feed) => {
return (
<SwiperSlide key={feed.id} style={{ width: `${slideWidth}px` }}>
<Card
variant="feed"
className="h-[170px] w-[240px] md:w-[360px] cursor-pointer"
onClick={() => openFeedDetails(feed)}
>
<Pin
className="w-5 h-5 mb-3 cursor-pointer shrink-0"
onClick={() => {
onCompleted;
}}
/>
{feed.title ? (
<div className="text-title_l truncate shrink-0">
{feed.title}
</div>
) : (
<div className="mb-[18px]"></div>
)}
<div
className="my-3 truncate"
dangerouslySetInnerHTML={{ __html: feed.description }}
/>
<div className="text-label_s text-text-secondary">
{formatDate(feed.pinned_at, getLocale())}
</div>
</Card>
</SwiperSlide>
);
})}
</Swiper>
{selectedFeed && (
<FeedDetails
dialogOpen={dialogOpen}
setDialogOpen={setDialogOpen}
details={selectedFeed}
onCompleted={onCompleted}
/>
)}
</div>
)}
</>
);
// 적용 코드
<div className="flex justify-between">
<h4 className="text-title_l md:text-subhead_s grow-0 mb-6">
{defaultValue ? "게시글 수정하기" : "게시글 작성하기"}
</h4>
{role === "owner" && (
<Pin
className={`w-6 h-6 cursor-pointer ${
isPinned ? "text-icon-primary" : "text-icon-secondary"
}`}
onClick={() => setIsPinned(!isPinned)}
/>
)}
</div>
'인턴' 카테고리의 다른 글
커뮤니티 게시글 관련 QA 및 리팩토링 (1) | 2024.11.14 |
---|---|
커뮤니티 (게시글 고정) API 연동 (2) | 2024.11.13 |
프로필 아바타 및 이미지 수정 (1) | 2024.11.12 |
게시글 삭제, 상세 게시글 DropDownMenu 연결 (0) | 2024.11.12 |
게시글 생성/수정 ( defaultValues로 관리 ) (1) | 2024.11.12 |