diff --git a/CHANGELOG.MD b/CHANGELOG.MD index e17b71d36..89c44e603 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -1,5 +1,9 @@ ## May 29, 2024 +- **Bugfix** Null in the public URL [🎟️ DESENG-625](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-625) + - Removed language from URLs other than engagement/survey links + - Fixed the issue of null appearing in public URLs + - **Feature** MET split out tenant specific variables from locale files [🎟️ DESENG-612](https://apps.itsm.gov.bc.ca/jira/browse/DESENG-612) - Replaced tenant based values with data from tenant detail API diff --git a/met-api/sample.env b/met-api/sample.env index c83cee67c..700c4ca2b 100644 --- a/met-api/sample.env +++ b/met-api/sample.env @@ -90,15 +90,15 @@ ACCESS_REQUEST_EMAIL_ADDRESS="accessRequestHandler.fakeName@gov.bc.ca" # Site paths for creating emails from templates SITE_URL=http://localhost:3000 -SURVEY_PATH=/{lang}/surveys/submit/{survey_id}/{token} +SURVEY_PATH=/surveys/submit/{survey_id}/{token}/{lang} USER_MANAGEMENT_PATH=/usermanagement -SUBMISSION_PATH=/{lang}/engagements/{engagement_id}/edit/{token} -SUBSCRIBE_PATH=/{lang}/engagements/{engagement_id}/subscribe/{token} -UNSUBSCRIBE_PATH=/{lang}/engagements/{engagement_id}/unsubscribe/{participant_id} -ENGAGEMENT_PATH=/{lang}/engagements/{engagement_id}/view -ENGAGEMENT_PATH_SLUG=/{lang}/{slug} -ENGAGEMENT_DASHBOARD_PATH=/{lang}/engagements/{engagement_id}/comments/public -ENGAGEMENT_DASHBOARD_PATH_SLUG=/{lang}/{slug}/comments/public +SUBMISSION_PATH=/engagements/{engagement_id}/edit/{token}/{lang} +SUBSCRIBE_PATH=/engagements/{engagement_id}/subscribe/{token}/{lang} +UNSUBSCRIBE_PATH=/engagements/{engagement_id}/unsubscribe/{participant_id}/{lang} +ENGAGEMENT_PATH=/engagements/{engagement_id}/view/{lang} +ENGAGEMENT_PATH_SLUG=/{slug}/{lang} +ENGAGEMENT_DASHBOARD_PATH=/engagements/{engagement_id}/comments/public/{lang} +ENGAGEMENT_DASHBOARD_PATH_SLUG=/{slug}/comments/public/{lang} #CDogs API settings CDOGS_ACCESS_TOKEN= diff --git a/met-api/src/met_api/config.py b/met-api/src/met_api/config.py index 6ea72460d..706a641bc 100644 --- a/met-api/src/met_api/config.py +++ b/met-api/src/met_api/config.py @@ -239,25 +239,25 @@ def SQLALCHEMY_DATABASE_URI(self) -> str: # construct the links in the emails sent to users. PATH_CONFIG = PATHS = { 'SITE': os.getenv('SITE_URL'), - 'SURVEY': os.getenv('SURVEY_PATH', '/{lang}/surveys/submit/{survey_id}/{token}'), + 'SURVEY': os.getenv('SURVEY_PATH', '/surveys/submit/{survey_id}/{token}/{lang}'), 'USER_MANAGEMENT': os.getenv('USER_MANAGEMENT_PATH', '/usermanagement'), 'SUBMISSION': os.getenv( - 'SUBMISSION_PATH', '/{lang}/engagements/{engagement_id}/edit/{token}' + 'SUBMISSION_PATH', '/engagements/{engagement_id}/edit/{token}/{lang}' ), 'SUBSCRIBE': os.getenv( - 'SUBSCRIBE_PATH', '/{lang}/engagements/{engagement_id}/subscribe/{token}' + 'SUBSCRIBE_PATH', '/engagements/{engagement_id}/subscribe/{token}/{lang}' ), 'UNSUBSCRIBE': os.getenv( - 'UNSUBSCRIBE_PATH', '/{lang}/engagements/{engagement_id}/unsubscribe/{participant_id}' + 'UNSUBSCRIBE_PATH', '/engagements/{engagement_id}/unsubscribe/{participant_id}/{lang}' ), 'ENGAGEMENT': { - 'VIEW': os.getenv('ENGAGEMENT_PATH', '/{lang}/engagements/{engagement_id}/view'), - 'SLUG': os.getenv('ENGAGEMENT_PATH_SLUG', '/{lang}/{slug}'), + 'VIEW': os.getenv('ENGAGEMENT_PATH', '/engagements/{engagement_id}/view/{lang}'), + 'SLUG': os.getenv('ENGAGEMENT_PATH_SLUG', '/{slug}/{lang}'), 'DASHBOARD': os.getenv( - 'ENGAGEMENT_DASHBOARD_PATH', '/{lang}/engagements/{engagement_id}/comments/public' + 'ENGAGEMENT_DASHBOARD_PATH', '/engagements/{engagement_id}/comments/public/{lang}' ), 'DASHBOARD_SLUG': os.getenv( - 'ENGAGEMENT_DASHBOARD_PATH_SLUG', '/{lang}/{slug}/comments/public' + 'ENGAGEMENT_DASHBOARD_PATH_SLUG', '/{slug}/comments/public/{lang}' ), } } diff --git a/met-web/src/App.tsx b/met-web/src/App.tsx index d70ed0191..8413a16f8 100644 --- a/met-web/src/App.tsx +++ b/met-web/src/App.tsx @@ -94,25 +94,22 @@ const App = () => { } const defaultTenant = AppConfig.tenant.defaultTenant; - const defaultLanguage = AppConfig.language.defaultLanguageId; - + sessionStorage.setItem('languageId', AppConfig.language.defaultLanguageId); // Determine the appropriate URL to redirect - const redirectToDefaultUrl = (base: string, includeLanguage = true) => { - const languageSegment = includeLanguage ? `/${defaultLanguage}` : '/home'; - window.location.replace(`/${base}${languageSegment}`); + const redirectToDefaultUrl = (base: string, isAuthenticated: boolean) => { + const redirectUrl = `/${base}${isAuthenticated ? '/home' : ''}`; + window.location.replace(redirectUrl); }; - const shouldIncludeLanguage = !isAuthenticated; - if (basename) { fetchTenant(basename); - // if language or admin dashboard url not set - if (pathSegments.length < 2) { - redirectToDefaultUrl(basename, shouldIncludeLanguage); + // if admin dashboard url not set + if (pathSegments.length < 2 && isAuthenticated) { + redirectToDefaultUrl(basename, isAuthenticated); } } else if (defaultTenant) { fetchTenant(defaultTenant); - redirectToDefaultUrl(defaultTenant, shouldIncludeLanguage); + redirectToDefaultUrl(defaultTenant, isAuthenticated); } else { dispatch(loadingTenant(false)); } @@ -213,9 +210,7 @@ const App = () => { - - } /> - + diff --git a/met-web/src/components/engagement/dashboard/comment/CommentsBlock.tsx b/met-web/src/components/engagement/dashboard/comment/CommentsBlock.tsx index 63a695d1f..8e9fa7614 100644 --- a/met-web/src/components/engagement/dashboard/comment/CommentsBlock.tsx +++ b/met-web/src/components/engagement/dashboard/comment/CommentsBlock.tsx @@ -55,7 +55,7 @@ export const CommentsBlock: React.FC = ({ dashboardType }) = if (isLoggedIn) { navigate(`${basePath}/dashboard/public`); } else { - navigate(`${languagePath}${basePath}/dashboard/public`); + navigate(`${basePath}/dashboard/public${languagePath}`); } }; @@ -67,7 +67,7 @@ export const CommentsBlock: React.FC = ({ dashboardType }) = <> {translate('commentDashboard.block.link.0') + diff --git a/met-web/src/components/engagement/view/SurveyBlock.tsx b/met-web/src/components/engagement/view/SurveyBlock.tsx index 60d70f8de..3d1168cc4 100644 --- a/met-web/src/components/engagement/view/SurveyBlock.tsx +++ b/met-web/src/components/engagement/view/SurveyBlock.tsx @@ -69,7 +69,7 @@ const SurveyBlock = ({ startSurvey }: SurveyBlockProps) => { isLoggedIn ? navigate(`/engagements/${savedEngagement.id}/dashboard/public`) : navigate( - `${languagePath}/engagements/${savedEngagement.id}/dashboard/public`, + `/engagements/${savedEngagement.id}/dashboard/public/${languagePath}`, ); }} > diff --git a/met-web/src/components/engagement/view/widgets/Subscribe/FormSignUpSection.tsx b/met-web/src/components/engagement/view/widgets/Subscribe/FormSignUpSection.tsx index aa24c4523..b7b5e57cc 100644 --- a/met-web/src/components/engagement/view/widgets/Subscribe/FormSignUpSection.tsx +++ b/met-web/src/components/engagement/view/widgets/Subscribe/FormSignUpSection.tsx @@ -13,7 +13,7 @@ const FormSignUpSection = ({ subscribeOption, widget }: { subscribeOption: Subsc const languagePath = `${sessionStorage.getItem('languageId')}`; const handleNavigate = () => { const baseUrl = getBaseUrl(); - window.open(`${baseUrl}/${languagePath}/engagements/${widget.engagement_id}/cacform/${widget.id}`, '_blank'); + window.open(`${baseUrl}/engagements/${widget.engagement_id}/cacform/${widget.id}/${languagePath}`, '_blank'); }; return ( diff --git a/met-web/src/components/landing/EngagementTile.tsx b/met-web/src/components/landing/EngagementTile.tsx index 7754f0de0..5a0d5f638 100644 --- a/met-web/src/components/landing/EngagementTile.tsx +++ b/met-web/src/components/landing/EngagementTile.tsx @@ -29,7 +29,7 @@ const EngagementTile = ({ passedEngagement, engagementId }: EngagementTileProps) const dateFormat = 'MMM DD, YYYY'; const languagePath = `/${sessionStorage.getItem('languageId')}`; const engagementPath = `/${slug}`; - const engagementUrl = `${getBaseUrl()}${languagePath}${engagementPath}`; + const engagementUrl = `${getBaseUrl()}${engagementPath}${languagePath}`; const loadEngagement = async () => { if (passedEngagement) { diff --git a/met-web/src/components/layout/Footer/index.tsx b/met-web/src/components/layout/Footer/index.tsx index cb7444b26..c42025f6b 100644 --- a/met-web/src/components/layout/Footer/index.tsx +++ b/met-web/src/components/layout/Footer/index.tsx @@ -16,7 +16,6 @@ import { IconButton, Link } from 'components/common/Input'; const Footer = () => { const baseURL = getBaseUrl(); - const LanguageId = sessionStorage.getItem('languageId'); const { t: translate } = useAppTranslation(); const isLoggedIn = useAppSelector((state) => state.user.authentication.authenticated); @@ -79,7 +78,7 @@ const Footer = () => { {translate('footer.moreInfo')} - + {translate('footer.home')} diff --git a/met-web/src/components/layout/Header/PublicHeader.tsx b/met-web/src/components/layout/Header/PublicHeader.tsx index 487e1cf04..3e2ece777 100644 --- a/met-web/src/components/layout/Header/PublicHeader.tsx +++ b/met-web/src/components/layout/Header/PublicHeader.tsx @@ -17,7 +17,6 @@ import { TenantState } from 'reduxSlices/tenantSlice'; const PublicHeader = () => { const isLoggedIn = useAppSelector((state) => state.user.authentication.authenticated); - const language = sessionStorage.getItem('languageId'); const [imageError, setImageError] = useState(false); const navigate = useNavigate(); const { t: translate } = useAppTranslation(); @@ -56,7 +55,7 @@ const PublicHeader = () => { cursor: 'pointer', }} onClick={() => { - navigate(`/${language}`); + navigate(`/`); }} onError={(_e) => { setImageError(true); @@ -74,7 +73,7 @@ const PublicHeader = () => { cursor: 'pointer', }} onClick={() => { - navigate(`/${language}`); + navigate(`/`); }} alt={translate('common.defaultBCText')} /> @@ -82,7 +81,7 @@ const PublicHeader = () => { { - navigate(`/${language}`); + navigate(`/`); }} > {headerTitle} diff --git a/met-web/src/components/publicDashboard/Dashboard.tsx b/met-web/src/components/publicDashboard/Dashboard.tsx index bdd149485..1c969d06a 100644 --- a/met-web/src/components/publicDashboard/Dashboard.tsx +++ b/met-web/src/components/publicDashboard/Dashboard.tsx @@ -39,7 +39,7 @@ const Dashboard = () => { if (isLoggedIn) { navigate(`${basePath}/comments/${dashboardType}`); } else { - navigate(`${languagePath}${basePath}/comments/${dashboardType}`); + navigate(`${basePath}/comments/${dashboardType}${languagePath}`); } }; @@ -83,7 +83,7 @@ const Dashboard = () => { {translate('dashboard.link.0') + engagement.name + translate('dashboard.link.1')} diff --git a/met-web/src/components/survey/edit/FormWrapped.tsx b/met-web/src/components/survey/edit/FormWrapped.tsx index ab85ce03c..12eb08fc1 100644 --- a/met-web/src/components/survey/edit/FormWrapped.tsx +++ b/met-web/src/components/survey/edit/FormWrapped.tsx @@ -14,7 +14,7 @@ const FormWrapped = () => { const { isTokenValid, isLoading, savedEngagement, submission } = useContext(ActionContext); const navigate = useNavigate(); const languagePath = `/${sessionStorage.getItem('languageId')}`; - const engagementPath = slug ? `${languagePath}/${slug}` : `${languagePath}/engagements/${savedEngagement?.id}/view`; + const engagementPath = slug ? `${slug}/${languagePath}` : `engagements/${savedEngagement?.id}/view/${languagePath}`; if (isLoading || !savedEngagement) { return ; diff --git a/met-web/src/components/survey/submit/ActionContext.tsx b/met-web/src/components/survey/submit/ActionContext.tsx index b401bb460..8d72f7e28 100644 --- a/met-web/src/components/survey/submit/ActionContext.tsx +++ b/met-web/src/components/survey/submit/ActionContext.tsx @@ -188,7 +188,7 @@ export const ActionProvider = ({ children }: { children: JSX.Element }) => { text: translate('surveySubmit.surveySubmitNotification.success'), }), ); - navigate(`${languagePath}/${slug}`, { + navigate(`/${slug}/${languagePath}`, { state: { open: true, }, diff --git a/met-web/src/components/survey/submit/SurveySubmitWrapped.tsx b/met-web/src/components/survey/submit/SurveySubmitWrapped.tsx index e5f0587e1..7f61f7c88 100644 --- a/met-web/src/components/survey/submit/SurveySubmitWrapped.tsx +++ b/met-web/src/components/survey/submit/SurveySubmitWrapped.tsx @@ -39,14 +39,14 @@ const SurveySubmitWrapped = () => { { - navigate(`${languagePath}/${slug}`); + navigate(`/${slug}/${languagePath}`); }} /> { - navigate(`${languagePath}/${slug}`); + navigate(`/${slug}/${languagePath}`); }} /> diff --git a/met-web/src/routes/LanguageParam.tsx b/met-web/src/routes/LanguageParam.tsx new file mode 100644 index 000000000..4b246fd1d --- /dev/null +++ b/met-web/src/routes/LanguageParam.tsx @@ -0,0 +1,53 @@ +import React, { useEffect, ComponentType, useMemo } from 'react'; +import { useParams, useNavigate } from 'react-router-dom'; +import { useAppSelector } from '../hooks'; +import { LanguageState } from 'reduxSlices/languageSlice'; + +interface RouteParams { + [key: string]: string | undefined; + engagementId?: string; + slug?: string; + subscriptionStatus?: string; + scriptionKey?: string; + dashboardType?: string; + token?: string; + widgetId?: string; +} + +/** + * Higher-Order Component (HOC) to handle language parameter in the URL. + * This HOC checks if the current URL includes the language code and adds it if necessary. + * It uses the language state and available translations from the context to determine if the language code should be added. + * @param Component - The component to be wrapped by this HOC. + * @returns A new component with language parameter handling. + */ +const withLanguageParam = (Component: ComponentType) => { + return (props: P) => { + const languageState: LanguageState = useAppSelector((state) => state.language); + const languageCode = languageState.id; + const rawParams = useParams(); + const params = useMemo(() => rawParams, [rawParams]); + const navigate = useNavigate(); + + useEffect(() => { + const currentUrl = window.location.pathname; + if (languageCode && !currentUrl.includes(languageCode)) { + let newUrl = currentUrl; + + for (const param in params) { + if (params[param as keyof RouteParams]) { + newUrl = newUrl.replace(`:${param}`, params[param as keyof RouteParams] as string); + } + } + + newUrl = newUrl.replace(':language', languageCode); + + navigate(newUrl, { replace: true }); + } + }, [languageCode, navigate, params]); + + return ; + }; +}; + +export default withLanguageParam; diff --git a/met-web/src/routes/NotFound.tsx b/met-web/src/routes/NotFound.tsx index 6bf059988..b58a3b9d7 100644 --- a/met-web/src/routes/NotFound.tsx +++ b/met-web/src/routes/NotFound.tsx @@ -9,7 +9,6 @@ const listItemStyle = { marginBottom: 1 }; const marginStyle = { mr: 2 }; const tenantId = sessionStorage.getItem('tenantId'); -const LanguageId = sessionStorage.getItem('languageId'); const SuggestionsList = ({ translate }: { translate: (key: string) => string }) => ( @@ -18,7 +17,7 @@ const SuggestionsList = ({ translate }: { translate: (key: string) => string }) {translate('notFound.list.0')} {translate('notFound.list.1')}{' '} - + {translate('notFound.list.2')} {' '} {translate('notFound.list.3')} diff --git a/met-web/src/routes/UnauthenticatedRoutes.tsx b/met-web/src/routes/UnauthenticatedRoutes.tsx index b1ef03ef5..98fc9efeb 100644 --- a/met-web/src/routes/UnauthenticatedRoutes.tsx +++ b/met-web/src/routes/UnauthenticatedRoutes.tsx @@ -12,6 +12,17 @@ import ManageSubscription from '../components/engagement/view/widgets/Subscribe/ import { FormCAC } from 'components/FormCAC'; import ScrollToTop from 'components/scrollToTop'; import { RedirectLogin } from './RedirectLogin'; +import withLanguageParam from './LanguageParam'; + +const ManageSubscriptionWrapper = withLanguageParam(ManageSubscription); +const EngagementViewWrapper = withLanguageParam(EngagementView); +const PublicDashboardWrapper = withLanguageParam(PublicDashboard); +const EngagementCommentsWrapper = withLanguageParam(EngagementComments); +const EditSurveyWrapper = withLanguageParam(EditSurvey); +const SurveySubmitWrapper = withLanguageParam(SurveySubmit); +const FormCACWrapper = withLanguageParam(FormCAC); +const RedirectLoginWrapper = withLanguageParam(RedirectLogin); + const UnauthenticatedRoutes = () => { return ( <> @@ -19,20 +30,26 @@ const UnauthenticatedRoutes = () => { } /> } + path="/engagements/:engagementId/:subscriptionStatus/:scriptionKey/:language" + element={} + /> + } /> + } /> + } + /> + } /> + } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> } /> } /> diff --git a/met-web/src/services/userService/index.ts b/met-web/src/services/userService/index.ts index d1dacefee..526752648 100644 --- a/met-web/src/services/userService/index.ts +++ b/met-web/src/services/userService/index.ts @@ -98,7 +98,7 @@ const refreshToken = (dispatch: Dispatch) => { }, 60000); }; -const doLogin = (redirectUri?: string) => KeycloakData.login({ redirectUri: (redirectUri ?? getBaseUrl()) + '/' }); +const doLogin = (redirectUri?: string) => KeycloakData.login({ redirectUri: redirectUri ?? getBaseUrl() }); const doLogout = async () => { // Remove tokens from session storage @@ -108,11 +108,10 @@ const doLogout = async () => { sessionStorage.removeItem('refreshToken'); clearInterval(refreshInterval); const baseURL = getBaseUrl(); - const language = sessionStorage.getItem('languageId'); // Check if the ID token is available and pass it as id_token_hint const logoutOptions = { - redirectUri: `${baseURL}/${language}`, + redirectUri: `${baseURL}`, id_token_hint: idToken, };
(Component: ComponentType
) => { + return (props: P) => { + const languageState: LanguageState = useAppSelector((state) => state.language); + const languageCode = languageState.id; + const rawParams = useParams(); + const params = useMemo(() => rawParams, [rawParams]); + const navigate = useNavigate(); + + useEffect(() => { + const currentUrl = window.location.pathname; + if (languageCode && !currentUrl.includes(languageCode)) { + let newUrl = currentUrl; + + for (const param in params) { + if (params[param as keyof RouteParams]) { + newUrl = newUrl.replace(`:${param}`, params[param as keyof RouteParams] as string); + } + } + + newUrl = newUrl.replace(':language', languageCode); + + navigate(newUrl, { replace: true }); + } + }, [languageCode, navigate, params]); + + return ; + }; +}; + +export default withLanguageParam; diff --git a/met-web/src/routes/NotFound.tsx b/met-web/src/routes/NotFound.tsx index 6bf059988..b58a3b9d7 100644 --- a/met-web/src/routes/NotFound.tsx +++ b/met-web/src/routes/NotFound.tsx @@ -9,7 +9,6 @@ const listItemStyle = { marginBottom: 1 }; const marginStyle = { mr: 2 }; const tenantId = sessionStorage.getItem('tenantId'); -const LanguageId = sessionStorage.getItem('languageId'); const SuggestionsList = ({ translate }: { translate: (key: string) => string }) => ( @@ -18,7 +17,7 @@ const SuggestionsList = ({ translate }: { translate: (key: string) => string }) {translate('notFound.list.0')} {translate('notFound.list.1')}{' '} - + {translate('notFound.list.2')} {' '} {translate('notFound.list.3')} diff --git a/met-web/src/routes/UnauthenticatedRoutes.tsx b/met-web/src/routes/UnauthenticatedRoutes.tsx index b1ef03ef5..98fc9efeb 100644 --- a/met-web/src/routes/UnauthenticatedRoutes.tsx +++ b/met-web/src/routes/UnauthenticatedRoutes.tsx @@ -12,6 +12,17 @@ import ManageSubscription from '../components/engagement/view/widgets/Subscribe/ import { FormCAC } from 'components/FormCAC'; import ScrollToTop from 'components/scrollToTop'; import { RedirectLogin } from './RedirectLogin'; +import withLanguageParam from './LanguageParam'; + +const ManageSubscriptionWrapper = withLanguageParam(ManageSubscription); +const EngagementViewWrapper = withLanguageParam(EngagementView); +const PublicDashboardWrapper = withLanguageParam(PublicDashboard); +const EngagementCommentsWrapper = withLanguageParam(EngagementComments); +const EditSurveyWrapper = withLanguageParam(EditSurvey); +const SurveySubmitWrapper = withLanguageParam(SurveySubmit); +const FormCACWrapper = withLanguageParam(FormCAC); +const RedirectLoginWrapper = withLanguageParam(RedirectLogin); + const UnauthenticatedRoutes = () => { return ( <> @@ -19,20 +30,26 @@ const UnauthenticatedRoutes = () => { } /> } + path="/engagements/:engagementId/:subscriptionStatus/:scriptionKey/:language" + element={} + /> + } /> + } /> + } + /> + } /> + } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> } /> } /> } /> diff --git a/met-web/src/services/userService/index.ts b/met-web/src/services/userService/index.ts index d1dacefee..526752648 100644 --- a/met-web/src/services/userService/index.ts +++ b/met-web/src/services/userService/index.ts @@ -98,7 +98,7 @@ const refreshToken = (dispatch: Dispatch) => { }, 60000); }; -const doLogin = (redirectUri?: string) => KeycloakData.login({ redirectUri: (redirectUri ?? getBaseUrl()) + '/' }); +const doLogin = (redirectUri?: string) => KeycloakData.login({ redirectUri: redirectUri ?? getBaseUrl() }); const doLogout = async () => { // Remove tokens from session storage @@ -108,11 +108,10 @@ const doLogout = async () => { sessionStorage.removeItem('refreshToken'); clearInterval(refreshInterval); const baseURL = getBaseUrl(); - const language = sessionStorage.getItem('languageId'); // Check if the ID token is available and pass it as id_token_hint const logoutOptions = { - redirectUri: `${baseURL}/${language}`, + redirectUri: `${baseURL}`, id_token_hint: idToken, };