Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add redirection and logout button to the login functionality #249

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
101749a
Add new Login page separate from setting page
SamuelPelletierEvraire Sep 24, 2024
2727e60
fix lint
SamuelPelletierEvraire Sep 24, 2024
803ea06
fix all file should finish with a newline
SamuelPelletierEvraire Sep 24, 2024
c1b7d68
fix all file should finish with a newline
SamuelPelletierEvraire Sep 24, 2024
39f9a56
fix refresh page
SamuelPelletierEvraire Sep 24, 2024
9c2097d
Add rederect to settingPage if not authentificated else go to homePage
SamuelPelletierEvraire Sep 25, 2024
9822a59
fix lint
SamuelPelletierEvraire Sep 25, 2024
395af02
fix missing import error during merge conflit
SamuelPelletierEvraire Sep 25, 2024
aa38f0e
removing LoginPage
SamuelPelletierEvraire Sep 25, 2024
2e70fe5
putting comment in english and removing some comment
SamuelPelletierEvraire Sep 25, 2024
ffff91e
fix css of the login section
SamuelPelletierEvraire Sep 25, 2024
e08ef16
Fixing issue: https://github.com/ai-cfia/fertiscan-frontend/issues/222
SamuelPelletierEvraire Sep 25, 2024
a1c8c32
fix lint
SamuelPelletierEvraire Sep 25, 2024
daf1c0d
fix the refresh that was remove after quick ask to gpt
SamuelPelletierEvraire Sep 25, 2024
43e519e
fix lint
SamuelPelletierEvraire Sep 25, 2024
2586339
Fix the comment made buy @k-allagbe
SamuelPelletierEvraire Oct 1, 2024
488de28
fix lint
SamuelPelletierEvraire Oct 1, 2024
877aada
fix lint
SamuelPelletierEvraire Oct 1, 2024
9ef69b4
Fix the redirectoring that was not working all the time
SamuelPelletierEvraire Oct 3, 2024
e7a779f
fix lint
SamuelPelletierEvraire Oct 3, 2024
5b72c43
last fix to make the redirection work
SamuelPelletierEvraire Oct 3, 2024
4f219d8
issue #226: use axios to handle timeouts
k-allagbe Oct 4, 2024
a1359ef
Merge branch 'main' into 226-as-a-user-i-want-to-be-directed-to-the-m…
k-allagbe Oct 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
217 changes: 146 additions & 71 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
},
"dependencies": {
"@dts-stn/service-canada-design-system": "^1.67.3",
"axios": "^1.7.7",
"deepmerge": "^4.3.1",
"dotenv": "^16.4.5",
"i18next": "^23.11.5",
Expand Down
6 changes: 5 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { AlertProvider } from "./Utils/AlertContext";
import { SessionProvider } from "./Utils/SessionContext";
import LabelPage from "./Pages/LabelPage/LabelPage";
import AlertBanner from "./Components/AlertBanner/AlertBanner";
import { isAuthenticated } from "./Utils/Auth/AuthUtil";

function App() {
useEffect(() => {
Expand All @@ -30,7 +31,10 @@ function App() {
</StrictMode>
<Routes>
<Route path="/">
<Route index element={<HomePage />} />
<Route
index
element={isAuthenticated() ? <HomePage /> : <SettingPage />}
k-allagbe marked this conversation as resolved.
Show resolved Hide resolved
/>
<Route path="Settings" element={<SettingPage />} />
<Route path="Saved" element={<SavedListPage />} />
<Route path="Label/:labelId" element={<LabelPage />} />
Expand Down
7 changes: 6 additions & 1 deletion src/Components/SideMenu/SideMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import list from "../../assets/list.svg";
import { SessionContext, SetSessionContext } from "../../Utils/SessionContext";
import Data from "../../Model/Data-Model";
import Inspection from "../../interfaces/Inspection.ts";
import { isAuthenticated } from "../../Utils/Auth/AuthUtil";

function SideMenu() {
const { t } = useTranslation();
Expand Down Expand Up @@ -54,7 +55,11 @@ function SideMenu() {

const goToHome = () => {
retrieveState();
navigate("/");
if (isAuthenticated()) {
navigate("/");
} else {
navigate("/Settings");
}
};

const goToSettings = () => {
Expand Down
21 changes: 18 additions & 3 deletions src/Pages/SettingPage/SettingPage.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@
border-radius: 5px;
}

.settings hr {
width: 100%;
}

/* LoginPage.css */
.login-page {
margin: 20px;
padding: 20px;
border: 1px solid #ccc;
border-radius: 5px;
display: flex;
flex-direction: column;
}

#login,
#uname,
#password {
Expand All @@ -36,6 +50,7 @@
#password label {
width: fit-content;
}

#uname input,
#password input {
width: 20%;
Expand All @@ -49,17 +64,16 @@
#validate-uname {
display: flex;
}

#validate-uname input {
margin: auto 20px auto 0;
width: fit-content;
}

#validate-uname p {
width: 35%;
text-align: left;
}
.settings hr {
width: 100%;
}

.send-uname {
width: fit-content;
Expand All @@ -69,6 +83,7 @@
background-color: #666666 !important;
cursor: not-allowed;
}

.send-uname:disabled:hover {
transform: none !important;
}
222 changes: 134 additions & 88 deletions src/Pages/SettingPage/SettingPage.tsx
Original file line number Diff line number Diff line change
@@ -1,121 +1,167 @@
import { useState } from "react";
import axios from "axios";
import { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
import LanguageButton from "../../Components/LanguageButton/LanguageButton";
import { useAlert } from "../../Utils/AlertContext.tsx";
import { useAlert } from "../../Utils/AlertContext";
import {
login as authLogin,
isAuthenticated,
logout,
} from "../../Utils/Auth/AuthUtil";
import "./SettingPage.css";

function SettingPage() {
const SettingsPage = () => {
const navigate = useNavigate();
const { t } = useTranslation();
const { showAlert } = useAlert();
const [uname_validated, setUnameValidated] = useState(false);
const [uname, setUname] = useState("");
const [password, setPassword] = useState("");
const login = () => {
const form = new FormData();
form.append("username", uname);
form.append("password", password);
if (process.env.VITE_APP_ACTIVATE_USING_JSON == "true") {
document.cookie = `auth=${btoa(uname + ":" + password)}`;
showAlert(t("loggedIn"), "confirm");
const [auth, setAuth] = useState(false);
const [isLoading, setIsLoading] = useState(false);

useEffect(() => {
setAuth(isAuthenticated());
}, []);

const finalizeAuth = (messageKey: string) => {
authLogin(uname, password);
showAlert(t(messageKey), "confirm");
setAuth(true);
navigate("/");
};

const login = async () => {
setIsLoading(true);

if (process.env.VITE_APP_ACTIVATE_USING_JSON === "true") {
finalizeAuth("loggedIn");
setIsLoading(false);
return;
}
fetch(process.env.VITE_API_URL + "/login", {
method: "POST",
body: form,
headers: {
Authorization: "Basic " + btoa(uname + ":" + password),
},
})
.then((r) => {
if (r.status !== 200) {
fetch(process.env.VITE_API_URL + "/signup", {
method: "POST",
body: form,
headers: {
Authorization: "Basic " + btoa(uname + ":" + password),
},
})
.then((r) => {
if (r.status !== 201) {
r.json().then((data) => {
showAlert(data.error, "error");
});
} else {
document.cookie = `auth=${btoa(uname + ":" + password)}`;
showAlert(t("loggedIn"), "confirm");
}

console.info("logging in");
axios
.post(
process.env.VITE_API_URL + "/login",
new URLSearchParams({ uname, password }),
{
headers: {
Authorization: "Basic " + btoa(uname + ":" + password),
},
timeout: 5000,
},
)
.then((response) => {
console.log(response);
finalizeAuth("loggedIn");
})
.catch((error) => {
if (error.response) {
console.error("login failed:", error.response);
console.info("signing up");
axios
.post(
`${process.env.VITE_API_URL}/signup`,
new URLSearchParams({
username: uname,
password: password,
}),
{
headers: {
Authorization: "Basic " + btoa(uname + ":" + password),
},
timeout: 5000,
},
)
.then((response) => {
console.log(response);
finalizeAuth("registered");
})
.catch((e) => {
showAlert(e, "error");
.catch((error) => {
console.error("unexpected error during signup", error.message);
showAlert(String(error), "error");
});
} else {
document.cookie = `auth=${btoa(uname + ":" + password)}`;
showAlert(t("registered"), "confirm");
}
console.error("unexpected error during login:", error.message);
showAlert(String(error), "error");
})
.catch((e) => {
showAlert(e, "error");
.finally(() => {
setIsLoading(false);
});
};

const handleLogout = () => {
logout();
setAuth(false);
};

return (
<div className="${theme}">
<div>
<h1>{t("settingH1")}</h1>

<div className="settings">
<div id="language">
<label>{t("languageLabel")} : </label>
<LanguageButton />
</div>
<hr />
<div id={"login"}>
<div id={"inputs"}>
<div id={"uname"}>
<label>{t("askForUName")} : </label>
<input
type={"text"}
value={uname}
onChange={(e) => setUname(e.target.value)}
></input>
</div>
<div id={"password"}>
<label>{t("askForPassword")} : </label>
<input
type={"password"}
value={password}
onChange={(e) => setPassword(e.target.value)}
></input>
<div id="login">
{auth ? (
<div>
<button onClick={handleLogout}>{t("logout")}</button>
</div>
</div>
<div id={"validate-uname"}>
<div
className={"checkbox-container"}
onClick={() => setUnameValidated(!uname_validated)}
>
<input
type="checkbox"
value={"accepted-uname"}
checked={uname_validated}
onChange={() => setUnameValidated(!uname_validated)}
/>
) : (
<div>
<div id="inputs">
<div id="uname">
<label>{t("askForUName")} : </label>
<input
type="text"
value={uname}
onChange={(e) => setUname(e.target.value)}
/>
</div>
<div id="password">
<label>{t("askForPassword")} : </label>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</div>
</div>
<div id="validate-uname">
<div
className="checkbox-container"
onClick={() => setUnameValidated(!uname_validated)}
>
<input
type="checkbox"
value="accepted-uname"
checked={uname_validated}
onChange={() => setUnameValidated(!uname_validated)}
/>
</div>
<p id="accept-uname">
{t("acceptUName")}
<br />
{t("reminderSensitive")}
</p>
</div>
<button
className="language-button en send-uname"
onClick={login}
disabled={!uname_validated || uname === "" || isLoading}
>
{isLoading ? t("loading...") : t("login")}
</button>
</div>
<p id={"accept-uname"}>
{t("acceptUName")}
<br />
{t("reminderSensitive")}
</p>
</div>
<button
className={"language-button en send-uname"}
onClick={login}
disabled={!uname_validated || uname === ""}
>
{t("login")}
</button>
)}
</div>
</div>
</div>
);
}
};

export default SettingPage;
export default SettingsPage;
25 changes: 25 additions & 0 deletions src/Utils/Auth/AuthUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
const isAuthenticated = () => {
// Look for the `auth` cookie
const authCookie = document.cookie
.split("; ")
.find((row) => row.startsWith("auth="));

// Check that the cookie is present and not empty
if (authCookie) {
const authValue = authCookie.split("=")[1];
return authValue !== undefined && authValue !== "";
}

return false;
};

const login = (username: string, password: string) => {
document.cookie = `auth=${btoa(username + ":" + password)}`;
};

const logout = () => {
k-allagbe marked this conversation as resolved.
Show resolved Hide resolved
// Set the cookie's expiry date to a past date to effectively remove it
document.cookie = "auth=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
};

export { isAuthenticated, login, logout };
4 changes: 2 additions & 2 deletions src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import i18n from "i18next";
import { initReactI18next } from "react-i18next";

// Import your translations (replace with your actual files)
import en from "../public/locales/en.json";
import fr from "../public/locales/fr.json";
import en from "./locales/en.json";
import fr from "./locales/fr.json";

i18n
.use(initReactI18next) // Initializes i18n with React
Expand Down
Loading
Loading