Thanks to visit codestin.com
Credit goes to Github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
20 changes: 15 additions & 5 deletions js/apps/account-ui/src/account-security/DeviceActivity.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {
ContinueCancelModal,
useEnvironment,
label,
useEnvironment,
} from "@keycloak/keycloak-ui-shared";
import {
Button,
Expand Down Expand Up @@ -29,6 +29,7 @@ import {
import { useState } from "react";
import { useTranslation } from "react-i18next";

import { AccountEnvironment } from "..";
import { deleteSession, getDevices } from "../api/methods";
import {
ClientRepresentation,
Expand All @@ -42,7 +43,7 @@ import { usePromise } from "../utils/usePromise";

export const DeviceActivity = () => {
const { t } = useTranslation();
const context = useEnvironment();
const context = useEnvironment<AccountEnvironment>();
const { addAlert, addError } = useAccountAlerts();

const [devices, setDevices] = useState<DeviceRepresentation[]>();
Expand Down Expand Up @@ -211,7 +212,10 @@ export const DeviceActivity = () => {
{t("lastAccessedOn")}
</DescriptionListTerm>
<DescriptionListDescription>
{formatDate(new Date(session.lastAccess * 1000))}
{formatDate(
new Date(session.lastAccess * 1000),
context.environment.locale,
)}
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
Expand All @@ -227,15 +231,21 @@ export const DeviceActivity = () => {
{t("started")}
</DescriptionListTerm>
<DescriptionListDescription>
{formatDate(new Date(session.started * 1000))}
{formatDate(
new Date(session.started * 1000),
context.environment.locale,
)}
</DescriptionListDescription>
</DescriptionListGroup>
<DescriptionListGroup>
<DescriptionListTerm>
{t("expires")}
</DescriptionListTerm>
<DescriptionListDescription>
{formatDate(new Date(session.expires * 1000))}
{formatDate(
new Date(session.expires * 1000),
context.environment.locale,
)}
</DescriptionListDescription>
</DescriptionListGroup>
</DescriptionList>
Expand Down
16 changes: 12 additions & 4 deletions js/apps/account-ui/src/account-security/SigningIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,10 @@ import {
} from "../api/representations";
import { EmptyRow } from "../components/datalist/EmptyRow";
import { Page } from "../components/page/Page";
import { TFuncKey } from "../i18n";
import type { TFuncKey } from "../i18n-type";
import { formatDate } from "../utils/formatDate";
import { usePromise } from "../utils/usePromise";
import { AccountEnvironment } from "..";

type MobileLinkProps = {
title: string;
Expand Down Expand Up @@ -84,7 +85,7 @@ const MobileLink = ({ title, onClick, testid }: MobileLinkProps) => {

export const SigningIn = () => {
const { t } = useTranslation();
const context = useEnvironment();
const context = useEnvironment<AccountEnvironment>();
const { login } = context.keycloak;

const [credentials, setCredentials] = useState<CredentialContainer[]>();
Expand Down Expand Up @@ -119,9 +120,16 @@ export const SigningIn = () => {
key={"created" + credential.id}
data-testrole="created-at"
>
<Trans i18nKey="credentialCreatedAt">
<Trans
i18nKey="credentialCreatedAt"
values={{
date: formatDate(
new Date(credential.createdDate),
context.environment.locale,
),
}}
>
<strong className="pf-v5-u-mr-md"></strong>
{{ date: formatDate(new Date(credential.createdDate)) }}
</Trans>
</DataListCell>,
);
Expand Down
10 changes: 7 additions & 3 deletions js/apps/account-ui/src/applications/Applications.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,11 @@ import {
import { useState } from "react";
import { useTranslation } from "react-i18next";

import { AccountEnvironment } from "..";
import { deleteConsent, getApplications } from "../api/methods";
import { ClientRepresentation } from "../api/representations";
import { Page } from "../components/page/Page";
import { TFuncKey } from "../i18n";
import type { TFuncKey } from "../i18n-type";
import { formatDate } from "../utils/formatDate";
import { useAccountAlerts } from "../utils/useAccountAlerts";
import { usePromise } from "../utils/usePromise";
Expand All @@ -42,7 +43,7 @@ type Application = ClientRepresentation & {

export const Applications = () => {
const { t } = useTranslation();
const context = useEnvironment();
const context = useEnvironment<AccountEnvironment>();
const { addAlert, addError } = useAccountAlerts();

const [applications, setApplications] = useState<Application[]>();
Expand Down Expand Up @@ -254,7 +255,10 @@ export const Applications = () => {
{t("accessGrantedOn")}
</DescriptionListTerm>
<DescriptionListDescription>
{formatDate(new Date(application.consent.createdDate))}
{formatDate(
new Date(application.consent.createdDate),
context.environment.locale,
)}
</DescriptionListDescription>
</DescriptionListGroup>
</>
Expand Down
3 changes: 2 additions & 1 deletion js/apps/account-ui/src/content/ContentComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ const Component = ({ modulePath }: ComponentProps) => {
const { environment } = useEnvironment();

const Element = lazy(
() => import(joinPath(environment.resourceUrl, modulePath)),
() =>
import(/* @vite-ignore */ joinPath(environment.resourceUrl, modulePath)),
);
return (
<Suspense fallback={<Spinner />}>
Expand Down
34 changes: 3 additions & 31 deletions js/apps/account-ui/src/environment.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,4 @@
import {
getInjectedEnvironment,
type BaseEnvironment,
} from "@keycloak/keycloak-ui-shared";
import { getInjectedEnvironment } from "@keycloak/keycloak-ui-shared";
import { type AccountEnvironment } from ".";

export type Environment = BaseEnvironment & {
/** The URL to the root of the account console. */
baseUrl: string;
/** The locale of the user */
locale: string;
/** Name of the referrer application in the back link */
referrerName?: string;
/** UR to the referrer application in the back link */
referrerUrl?: string;
/** Feature flags */
features: Feature;
};

export type Feature = {
isRegistrationEmailAsUsername: boolean;
isEditUserNameAllowed: boolean;
isLinkedAccountsEnabled: boolean;
isMyResourcesEnabled: boolean;
deleteAccountAllowed: boolean;
updateEmailFeatureEnabled: boolean;
updateEmailActionEnabled: boolean;
isViewGroupsEnabled: boolean;
isViewOrganizationsEnabled: boolean;
isOid4VciEnabled: boolean;
};

export const environment = getInjectedEnvironment<Environment>();
export const environment = getInjectedEnvironment<AccountEnvironment>();
4 changes: 4 additions & 0 deletions js/apps/account-ui/src/i18n-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This type is aliased to any, so that we can find all the places where we use it.
// In the future all casts to this type should be removed from the code, so
// that we can have a proper type-safe translation function.
export type TFuncKey = any;
21 changes: 16 additions & 5 deletions js/apps/account-ui/src/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,6 @@ const DEFAULT_LOCALE = "en";

type KeyValue = { key: string; value: string };

// This type is aliased to any, so that we can find all the places where we use it.
// In the future all casts to this type should be removed from the code, so
// that we can have a proper type-safe translation function.
export type TFuncKey = any;

export const keycloakLanguageDetector: LanguageDetectorModule = {
type: "languageDetector",

Expand All @@ -22,6 +17,22 @@ export const keycloakLanguageDetector: LanguageDetectorModule = {
},
};

// Listen to language changes and update the environment locale
window.addEventListener("languageChanged", (event: Event) => {
const customEvent = event as CustomEvent<{ language: string }>;
void (async () => {
await i18n.changeLanguage(customEvent.detail.language, (error) => {
if (error) {
console.warn(
"Error(s) loading locale",
customEvent.detail.language,
error,
);
}
});
})();
});

export const i18n = createInstance({
fallbackLng: DEFAULT_LOCALE,
nsSeparator: false,
Expand Down
29 changes: 28 additions & 1 deletion js/apps/account-ui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { BaseEnvironment } from "@keycloak/keycloak-ui-shared";

export { PersonalInfo } from "./personal-info/PersonalInfo";
export { Header } from "./root/Header";
export { PageNav } from "./root/PageNav";
Expand Down Expand Up @@ -54,7 +56,32 @@ export {
savePersonalInfo,
unLinkAccount,
} from "./api/methods";
export type { Environment as AccountEnvironment } from "./environment";
export type AccountEnvironment = BaseEnvironment & {
/** The URL to the root of the account console. */
baseUrl: string;
/** The locale of the user */
locale: string;
/** Name of the referrer application in the back link */
referrerName?: string;
/** UR to the referrer application in the back link */
referrerUrl?: string;
/** Feature flags */
features: Feature;
};

export type Feature = {
isRegistrationEmailAsUsername: boolean;
isEditUserNameAllowed: boolean;
isLinkedAccountsEnabled: boolean;
isMyResourcesEnabled: boolean;
deleteAccountAllowed: boolean;
updateEmailFeatureEnabled: boolean;
updateEmailActionEnabled: boolean;
isViewGroupsEnabled: boolean;
isViewOrganizationsEnabled: boolean;
isOid4VciEnabled: boolean;
};

export { KeycloakProvider, useEnvironment } from "@keycloak/keycloak-ui-shared";
export { useAccountAlerts } from "./utils/useAccountAlerts";
export { usePromise } from "./utils/usePromise";
Expand Down
4 changes: 2 additions & 2 deletions js/apps/account-ui/src/organizations/Organizations.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@ import {
} from "@keycloak/keycloak-ui-shared";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import { AccountEnvironment } from "..";
import { getUserOrganizations } from "../api/methods";
import { Page } from "../components/page/Page";
import { Environment } from "../environment";
import { usePromise } from "../utils/usePromise";

export const Organizations = () => {
const { t } = useTranslation();
const context = useEnvironment<Environment>();
const context = useEnvironment<AccountEnvironment>();

const [userOrgs, setUserOrgs] = useState<OrganizationRepresentation[]>([]);

Expand Down
14 changes: 6 additions & 8 deletions js/apps/account-ui/src/personal-info/PersonalInfo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@ import {
UserRepresentation,
} from "../api/representations";
import { Page } from "../components/page/Page";
import type { Environment } from "../environment";
import { TFuncKey, i18n } from "../i18n";
import { type AccountEnvironment } from "..";
import type { TFuncKey } from "../i18n-type";
import { useAccountAlerts } from "../utils/useAccountAlerts";
import { usePromise } from "../utils/usePromise";

export const PersonalInfo = () => {
const { t } = useTranslation();
const context = useEnvironment<Environment>();
const context = useEnvironment<AccountEnvironment>();
const [userProfileMetadata, setUserProfileMetadata] =
useState<UserProfileMetadata>();
const [supportedLocales, setSupportedLocales] = useState<string[]>([]);
Expand Down Expand Up @@ -72,11 +72,9 @@ export const PersonalInfo = () => {
await savePersonalInfo(context, { ...user, attributes });
const locale = attributes["locale"]?.toString();
if (locale) {
await i18n.changeLanguage(locale, (error) => {
if (error) {
console.warn("Error(s) loading locale", locale, error);
}
});
window.dispatchEvent(
new CustomEvent("languageChanged", { detail: { language: locale } }),
);
}
await context.keycloak.updateToken();
addAlert(t("accountUpdatedMessage"));
Expand Down
3 changes: 2 additions & 1 deletion js/apps/account-ui/src/root/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,13 @@ import { ExternalLinkSquareAltIcon } from "@patternfly/react-icons";
import { useTranslation } from "react-i18next";
import { useHref } from "react-router-dom";

import { environment } from "../environment";
import { AccountEnvironment } from "..";
import { joinPath } from "../utils/joinPath";

import style from "./header.module.css";

const ReferrerLink = () => {
const { environment } = useEnvironment<AccountEnvironment>();
const { t } = useTranslation();

return environment.referrerUrl ? (
Expand Down
Loading
Loading