Skip to content

5. Fitur lain

Membuat Service untuk get previos chat BE

chat.dto.ts
export class PreviosMessageDto  {
  @IsInt()
  @Type(() => Number)
  conversation_id: number;


  @IsInt()
  @Type(() => Number)
  pageSize :  number;

  @IsInt()
  @IsOptional()
  limit : number
}
chat.controller.ts
@Post('previos-message')
  async previosMessage(@Body() payload: PreviosMessageDto) {
    return this.chat.getPreviosMessage(payload);
  }
chat.service.ts
async getPreviosMessage(
    payload: PreviosMessageDto,
  ): Promise<ResponsePreviosMessage> {
    const previosMessage = await this.messageRepository.find({
      relations: ['sender', 'receiver'],
      select: {
        sender: { id: true },
        receiver: { id: true },
      },
      where: {
        conversation_id: {
          id: payload.conversation_id,
        },
      },
      skip: payload.limit,
      take: payload.pageSize,
      order: {
        id: 'DESC',
      },
    });

    return this._prevMessage('OK', payload.conversation_id, previosMessage);
  }

alt text

Interasi FE

chat/interface/index.ts
export interface PreviosMessage {
  conversation_id : number,
  limit:number,
  pageSize:number
}
chat/lib/index.ts
import { useSession } from "next-auth/react";
import useAxiosAuth from "@/hook/useAxiosAuth";
import { useMutation, useQuery } from "@tanstack/react-query";
import { PreviosMessage } from "../interface";
import useCache from "../socket/useCache";

const useConversation = () => {
  const axiosAuthClient = useAxiosAuth();
  const { data: session } = useSession();
  const {handleAddPreMessage} = useCache()

...


  const usePreviosMessage = () => {
    const mutate = useMutation((payload: PreviosMessage) => {
      console.log('gpatkan tiket baru', payload)
      return axiosAuthClient.post("/chat/previos-message", payload);
    }, {
      onSuccess : (data)=> {
       console.log('previos', data)
      }
    });
    return mutate;
  };





  return { useGetList, useSendMessage, usePreviosMessage };
};

export default useConversation;

Merubah page.ts

chat/page.ts
"use client";
import { useEffect, useState } from "react";
import useConversation from "./lib";
import clsx from "clsx";
import { useSession } from "next-auth/react";
import useWebSocket from "@/app/admin/chat/socket/useWebSocket";
import useMessage from "@/app/admin/chat/socket/useMessage";
import InfiniteScroll from "react-infinite-scroll-component";
import { ChatMessage, UserChat, UserChatList } from "./interface";
import useEmitSocket from "./socket/useEmitSocket";
import useStoreChat from "@/store/useStoreChat";

export default function Chat() {
  const { data: session } = useSession();
  const { useGetList, useSendMessage, usePreviosMessage } = useConversation();
  ...
  const [selected, setSelected] = useState<UserChat>({
    totalMessages: 0,
    messages: [],
    limit :1,
    pageSize : 10,
    conversation_id : 0
  });

  ...

  const mutatePreviosMessage = usePreviosMessage();

 ...



  return (
    <>


          <div
            id="ticketLists"
            className="h-screen-160 text-white flex flex-col-reverse overflow-auto px-5"
          >
            <InfiniteScroll
              style={{ overflowX: "hidden", overflowY: "hidden" }}
              dataLength={chatList.length} //This is important field to render the next data
              next={ () => {
                mutatePreviosMessage.mutate({
                  conversation_id : selected?.conversation_id|| 0,
                  limit : chatList.length,
                  pageSize : 10
                });
              }}
              className="flex flex-col-reverse pb-40 space-y-5"
              hasMore={selected.totalMessages  > selected.messages?.length}


              loader={mutatePreviosMessage.isLoading ? <p>Loding</p> : null}
              endMessage={
                <p style={{ textAlign: "center" }}>
                  <b>Yay! You have seen it all</b>
                </p>
              }
              inverse={true}
              scrollableTarget="ticketLists"
            >
              {[...chatList].map((x: ChatMessage, i: number) => (
                <div
                  className={clsx(
                    "w-full flex mt-5", // Memastikan pesan menggunakan lebar penuh
                    {
                      "justify-end": x.sender.id === session?.user.id, // Pesan di sebelah kanan
                      "justify-start": x.sender.id !== session?.user.id, // Pesan di sebelah kiri
                    }
                  )}
                  key={i}
                >
                  <div
                    className={clsx(
                      "px-1 py-1 rounded max-w-[75%] break-words", // Membatasi lebar pesan max 75% dan membiarkan teks membungkus
                      {
                        "bg-[#015C4B]": x.sender.id === session?.user.id, // Warna untuk pesan user sendiri
                        "bg-[#1D282F]": x.sender.id !== session?.user.id, // Warna untuk pesan orang lain
                      }
                    )}
                  >
                    <span className="text-sm whitespace-pre-wrap">
                      {x.message}
                    </span>
                    <span className="text-[10px] text-right block">
                      {formatDate(x.created_at)}
                    </span>
                  </div>
                </div>
              ))}
            </InfiniteScroll>
          </div>

    </>
  );
}

alt text

ketikka kita scroll kita telah barhasil ...

Memperbahrui cache list message

chat/socket/useCache.ts
import { useQueryClient } from "@tanstack/react-query";
import { ChatMessage, Typing, UserChat, UserChatList } from "../interface";

const useCache = () => {
  const queryClient = useQueryClient();

  ...

  const handleAddPreMessage = async (data: any) => {
    await queryClient.cancelQueries(["/chat/list"]);

    console.log("data pre mess", data);

    // Ambil data sebelumnya dari cache
    const previousConversations = queryClient.getQueryData<UserChatList>([
      "/chat/list",
    ]);

    if (previousConversations) {
      // Temukan apakah conversation_id sudah ada
      const existingConversationIndex = previousConversations.data.findIndex(
        (convo: UserChat) => convo.conversation_id === data.conversation_id
      );

      if (existingConversationIndex !== -1) {
        // Update existing conversation
        const updatedConversations = previousConversations.data.map((convo) => {

          console.log('onvo.conversation_id', convo.conversation_id)
          if (convo.conversation_id === data.conversation_id) {
            // Tambahkan pesan baru ke array messages
            const latest = convo.messages || [];
            const updatedMessages = [...latest, ...data.data
            ];
            return {
              ...convo,
              messages: updatedMessages,

            };
          }
          return convo;
        });

        console.log("updatedConversations", updatedConversations);
        const sortedConversations = updatedConversations.sort((a, b) => {
          const latestMessageA = a.latestMessage?.created_at
            ? new Date(a.latestMessage.created_at)
            : new Date(0);
          const latestMessageB = b.latestMessage?.created_at
            ? new Date(b.latestMessage.created_at)
            : new Date(0);
          return latestMessageB.getTime() - latestMessageA.getTime(); // Urutkan dari yang terbaru
        });

        // Perbarui cache dengan data yang telah diperbarui
        queryClient.setQueryData(["/chat/list"], {
          ...previousConversations,
          data: sortedConversations,
        });
      }
    } else {
      // Jika tidak ada data sebelumnya, set data baru ke cache
      queryClient.setQueryData(["/chat/list"], {
        status: "Success",
        message: "OK",
        data: [
          {
            id: data.conversation_id.id,
            created_at: new Date().toISOString(),
            updated_at: new Date().toISOString(),
            user1: {}, // Sesuaikan dengan data yang ada
            user2: {}, // Sesuaikan dengan data yang ada
            messages: [data],
            latestMessage: data,
            conversation_id: data.conversation_id.id,
          },
        ],
      });
    }
  };

  return { handleNewMessage, handleAddPreMessage };
};

export default useCache;
chat/lib/index.ts
import { useSession } from "next-auth/react";
import useAxiosAuth from "@/hook/useAxiosAuth";
import { useMutation, useQuery } from "@tanstack/react-query";
import { PreviosMessage } from "../interface";
import useCache from "../socket/useCache";

const useConversation = () => {
 ...
  const {handleAddPreMessage} = useCache()


 ...


  const usePreviosMessage = () => {
    const mutate = useMutation((payload: PreviosMessage) => {
      console.log('gpatkan tiket baru', payload)
      return axiosAuthClient.post("/chat/previos-message", payload);
    }, {
      onSuccess : (data)=> {


        handleAddPreMessage(data.data)
      }
    });
    return mutate;
  };





  return { useGetList, useSendMessage, usePreviosMessage };
};

export default useConversation;