diff --git a/packages/core/package.json b/packages/core/package.json index 9ee83335..b921c6b9 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -36,6 +36,7 @@ "@rollup/plugin-dynamic-import-vars": "^2.1.2", "@rollup/plugin-node-resolve": "^15.2.3", "@rollup/plugin-typescript": "^11.1.6", + "@types/lodash.isempty": "^4.4.9", "@types/lodash.merge": "^4.6.9", "@types/node": "^20.12.7", "@wso2/eslint-plugin": "https://gitpkg.now.sh/brionmario/wso2-ui-configs/packages/eslint-plugin?fa0b844715320a3953d6d055997c0770f8695082", @@ -44,7 +45,7 @@ "prettier": "^3.2.5", "rollup-plugin-dts": "^6.1.0", "tslib": "^2.6.2", - "typescript": "^5.4.5" + "typescript": "^5.1.6" }, "publishConfig": { "access": "public" @@ -52,6 +53,7 @@ "dependencies": { "@asgardeo/auth-js": "^5.0.1", "csstype": "^3.1.3", + "lodash.isempty": "^4.4.0", "lodash.merge": "^4.6.2" } } diff --git a/packages/core/src/api/branding-preference-text.ts b/packages/core/src/api/get-branding-preference-text.ts similarity index 100% rename from packages/core/src/api/branding-preference-text.ts rename to packages/core/src/api/get-branding-preference-text.ts diff --git a/packages/core/src/api/branding-preference.ts b/packages/core/src/api/get-branding-preference.ts similarity index 100% rename from packages/core/src/api/branding-preference.ts rename to packages/core/src/api/get-branding-preference.ts diff --git a/packages/core/src/api/profile.ts b/packages/core/src/api/get-profile-information.ts similarity index 100% rename from packages/core/src/api/profile.ts rename to packages/core/src/api/get-profile-information.ts diff --git a/packages/core/src/api/public-api.ts b/packages/core/src/api/public-api.ts index f87cf4a4..0eef3ae9 100644 --- a/packages/core/src/api/public-api.ts +++ b/packages/core/src/api/public-api.ts @@ -18,6 +18,7 @@ export {default as authorize} from './authorize'; export {default as authenticate} from './authenticate'; -export {default as getBrandingPreference} from './branding-preference'; -export {default as getProfileInformation} from './profile'; -export {default as getBrandingPreferenceText} from './branding-preference-text'; +export {default as getBrandingPreference} from './get-branding-preference'; +export {default as getProfileInformation} from './get-profile-information'; +export {default as getBrandingPreferenceText} from './get-branding-preference-text'; +export {default as signOut} from './sign-out'; diff --git a/packages/core/src/api/sign-out.ts b/packages/core/src/api/sign-out.ts new file mode 100644 index 00000000..c5f4b771 --- /dev/null +++ b/packages/core/src/api/sign-out.ts @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {AuthClient, ResponseMode} from '../auth-client'; +import AsgardeoUIException from '../exception'; + +/** + * Sign out the user. + * + * This function sends a signout request to the server. + * + * @returns {Promise} A promise that resolves when the sign out process is complete. + * + * @example + * signOut() + * .then(() => { + * console.log('Signed out!'); + * }) + * .catch((error) => { + * console.error('Failed to sign out:', error); + * }); + */ +const signOut = async (): Promise => { + let response: Response; + let signOutUrl: string; + + const headers: Headers = new Headers(); + headers.append('Accept', 'application/json'); + headers.append('Content-Type', 'application/x-www-form-urlencoded'); + + const formBody: URLSearchParams = new URLSearchParams(); + + try { + formBody.append('id_token_hint', await AuthClient.getInstance().getIDToken()); + formBody.append('client_id', (await AuthClient.getInstance().getDataLayer().getConfigData()).clientID); + formBody.append('response_mode', ResponseMode.direct); + } catch (error) { + throw new AsgardeoUIException('JS_UI_CORE-SIGNOUT-SO-IV', 'Failed to build the body of the signout request.'); + } + + const requestOptions: RequestInit = { + body: formBody.toString(), + headers, + method: 'POST', + }; + + try { + signOutUrl = (await AuthClient.getInstance().getOIDCServiceEndpoints()).endSessionEndpoint; + } catch (error) { + throw new AsgardeoUIException('JS_UI_CORE-SIGNOUT-SO-NF', 'Failed to retrieve the sign out endpoint.'); + } + + try { + response = await fetch(signOutUrl, requestOptions); + } catch (error) { + throw new AsgardeoUIException('JS_UI_CORE-SIGNOUT-SO-NE', 'Failed to send a request to the sign out endpoint.'); + } + + if (!response.ok) { + throw new AsgardeoUIException( + 'JS_UI_CORE-SIGNOUT-SO-HE', + 'Failed to receive a successful response from the sign out endpoint.', + ); + } +}; + +export default signOut; diff --git a/packages/core/src/branding/get-branding-css.ts b/packages/core/src/branding/get-branding-css.ts new file mode 100644 index 00000000..c0219905 --- /dev/null +++ b/packages/core/src/branding/get-branding-css.ts @@ -0,0 +1,108 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import {BrandingPreferenceThemeInterface, ThemeConfigInterface} from '../models/branding-api-response'; +import isEmpty from 'lodash.isempty'; + +const getBrandingCSS = (theme: BrandingPreferenceThemeInterface): string => { + if (!theme) { + return ''; + } + const activeTheme: ThemeConfigInterface = theme[theme.activeTheme]; + + const footerFontColor: string = !isEmpty(activeTheme.footer.font.color) ? activeTheme.footer.font.color : 'inherit'; + const headingFontColor: string = !isEmpty(activeTheme.typography.heading.font.color) + ? activeTheme.typography.heading.font.color + : 'inherit'; + const loginBoxFontColor: string = !isEmpty(activeTheme.loginBox.font.color) + ? activeTheme.loginBox.font.color + : 'inherit'; + const inputBaseFontColor: string = !isEmpty(activeTheme.inputs.base.font.color) + ? activeTheme.inputs.base.font.color + : 'inherit'; + const inputBaseLabelFontColor: string = !isEmpty(activeTheme.inputs.base.labels.font.color) + ? activeTheme.inputs.base.labels.font.color + : 'inherit'; + + return ` + ${activeTheme.typography.font.importURL ? `@import url(${activeTheme.typography.font.importURL});` : ''} + + :root { + --asg-colors-primary-main: ${activeTheme.colors.primary.main}; + --asg-colors-secondary-main: ${activeTheme.colors.secondary.main}; + --asg-colors-background-body-main: ${activeTheme.colors.background?.body?.main}; + --asg-colors-background-surface-main: ${activeTheme.colors.background?.surface?.main}; + --asg-colors-background-surface-light: ${activeTheme.colors.background?.surface?.light}; + --asg-colors-background-surface-dark: ${activeTheme.colors.background?.surface?.dark}; + --asg-colors-background-surface-inverted: ${activeTheme.colors.background?.surface?.inverted}; + --asg-colors-outlined-default: ${activeTheme.colors.outlined?.default}; + --asg-colors-text-primary: ${activeTheme.colors.text?.primary}; + --asg-colors-text-secondary: ${activeTheme.colors.text?.secondary}; + --asg-colors-alerts-error-main: ${activeTheme.colors.alerts?.error?.main}; + --asg-colors-alerts-neutral-main: ${activeTheme.colors.alerts?.neutral?.main}; + --asg-colors-alerts-info-main: ${activeTheme.colors.alerts?.info?.main}; + --asg-colors-alerts-warning-main: ${activeTheme.colors.alerts?.warning?.main}; + --asg-colors-illustrations-primary-main: ${activeTheme.colors.illustrations?.primary?.main}; + --asg-colors-illustrations-secondary-main: ${activeTheme.colors.illustrations?.secondary?.main}; + --asg-colors-illustrations-accent1-main: ${activeTheme.colors.illustrations?.accent1?.main}; + --asg-colors-illustrations-accent2-main: ${activeTheme.colors.illustrations?.accent2?.main}; + --asg-colors-illustrations-accent3-main: ${activeTheme.colors.illustrations?.accent3?.main}; + + /* Components */ + --asg-footer-text-color: ${footerFontColor}; + --asg-footer-border-color: ${activeTheme.footer?.border?.borderColor || 'var(--asg-colors-outlined-default)'}; + --asg-primary-font-family: ${activeTheme.typography.font.fontFamily}; + --asg-heading-text-color: ${headingFontColor}; + --asg-primary-button-base-text-color: ${activeTheme.buttons.primary.base.font.color}; + --asg-primary-button-base-border-radius: ${activeTheme.buttons.primary.base.border.borderRadius}; + --asg-secondary-button-base-text-color: ${activeTheme.buttons.secondary.base.font.color}; + --asg-secondary-button-base-border-radius: ${activeTheme.buttons.secondary.base.border.borderRadius}; + --asg-external-login-button-base-background-color: ${ + activeTheme.buttons.externalConnection.base.background.backgroundColor + }; + --asg-external-login-button-base-text-color: ${activeTheme.buttons.externalConnection.base.font.color}; + --asg-external-login-button-base-border-radius: ${activeTheme.buttons.externalConnection.base.border.borderRadius}; + --asg-login-box-background-color: ${ + activeTheme.loginBox?.background?.backgroundColor || 'var(--asg-colors-background-surface-main)' + }; + --asg-login-box-border-color: ${activeTheme.loginBox?.border?.borderColor || 'var(--asg-colors-outlined-default)'}; + --asg-login-box-border-width: ${activeTheme.loginBox.border.borderWidth}; + --asg-login-box-border-style: solid; + --asg-login-box-border-radius: ${activeTheme.loginBox.border.borderRadius}; + --asg-login-box-text-color: ${loginBoxFontColor}; + --asg-login-page-background-color: ${ + activeTheme.loginPage?.background?.backgroundColor || 'var(--asg-colors-background-body-main)' + }; + --asg-login-page-font-color: ${activeTheme.loginPage?.font?.color || 'var(--asg-colors-text-primary)'}; + --asg-input-field-base-text-color: ${inputBaseFontColor || 'var(--asg-colors-text-primary)'}; + --asg-input-field-base-background-color: ${activeTheme.inputs.base.background.backgroundColor}; + --asg-input-field-base-label-text-color: ${inputBaseLabelFontColor}; + --asg-input-field-base-border-color: ${ + activeTheme.inputs.base.border.borderColor || 'var(--asg-colors-outlined-default)' + }; + --asg-input-field-base-border-radius: ${activeTheme.inputs.base.border.borderRadius}; + --language-selector-background-color: var(--asg-login-page-background-color) !important; + --language-selector-text-color: var(--asg-footer-text-color) !important; + --language-selector-border-color: var(--asg-colors-primary-main) !important; + + /* Oxygen UI variables */ + --oxygen-palette-text-primary: ${activeTheme.colors.text?.primary}; +} `; +}; + +export default getBrandingCSS; diff --git a/packages/core/src/branding/branding.ts b/packages/core/src/branding/get-branding.ts similarity index 96% rename from packages/core/src/branding/branding.ts rename to packages/core/src/branding/get-branding.ts index 60e224ec..c9516de2 100644 --- a/packages/core/src/branding/branding.ts +++ b/packages/core/src/branding/get-branding.ts @@ -18,7 +18,7 @@ import merge from 'lodash.merge'; import DEFAULT_BRANDING from './default-branding/default-branding'; -import getBrandingPreference from '../api/branding-preference'; +import getBrandingPreference from '../api/get-branding-preference'; import {AuthClient} from '../auth-client'; import {BrandingPreferenceAPIResponseInterface} from '../models/branding-api-response'; import {Customization, GetBranding} from '../models/customization'; diff --git a/packages/core/src/branding/public.ts b/packages/core/src/branding/public.ts new file mode 100644 index 00000000..280677f5 --- /dev/null +++ b/packages/core/src/branding/public.ts @@ -0,0 +1,20 @@ +/** + * Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com). + * + * WSO2 LLC. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export {default as getBranding} from './get-branding'; +export {default as getBrandingCSS} from './get-branding-css'; diff --git a/packages/core/src/i18n/i18n.ts b/packages/core/src/i18n/get-localization.ts similarity index 96% rename from packages/core/src/i18n/i18n.ts rename to packages/core/src/i18n/get-localization.ts index 1efafafb..934eb612 100644 --- a/packages/core/src/i18n/i18n.ts +++ b/packages/core/src/i18n/get-localization.ts @@ -17,10 +17,10 @@ */ import merge from 'lodash.merge'; -import getBrandingPreferenceText from '../api/branding-preference-text'; +import {GetLocalization, TextObject} from './screens/model'; +import getBrandingPreferenceText from '../api/get-branding-preference-text'; import {AuthClient} from '../auth-client'; import {BrandingPreferenceTextAPIResponse} from '../models/branding-text-api-response'; -import {GetLocalization, TextObject} from './screens/model'; /** * Fetch and merge branding properties. diff --git a/packages/core/src/i18n/public.ts b/packages/core/src/i18n/public.ts index 34ffb7ba..a8c9cec7 100644 --- a/packages/core/src/i18n/public.ts +++ b/packages/core/src/i18n/public.ts @@ -18,4 +18,4 @@ export * from './screens/model'; export * from './screens/keys'; -export {default as getLocalization} from './i18n'; +export {default as getLocalization} from './get-localization'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 2b65a8a7..9f27cbb7 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -17,7 +17,7 @@ */ export * from './api/public-api'; -export {default as getBranding} from './branding/branding'; +export * from './branding/public'; export * from './i18n/public'; export * from './auth-client'; export * from './models/public-models'; diff --git a/packages/core/src/models/customization.ts b/packages/core/src/models/customization.ts index b3f37bc3..2a1fc058 100644 --- a/packages/core/src/models/customization.ts +++ b/packages/core/src/models/customization.ts @@ -45,7 +45,7 @@ export interface Customization { /** * Preference type. */ - type?: RecursivePartial; + type?: BrandingPreferenceTypes; } /** diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index 6bc65fc5..62ff812c 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -22,7 +22,6 @@ "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "resolveJsonModule": true, - "baseUrl": ".", "types": ["node", "jest"], }, "exclude": ["node_modules", "tmp"], diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7f156731..cfb9d89b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,6 +20,9 @@ importers: csstype: specifier: ^3.1.3 version: 3.1.3 + lodash.isempty: + specifier: ^4.4.0 + version: 4.4.0 lodash.merge: specifier: ^4.6.2 version: 4.6.2 @@ -36,6 +39,9 @@ importers: '@rollup/plugin-typescript': specifier: ^11.1.6 version: 11.1.6(rollup@4.16.4)(tslib@2.6.2)(typescript@5.4.5) + '@types/lodash.isempty': + specifier: ^4.4.9 + version: 4.4.9 '@types/lodash.merge': specifier: ^4.6.9 version: 4.6.9 @@ -61,7 +67,7 @@ importers: specifier: ^2.6.2 version: 2.6.2 typescript: - specifier: ^5.4.5 + specifier: ^5.1.6 version: 5.4.5 packages/react: @@ -858,6 +864,12 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true + /@types/lodash.isempty@4.4.9: + resolution: {integrity: sha512-DPSFfnT2JmZiAWNWOU8IRZws/Ha6zyGF5m06TydfsY+0dVoQqby2J61Na2QU4YtwiZ+moC6cJS6zWYBJq4wBVw==} + dependencies: + '@types/lodash': 4.17.0 + dev: true + /@types/lodash.merge@4.6.9: resolution: {integrity: sha512-23sHDPmzd59kUgWyKGiOMO2Qb9YtqRO/x4IhkgNUiPQ1+5MUVqi6bCZeq9nBJ17msjIMbEIO5u+XW4Kz6aGUhQ==} dependencies: @@ -3116,6 +3128,10 @@ packages: p-locate: 5.0.0 dev: true + /lodash.isempty@4.4.0: + resolution: {integrity: sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==} + dev: false + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}