Skip to content

Commit b8155a4

Browse files
Reorder pages (#189)
* reorder links wip * new linux menu * new style of download on client config page * fix step final style * correct step counter config * Update ConfigureClientPage.tsx
1 parent 364ee35 commit b8155a4

File tree

43 files changed

+1434
-233
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1434
-233
lines changed

webnext/messages/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@
2222
"cmp_openid_button": "Sign in with {provider}",
2323
"cmp_copy_field_tooltip": "Copied",
2424
"footer_contact": "If you need assistance, please contact your defguard administrator at.",
25+
"session_end_title": "Session expired.",
26+
"session_end_subtitle": "Please start the process again.",
27+
"session_end_link": "Back to main page",
2528
"start_footer_copyright": "Copyright ©2023-{currentYear} Defguard Sp. z o.o.",
2629
"start_multi_title": "Get Started with Defguard",
2730
"start_multi_subtitle": "Please select the option that suits your needs.",
@@ -70,6 +73,7 @@
7073
"client_download_modal_content": "Please make sure to download at least one client, as you'll need it in the next step to configure your VPN device.",
7174
"client_download_modal_cancel": "Back to download",
7275
"client_download_apple_help_header": "Apple Hardware",
76+
"client_download_mobile_warning": "Enrollment process (setting up device, setting up account password and Multi-Factor) is only supported now on desktop client. You can configure your mobile client later in Defguard - after connecting to vpn from desktop client and accessing defguard-url.com",
7377
"enrollment_start_title": "Select activation type",
7478
"enrollment_start_subtitle": "Select the configuration type based on your organization's approach.",
7579
"enrollment_start_external_title": "Sign in with External SSO",
@@ -78,6 +82,7 @@
7882
"enrollment_start_internal_subtitle": "Select this option if your administrator has sent you an email or message with your personal token. If you haven't received your token, please contact your administrator.",
7983
"client_setup_title": "Configure your defguard client/app",
8084
"client_setup_subtitle": "Select the activation method according to your device type.",
85+
"client_setup_download_label": "Get the desktop client",
8186
"client_setup_desktop_title": "Desktop client",
8287
"client_setup_desktop_auto_title": "Automatic configuration",
8388
"client_setup_desktop_auto_explain_1": "Click the button below for automatic configuration.",

webnext/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,14 @@
2626
"axios": "^1.12.2",
2727
"change-case": "^5.4.4",
2828
"clsx": "^2.1.1",
29+
"dayjs": "^1.11.18",
2930
"lodash-es": "^4.17.21",
3031
"motion": "^12.23.21",
3132
"qrcode.react": "^4.2.0",
3233
"qs": "^6.14.0",
3334
"react": "^19.1.1",
3435
"react-dom": "^19.1.1",
36+
"react-markdown": "^10.1.0",
3537
"rxjs": "^7.8.2",
3638
"zod": "^4.1.11",
3739
"zustand": "^5.0.8"

webnext/pnpm-lock.yaml

Lines changed: 681 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

webnext/src/app/App.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { QueryClientProvider } from '@tanstack/react-query';
22
import { RouterProvider } from '@tanstack/react-router';
3+
import dayjs from 'dayjs';
4+
import utc from 'dayjs/plugin/utc';
35
import { queryClient } from './query';
46
import { router } from './router';
57

8+
dayjs.extend(utc);
9+
610
export const App = () => {
711
return (
812
<QueryClientProvider client={queryClient}>

webnext/src/app/SessionGuard.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { useNavigate } from '@tanstack/react-router';
2+
import dayjs from 'dayjs';
3+
import { useCallback, useEffect } from 'react';
4+
import { useEnrollmentStore } from '../shared/hooks/useEnrollmentStore';
5+
6+
export const SessionGuard = () => {
7+
const navigate = useNavigate();
8+
const sessionEnd = useEnrollmentStore((s) => s.enrollmentData?.deadline_timestamp);
9+
10+
const handleSessionEnd = useCallback(() => {
11+
navigate({
12+
to: '/session-end',
13+
replace: true,
14+
});
15+
}, [navigate]);
16+
17+
useEffect(() => {
18+
if (!sessionEnd) return;
19+
20+
const deadline = dayjs.unix(sessionEnd).diff(dayjs());
21+
if (deadline > 0) {
22+
const timeout = setTimeout(handleSessionEnd, deadline);
23+
return () => {
24+
clearTimeout(timeout);
25+
};
26+
} else {
27+
handleSessionEnd();
28+
}
29+
}, [sessionEnd, handleSessionEnd]);
30+
31+
return null;
32+
};

webnext/src/pages/ClientDownload/ClientDownloadPage.tsx

Lines changed: 85 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import './style.scss';
22
import { useQuery } from '@tanstack/react-query';
3-
import { type RouterState, useNavigate, useRouterState } from '@tanstack/react-router';
3+
import {
4+
type RouterState,
5+
useLoaderData,
6+
useNavigate,
7+
useRouterState,
8+
} from '@tanstack/react-router';
49
import { useMemo, useState } from 'react';
510
import { m } from '../../paraglide/messages';
611
import { AppleHelpModal } from '../../shared/components/AppleHelpModal/AppleHelpModal';
@@ -12,6 +17,7 @@ import { Button } from '../../shared/defguard-ui/components/Button/Button';
1217
import { ButtonMenu } from '../../shared/defguard-ui/components/ButtonMenu/MenuButton';
1318
import { Icon } from '../../shared/defguard-ui/components/Icon';
1419
import type { IconKindValue } from '../../shared/defguard-ui/components/Icon/icon-types';
20+
import { InfoBanner } from '../../shared/defguard-ui/components/InfoBanner/InfoBanner';
1521
import type { MenuItemsGroup } from '../../shared/defguard-ui/components/Menu/types';
1622
import { Modal } from '../../shared/defguard-ui/components/Modal/Modal';
1723
import { ModalControls } from '../../shared/defguard-ui/components/ModalControls/ModalControls';
@@ -23,10 +29,14 @@ import { openVirtualLink } from '../../shared/utils/openVirtualLink';
2329
import androidIcon from './assets/android.png';
2430
import iosIcon from './assets/ios.png';
2531
import laptopIcon from './assets/laptop.png';
32+
import linuxIcon from './assets/linux.png';
2633
import desktopIcon from './assets/pc-tower.png';
2734

2835
export const ClientDownloadPage = () => {
2936
const { data: pageData } = useQuery(getClientArtifactsQueryOptions);
37+
const { enrollmentState } = useLoaderData({
38+
from: '/download',
39+
});
3040
const routerLoading = useRouterState({ select: (s: RouterState) => s.isLoading });
3141

3242
const navigate = useNavigate();
@@ -58,44 +68,71 @@ export const ClientDownloadPage = () => {
5868
[pageData],
5969
);
6070

61-
const linuxMenu: MenuItemsGroup[] = useMemo(
62-
() => [
71+
const linuxMenu: MenuItemsGroup[] = useMemo(() => {
72+
const res: MenuItemsGroup[] = [
6373
{
6474
items: [
6575
{
66-
text: 'Deb X86',
76+
icon: 'ubuntu',
77+
text: 'Ubuntu 24.04 ARM',
78+
onClick: () => openVirtualLink(pageData?.deb_arm64),
79+
},
80+
{
81+
icon: 'ubuntu',
82+
text: 'Ubuntu 24.04 AMD64',
6783
onClick: () => openVirtualLink(pageData?.deb_amd64),
6884
},
85+
],
86+
},
87+
{
88+
items: [
6989
{
70-
text: 'Deb ARM',
90+
icon: 'debian',
91+
text: 'Ubuntu 22.04 / Debian 12&13 ARM',
7192
onClick: () => openVirtualLink(pageData?.deb_arm64),
7293
},
7394
{
74-
text: 'RPM X86',
75-
onClick: () => openVirtualLink(pageData?.rpm_amd64),
95+
icon: 'debian',
96+
text: 'Ubuntu 22.04 / Debian 12&13 AMD64',
97+
onClick: () => openVirtualLink(pageData?.deb_amd64),
7698
},
99+
],
100+
},
101+
{
102+
items: [
77103
{
104+
icon: 'linux',
78105
text: 'RPM ARM',
79106
onClick: () => openVirtualLink(pageData?.rpm_arm64),
80107
},
81108
{
109+
icon: 'linux',
110+
text: 'RPM AMD64',
111+
onClick: () => openVirtualLink(pageData?.rpm_amd64),
112+
},
113+
],
114+
},
115+
{
116+
items: [
117+
{
118+
icon: 'arch-linux',
82119
text: 'Arch Linux',
83120
onClick: () => openVirtualLink(externalLink.client.desktop.linux.arch),
84121
},
85122
],
86123
},
87-
],
88-
[pageData],
89-
);
124+
];
125+
return res;
126+
}, [pageData]);
90127

91128
return (
92129
<Page id="client-download-page" nav>
93-
<EnrollmentStep current={0} max={2} />
130+
<EnrollmentStep current={1} max={2} />
94131
<header>
95132
<h1>{m.client_download_title()}</h1>
96133
<p>{m.client_download_subtitle()}</p>
97134
</header>
98-
<SizedBox height={ThemeSpacing.Xl4} />
135+
<SizedBox height={ThemeSpacing.Xl3} />
99136
<div className="platforms">
100137
<div className="label">
101138
<Icon icon="desktop" size={20} /> <p>{m.client_download_label_desktop()}</p>
@@ -121,7 +158,7 @@ export const ClientDownloadPage = () => {
121158
buttonText={m.client_download_for({ platform: 'Linux' })}
122159
buttonIconKind="linux"
123160
menuItems={linuxMenu}
124-
icon={desktopIcon}
161+
icon={linuxIcon}
125162
/>
126163
<Platform
127164
testId="macos"
@@ -136,33 +173,42 @@ export const ClientDownloadPage = () => {
136173
/>
137174
</div>
138175
<SizedBox height={ThemeSpacing.Xl3} />
139-
<div className="platforms">
140-
<div className="label">
141-
<Icon icon="mobile" size={20} /> <p>{m.client_download_label_mobile()}</p>
176+
{enrollmentState.enrollmentData.user.enrolled && (
177+
<div className="platforms">
178+
<div className="label">
179+
<Icon icon="mobile" size={20} /> <p>{m.client_download_label_mobile()}</p>
180+
</div>
181+
<Platform
182+
testId="android"
183+
title={m.client_download_for({ platform: 'Android' })}
184+
subtitle={m.client_download_supports_newer({
185+
platform: 'Android 12.0 (Snow Cone)',
186+
})}
187+
buttonText={m.client_download_for({ platform: 'Android' })}
188+
buttonIconKind="android"
189+
directLink={externalLink.client.mobile.google}
190+
icon={androidIcon}
191+
/>
192+
<Platform
193+
testId="iOS"
194+
title={m.client_download_for({ platform: 'iOS' })}
195+
subtitle={m.client_download_supports_newer({
196+
platform: 'iOS 15+',
197+
})}
198+
buttonText={m.client_download_for({ platform: 'iOS' })}
199+
buttonIconKind="apple"
200+
directLink={externalLink.client.mobile.apple}
201+
icon={iosIcon}
202+
/>
142203
</div>
143-
<Platform
144-
testId="android"
145-
title={m.client_download_for({ platform: 'Android' })}
146-
subtitle={m.client_download_supports_newer({
147-
platform: 'Android 12.0 (Snow Cone)',
148-
})}
149-
buttonText={m.client_download_for({ platform: 'Android' })}
150-
buttonIconKind="android"
151-
directLink={externalLink.client.mobile.google}
152-
icon={androidIcon}
153-
/>
154-
<Platform
155-
testId="iOS"
156-
title={m.client_download_for({ platform: 'iOS' })}
157-
subtitle={m.client_download_supports_newer({
158-
platform: 'iOS 15+',
159-
})}
160-
buttonText={m.client_download_for({ platform: 'iOS' })}
161-
buttonIconKind="apple"
162-
directLink={externalLink.client.mobile.apple}
163-
icon={iosIcon}
204+
)}
205+
{!enrollmentState.enrollmentData.user.enrolled && (
206+
<InfoBanner
207+
variant="warning"
208+
icon="warning"
209+
text={m.client_download_mobile_warning()}
164210
/>
165-
</div>
211+
)}
166212
<AppleHelpModal
167213
isOpen={appleHelpModalOpen}
168214
onClose={() => {
@@ -194,21 +240,14 @@ export const ClientDownloadPage = () => {
194240
loading: routerLoading,
195241
onClick: () => {
196242
navigate({
197-
to: '/enrollment-start',
243+
to: '/client-setup',
198244
replace: true,
199245
});
200246
},
201247
}}
202248
/>
203249
</Modal>
204250
<PageNavigation
205-
backText={m.controls_back()}
206-
onBack={() => {
207-
navigate({
208-
to: '/',
209-
replace: true,
210-
});
211-
}}
212251
nextText={m.controls_continue()}
213252
onNext={() => {
214253
setConfirmModalOpen(true);
5.6 KB
Loading

webnext/src/pages/Home/components/HomeChoice.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export const HomeChoice = () => {
2222
subtitle={m.start_multi_enrollment_subtitle()}
2323
buttonText={m.start_multi_enrollment_button()}
2424
buttonIcon="arrow-big"
25-
link="/download"
25+
link="/enrollment-start"
2626
onClick={() => {}}
2727
/>
2828
<Card
@@ -41,7 +41,7 @@ export const HomeChoice = () => {
4141

4242
type CardProps = {
4343
img: 'enroll' | 'password';
44-
link: '/password' | '/download';
44+
link: '/password' | '/enrollment-start';
4545
buttonIcon: IconKindValue;
4646
buttonText: string;
4747
subtitle: string;
@@ -82,7 +82,7 @@ const Card = ({
8282
<SizedBox height={ThemeSpacing.Md} />
8383
<p className="subtitle">{subtitle}</p>
8484
<SizedBox height={ThemeSpacing.Xl2} />
85-
<Link to={link} data-testId={testId}>
85+
<Link to={link} data-testid={testId}>
8686
<Button
8787
size="primary"
8888
variant="primary"

webnext/src/pages/Home/components/style.scss

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
11
#home-choice {
22
display: grid;
3-
grid-template-columns: 1fr 1fr;
4-
grid-template-rows: 1fr;
5-
column-gap: var(--spacing-4xl);
3+
grid-template-columns: 1fr;
4+
grid-template-rows: 1fr 1fr;
5+
gap: var(--spacing-4xl);
6+
7+
@include break-up(md) {
8+
grid-template-columns: 1fr 1fr;
9+
grid-template-rows: 1fr;
10+
}
611

712
& > .choice {
813
--border-color: var(--border-default);
@@ -15,6 +20,10 @@
1520
transition-duration: 400ms;
1621
transition-property: border-color;
1722

23+
@include break-down(md) {
24+
max-width: 390px;
25+
}
26+
1827
.title {
1928
color: var(--fg-faded);
2029
font: var(--t-title-h3);
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { m } from '../../paraglide/messages';
2+
import { PageProcessEnd } from '../../shared/components/PageProcessEnd/PageProcessEnd';
3+
4+
export const SessionEndPage = () => {
5+
return (
6+
<PageProcessEnd
7+
link="/"
8+
icon="disabled"
9+
title={m.session_end_title()}
10+
subtitle={m.session_end_subtitle()}
11+
linkText={m.session_end_link()}
12+
/>
13+
);
14+
};

0 commit comments

Comments
 (0)