1import { useTelephonyStore } from "@/stores/telephony";
2import { storeToRefs } from "pinia";
3import { ref, watch } from "vue";
4import { useRoute, useRouter } from "vue-router";
5
6/**
7 * Keeps the selected tab in sync with the URL hash. frappe-ui v1 Tabs are
8 * keyed by `tab.value`, so this tracks the value rather than an index; the
9 * first tab is the default and carries no hash.
10 */
11export function useActiveTabManager(tabs) {
12 const route = useRoute();
13 const router = useRouter();
14 const telephonyStore = useTelephonyStore();
15 const { isLoading: isTelephonyLoading } = storeToRefs(telephonyStore);
16
17 const activeTab = ref("");
18
19 const firstTab = () => tabs.value?.[0]?.value;
20
21 const changeTabTo = (tab) => {
22 activeTab.value = tab;
23 if (tab === firstTab()) {
24 router.replace({ path: route.path, query: route.query });
25 } else {
26 setActiveTabInUrl(tab);
27 }
28 };
29
30 function setActiveTabInUrl(tab) {
31 const hash = "#" + tab?.toLowerCase();
32 if (route.hash === hash) return;
33 router.push({ hash, query: route.query });
34 }
35
36 function findTab(hash) {
37 return tabs.value?.find((tab) => tab.value.toLowerCase() === hash)?.value;
38 }
39
40 const setActiveTab = () => {
41 const fromHash = findTab(route.hash.replace("#", ""));
42 if (fromHash) {
43 activeTab.value = fromHash;
44 setActiveTabInUrl(fromHash);
45 return;
46 }
47
48 activeTab.value = firstTab();
49 router.replace({ path: route.path, query: route.query });
50 };
51
52 // Handle when page is navigated
53 watch(
54 () => route.hash,
55 (newHash) => {
56 const tab = findTab(newHash.replace("#", "")) ?? firstTab();
57
58 if (tab === firstTab()) {
59 router.replace({ path: route.path, query: route.query });
60 }
61
62 activeTab.value = tab;
63 }
64 );
65
66 // Handle when tabs array is updated. `immediate` also applies the URL hash
67 // when the panel remounts on soft navigation between tickets.
68 watch(
69 [tabs, isTelephonyLoading],
70 ([tabsValue, isLoading]) => {
71 if (!tabsValue?.length) return;
72 if (!isLoading) {
73 setActiveTab();
74 }
75 },
76 { deep: true, flush: "post", immediate: true }
77 );
78
79 return { activeTab, changeTabTo };
80}
81