PluginProbe
Extendify / 1.17.1
Extendify v1.17.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 0.7.0 All 126 releases
extendify / src / Launch / components / PageControl.jsx

PageControl.jsx in Extendify 1.17.1, at src/Launch/components/PageControl.jsx

211 lines 5.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import { useEffect, useLayoutEffect, useState } from '@wordpress/element';
2 import { __, isRTL } from '@wordpress/i18n';
3 import { NavigationButton } from '@launch/components/NavigationButton';
4 import {
5 PagesSelect,
6 state as pagesSelectState,
7 } from '@launch/pages/PagesSelect';
8 import { useGlobalStore } from '@launch/state/Global';
9 import { usePagesStore } from '@launch/state/Pages';
10 import { useUserSelectionStore } from '@launch/state/user-selections';
11 import { RightCaret, LeftCaret } from '@launch/svg';
12
13 const PagesPageData = {
14 component: PagesSelect,
15 state: pagesSelectState,
16 };
17
18 export const PageControl = () => {
19 const {
20 currentPageIndex,
21 addPage,
22 removePage,
23 pages,
24 getPageState,
25 previousPage,
26 replaceHistory,
27 } = usePagesStore();
28 const { siteStructure } = useUserSelectionStore();
29
30 useLayoutEffect(() => {
31 // If we later add more structures, consider having predefined paths
32 if (siteStructure === 'multi-page') {
33 addPage('page-select', PagesPageData, 'layout');
34 return;
35 }
36 removePage('page-select');
37 }, [siteStructure, addPage, removePage]);
38
39 useEffect(() => {
40 const replaceStateHistory = () => {
41 history.state === null && replaceHistory(currentPageIndex);
42 };
43 window.addEventListener('load', replaceStateHistory);
44
45 const popstate = () => {
46 const page = currentPageIndex - 1;
47 if (page === -1) history.go(-1);
48 previousPage();
49 };
50 window.addEventListener('popstate', popstate);
51 return () => {
52 window.removeEventListener('popstate', popstate);
53 };
54 }, [previousPage, currentPageIndex, replaceHistory]);
55
56 const pagesList = Array.from(pages.entries());
57 // Some pages act as a notice or loading message and move on their own
58 if (!getPageState(pagesList[currentPageIndex][0])?.useNav) return null;
59
60 return (
61 <div className="z-10 w-full flex-none border-t border-gray-100 bg-white px-6 py-5 shadow-surface md:px-12 md:py-6">
62 <div className="flex justify-between">
63 <span className="flex-1 self-start">
64 <PrevButton />
65 </span>
66 <span className="hidden grow items-center justify-center md:flex">
67 <Steps />
68 </span>
69 <span className="flex flex-1 justify-end">
70 <NextButton />
71 </span>
72 </div>
73 </div>
74 );
75 };
76
77 const Steps = () => {
78 const { currentPageIndex, pages, getPageState } = usePagesStore();
79 const totalPages = usePagesStore((state) => state.count());
80 const pagesList = Array.from(pages.entries());
81
82 return (
83 <div
84 className="flex"
85 role="progressbar"
86 aria-valuenow={currentPageIndex}
87 aria-valuemin="0"
88 aria-valuetext={pagesList[currentPageIndex][1].state.getState().title}
89 aria-valuemax={totalPages - 1}>
90 {pagesList.map(([page], index) => {
91 const bgColor =
92 index < currentPageIndex ? 'bg-design-main' : 'bg-gray-200';
93 if (!getPageState(page)?.useNav) return null;
94 return (
95 <div key={page} className="flex items-center">
96 {(index !== currentPageIndex && (
97 <div className={`${bgColor} h-2.5 w-2.5 rounded-full`} />
98 )) || (
99 <div className="flex h-4 w-4 items-center justify-center rounded-full bg-design-main">
100 <div className="h-1.5 w-1.5 rounded-full bg-white/80" />
101 </div>
102 )}
103 {index < totalPages - 1 && (
104 <div className={`${bgColor} h-0.5 w-16`} />
105 )}
106 </div>
107 );
108 })}
109 </div>
110 );
111 };
112
113 const PrevButton = () => {
114 const { previousPage, currentPageIndex } = usePagesStore();
115 const onFirstPage = currentPageIndex === 0;
116
117 if (onFirstPage) {
118 return (
119 <NavigationButton
120 onClick={() =>
121 (window.location.href = `${window.extSharedData.adminUrl}admin.php?page=extendify-assist`)
122 }
123 className="border-gray-200 bg-white text-design-main hover:bg-gray-50 focus:bg-gray-50">
124 <>
125 {isRTL() ? (
126 <RightCaret className="mt-px h-5 w-5" />
127 ) : (
128 <LeftCaret className="mt-px h-5 w-5" />
129 )}
130 <span>{__('Exit Launch', 'extendify-local')}</span>
131 </>
132 </NavigationButton>
133 );
134 }
135
136 return (
137 <NavigationButton
138 onClick={previousPage}
139 data-test="back-button"
140 className="border-gray-200 bg-white text-design-main hover:bg-gray-50 focus:bg-gray-50">
141 <>
142 {isRTL() ? (
143 <RightCaret className="mt-px h-5 w-5" />
144 ) : (
145 <LeftCaret className="mt-px h-5 w-5" />
146 )}
147 <span>{__('Back', 'extendify-local')}</span>
148 </>
149 </NavigationButton>
150 );
151 };
152
153 const NextButton = () => {
154 const { nextPage, currentPageIndex, pages } = usePagesStore();
155 const totalPages = usePagesStore((state) => state.count());
156 const onLastPage = currentPageIndex === totalPages - 1;
157 const currentPageKey = Array.from(pages.keys())[currentPageIndex];
158 const pageState = pages.get(currentPageKey).state;
159 const [canProgress, setCanProgress] = useState(false);
160 const [canSkip, setCanSkip] = useState(false);
161
162 const nextPageOrComplete = () => {
163 if (onLastPage) {
164 useGlobalStore.setState({ generating: true });
165 } else {
166 nextPage();
167 }
168 };
169
170 useEffect(() => {
171 const { ready, canSkip } = pageState?.getState() || {};
172 setCanSkip(canSkip ?? false);
173 setCanProgress(ready ?? false);
174 return pageState.subscribe((s) => {
175 setCanSkip(s.canSkip);
176 setCanProgress(s.ready);
177 });
178 }, [pageState, currentPageIndex]);
179
180 return canSkip ? (
181 <NavigationButton
182 onClick={() => nextPageOrComplete()}
183 data-test="back-button"
184 className="mr-2 border-gray-200 bg-white text-design-main hover:bg-gray-50 focus:bg-gray-50">
185 <>
186 {__('Skip', 'extendify-local')}
187 {isRTL() ? (
188 <LeftCaret className="mt-px h-5 w-5" />
189 ) : (
190 <RightCaret className="mt-px h-5 w-5" />
191 )}
192 </>
193 </NavigationButton>
194 ) : (
195 <NavigationButton
196 onClick={nextPageOrComplete}
197 disabled={!canProgress}
198 className="border-design-main bg-design-main text-design-text"
199 data-test="next-button">
200 <>
201 {__('Next', 'extendify-local')}
202 {isRTL() ? (
203 <LeftCaret className="mt-px h-5 w-5" />
204 ) : (
205 <RightCaret className="mt-px h-5 w-5" />
206 )}
207 </>
208 </NavigationButton>
209 );
210 };
211