inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

[인프런 워밍업 스터디 클럽 3기 풀스택] 4주차 발자국

jomootgrn88
0

강의수강

supabase Auth

supabase RLS

 

미션

채팅 메시지 삭제

/actions/chat-actions.ts

export async function deleteMessage({ message }) {
  const supabase = await createServerSupabaseClient();

  const {
    data: { session },
    error,
  } = await supabase.auth.getSession();

  if (error || !session.user) {
    throw new Error("User is not authenticated");
  }

  const { error: updateError } = await supabase
    .from("message")
    .update({
      ...message,
      is_deleted: true,
    })
    .eq("id", message.id);

  if (updateError) {
    throw new Error("Message error");
  }
}

export async function getMessage(id: string) {
  if (!id) {
    return null;
  }
  const supabase = await createServerSupabaseClient();

  const { data, error } = await supabase
    .from("message")
    .select("*")
    .eq("id", Number(id))
    .maybeSingle();

  if (error) {
    return null;
  }

  return data;
}

deleteMessage: 메시지 객체를 받아 is_deleted 컬럼의 값을 true 변경

getMessage: 모달 창에서 이용할 action message의 id를 받아 해당 id로 message 테이블을 쿼리해 메시지를 반환

 

/components/chat/chat-delete-button.tsx

"use client";

import { useMutation, useQueryClient } from "@tanstack/react-query";
import { deleteMessage } from "actions/chat-actions";
import { useRouter } from "next/navigation";
import { useRecoilValue } from "recoil";
import { selectedUserIdState } from "utils/recoil/atoms";

export default function ChatDeleteButton({ message }) {
  const queryClient = useQueryClient();

  const selectedUserId = useRecoilValue(selectedUserIdState);

  const deleteMessageMutaition = useMutation({
    mutationFn: () => deleteMessage({ message }),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["messages", selectedUserId] });
    },
  });

  const router = useRouter();

  return (
    <div className="flex flex-col gap-1 font-bold bg-white border-2 px-6 pt-8 py-4 rounded-md">
      <p>
        message : <span className="underline">{message.message}</span>
      </p>
      <p>Are you sure you want to delete this message?</p>
      <div className="flex gap-2 justify-center py-4">
        <button
          onClick={() => {
            deleteMessageMutaition.mutate();
            router.back();
          }}
          className="w-14 py-1 px-2 bg-red-100 rounded-md border-2"
        >
          yes
        </button>
        <button
          onClick={() => router.back()}
          className="w-14 py-1 px-2 bg-blue-100 rounded-md border-2"
        >
          no
        </button>
      </div>
    </div>
  );
}

모달 창에서 렌더링할 컴포넌트 yes 버튼은 deleteMessageMutation.mutate()를 호출해 deleteMessage action을 호출한다. yes, no 버튼 마지막에 router.back()을 호출해 모달창을 종료한다.

/components/chat/chat-screen.tsx

  useEffect(() => {
    const channel = supabase
      .channel("message_postgres_changes")
      .on(
        "postgres_changes",
        { event: "INSERT", schema: "public", table: "message" },
        (payload) => {
          if (
            payload.eventType === "INSERT" &&
            !payload.errors &&
            !!payload.new
          ) {
            getAllMessagesQuery.refetch();
          }
        }
      )
      .on(
        "postgres_changes",
        { event: "UPDATE", schema: "public", table: "message" },
        (payload) => {
          if (payload.eventType === "UPDATE" && !payload.errors) {
            getAllMessagesQuery.refetch();
          }
        }
      )
      .subscribe();

    return () => {
      channel.unsubscribe();
    };
  }, []);

chat-screen.tsx 컴포넌트에 supabase.channel 구독에서 { event: 'UPDATE' }를 추가함으로 message 테이블에 변경사항이 있으면 모든 메시지를 리패치하도록 함

 

 

답변 0