Web: Added changing the language without reloading the page.

This commit is contained in:
Tatiana Lopaeva 2024-04-16 16:12:02 +03:00
parent ed598a4b47
commit 918daa782c
6 changed files with 40 additions and 39 deletions

View File

@ -1,19 +1,18 @@
import { observer, inject } from "mobx-react"; import { observer, inject } from "mobx-react";
import React, { useEffect, useMemo } from "react"; import React, { useEffect, useMemo } from "react";
import { withTranslation, I18nextProviderProps } from "react-i18next"; import { withTranslation } from "react-i18next";
import { getCookie, setCookie } from "@docspace/shared/utils/cookie"; import { getCookie, setCookie } from "@docspace/shared/utils/cookie";
import { Loader, LoaderTypes } from "@docspace/shared/components/loader"; import { Loader, LoaderTypes } from "@docspace/shared/components/loader";
import { COOKIE_EXPIRATION_YEAR, LANGUAGE } from "@docspace/shared/constants"; import { COOKIE_EXPIRATION_YEAR, LANGUAGE } from "@docspace/shared/constants";
import { mapCulturesToArray } from "@docspace/shared/utils/common"; import { mapCulturesToArray } from "@docspace/shared/utils/common";
import i18n from "../i18n";
type I18n = I18nextProviderProps["i18n"];
interface ComponentWithCultureNamesProps { interface ComponentWithCultureNamesProps {
tReady: boolean; tReady: boolean;
cultures: string[]; cultures: string[];
isAuthenticated: boolean;
getPortalCultures: () => Promise<void>; getPortalCultures: () => Promise<void>;
i18n: I18n;
} }
interface WrappedComponentProps extends ComponentWithCultureNamesProps { interface WrappedComponentProps extends ComponentWithCultureNamesProps {
@ -35,8 +34,7 @@ export default function withCultureNames<
props: Omit<T, keyof WrappedComponentProps> & props: Omit<T, keyof WrappedComponentProps> &
ComponentWithCultureNamesProps, ComponentWithCultureNamesProps,
) => { ) => {
const { tReady, cultures, i18n, getPortalCultures, isAuthenticated } = const { tReady, cultures, getPortalCultures, isAuthenticated } = props;
props;
useEffect(() => { useEffect(() => {
if (cultures.length > 0) return; if (cultures.length > 0) return;
@ -47,7 +45,7 @@ export default function withCultureNames<
const cultureNames = useMemo( const cultureNames = useMemo(
() => mapCulturesToArray(cultures, isAuthenticated, i18n), () => mapCulturesToArray(cultures, isAuthenticated, i18n),
[cultures, i18n], [cultures, isAuthenticated],
); );
const url = new URL(window.location.href); const url = new URL(window.location.href);
const culture = url.searchParams.get("culture"); const culture = url.searchParams.get("culture");
@ -56,17 +54,19 @@ export default function withCultureNames<
(item) => item.key === currentCultureName, (item) => item.key === currentCultureName,
); );
const onLanguageSelect = (e) => { const onLanguageSelect = (e: KeyboardEvent) => {
i18n.changeLanguage(e.key);
setCookie(LANGUAGE, e.key, { setCookie(LANGUAGE, e.key, {
"max-age": COOKIE_EXPIRATION_YEAR, "max-age": COOKIE_EXPIRATION_YEAR,
}); });
if (culture) { if (culture) {
location.href = url.replace(`culture=${culture}`, `culture=${e.key}`); window.location.href = url.replace(
return; `culture=${culture}`,
`culture=${e.key}`,
);
} }
location.reload();
}; };
return cultures.length > 0 && tReady ? ( return cultures.length > 0 && tReady ? (

View File

@ -184,7 +184,7 @@ const CreateUserForm = (props) => {
window.location.href = combineUrl( window.location.href = combineUrl(
window.DocSpaceConfig?.proxy?.url, window.DocSpaceConfig?.proxy?.url,
"/login", "/login",
`?culture=${currentCultureName}&loginData=${loginData}`, `?loginData=${loginData}`,
); );
} catch (err) { } catch (err) {
console.error(err); console.error(err);

View File

@ -2,7 +2,7 @@ import React, { useState, useCallback, useEffect, useMemo } from "react";
import {} from "react-router-dom"; import {} from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { inject, observer } from "mobx-react"; import { inject, observer } from "mobx-react";
import { useLocation, useSearchParams } from "react-router-dom"; import { useLocation } from "react-router-dom";
import { LoginFormWrapper, LoginContent } from "./StyledLogin"; import { LoginFormWrapper, LoginContent } from "./StyledLogin";
import { Text } from "@docspace/shared/components/text"; import { Text } from "@docspace/shared/components/text";
@ -13,7 +13,7 @@ import {
mapCulturesToArray, mapCulturesToArray,
} from "@docspace/shared/utils/common"; } from "@docspace/shared/utils/common";
import { Link } from "@docspace/shared/components/link"; import { Link } from "@docspace/shared/components/link";
import { checkIsSSR, getCookie } from "@docspace/shared/utils"; import { checkIsSSR } from "@docspace/shared/utils";
import { import {
COOKIE_EXPIRATION_YEAR, COOKIE_EXPIRATION_YEAR,
LANGUAGE, LANGUAGE,
@ -68,15 +68,11 @@ const Login: React.FC<ILoginProps> = ({
const isRestoringPortal = const isRestoringPortal =
portalSettings?.tenantStatus === TenantStatus.PortalRestore; portalSettings?.tenantStatus === TenantStatus.PortalRestore;
let [searchParams] = useSearchParams();
const cultureNames = useMemo( const cultureNames = useMemo(
() => mapCulturesToArray(cultures, false), () => mapCulturesToArray(cultures, false),
[cultures] [cultures]
); );
const culture = searchParams.get("culture");
useEffect(() => { useEffect(() => {
if (search) { if (search) {
const firstIndex = search.indexOf("loginData="); const firstIndex = search.indexOf("loginData=");
@ -103,13 +99,11 @@ const Login: React.FC<ILoginProps> = ({
window.history.replaceState({}, document.title, window.location.pathname); window.history.replaceState({}, document.title, window.location.pathname);
} }
const cultureName = culture ?? getCookie(LANGUAGE);
setCurrantCultureName(cultureName);
isRestoringPortal && window.location.replace("/preparation-portal"); isRestoringPortal && window.location.replace("/preparation-portal");
}, []); }, []);
const [currentCultureName, setCurrantCultureName] = useState("en-GB"); const { t, i18n } = useTranslation(["Login", "Common"]);
const [isLoading, setIsLoading] = useState(false); const [isLoading, setIsLoading] = useState(false);
const [recoverDialogVisible, setRecoverDialogVisible] = useState(false); const [recoverDialogVisible, setRecoverDialogVisible] = useState(false);
const [invitationLinkData, setInvitationLinkData] = useState({ const [invitationLinkData, setInvitationLinkData] = useState({
@ -132,29 +126,25 @@ const Login: React.FC<ILoginProps> = ({
cookieSettingsEnabled: false, cookieSettingsEnabled: false,
}; };
const currentCultureName = i18n.language;
const selectedCultureObj = cultureNames.find( const selectedCultureObj = cultureNames.find(
(item) => item.key === currentCultureName (item) => item.key === currentCultureName
); );
const onLanguageSelect = (e) => { const onLanguageSelect = (e: KeyboardEvent) => {
setCookie(LANGUAGE, e.key, { const culture = e.key;
i18n.changeLanguage(culture);
setCookie(LANGUAGE, culture, {
"max-age": COOKIE_EXPIRATION_YEAR, "max-age": COOKIE_EXPIRATION_YEAR,
}); });
if (culture) {
window.location.href = window.location.href.replace(
`culture=${culture}`,
`culture=${e.key}`
);
return;
}
window.location.reload();
}; };
const ssoLabel = capabilities?.ssoLabel || ""; const ssoLabel = capabilities?.ssoLabel || "";
const ssoUrl = capabilities?.ssoUrl || ""; const ssoUrl = capabilities?.ssoUrl || "";
const { t } = useTranslation(["Login", "Common"]);
const mounted = useMounted(); const mounted = useMounted();
useIsomorphicLayoutEffect(() => { useIsomorphicLayoutEffect(() => {

View File

@ -68,7 +68,7 @@ const LoginForm: React.FC<ILoginFormProps> = ({
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
const { t, ready } = useTranslation(["Login", "Common"]); const { t, ready, i18n } = useTranslation(["Login", "Common"]);
const { message, confirmedEmail, authError } = match || { const { message, confirmedEmail, authError } = match || {
message: "", message: "",
@ -194,7 +194,9 @@ const LoginForm: React.FC<ILoginFormProps> = ({
isDesktop && checkPwd(); isDesktop && checkPwd();
const session = !isChecked; const session = !isChecked;
login(user, hash, session, captchaToken) const currentCulture = i18n.language;
login(user, hash, session, captchaToken, currentCulture)
.then((res: string | object) => { .then((res: string | object) => {
const isConfirm = typeof res === "string" && res.includes("confirm"); const isConfirm = typeof res === "string" && res.includes("confirm");
const redirectPath = sessionStorage.getItem("referenceUrl"); const redirectPath = sessionStorage.getItem("referenceUrl");

View File

@ -1,11 +1,18 @@
import { request, setWithCredentialsStatus } from "../client"; import { request, setWithCredentialsStatus } from "../client";
export function login(userName, passwordHash, session, recaptchaResponse) { export function login(
userName,
passwordHash,
session,
recaptchaResponse,
culture,
) {
const data = { const data = {
userName, userName,
passwordHash, passwordHash,
session, session,
recaptchaResponse, recaptchaResponse,
culture,
}; };
return request({ return request({

View File

@ -7,6 +7,7 @@ export async function login(
hash: string, hash: string,
session = true, session = true,
captchaToken: string = "", captchaToken: string = "",
currentCultureName: string = "",
): Promise<string | object> { ): Promise<string | object> {
try { try {
const response = (await api.user.login( const response = (await api.user.login(
@ -14,6 +15,7 @@ export async function login(
hash, hash,
session, session,
captchaToken, captchaToken,
currentCultureName,
)) as { )) as {
token?: string; token?: string;
tfa?: string; tfa?: string;