Notice
Recent Posts
Recent Comments
Link
«   2025/03   »
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31
Tags
more
Archives
Today
Total
관리 메뉴

juni

커뮤니티 (게시글 고정) API 연동 본문

인턴

커뮤니티 (게시글 고정) API 연동

juni_shin 2024. 11. 13. 23:04

게시글 상세 조회 API 예시 -> 고정 게시글 리스트에서도 상세보기를 위해 사용

// 글 목록 조회
export const findFeeds = async (
  domain: string,
  tagKey?: string,
  limit?: number,
  lastId?: number
) => {
  let searchParams;

  if (!tagKey) {
    searchParams = { limit, lastId };
  } else {
    searchParams = { tagKey, limit, lastId };
  }

  return await getApi(`/clubs/${domain}/feeds`, searchParams, false);
};


// 글 상세 조회
export const getFeedDetail = async (domain: string, feedId: number) => {
  return await getApi(`/clubs/${domain}/feeds/${feedId}`, {}, false);
};

 

고정 게시글 예시

 const resetFeeds = async () => {
    setLoading(true);

    const results = await findFeeds(
      params.domain as string,
      selectedTag,
      FEED_LIMIT
    );

    if (results.statusCode === 500) {
      toast({ state: "warning", description: results.message });
    } else if (results.statusCode === 200) {
      // 고정 피드
      setPinnedFeeds(results.pinnedFeeds);
      // 피드
      setFeeds(results.feeds);

      if (results.feeds.length < FEED_LIMIT) {
        setHasMore(false); // 새로운 피드의 갯수가 FEED_LIMIT보다 적으면 더 이상 가져올 데이터가 없음
      }
    }

    if (tagList.length == 0) {
      fetchRankingAndTags();
    }

    setLoading(false);
  };





			<FixedFeedList
            pinnedFeeds={pinnedFeeds}
            onCompleted={() => {
              resetFeeds();
            }}
          />

 

고정 게시글 목록에서 사용된 상세 게시글 코드 예시

  const [isPinned, setIsPinned] = useState(!!defaultValue?.pinnedTagKey); // 생성/수정 고정 상태


const openFeedDetails = async (feed: IFeedItem) => {
    setLoading(true);

    const result = await getFeedDetail(
      params.domain as string,
      feed.id
    );

    if (result.statusCode === 200) {
      if (result.feed) {
        const feedDetails = {
          ...result.feed,
          images: result.feed.images || { feed_image: [] },
          comments: result.feed.comments || [],
        };
        setSelectedFeed(feedDetails);
        setDialogOpen(true);
      }

      if (result.challenge) {
        // 챌린지 자동생성
        router.push(`/${params.domain}/classes/${result.challenge.id}`);
        return;
      }

      if (result.achievement) {
        // console.log(result);
        if (feed.userId) {
          router.push(
            `/${params.domain}/certificate/${result.achievement.id}`
          );
        }
        return;
      }
    }

    if (result.statusCode == 410) {
      toast({
        state: "warning",
        description: "회원가입하지 않은 사용자입니다",
      });
    }

    if (result.statusCode == 500) {
      toast({ state: "warning", description: result.message });
    }

    setLoading(false);
  };
  
                  <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>

 

커스텀 DropDownMenu에서 DB반영을 위해 API 예시

// 게시물 고정
export const pinFeed = async (
  domain: string,
  feedId: number,
  tagKey: string
) => {
  const pinInfo = {
    tagKey,
  };
  return await patchApi(`/clubs/${domain}/feeds/${feedId}/pin`, pinInfo);
};

// 게시물 고정 해제
export const unpinFeed = async (domain: string, feedId: number) => {
  return await patchApi(`/clubs/${domain}/feeds/${feedId}/unpin`, {});
};

 

커스텀 DropDownMenu 게시글 고정 코드 예시

import { pinFeed, unpinFeed } from "@/lib/api/community";

  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기능 예시

  const [isPinned, setIsPinned] = useState(!!defaultValue?.pinnedTagKey); // 생성/수정 고정 상태
  const [defaultImages, setDefaultImages] = useState<any>([]);

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




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

'인턴' 카테고리의 다른 글

푸터  (3) 2024.11.15
커뮤니티 게시글 관련 QA 및 리팩토링  (1) 2024.11.14
게시글 고정  (1) 2024.11.13
프로필 아바타 및 이미지 수정  (1) 2024.11.12
게시글 삭제, 상세 게시글 DropDownMenu 연결  (0) 2024.11.12