6 Commits

10 changed files with 163 additions and 26 deletions

View File

@@ -11,6 +11,9 @@ import { UserContext, type User } from "./states/Context";
import { triggerLogoutAtom } from "@/states/Atoms";
import { MyLoansPage } from "./pages/MyLoansPage";
import Landingpage from "./pages/Landingpage";
import { changeLanguage } from "i18next";
import { Box, Flex } from "@chakra-ui/react";
import { Footer } from "./components/Footer";
const API_BASE =
(import.meta as any).env?.VITE_BACKEND_URL ||
@@ -44,24 +47,42 @@ function App() {
};
verifyToken();
}
// set initial language
if (!Cookies.get("language")) {
const getBrowserLanguage = () => {
const lang = navigator.languages?.[0] || navigator.language || "en";
return lang.split("-")[0].toLowerCase();
};
changeLanguage(getBrowserLanguage());
Cookies.set("language", getBrowserLanguage());
}
if (Cookies.get("language")) {
changeLanguage(Cookies.get("language") || "en");
}
}, []);
return (
<>
<UserContext.Provider value={user}>
<BrowserRouter>
<Routes>
<Route element={<ProtectedRoutes />}>
<Route path="/" element={<HomePage />} />
<Route path="/my-loans" element={<MyLoansPage />} />
<Route path="/landing" element={<Landingpage />} />
</Route>
<Flex direction="column" minH="100vh">
<Box as="main" flex="1">
<UserContext.Provider value={user}>
<BrowserRouter>
<Routes>
<Route element={<ProtectedRoutes />}>
<Route path="/" element={<HomePage />} />
<Route path="/my-loans" element={<MyLoansPage />} />
<Route path="/landing" element={<Landingpage />} />
</Route>
<Route path="/login" element={<LoginPage />} />
</Routes>
</BrowserRouter>
</UserContext.Provider>
</>
<Route path="/login" element={<LoginPage />} />
</Routes>
</BrowserRouter>
</UserContext.Provider>
</Box>
<Footer />
</Flex>
);
}

View File

@@ -0,0 +1,19 @@
import { Box } from "@chakra-ui/react";
export const Footer = () => {
return (
<Box
as="footer"
py={4}
textAlign="center"
position="fixed"
bottom="0"
left="0"
right="0"
>
Made with by Theis Gaedigk - Year 2019 at MCS-Bochum
<br />
v2.0
</Box>
);
};

View File

@@ -26,6 +26,7 @@ import {
LogOut,
CalendarPlus,
MoreVertical,
Flag,
} from "lucide-react";
import { useUserContext } from "@/states/Context";
import { useState } from "react";
@@ -102,6 +103,7 @@ export const Header = () => {
Cookies.remove("token");
setIsLoggedIn(false);
setTriggerLogout(true);
navigate("/login", { replace: true });
};
return (
@@ -166,6 +168,21 @@ export const Header = () => {
</HStack>
}
/>
<Menu.Item
value="change-language"
onSelect={() => {
const currentLang = Cookies.get("language") || "en";
const newLang = currentLang === "en" ? "de" : "en";
Cookies.set("language", newLang);
window.location.reload();
}}
children={
<HStack gap={3}>
<LifeBuoy size={16} />
<Text as="span">{t("change-language")}</Text>
</HStack>
}
/>
<Menu.Item
value="help"
onSelect={() =>
@@ -276,6 +293,21 @@ export const Header = () => {
</HStack>
</Button>
<Button
variant="ghost"
onClick={() => {
const currentLang = Cookies.get("language") || "en";
const newLang = currentLang === "en" ? "de" : "en";
Cookies.set("language", newLang);
window.location.reload();
}}
>
<HStack gap={2}>
<Flag size={18} />
<Text as="span">{t("change-language")}</Text>
</HStack>
</Button>
<a
href="https://git.the1s.de/Matthias-Claudius-Schule/borrow-system/wiki"
target="_blank"

View File

@@ -5,6 +5,10 @@ import "./index.css";
import App from "./App.tsx";
import i18n from "./utils/i18n"; // import i18n configuration DO NOT REMOVE
// code below is to avoid linter error for unused import
let i18nUnused = i18n;
console.log(i18nUnused);
createRoot(document.getElementById("root")!).render(
<StrictMode>
<Provider>

View File

@@ -46,7 +46,7 @@ export const HomePage = () => {
};
return (
<Container maxW="7xl" className="px-6 sm:px-8 pt-10">
<Container className="px-6 sm:px-8 pt-10">
<Header />
{isMsg && (
<MyAlert
@@ -92,9 +92,7 @@ export const HomePage = () => {
if (response && response.status === "error") {
setMsgStatus("error");
setMsgTitle(response.title || t("error"));
setMsgDescription(
response.description || t("unknown-error")
);
setMsgDescription(response.description || t("unknown-error"));
setIsMsg(true);
return;
}
@@ -147,15 +145,13 @@ export const HomePage = () => {
if (response.status === "error") {
setMsgStatus("error");
setMsgTitle(response.title || t("error"));
setMsgDescription(
response.description || t("unknown-error")
);
setMsgDescription(response.description || t("unknown-error"));
setIsMsg(true);
return;
}
setMsgStatus("success");
setMsgTitle(t("success"));
setMsgDescription(t("loan-success")) ;
setMsgDescription(t("loan-success"));
setIsMsg(true);
})
}

View File

@@ -7,6 +7,7 @@ import Cookies from "js-cookie";
import { Navigate, useNavigate } from "react-router-dom";
import { PasswordInput } from "@/components/ui/password-input";
import { useTranslation } from "react-i18next";
import { Footer } from "@/components/Footer";
const API_BASE =
(import.meta as any).env?.VITE_BACKEND_URL ||
@@ -23,6 +24,7 @@ export const LoginPage = () => {
useEffect(() => {
if (isLoggedIn) {
navigate("/", { replace: true });
window.location.reload(); // Mit Tobais besprechen, ob das so bleiben soll
}
}, [isLoggedIn, navigate]);
@@ -115,6 +117,7 @@ export const LoginPage = () => {
</Card.Footer>
</Card.Root>
</form>
<Footer />
</div>
);
};

View File

@@ -117,7 +117,7 @@ export const MyLoansPage = () => {
return (
<>
<Container maxW="7xl" className="px-6 sm:px-8 pt-10">
<Container className="px-6 sm:px-8 pt-10">
<Header />
{isMsg && (
<MyAlert

View File

@@ -1,5 +1,6 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import Cookies from "js-cookie";
import enLang from "./locales/en/en.json";
import deLang from "./locales/de/de.json";
@@ -21,7 +22,7 @@ i18n
.init({
resources,
fallbackLng: "en", // use en if detected lng is not available
lng: "de", // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
lng: Cookies.get("language") || "en", // language to use, more information here: https://www.i18next.com/overview/configuration-options#languages-namespaces-resources
// you can use the i18n.changeLanguage function to change the language manually: https://www.i18next.com/overview/api#changelanguage
// if you're using a language detector, do not define the lng option

View File

@@ -58,5 +58,6 @@
"sure-delete-loan-0": "Möchten Sie die Ausleihe mit dem ",
"sure-delete-loan-1": " Ausleihcode wirklich löschen?",
"sure-delete-loan-2": "Für den Admin bleibt sie weiterhin sichtbar.",
"delete": "Löschen"
"delete": "Löschen",
"change-language": "Sprache ändern"
}

View File

@@ -1,3 +1,63 @@
{
"greeting": "Welcome back, "
"greeting": "Welcome back, ",
"err_pw_change": "Password change failed",
"pw_mismatch": "Please check your input",
"pw_success": "Password changed successfully",
"pw_success_desc": "Your password was changed successfully.",
"create-loan": "Create loan",
"my-loans": "My loans",
"change-password": "Change password",
"help": "Help",
"source-code": "Source code",
"logout": "Log out",
"old-password": "Old password",
"new-password": "New password",
"confirm-password": "Repeat new password",
"cancel": "Cancel",
"save": "Save",
"start-date": "Start date",
"end-date": "End date",
"missing-fields": "Missing fields",
"missing-fields-desc": "Please provide start and end date.",
"error": "Error",
"unknown-error": "Unknown frontend error",
"get-borrowable-items": "Fetch available items",
"loading": "Loading...",
"item": "Item",
"success": "Success",
"loan-success": "Loan created successfully",
"error-by-loading": "Error while loading",
"unexpected-date-format_loan": "Unexpected date format received. (Loans)",
"unexpected-date-format_device": "Unexpected date format received. (Device)",
"error-fetching-loans": "The loans could not be retrieved.",
"all-loans": "All loans",
"username": "Username",
"rented-items": "Borrowed items",
"return-date": "Return date",
"take-date": "Collection date",
"no-loans-found": "No loans found.",
"all-devices": "All devices",
"rent-role": "Loan role",
"legend": "Legend",
"in-locker": "In locker",
"not-in-locker": "Not in locker",
"login-failed": "Login failed",
"login": "Log in",
"enter-credentials": "Please enter your credentials below.",
"password": "Password",
"logout-success": "Successfully logged out",
"logout-success-desc": "You have been logged out successfully.",
"network-error-fetching-loans": "Network error while loading loans.",
"error-deleting-loan": "The loan could not be deleted.",
"loan-deletion-success": "The loan was deleted successfully.",
"network-error-deleting-loan": "Network error while deleting the loan.",
"loan-code": "Loan code",
"devices": "Devices",
"actions": "Actions",
"sure": "Are you sure?",
"sure-delete-loan-0": "Do you really want to delete the loan with the ",
"sure-delete-loan-1": " loan code?",
"sure-delete-loan-2": "It will remain visible to the admin.",
"delete": "Delete",
"change-language": "Change language"
}