PluginProbe
Extendify / 3.2.1
Extendify v3.2.1
3.2.1 3.2.0 3.1.6 3.1.5 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.6 3.0.5 3.0.4 trunk 0.1.0 0.10.0 0.10.1 0.10.2 0.11.0 0.11.1 0.2.0 0.3.0 0.3.1 0.4.0 0.5.0 0.6.0 All 127 releases
extendify / src / Assist / hooks / useRouter.js

useRouter.js in Extendify 3.2.1, at src/Assist/hooks/useRouter.js

146 lines 3.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { Dashboard } from '@assist/pages/Dashboard';
2 import { homeIcon } from '@assist/svg';
3 import { safeParseJson } from '@shared/lib/parsing';
4 import { useActivityStore } from '@shared/state/activity';
5 import apiFetch from '@wordpress/api-fetch';
6 import { useCallback, useEffect, useLayoutEffect } from '@wordpress/element';
7 import { __ } from '@wordpress/i18n';
8 import { create } from 'zustand';
9 import { createJSONStorage, devtools, persist } from 'zustand/middleware';
10
11 const pages = [
12 {
13 slug: 'dashboard',
14 name: __('Dashboard', 'extendify-local'),
15 icon: homeIcon,
16 component: Dashboard,
17 },
18 ];
19
20 let onChangeEvents = [];
21 const state = (set, get) => ({
22 history: [],
23 viewedPages: [],
24 current: null,
25 // initialize the state with default values
26 ...(safeParseJson(window.extAssistData.userData.routerData)?.state ?? {}),
27 setCurrent: async (page) => {
28 if (!page) return;
29 for (const event of onChangeEvents) {
30 await event(page, { ...get() });
31 }
32 // If history is the same, dont add (they pressed the same nav button)
33 if (get().history[0]?.slug === page.slug) return;
34 useActivityStore.getState().incrementActivity(`assist-${page.slug}`);
35 set((state) => {
36 const lastViewedAt = new Date().toISOString();
37 const firstViewedAt = lastViewedAt;
38 const visited = state.viewedPages.find((a) => a.slug === page.slug);
39 return {
40 history: [page, ...state.history].filter(Boolean),
41 current: page,
42 viewedPages: [
43 // Remove the page if it's already in the list
44 ...state.viewedPages.filter((a) => a.slug !== page.slug),
45 // Either add the page or update the count
46 visited
47 ? { ...visited, count: visited.count + 1, lastViewedAt }
48 : {
49 slug: page.slug,
50 firstViewedAt,
51 lastViewedAt,
52 count: 1,
53 },
54 ],
55 };
56 });
57 },
58 });
59
60 const path = '/extendify/v1/assist/router-data';
61 const storage = {
62 getItem: async () => await apiFetch({ path }),
63 setItem: async (_name, state) =>
64 await apiFetch({ path, method: 'POST', data: { state } }),
65 };
66
67 const useRouterState = create(
68 persist(devtools(state, { name: 'Extendify Assist Router' }), {
69 name: 'extendify-assist-router',
70 storage: createJSONStorage(() => storage),
71 skipHydration: true,
72 partialize: ({ viewedPages }) => ({ viewedPages }),
73 }),
74 );
75 export const router = {
76 onRouteChange: (event) => {
77 // dont add if duplicate
78 if (onChangeEvents.includes(event)) return;
79 onChangeEvents = [...onChangeEvents, event];
80 },
81 removeOnRouteChange: (event) => {
82 onChangeEvents = onChangeEvents.filter((e) => e !== event);
83 },
84 };
85
86 let once = false;
87 export const useRouter = () => {
88 const { current, setCurrent, history } = useRouterState();
89 const Component = current?.component ?? (() => null);
90
91 const navigateTo = (slug) => {
92 if (window.location.hash === `#${slug}`) {
93 // Fire the event only
94 window.dispatchEvent(new Event('hashchange'));
95 return;
96 }
97 window.location.hash = `#${slug}`;
98 };
99 useLayoutEffect(() => {
100 // if no hash is present use previous or add #dashboard
101 if (!window.location.hash) {
102 window.location.hash = `#${current?.slug ?? 'dashboard'}`;
103 }
104 }, [current]);
105
106 useEffect(() => {
107 if (once) return;
108 once = true;
109 // watch url changes for #dashboard, etc
110 const handle = () => {
111 const hash = window.location.hash.replace('#', '');
112 const page = pages.find((page) => page.slug === hash);
113 if (!page) {
114 navigateTo(current?.slug ?? 'dashboard');
115 return;
116 }
117 setCurrent(page);
118 // Update title to match the page
119 document.title = page.name;
120 };
121 window.addEventListener('hashchange', handle);
122 if (!current) handle();
123 return () => {
124 once = false;
125 window.removeEventListener('hashchange', handle);
126 };
127 }, [current, setCurrent]);
128
129 return {
130 current,
131 CurrentPage: useCallback(
132 () => (
133 <section aria-live="polite">
134 {/* Announce to SR on change */}
135 <h1 className="sr-only">{current?.name}</h1>
136 <Component />
137 </section>
138 ),
139 [current],
140 ),
141 pages,
142 navigateTo,
143 history,
144 };
145 };
146