Skip to content

Commit 4ef5eef

Browse files
committed
refactor: rework hooks usage
1 parent 3873bb2 commit 4ef5eef

8 files changed

Lines changed: 96 additions & 76 deletions

File tree

‎frontend/src/components/layout/layout.tsx‎

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useAppContext } from "@/context/app-context";
22
import { LanguageSelector } from "../language/language";
33
import { Outlet } from "react-router";
4-
import { useState } from "react";
4+
import { useCallback, useState } from "react";
55
import { DomainWarning } from "../domain-warning/domain-warning";
66

77
const BaseLayout = ({ children }: { children: React.ReactNode }) => {
@@ -24,20 +24,17 @@ const BaseLayout = ({ children }: { children: React.ReactNode }) => {
2424

2525
export const Layout = () => {
2626
const { appUrl } = useAppContext();
27-
const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(false);
27+
const [ignoreDomainWarning, setIgnoreDomainWarning] = useState(() => {
28+
return window.sessionStorage.getItem("ignoreDomainWarning") === "true";
29+
});
2830
const currentUrl = window.location.origin;
29-
const sessionIgnore = window.sessionStorage.getItem("ignoreDomainWarning");
3031

31-
const handleIgnore = () => {
32+
const handleIgnore = useCallback(() => {
3233
window.sessionStorage.setItem("ignoreDomainWarning", "true");
3334
setIgnoreDomainWarning(true);
34-
};
35+
}, [setIgnoreDomainWarning]);
3536

36-
if (
37-
!ignoreDomainWarning &&
38-
appUrl !== currentUrl &&
39-
sessionIgnore !== "true"
40-
) {
37+
if (!ignoreDomainWarning && appUrl !== currentUrl) {
4138
return (
4239
<BaseLayout>
4340
<DomainWarning

‎frontend/src/lib/i18n/locales/en-US.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"loginOauthFailSubtitle": "Failed to get OAuth URL",
1515
"loginOauthSuccessTitle": "Redirecting",
1616
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
17+
"continueTitle": "Continue",
1718
"continueRedirectingTitle": "Redirecting...",
1819
"continueRedirectingSubtitle": "You should be redirected to the app soon",
1920
"continueRedirectManually": "Redirect me manually",

‎frontend/src/lib/i18n/locales/en.json‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
"loginOauthFailSubtitle": "Failed to get OAuth URL",
1515
"loginOauthSuccessTitle": "Redirecting",
1616
"loginOauthSuccessSubtitle": "Redirecting to your OAuth provider",
17+
"continueTitle": "Continue",
1718
"continueRedirectingTitle": "Redirecting...",
1819
"continueRedirectingSubtitle": "You should be redirected to the app soon",
1920
"continueRedirectManually": "Redirect me manually",

‎frontend/src/pages/continue-page.tsx‎

Lines changed: 50 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,42 +15,68 @@ import DOMPurify from "dompurify";
1515
import { useEffect, useState } from "react";
1616

1717
export const ContinuePage = () => {
18-
const { isLoggedIn } = useUserContext();
19-
20-
if (!isLoggedIn) {
21-
return <Navigate to="/login" />;
22-
}
23-
2418
const { rootDomain } = useAppContext();
19+
const { isLoggedIn } = useUserContext();
2520
const { search } = useLocation();
21+
const { t } = useTranslation();
22+
const navigate = useNavigate();
23+
2624
const [loading, setLoading] = useState(false);
2725
const [showRedirectButton, setShowRedirectButton] = useState(false);
2826

2927
const searchParams = new URLSearchParams(search);
30-
const redirectURI = searchParams.get("redirect_uri");
28+
const redirectUri = searchParams.get("redirect_uri");
3129

32-
if (!redirectURI) {
33-
return <Navigate to="/logout" />;
34-
}
35-
36-
if (!isValidUrl(DOMPurify.sanitize(redirectURI))) {
37-
return <Navigate to="/logout" />;
38-
}
39-
40-
const { t } = useTranslation();
41-
const navigate = useNavigate();
30+
const isValidRedirectUri =
31+
redirectUri !== null ? isValidUrl(DOMPurify.sanitize(redirectUri)) : false;
32+
const redirectUriObj = isValidRedirectUri
33+
? new URL(redirectUri as string)
34+
: null;
35+
const isTrustedRedirectUri =
36+
redirectUriObj !== null
37+
? redirectUriObj.hostname === rootDomain ||
38+
redirectUriObj.hostname.endsWith(`.${rootDomain}`)
39+
: false;
40+
const isHttpsDowngrade =
41+
redirectUriObj !== null
42+
? redirectUriObj.protocol === "http:" &&
43+
window.location.protocol === "https:"
44+
: false;
4245

4346
const handleRedirect = () => {
4447
setLoading(true);
45-
window.location.href = DOMPurify.sanitize(redirectURI);
48+
window.location.replace(DOMPurify.sanitize(redirectUriObj!.toString()));
4649
};
4750

48-
const redirectURLObj = new URL(redirectURI);
51+
useEffect(() => {
52+
if (
53+
!isLoggedIn ||
54+
!isValidRedirectUri ||
55+
!isTrustedRedirectUri ||
56+
isHttpsDowngrade
57+
) {
58+
return;
59+
}
60+
61+
setTimeout(() => {
62+
handleRedirect();
63+
}, 100);
64+
65+
setTimeout(() => {
66+
setLoading(false);
67+
setShowRedirectButton(true);
68+
}, 1000);
69+
}, []);
70+
71+
if (!isLoggedIn) {
72+
return <Navigate to="/login" />;
73+
}
4974

50-
if (
51-
!(redirectURLObj.hostname == rootDomain) &&
52-
!redirectURLObj.hostname.endsWith(`.${rootDomain}`)
53-
) {
75+
if (!isValidRedirectUri) {
76+
return <Navigate to="/logout" />;
77+
}
78+
79+
if (!isTrustedRedirectUri) {
5480
return (
5581
<Card className="min-w-xs sm:min-w-sm">
5682
<CardHeader>
@@ -88,10 +114,7 @@ export const ContinuePage = () => {
88114
);
89115
}
90116

91-
if (
92-
redirectURLObj.protocol === "http:" &&
93-
window.location.protocol === "https:"
94-
) {
117+
if (isHttpsDowngrade) {
95118
return (
96119
<Card className="min-w-xs sm:min-w-sm">
97120
<CardHeader>
@@ -124,16 +147,6 @@ export const ContinuePage = () => {
124147
);
125148
}
126149

127-
useEffect(() => {
128-
setTimeout(() => {
129-
handleRedirect();
130-
}, 100);
131-
setTimeout(() => {
132-
setLoading(false);
133-
setShowRedirectButton(true);
134-
}, 1000);
135-
}, []);
136-
137150
return (
138151
<Card className="min-w-xs sm:min-w-sm">
139152
<CardHeader>

‎frontend/src/pages/login-page.tsx‎

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,8 @@ import { toast } from "sonner";
2424

2525
export const LoginPage = () => {
2626
const { isLoggedIn } = useUserContext();
27-
28-
if (isLoggedIn) {
29-
return <Navigate to="/logout" />;
30-
}
31-
32-
const { configuredProviders, title, oauthAutoRedirect, genericName } = useAppContext();
27+
const { configuredProviders, title, oauthAutoRedirect, genericName } =
28+
useAppContext();
3329
const { search } = useLocation();
3430
const { t } = useTranslation();
3531
const isMounted = useIsMounted();
@@ -54,7 +50,7 @@ export const LoginPage = () => {
5450
});
5551

5652
setTimeout(() => {
57-
window.location.href = data.data.url;
53+
window.location.replace(data.data.url);
5854
}, 500);
5955
},
6056
onError: () => {
@@ -100,13 +96,18 @@ export const LoginPage = () => {
10096
if (
10197
oauthConfigured &&
10298
configuredProviders.includes(oauthAutoRedirect) &&
99+
!isLoggedIn &&
103100
redirectUri
104101
) {
105102
oauthMutation.mutate(oauthAutoRedirect);
106103
}
107104
}
108105
}, []);
109106

107+
if (isLoggedIn) {
108+
return <Navigate to="/logout" />;
109+
}
110+
110111
return (
111112
<Card className="min-w-xs sm:min-w-sm">
112113
<CardHeader>
@@ -126,7 +127,10 @@ export const LoginPage = () => {
126127
icon={<GoogleIcon />}
127128
className="w-full"
128129
onClick={() => oauthMutation.mutate("google")}
129-
loading={oauthMutation.isPending && oauthMutation.variables === "google"}
130+
loading={
131+
oauthMutation.isPending &&
132+
oauthMutation.variables === "google"
133+
}
130134
disabled={oauthMutation.isPending || loginMutation.isPending}
131135
/>
132136
)}
@@ -136,7 +140,10 @@ export const LoginPage = () => {
136140
icon={<GithubIcon />}
137141
className="w-full"
138142
onClick={() => oauthMutation.mutate("github")}
139-
loading={oauthMutation.isPending && oauthMutation.variables === "github"}
143+
loading={
144+
oauthMutation.isPending &&
145+
oauthMutation.variables === "github"
146+
}
140147
disabled={oauthMutation.isPending || loginMutation.isPending}
141148
/>
142149
)}
@@ -146,7 +153,10 @@ export const LoginPage = () => {
146153
icon={<GenericIcon />}
147154
className="w-full"
148155
onClick={() => oauthMutation.mutate("generic")}
149-
loading={oauthMutation.isPending && oauthMutation.variables === "generic"}
156+
loading={
157+
oauthMutation.isPending &&
158+
oauthMutation.variables === "generic"
159+
}
150160
disabled={oauthMutation.isPending || loginMutation.isPending}
151161
/>
152162
)}

‎frontend/src/pages/logout-page.tsx‎

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,6 @@ import { toast } from "sonner";
1717

1818
export const LogoutPage = () => {
1919
const { provider, username, isLoggedIn, email } = useUserContext();
20-
21-
if (!isLoggedIn) {
22-
return <Navigate to="/login" />;
23-
}
24-
2520
const { genericName } = useAppContext();
2621
const { t } = useTranslation();
2722

@@ -33,7 +28,7 @@ export const LogoutPage = () => {
3328
description: t("logoutSuccessSubtitle"),
3429
});
3530

36-
setTimeout(async () => {
31+
setTimeout(() => {
3732
window.location.replace("/login");
3833
}, 500);
3934
},
@@ -44,6 +39,10 @@ export const LogoutPage = () => {
4439
},
4540
});
4641

42+
if (!isLoggedIn) {
43+
return <Navigate to="/login" />;
44+
}
45+
4746
return (
4847
<Card className="min-w-xs sm:min-w-sm">
4948
<CardHeader>

‎frontend/src/pages/totp-page.tsx‎

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,6 @@ import { toast } from "sonner";
1919

2020
export const TotpPage = () => {
2121
const { totpPending } = useUserContext();
22-
23-
if (!totpPending) {
24-
return <Navigate to="/" />;
25-
}
26-
2722
const { t } = useTranslation();
2823
const { search } = useLocation();
2924
const formId = useId();
@@ -52,6 +47,10 @@ export const TotpPage = () => {
5247
},
5348
});
5449

50+
if (!totpPending) {
51+
return <Navigate to="/" />;
52+
}
53+
5554
return (
5655
<Card className="min-w-xs sm:min-w-sm">
5756
<CardHeader>

‎frontend/src/pages/unauthorized-page.tsx‎

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,26 @@ import { Navigate, useLocation, useNavigate } from "react-router";
1212

1313
export const UnauthorizedPage = () => {
1414
const { search } = useLocation();
15+
const { t } = useTranslation();
16+
const navigate = useNavigate();
17+
18+
const [loading, setLoading] = useState(false);
1519

1620
const searchParams = new URLSearchParams(search);
1721
const username = searchParams.get("username");
1822
const resource = searchParams.get("resource");
1923
const groupErr = searchParams.get("groupErr");
2024
const ip = searchParams.get("ip");
2125

22-
if (!username && !ip) {
23-
return <Navigate to="/" />;
24-
}
25-
26-
const { t } = useTranslation();
27-
const navigate = useNavigate();
28-
const [loading, setLoading] = useState(false);
29-
3026
const handleRedirect = () => {
3127
setLoading(true);
3228
navigate("/login");
3329
};
3430

31+
if (!username && !ip) {
32+
return <Navigate to="/" />;
33+
}
34+
3535
let i18nKey = "unauthorizedLoginSubtitle";
3636

3737
if (resource) {

0 commit comments

Comments
 (0)