IKHSAN
EN Read in EnglishID

opendesk

Publik
Branch
main
Commit terakhir
08d9f3328 Oktober 2026

realtime.ts

Buka raw
import { useAuthStore } from "@/stores/auth";
import { globalStore } from "@/stores/globalStore";
import { reactive, ref, watch } from "vue";

const currentViewers = reactive<Record<string, string[]> | null>({});

export function useActiveViewers(ticketId: string) {
  const { $socket } = globalStore();

  const { userId } = useAuthStore();
  $socket.on("ticket_viewers", (data: { ticket_id: string; users: string }) => {
    if (data.ticket_id === ticketId) {
      const viewers = JSON.parse(data.users).filter(
        (u: string) => u !== userId
      );
      currentViewers[ticketId] = viewers;
    }
  });

  const handleBeforeUnload = (_ticketId: string) => {
    $socket.emit("stop_view_ticket", _ticketId);
  };
  const startViewing = (_ticketId: string) => {
    $socket.emit("view_ticket", _ticketId);
    window.addEventListener("beforeunload", () =>
      handleBeforeUnload(_ticketId)
    );
  };

  const stopViewing = (_ticketId: string) => {
    $socket.emit("stop_view_ticket", _ticketId);

    window.removeEventListener("beforeunload", () =>
      handleBeforeUnload(_ticketId)
    );
  };

  return {
    currentViewers,
    startViewing,
    stopViewing,
  };
}

export function useNotifyTicketUpdate(ticketId: string) {
  const { $socket } = globalStore();
  const notifyTicketUpdate = (field: string, value: string) => {
    $socket.emit("notify_ticket_update", ticketId, field, value);
  };
  // how to check if $socket is already listening to avoid multiple listeners
  return { notifyTicketUpdate };
}

export function useTyping(ticketId: string) {
  const { $socket } = globalStore();
  const { userId } = useAuthStore();

  const typingCounter = ref(0);
  const isTyping = ref(false);
  const typingUsers = reactive<string[]>([]);
  let timeout: any = null;

  // Listen for typing events from other users
  const onTyping = (data: { ticket_id: string; user: string }) => {
    if (data.ticket_id === ticketId && data.user !== userId) {
      // Add user to typing list if not already present
      if (!typingUsers.includes(data.user)) {
        typingUsers.push(data.user);
      }
    }
  };
  $socket.on("opendesk_ticket_typing", onTyping);

  // Listen for typing stopped events
  const onTypingStopped = (data: { ticket_id: string; user: string }) => {
    if (data.ticket_id === ticketId) {
      // Remove user from typing list
      const index = typingUsers.indexOf(data.user);
      if (index > -1) {
        typingUsers.splice(index, 1);
      }
    }
  };
  $socket.on("opendesk_ticket_typing_stopped", onTypingStopped);

  const emitStartTyping = () => {
    $socket?.emit("opendesk_ticket_typing", ticketId);
  };

  const emitStopTyping = () => {
    $socket?.emit("opendesk_ticket_typing_stopped", ticketId);
  };

  const onUserType = () => {
    if (!isTyping.value) {
      isTyping.value = true;
      typingCounter.value = typingCounter.value + 1;
      emitStartTyping();
    }
  };

  // Reset the typing state after 10 seconds of inactivity
  // If agent is not typing for 10 seconds, we assume they have stopped typing
  watch(typingCounter, (newVal) => {
    if (timeout) {
      clearTimeout(timeout);
    }

    if (newVal > 0) {
      timeout = setTimeout(() => {
        isTyping.value = false;
        typingCounter.value = 0;
        emitStopTyping();
      }, 10000);
    }
  });

  const stopTyping = () => {
    emitStopTyping();
    isTyping.value = false;
    typingCounter.value = 0;
    if (timeout) {
      clearTimeout(timeout);
    }
  };

  const cleanup = () => {
    stopTyping();
    if (timeout) {
      clearTimeout(timeout);
    }
    // Remove socket listeners
    $socket.off("opendesk_ticket_typing", onTyping);
    $socket.off("opendesk_ticket_typing_stopped", onTypingStopped);
  };

  return {
    stopTyping,
    onUserType,
    typingUsers,
    cleanup,
  };
}
byte
3.850
baris
144
Jenis
ts
Commit terakhir
28 Oktober 2026