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

게시글 고정 본문

인턴

게시글 고정

juni_shin 2024. 11. 13. 21:26

이전 게시글 관련글과 연계

 

모달

 

페이지

 

커스텀 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>