IKHSAN
ENID Baca dalam Bahasa Indonesia

opendesk

Public
Branch
main
Latest commit
08d9f3328 October 2026

useActiveTabManager.ts

Open raw
import { useTelephonyStore } from "@/stores/telephony";
import { storeToRefs } from "pinia";
import { ref, watch } from "vue";
import { useRoute, useRouter } from "vue-router";

/**
 * Keeps the selected tab in sync with the URL hash. frappe-ui v1 Tabs are
 * keyed by `tab.value`, so this tracks the value rather than an index; the
 * first tab is the default and carries no hash.
 */
export function useActiveTabManager(tabs) {
  const route = useRoute();
  const router = useRouter();
  const telephonyStore = useTelephonyStore();
  const { isLoading: isTelephonyLoading } = storeToRefs(telephonyStore);

  const activeTab = ref("");

  const firstTab = () => tabs.value?.[0]?.value;

  const changeTabTo = (tab) => {
    activeTab.value = tab;
    if (tab === firstTab()) {
      router.replace({ path: route.path, query: route.query });
    } else {
      setActiveTabInUrl(tab);
    }
  };

  function setActiveTabInUrl(tab) {
    const hash = "#" + tab?.toLowerCase();
    if (route.hash === hash) return;
    router.push({ hash, query: route.query });
  }

  function findTab(hash) {
    return tabs.value?.find((tab) => tab.value.toLowerCase() === hash)?.value;
  }

  const setActiveTab = () => {
    const fromHash = findTab(route.hash.replace("#", ""));
    if (fromHash) {
      activeTab.value = fromHash;
      setActiveTabInUrl(fromHash);
      return;
    }

    activeTab.value = firstTab();
    router.replace({ path: route.path, query: route.query });
  };

  // Handle when page is navigated
  watch(
    () => route.hash,
    (newHash) => {
      const tab = findTab(newHash.replace("#", "")) ?? firstTab();

      if (tab === firstTab()) {
        router.replace({ path: route.path, query: route.query });
      }

      activeTab.value = tab;
    }
  );

  // Handle when tabs array is updated. `immediate` also applies the URL hash
  // when the panel remounts on soft navigation between tickets.
  watch(
    [tabs, isTelephonyLoading],
    ([tabsValue, isLoading]) => {
      if (!tabsValue?.length) return;
      if (!isLoading) {
        setActiveTab();
      }
    },
    { deep: true, flush: "post", immediate: true }
  );

  return { activeTab, changeTabTo };
}
bytes
2,194
lines
81
Type
ts
Latest commit
28 October 2026