diff --git a/src/apps/admin/src/AdminApp.tsx b/src/apps/admin/src/AdminApp.tsx index 564392814..e255dad1d 100644 --- a/src/apps/admin/src/AdminApp.tsx +++ b/src/apps/admin/src/AdminApp.tsx @@ -3,7 +3,7 @@ import { Outlet, Routes } from 'react-router-dom' import { routerContext, RouterContextData } from '~/libs/core' -import { AdminAppContextProvider, Layout, SWRConfigProvider } from './lib' +import { AdminAppContextProvider, LayoutProps, SWRConfigProvider, useLayout } from './lib' import { toolTitle } from './admin-app.routes' import './lib/styles/index.scss' @@ -14,6 +14,7 @@ const AdminApp: FC = () => { const { getChildRoutes }: RouterContextData = useContext(routerContext) // eslint-disable-next-line react-hooks/exhaustive-deps -- missing dependency: getChildRoutes const childRoutes = useMemo(() => getChildRoutes(toolTitle), []) + const { Layout }: { Layout: FC } = useLayout() useEffect(() => { document.body.classList.add('admin-app') diff --git a/src/apps/admin/src/admin-app.routes.tsx b/src/apps/admin/src/admin-app.routes.tsx index a6f0023dd..b64649b3b 100644 --- a/src/apps/admin/src/admin-app.routes.tsx +++ b/src/apps/admin/src/admin-app.routes.tsx @@ -1,3 +1,4 @@ +import { baseDetailPath, createBadgePath } from '~/apps/gamification-admin' import { AppSubdomain, ToolTitle } from '~/config' import { lazyLoad, @@ -9,12 +10,15 @@ import { import { billingAccountRouteId, + gamificationAdminRouteId, manageChallengeRouteId, manageReviewRouteId, permissionManagementRouteId, + platformRouteId, rootRoute, userManagementRouteId, } from './config/routes.config' +import { platformSkillRouteId } from './platform/routes.config' const AdminApp: LazyLoadedComponent = lazyLoad(() => import('./AdminApp')) @@ -107,6 +111,24 @@ const PermissionAddGroupMembersPage: LazyLoadedComponent = lazyLoad( 'PermissionAddGroupMembersPage', ) +const Platform: LazyLoadedComponent = lazyLoad(() => import('./platform/Platform')) +const SkillManagement: LazyLoadedComponent = lazyLoad( + () => import('./platform/skill-management/SkillManagement'), +) +const SkillManagementLandingPage: LazyLoadedComponent = lazyLoad( + () => import('./platform/skill-management/LandingPage'), + 'LandingPage', +) +const BadgeDetailPage: LazyLoadedComponent = lazyLoad( + () => import('../../gamification-admin/src/pages/badge-detail/BadgeDetailPage'), +) +const BadgeListingPage: LazyLoadedComponent = lazyLoad( + () => import('../../gamification-admin/src/pages/badge-listing/BadgeListingPage'), +) +const CreateBadgePage: LazyLoadedComponent = lazyLoad( + () => import('../../gamification-admin/src/pages/create-badge/CreateBadgePage'), +) + export const toolTitle: string = ToolTitle.admin export const adminRoutes: ReadonlyArray = [ @@ -256,6 +278,43 @@ export const adminRoutes: ReadonlyArray = [ id: permissionManagementRouteId, route: permissionManagementRouteId, }, + + // Platform Management Module + { + children: [ + { + children: [ + { + element: , + id: 'skills-landing-page', + route: '', + }, + ], + element: , + id: platformSkillRouteId, + route: platformSkillRouteId, + }, + { + element: ( + + ), + route: gamificationAdminRouteId, + }, + { + element: , + route: `${gamificationAdminRouteId}${createBadgePath}`, + }, + { + element: , + route: `${gamificationAdminRouteId}${baseDetailPath}/:id`, + }, + ], + element: , + id: platformRouteId, + route: platformRouteId, + }, ], domain: AppSubdomain.admin, element: , diff --git a/src/apps/admin/src/config/routes.config.ts b/src/apps/admin/src/config/routes.config.ts index 080a79e7d..fe857eb00 100644 --- a/src/apps/admin/src/config/routes.config.ts +++ b/src/apps/admin/src/config/routes.config.ts @@ -13,3 +13,5 @@ export const manageReviewRouteId = 'review-management' export const userManagementRouteId = 'user-management' export const billingAccountRouteId = 'billing-account' export const permissionManagementRouteId = 'permission-management' +export const gamificationAdminRouteId = 'gamification-admin' +export const platformRouteId = 'platform' diff --git a/src/apps/admin/src/lib/components/DialogEditUserEmail/DialogEditUserEmail.module.scss b/src/apps/admin/src/lib/components/DialogEditUserEmail/DialogEditUserEmail.module.scss index 917d059dd..2104049c7 100644 --- a/src/apps/admin/src/lib/components/DialogEditUserEmail/DialogEditUserEmail.module.scss +++ b/src/apps/admin/src/lib/components/DialogEditUserEmail/DialogEditUserEmail.module.scss @@ -5,6 +5,13 @@ position: relative; } +.blockForm { + display: flex; + flex-direction: column; + gap: 20px; + position: relative; +} + .actionButtons { display: flex; justify-content: flex-end; diff --git a/src/apps/admin/src/lib/components/DialogEditUserEmail/DialogEditUserEmail.tsx b/src/apps/admin/src/lib/components/DialogEditUserEmail/DialogEditUserEmail.tsx index 81157ab45..1ea8baac3 100644 --- a/src/apps/admin/src/lib/components/DialogEditUserEmail/DialogEditUserEmail.tsx +++ b/src/apps/admin/src/lib/components/DialogEditUserEmail/DialogEditUserEmail.tsx @@ -67,7 +67,7 @@ export const DialogEditUserEmail: FC = (props: Props) => { className={classNames(styles.container, props.className)} onSubmit={handleSubmit(onSubmit)} > -
+
void + userInfo: UserInfo + providers: SSOLoginProvider[] +} + +export const DialogEditUserSSOLogin: FC = (props: Props) => { + const { width: screenWidth }: WindowSize = useWindowSize() + const isTablet = useMemo(() => screenWidth <= 900, [screenWidth]) + const { + ssoUserLogins, + isLoading: isFetching, + isAdding, + isRemoving, + doAddSSOUserLogin, + doUpdateSSOUserLogin, + doRemoveSSOUserLogin, + }: useManageUserSSOLoginProps = useManageUserSSOLogin(props.userInfo) + const isRemovingBool = useMemo( + () => _.some(isRemoving, value => value === true), + [isRemoving], + ) + const isLoading = useMemo( + () => isFetching || isAdding || isRemovingBool, + [isFetching, isAdding, isRemovingBool], + ) + + const [showAddForm, setShowAddForm] = useState(false) + const [showEditForm, setShowEditForm] = useState() + + const handleClose = useCallback(() => { + if (!isLoading) { + props.setOpen(false) + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [isLoading]) + const columns = useMemo[]>( + () => [ + { + className: styles.tableCell, + label: 'User ID', + propertyName: 'userId', + type: 'text', + }, + { + className: styles.tableCell, + label: 'Name', + propertyName: 'name', + type: 'text', + }, + { + className: styles.tableCell, + label: 'Provider', + propertyName: 'provider', + type: 'text', + }, + { + className: styles.tableCell, + label: 'Email', + propertyName: 'email', + type: 'text', + }, + { + className: styles.blockAction, + label: 'Actions', + renderer: (data: SSOUserLogin) => ( +
+
+ ), + type: 'action', + }, + ], + [isAdding, isRemoving, doRemoveSSOUserLogin], + ) + + const columnsMobile = useMemo[][]>( + () => columns.map(column => { + if (column.label === 'Actions') { + return [ + { + ...column, + colSpan: 2, + mobileType: 'last-value', + }, + ] + } + + return [ + { + ...column, + className: '', + label: `${column.label as string} label`, + mobileType: 'label', + renderer: () => ( +
+ {column.label as string} + : +
+ ), + type: 'element', + }, + { + ...column, + mobileType: 'last-value', + }, + ] + }), + [columns], + ) + + const cancelEditForm = useCallback(() => { + setShowEditForm(undefined) + setShowAddForm(false) + }, [setShowAddForm, setShowEditForm]) + + return ( + +
+ {isFetching ? ( +
+ +
+ ) : ( + <> + {ssoUserLogins.length ? ( + <> + {isTablet ? ( + + ) : ( + + )} + + ) : ( +
No SSO logins
+ )} + + )} + + {showAddForm || showEditForm ? ( + + ) : ( + + )} +
+ +
+ + {(isAdding || isRemovingBool) && ( +
+ +
+ )} + + + ) +} + +export default DialogEditUserSSOLogin diff --git a/src/apps/admin/src/lib/components/DialogEditUserSSOLogin/index.ts b/src/apps/admin/src/lib/components/DialogEditUserSSOLogin/index.ts new file mode 100644 index 000000000..5c5b5b91d --- /dev/null +++ b/src/apps/admin/src/lib/components/DialogEditUserSSOLogin/index.ts @@ -0,0 +1 @@ +export { default as DialogEditUserSSOLogin } from './DialogEditUserSSOLogin' diff --git a/src/apps/admin/src/lib/components/FormAddSSOLogin/FormAddSSOLogin.module.scss b/src/apps/admin/src/lib/components/FormAddSSOLogin/FormAddSSOLogin.module.scss new file mode 100644 index 000000000..e20915d75 --- /dev/null +++ b/src/apps/admin/src/lib/components/FormAddSSOLogin/FormAddSSOLogin.module.scss @@ -0,0 +1,13 @@ +.container { + display: flex; + flex-direction: column; + gap: 20px; + position: relative; + width: 100%; +} + +.actionButtons { + display: flex; + justify-content: flex-end; + gap: 6px; +} diff --git a/src/apps/admin/src/lib/components/FormAddSSOLogin/FormAddSSOLogin.tsx b/src/apps/admin/src/lib/components/FormAddSSOLogin/FormAddSSOLogin.tsx new file mode 100644 index 000000000..289b41cee --- /dev/null +++ b/src/apps/admin/src/lib/components/FormAddSSOLogin/FormAddSSOLogin.tsx @@ -0,0 +1,173 @@ +/** + * Form Add SSO Login. + */ +import { FC, useCallback, useEffect, useMemo } from 'react' +import { + Controller, + ControllerRenderProps, + useForm, + UseFormReturn, +} from 'react-hook-form' +import _ from 'lodash' +import classNames from 'classnames' + +import { Button, InputSelectReact, InputText } from '~/libs/ui' +import { yupResolver } from '@hookform/resolvers/yup' + +import { FormAddSSOLoginData } from '../../models/FormAddSSOLoginData.model' +import { SSOLoginProvider, SSOUserLogin } from '../../models' +import { formAddSSOLoginSchema } from '../../utils' + +import styles from './FormAddSSOLogin.module.scss' + +interface Props { + className?: string + isAdding: boolean + onSubmit: (data: FormAddSSOLoginData) => void + onCancel: () => void + providers: SSOLoginProvider[] + editingData?: SSOUserLogin +} + +export const FormAddSSOLogin: FC = (props: Props) => { + const isEditing = !!props.editingData + const providerOptions = useMemo( + () => props.providers.map(item => ({ + label: item.name, + value: item.name, + })), + [props.providers], + ) + const { + register, + handleSubmit, + control, + reset, + formState: { errors, isValid, isDirty }, + }: UseFormReturn = useForm({ + defaultValues: { + email: '', + name: '', + provider: '', + userId: '', + }, + mode: 'all', + resolver: yupResolver(formAddSSOLoginSchema), + }) + const onSubmit = useCallback( + (data: FormAddSSOLoginData) => { + props.onSubmit(data) + }, + [props.onSubmit], + ) + + useEffect(() => { + if (props.editingData) { + reset({ + email: props.editingData.email, + name: props.editingData.name, + provider: props.editingData.provider, + userId: props.editingData.userId, + }) + } + }, [props.editingData]) + + return ( +
+ + {isEditing ? 'Edit' : 'Add'} + {' '} + SSO Login + +
+ + + + }) { + return ( + + ) + }} + /> + +
+
+ + +
+ + ) +} + +export default FormAddSSOLogin diff --git a/src/apps/admin/src/lib/components/FormAddSSOLogin/index.ts b/src/apps/admin/src/lib/components/FormAddSSOLogin/index.ts new file mode 100644 index 000000000..6a538903b --- /dev/null +++ b/src/apps/admin/src/lib/components/FormAddSSOLogin/index.ts @@ -0,0 +1 @@ +export { default as FormAddSSOLogin } from './FormAddSSOLogin' diff --git a/src/apps/admin/src/lib/components/UsersTable/UsersTable.tsx b/src/apps/admin/src/lib/components/UsersTable/UsersTable.tsx index 4ae53a4cf..aa65b2dee 100644 --- a/src/apps/admin/src/lib/components/UsersTable/UsersTable.tsx +++ b/src/apps/admin/src/lib/components/UsersTable/UsersTable.tsx @@ -21,15 +21,18 @@ import { CopyButton } from '../CopyButton' import { DialogEditUserEmail } from '../DialogEditUserEmail' import { DialogEditUserRoles } from '../DialogEditUserRoles' import { DialogEditUserGroups } from '../DialogEditUserGroups' +import { DialogEditUserSSOLogin } from '../DialogEditUserSSOLogin' import { DialogEditUserTerms } from '../DialogEditUserTerms' import { DialogEditUserStatus } from '../DialogEditUserStatus' import { DialogUserStatusHistory } from '../DialogUserStatusHistory' import { DropdownMenuButton } from '../common/DropdownMenuButton' -import { useTableFilterLocal, useTableFilterLocalProps } from '../../hooks' +import { useOnComponentDidMount, useTableFilterLocal, useTableFilterLocalProps } from '../../hooks' import { TABLE_DATE_FORMAT } from '../../../config/index.config' -import { UserInfo } from '../../models' +import { SSOLoginProvider, UserInfo } from '../../models' import { Pagination } from '../common/Pagination' import { ReactComponent as RectangleListRegularIcon } from '../../assets/i/rectangle-list-regular-icon.svg' +import { fetchSSOLoginProviders } from '../../services' +import { handleError } from '../../utils' import styles from './UsersTable.module.scss' @@ -47,6 +50,7 @@ interface Props { export const UsersTable: FC = props => { const [colWidth, setColWidth] = useState({}) + const [ssoLoginProviders, setSsoLoginProviders] = useState([]) const [showDialogEditUserEmail, setShowDialogEditUserEmail] = useState< UserInfo | undefined >() @@ -56,6 +60,9 @@ export const UsersTable: FC = props => { const [showDialogEditUserGroups, setShowDialogEditUserGroups] = useState< UserInfo | undefined >() + const [showDialogEditUserSSOLogin, setShowDialogEditSSOLogin] = useState< + UserInfo | undefined + >() const [showDialogEditUserTerms, setShowDialogEditUserTerms] = useState< UserInfo | undefined >() @@ -273,6 +280,8 @@ export const UsersTable: FC = props => { setShowDialogEditUserGroups(data) } else if (item === 'Terms') { setShowDialogEditUserTerms(data) + } else if (item === 'SSO Logins') { + setShowDialogEditSSOLogin(data) } else if (item === 'Deactivate') { setShowDialogEditUserStatus(data) } else if (item === 'Activate') { @@ -298,6 +307,7 @@ export const UsersTable: FC = props => { 'Roles', 'Groups', 'Terms', + 'SSO Logins', ...(data.active ? ['Deactivate'] : ['Activate']), @@ -318,6 +328,7 @@ export const UsersTable: FC = props => { 'Roles', 'Groups', 'Terms', + 'SSO Logins', ]} onSelectOption={onSelectOption} > @@ -359,6 +370,16 @@ export const UsersTable: FC = props => { [isTablet, isMobile], ) + useOnComponentDidMount(() => { + fetchSSOLoginProviders() + .then(result => { + setSsoLoginProviders(result) + }) + .catch(e => { + handleError(e) + }) + }) + return (
= props => { userInfo={showDialogEditUserGroups} /> )} + {showDialogEditUserSSOLogin && ( + + )} {showDialogEditUserTerms && ( = props => ( - <>{props.children} -) +export const NullLayout: FC = props => <>{props.children} + +export type LayoutProps = PropsWithChildren<{ + classes?: { // eslint-disable-line react/no-unused-prop-types -- it's actually used + contentClass?: string + innerClass?: string + outerClass?: string + layoutClass?: string + mainClass?: string + } +}> -export const Layout: FC = props => ( +export const Layout: FC = props => ( -
+
-
+
{props.children}
) +export const PlatformLayout: FC = props => ( + + {props.children} + +) + +export const PlatformSkillsLayout: FC = props => ( + + {props.children} + +) + +export function useLayout(): { Layout: FC } { + const routerContextData: RouterContextData = useContext(routerContext) + + if (!routerContextData.initialized) return { Layout } + + const platformBaseRouteId = EnvironmentConfig.SUBDOMAIN === AppSubdomain.admin + ? `/${platformRouteId}` + : `/${AppSubdomain.admin}/${platformRouteId}` + + const skillManagementRouteId = EnvironmentConfig.SUBDOMAIN === AppSubdomain.admin + ? `/${platformRouteId}/${platformSkillRouteId}` + : `/${AppSubdomain.admin}/${platformRouteId}/${platformSkillRouteId}` + + if (window.location.pathname.toLowerCase() + .startsWith(skillManagementRouteId.toLowerCase())) { + return { Layout: PlatformSkillsLayout } + } + + if (window.location.pathname.toLowerCase() + .startsWith(platformBaseRouteId.toLowerCase())) { + return { Layout: PlatformLayout } + } + + return { Layout } +} + export default Layout diff --git a/src/apps/admin/src/lib/components/common/Tab/config/system-admin-tabs-config.ts b/src/apps/admin/src/lib/components/common/Tab/config/system-admin-tabs-config.ts index fe9bbbeb2..b3f1b0de2 100644 --- a/src/apps/admin/src/lib/components/common/Tab/config/system-admin-tabs-config.ts +++ b/src/apps/admin/src/lib/components/common/Tab/config/system-admin-tabs-config.ts @@ -3,11 +3,14 @@ import _ from 'lodash' import { TabsNavItem } from '~/libs/ui' import { billingAccountRouteId, + gamificationAdminRouteId, manageChallengeRouteId, manageReviewRouteId, permissionManagementRouteId, + platformRouteId, userManagementRouteId, } from '~/apps/admin/src/config/routes.config' +import { platformSkillRouteId } from '~/apps/admin/src/platform/routes.config' export const SystemAdminTabsConfig: TabsNavItem[] = [ { @@ -50,6 +53,22 @@ export const SystemAdminTabsConfig: TabsNavItem[] = [ id: permissionManagementRouteId, title: 'Permission Management', }, + { + children: [ + { + + id: `${platformRouteId}/${platformSkillRouteId}`, + title: 'Skills', + }, + { + id: `${platformRouteId}/${gamificationAdminRouteId}`, + title: 'Badges', + + }, + ], + id: platformRouteId, + title: 'Platform', + }, ] export function getTabIdFromPathName(pathname: string): string { diff --git a/src/apps/admin/src/lib/hooks/index.ts b/src/apps/admin/src/lib/hooks/index.ts index c96c3ac3a..d0fc0d901 100644 --- a/src/apps/admin/src/lib/hooks/index.ts +++ b/src/apps/admin/src/lib/hooks/index.ts @@ -25,3 +25,4 @@ export * from './useManagePermissionGroupMembers' export * from './useSearchUserInfo' export * from './useManageBusEvent' export * from './useManageChallengeSubmissions' +export * from './useManageUserSSOLogin' diff --git a/src/apps/admin/src/lib/hooks/useManageUserSSOLogin.ts b/src/apps/admin/src/lib/hooks/useManageUserSSOLogin.ts new file mode 100644 index 000000000..4a0ef5c58 --- /dev/null +++ b/src/apps/admin/src/lib/hooks/useManageUserSSOLogin.ts @@ -0,0 +1,343 @@ +/** + * Manage sso user logins redux state + */ +import { useCallback, useReducer } from 'react' +import { toast } from 'react-toastify' +import _ from 'lodash' + +import { FormAddSSOLoginData } from '../models/FormAddSSOLoginData.model' +import { SSOLoginProvider, SSOUserLogin, UserInfo } from '../models' +import { + createSSOUserLogin, + deleteSSOUserLogin, + fetchSSOLoginProviders, + fetchSSOUserLogins, + updateSSOUserLogin, +} from '../services' +import { handleError } from '../utils' + +import { useOnComponentDidMount } from './useOnComponentDidMount' + +/// ///////////////// +// SSO user logins reducer +/// //////////////// + +type SSOUserLoginsState = { + isLoading: boolean + isAdding: boolean + providers: SSOLoginProvider[] + ssoUserLogins: SSOUserLogin[] + isRemoving: { [key: string]: boolean } +} + +const SSOUserLoginsActionType = { + ADD_SSO_USER_LOGIN_DONE: 'ADD_SSO_USER_LOGIN_DONE' as const, + ADD_SSO_USER_LOGIN_FAILED: 'ADD_SSO_USER_LOGIN_FAILED' as const, + ADD_SSO_USER_LOGIN_INIT: 'ADD_SSO_USER_LOGIN_INIT' as const, + FETCH_SSO_USER_LOGINS_DONE: 'FETCH_SSO_USER_LOGINS_DONE' as const, + FETCH_SSO_USER_LOGINS_FAILED: 'FETCH_SSO_USER_LOGINS_FAILED' as const, + FETCH_SSO_USER_LOGINS_INIT: 'FETCH_SSO_USER_LOGINS_INIT' as const, + REMOVE_SSO_USER_LOGIN_DONE: 'REMOVE_SSO_USER_LOGIN_DONE' as const, + REMOVE_SSO_USER_LOGIN_FAILED: 'REMOVE_SSO_USER_LOGIN_FAILED' as const, + REMOVE_SSO_USER_LOGIN_INIT: 'REMOVE_SSO_USER_LOGIN_INIT' as const, + UPDATE_SSO_USER_LOGIN_DONE: 'UPDATE_SSO_USER_LOGIN_DONE' as const, + UPDATE_SSO_USER_LOGIN_FAILED: 'UPDATE_SSO_USER_LOGIN_FAILED' as const, + UPDATE_SSO_USER_LOGIN_INIT: 'UPDATE_SSO_USER_LOGIN_INIT' as const, +} + +type SSOUserLoginsReducerAction = + | { + type: + | typeof SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_INIT + | typeof SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_FAILED + | typeof SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_INIT + | typeof SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_FAILED + | typeof SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_INIT + | typeof SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_FAILED + } + | { + type: typeof SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_DONE + payload: { + ssoUserLogins: SSOUserLogin[] + providers: SSOLoginProvider[] + } + } + | { + type: + | typeof SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_DONE + | typeof SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_DONE + payload: SSOUserLogin + } + | { + type: + | typeof SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_DONE + | typeof SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_INIT + | typeof SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_FAILED + payload: string + } + +const reducer = ( + previousState: SSOUserLoginsState, + action: SSOUserLoginsReducerAction, +): SSOUserLoginsState => { + switch (action.type) { + case SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_INIT: { + return { + ...previousState, + isLoading: true, + ssoUserLogins: [], + } + } + + case SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_DONE: { + return { + ...previousState, + isLoading: false, + providers: action.payload.providers, + ssoUserLogins: action.payload.ssoUserLogins, + } + } + + case SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_FAILED: { + return { + ...previousState, + isLoading: false, + } + } + + case SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_INIT: { + return { + ...previousState, + isAdding: true, + } + } + + case SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_DONE: { + return { + ...previousState, + isAdding: false, + ssoUserLogins: [...previousState.ssoUserLogins, action.payload], + } + } + + case SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_FAILED: { + return { + ...previousState, + isAdding: false, + } + } + + case SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_INIT: { + return { + ...previousState, + isAdding: true, + } + } + + case SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_DONE: { + return { + ...previousState, + isAdding: false, + ssoUserLogins: previousState.ssoUserLogins.map( + item => (item.provider === action.payload.provider + ? action.payload + : item), + ), + } + } + + case SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_FAILED: { + return { + ...previousState, + isAdding: false, + } + } + + case SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_INIT: { + return { + ...previousState, + isRemoving: { + ...previousState.isRemoving, + [action.payload]: true, + }, + } + } + + case SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_DONE: { + const ssoUserLogins = _.filter( + previousState.ssoUserLogins, + item => item.provider !== action.payload, + ) + return { + ...previousState, + isRemoving: { + ...previousState.isRemoving, + [action.payload]: false, + }, + ssoUserLogins, + } + } + + case SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_FAILED: { + return { + ...previousState, + isRemoving: { + ...previousState.isRemoving, + [action.payload]: false, + }, + } + } + + default: { + return previousState + } + } +} + +export interface useManageUserSSOLoginProps { + isLoading: boolean + isRemoving: { [key: string]: boolean } + isAdding: boolean + ssoUserLogins: SSOUserLogin[] + doAddSSOUserLogin: ( + formData: FormAddSSOLoginData, + onSuccess: () => void, + ) => void + doUpdateSSOUserLogin: ( + formData: FormAddSSOLoginData, + onSuccess: () => void, + ) => void + doRemoveSSOUserLogin: (ssoUserLogin: SSOUserLogin) => void +} + +/** + * Manage sso user logins redux state + * @param userInfo user info + * @returns state data + */ +export function useManageUserSSOLogin( + userInfo: UserInfo, +): useManageUserSSOLoginProps { + const [state, dispatch] = useReducer(reducer, { + isAdding: false, + isLoading: false, + isRemoving: {}, + providers: [], + ssoUserLogins: [], + }) + + const doFetchSSOUserLogins = useCallback(() => { + dispatch({ + type: SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_INIT, + }) + Promise.all([fetchSSOUserLogins(userInfo.id), fetchSSOLoginProviders()]) + .then(result => { + dispatch({ + payload: { + providers: result[1], + ssoUserLogins: result[0], + }, + type: SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_DONE, + }) + }) + .catch(e => { + dispatch({ + type: SSOUserLoginsActionType.FETCH_SSO_USER_LOGINS_FAILED, + }) + handleError(e) + }) + }, [dispatch, userInfo]) + + const doAddSSOUserLogin = useCallback( + (formData: FormAddSSOLoginData, onSuccess: () => void) => { + dispatch({ + type: SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_INIT, + }) + createSSOUserLogin(userInfo.id, formData) + .then(result => { + toast.success('SSO login added successfully', { + toastId: 'Add sso login', + }) + dispatch({ + payload: result, + type: SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_DONE, + }) + onSuccess() + }) + .catch(e => { + dispatch({ + type: SSOUserLoginsActionType.ADD_SSO_USER_LOGIN_FAILED, + }) + handleError(e) + }) + }, + [dispatch, userInfo], + ) + + const doUpdateSSOUserLogin = useCallback( + (formData: FormAddSSOLoginData, onSuccess: () => void) => { + dispatch({ + type: SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_INIT, + }) + updateSSOUserLogin(userInfo.id, formData) + .then(result => { + toast.success('SSO login updated successfully', { + toastId: 'Update sso login', + }) + dispatch({ + payload: result, + type: SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_DONE, + }) + onSuccess() + }) + .catch(e => { + dispatch({ + type: SSOUserLoginsActionType.UPDATE_SSO_USER_LOGIN_FAILED, + }) + handleError(e) + }) + }, + [dispatch, userInfo], + ) + + const doRemoveSSOUserLogin = useCallback( + (ssoUserLogin: SSOUserLogin) => { + dispatch({ + payload: ssoUserLogin.provider, + type: SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_INIT, + }) + deleteSSOUserLogin(userInfo.id, ssoUserLogin.provider) + .then(() => { + toast.success('SSO login removed successfully', { + toastId: 'Remove sso login', + }) + dispatch({ + payload: ssoUserLogin.provider, + type: SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_DONE, + }) + }) + .catch(e => { + dispatch({ + payload: ssoUserLogin.provider, + type: SSOUserLoginsActionType.REMOVE_SSO_USER_LOGIN_FAILED, + }) + handleError(e) + }) + }, + [dispatch, userInfo], + ) + + useOnComponentDidMount(() => { + doFetchSSOUserLogins() + }) + + return { + doAddSSOUserLogin, + doRemoveSSOUserLogin, + doUpdateSSOUserLogin, + isAdding: state.isAdding, + isLoading: state.isLoading, + isRemoving: state.isRemoving, + ssoUserLogins: state.ssoUserLogins, + } +} diff --git a/src/apps/admin/src/lib/models/FormAddSSOLoginData.model.ts b/src/apps/admin/src/lib/models/FormAddSSOLoginData.model.ts new file mode 100644 index 000000000..0ce1ea9c7 --- /dev/null +++ b/src/apps/admin/src/lib/models/FormAddSSOLoginData.model.ts @@ -0,0 +1,9 @@ +/** + * Model for add sso login data + */ +export interface FormAddSSOLoginData { + userId: string + name: string + email: string + provider: string +} diff --git a/src/apps/admin/src/lib/models/SSOLoginProvider.model.ts b/src/apps/admin/src/lib/models/SSOLoginProvider.model.ts new file mode 100644 index 000000000..f3f75c17f --- /dev/null +++ b/src/apps/admin/src/lib/models/SSOLoginProvider.model.ts @@ -0,0 +1,8 @@ +/** + * Model for sso login provider + */ +export interface SSOLoginProvider { + ssoLoginProviderId: number + name: string + type: string +} diff --git a/src/apps/admin/src/lib/models/SSOUserLogin.model.ts b/src/apps/admin/src/lib/models/SSOUserLogin.model.ts new file mode 100644 index 000000000..c80e19f01 --- /dev/null +++ b/src/apps/admin/src/lib/models/SSOUserLogin.model.ts @@ -0,0 +1,14 @@ +/** + * Model for sso user login + */ +export interface SSOUserLogin { + userId: string + name: string + email: string + providerType: string + provider: string + context: any + social: boolean + enterprise: boolean + emailVerified: boolean +} diff --git a/src/apps/admin/src/lib/models/index.ts b/src/apps/admin/src/lib/models/index.ts index 786d0dc93..d85a6e63a 100644 --- a/src/apps/admin/src/lib/models/index.ts +++ b/src/apps/admin/src/lib/models/index.ts @@ -33,6 +33,8 @@ export * from './RoleMemberInfo.model' export * from './Submission.model' export * from './RequestBusAPI.model' export * from './MemberSubmission.model' +export * from './SSOUserLogin.model' +export * from './SSOLoginProvider.model' export * from './FormAddGroupMembers.type' export * from './TableFilterType.type' export * from './TableRolesFilter.type' diff --git a/src/apps/admin/src/lib/services/user.service.ts b/src/apps/admin/src/lib/services/user.service.ts index 73920a830..4f1dcab54 100644 --- a/src/apps/admin/src/lib/services/user.service.ts +++ b/src/apps/admin/src/lib/services/user.service.ts @@ -1,15 +1,18 @@ import _ from 'lodash' import { EnvironmentConfig } from '~/config' -import { xhrGetAsync, xhrPatchAsync } from '~/libs/core' +import { xhrDeleteAsync, xhrGetAsync, xhrPatchAsync, xhrPostAsync, xhrPutAsync } from '~/libs/core' import { adjustUserInfoResponse, adjustUserStatusHistoryResponse, ApiV3Response, + SSOLoginProvider, + SSOUserLogin, UserInfo, UserStatusHistory, } from '../models' +import { FormAddSSOLoginData } from '../models/FormAddSSOLoginData.model' /** * Gets the member suggest by handle. @@ -154,3 +157,84 @@ export const findUserById = async (userId: string | number): Promise = ) return adjustUserInfoResponse(result.result.content) } + +/** + * Fetch list of sso user login. + * @param userId user id. + * @returns resolves to sso user logins + */ +export const fetchSSOUserLogins = async (userId: string | number): Promise => { + const result = await xhrGetAsync>( + `${EnvironmentConfig.API.V3}/users/${userId}/SSOUserLogins`, + ) + return result.result.content +} + +/** + * Fetch list of sso login provider. + * @returns resolves to sso user logins + */ +export const fetchSSOLoginProviders = async (): Promise => { + const result = await xhrGetAsync>( + `${EnvironmentConfig.API.V3}/ssoLoginProviders`, + ) + return result.result.content +} + +/** + * Create sso user login. + * @param userId user id. + * @param userLogin user login info. + * @returns resolves to sso user login + */ +export const createSSOUserLogin = async ( + userId: string | number, + userLogin: FormAddSSOLoginData, +): Promise => { + const result = await xhrPostAsync< + { + param: FormAddSSOLoginData + }, + ApiV3Response + >(`${EnvironmentConfig.API.V3}/users/${userId}/SSOUserLogin`, { + param: userLogin, + }) + return result.result.content +} + +/** + * Update sso user login. + * @param userId user id. + * @param userLogin user login info. + * @returns resolves to sso user login + */ +export const updateSSOUserLogin = async ( + userId: string | number, + userLogin: FormAddSSOLoginData, +): Promise => { + const result = await xhrPutAsync< + { + param: FormAddSSOLoginData + }, + ApiV3Response + >(`${EnvironmentConfig.API.V3}/users/${userId}/SSOUserLogin`, { + param: userLogin, + }) + return result.result.content +} + +/** + * Delete sso user login. + * @param userId user id. + * @param provider login provider. + * @returns resolves to sso user login + */ +export const deleteSSOUserLogin = async ( + userId: string | number, + provider: string, +): Promise => { + const result = await xhrDeleteAsync>( + `${EnvironmentConfig.API.V3}/users/${userId}/SSOUserLogin?provider=${provider}`, + ) + return result.result.content +} diff --git a/src/apps/admin/src/lib/utils/validation.ts b/src/apps/admin/src/lib/utils/validation.ts index 89e34212a..051761582 100644 --- a/src/apps/admin/src/lib/utils/validation.ts +++ b/src/apps/admin/src/lib/utils/validation.ts @@ -20,6 +20,7 @@ import { } from '../models' import { FormEditUserStatus } from '../models/FormEditUserStatus.model' import { FormAddRoleMembers } from '../models/FormAddRoleMembers.type' +import { FormAddSSOLoginData } from '../models/FormAddSSOLoginData.model' /** * validation schema for form filter users @@ -366,6 +367,26 @@ export const formEditUserEmailSchema: Yup.ObjectSchema .required('Email address is required.'), }) +/** + * validation schema for form edit sso user login + */ +export const formAddSSOLoginSchema: Yup.ObjectSchema + = Yup.object({ + email: Yup.string() + .trim() + .email('Invalid email address.') + .required('Email address is required.'), + name: Yup.string() + .trim() + .required('Name is required.'), + provider: Yup.string() + .trim() + .required('Provider is required.'), + userId: Yup.string() + .trim() + .required('User id is required.'), + }) + /** * validation schema for form add group */ diff --git a/src/apps/admin/src/platform-management/PlatformManagement.tsx b/src/apps/admin/src/platform-management/PlatformManagement.tsx new file mode 100644 index 000000000..e662b61c8 --- /dev/null +++ b/src/apps/admin/src/platform-management/PlatformManagement.tsx @@ -0,0 +1,34 @@ +import { FC, useContext, useMemo } from 'react' +import { Outlet, Routes } from 'react-router-dom' + +import { routerContext, RouterContextData } from '~/libs/core' + +import { adminRoutes } from '../admin-app.routes' +import { platformRouteId } from '../config/routes.config' + +/** + * The router outlet. + */ +export const PlatformManagement: FC = () => { + const childRoutes = useChildRoutes() + + return ( + <> + + {childRoutes} + + ) +} + +function useChildRoutes(): Array | undefined { + const { getRouteElement }: RouterContextData = useContext(routerContext) + const childRoutes = useMemo( + () => adminRoutes[0].children + ?.find(r => r.id === platformRouteId) + ?.children?.map(getRouteElement), + [], // eslint-disable-line react-hooks/exhaustive-deps -- missing dependency: getRouteElement + ) + return childRoutes +} + +export default PlatformManagement diff --git a/src/apps/admin/src/platform/Platform.tsx b/src/apps/admin/src/platform/Platform.tsx new file mode 100644 index 000000000..7990772f3 --- /dev/null +++ b/src/apps/admin/src/platform/Platform.tsx @@ -0,0 +1,37 @@ +/** + * Wrapper for permission managment + */ +import { FC, useContext, useMemo } from 'react' +import { Outlet, Routes } from 'react-router-dom' + +import { routerContext, RouterContextData } from '~/libs/core' + +import { adminRoutes } from '../admin-app.routes' +import { platformRouteId } from '../config/routes.config' + +/** + * The router outlet with layout. + */ +export const Platform: FC = () => { + const childRoutes = useChildRoutes() + + return ( + <> + + {childRoutes} + + ) +} + +function useChildRoutes(): Array | undefined { + const { getRouteElement }: RouterContextData = useContext(routerContext) + const childRoutes = useMemo( + () => adminRoutes[0].children + ?.find(r => r.id === platformRouteId) + ?.children?.map(getRouteElement), + [], // eslint-disable-line react-hooks/exhaustive-deps -- missing dependency: getRouteElement + ) + return childRoutes +} + +export default Platform diff --git a/src/apps/admin/src/platform/routes.config.ts b/src/apps/admin/src/platform/routes.config.ts new file mode 100644 index 000000000..4a95b6fe8 --- /dev/null +++ b/src/apps/admin/src/platform/routes.config.ts @@ -0,0 +1 @@ +export const platformSkillRouteId = 'skills' diff --git a/src/apps/skills-manager/src/skills-manager/landing-page/LandingPage.module.scss b/src/apps/admin/src/platform/skill-management/LandingPage/LandingPage.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/landing-page/LandingPage.module.scss rename to src/apps/admin/src/platform/skill-management/LandingPage/LandingPage.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/landing-page/LandingPage.tsx b/src/apps/admin/src/platform/skill-management/LandingPage/LandingPage.tsx similarity index 88% rename from src/apps/skills-manager/src/skills-manager/landing-page/LandingPage.tsx rename to src/apps/admin/src/platform/skill-management/LandingPage/LandingPage.tsx index 3400b27f7..ca5c0487c 100644 --- a/src/apps/skills-manager/src/skills-manager/landing-page/LandingPage.tsx +++ b/src/apps/admin/src/platform/skill-management/LandingPage/LandingPage.tsx @@ -1,8 +1,8 @@ import { FC } from 'react' -import { ContentLayout, InputCheckbox, PageTitle } from '~/libs/ui' +import { InputCheckbox, PageTitle } from '~/libs/ui' -import { SkillsManagerContextValue, useSkillsManagerContext } from '../context' +import { SkillsManagerContextValue, useSkillsManagerContext } from '../lib/context' import { CategoriesAccordion, CategoryModal, @@ -10,8 +10,8 @@ import { PageHeader, SearchInput, SkillModal, -} from '../components' -import { BulkEditor } from '../components/bulk-editor' +} from '../lib/components' +import { BulkEditor } from '../lib/components/bulk-editor' import styles from './LandingPage.module.scss' @@ -30,7 +30,7 @@ const LandingPage: FC<{}> = () => { }: SkillsManagerContextValue = useSkillsManagerContext() return ( - +
Skills Manager | Admin = () => { )} {!!showSkillModal && } - +
) } diff --git a/src/apps/skills-manager/src/skills-manager/landing-page/index.ts b/src/apps/admin/src/platform/skill-management/LandingPage/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/landing-page/index.ts rename to src/apps/admin/src/platform/skill-management/LandingPage/index.ts diff --git a/src/apps/admin/src/platform/skill-management/SkillManagement.tsx b/src/apps/admin/src/platform/skill-management/SkillManagement.tsx new file mode 100644 index 000000000..6e66d9795 --- /dev/null +++ b/src/apps/admin/src/platform/skill-management/SkillManagement.tsx @@ -0,0 +1,38 @@ +import { FC, useContext, useMemo } from 'react' +import { Outlet, Routes } from 'react-router-dom' + +import { routerContext, RouterContextData } from '~/libs/core' + +import { adminRoutes } from '../../admin-app.routes' +import { platformRouteId } from '../../config/routes.config' +import { platformSkillRouteId } from '../routes.config' + +import { SkillsManagerContext } from './lib/context' + +/** + * The router outlet. + */ +export const PlatformManagement: FC = () => { + const childRoutes = useChildRoutes() + + return ( + + + {childRoutes} + + ) +} + +function useChildRoutes(): Array | undefined { + const { getRouteElement }: RouterContextData = useContext(routerContext) + const childRoutes = useMemo( + () => adminRoutes[0].children + ?.find(r => r.id === platformRouteId) + ?.children?.find(r => r.id === platformSkillRouteId) + ?.children?.map(getRouteElement), + [], // eslint-disable-line react-hooks/exhaustive-deps -- missing dependency: getRouteElement + ) + return childRoutes +} + +export default PlatformManagement diff --git a/src/apps/skills-manager/src/skills-manager/components/accordion/Accordion.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/accordion/Accordion.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/accordion/Accordion.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/accordion/Accordion.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/accordion/Accordion.tsx b/src/apps/admin/src/platform/skill-management/lib/components/accordion/Accordion.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/accordion/Accordion.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/accordion/Accordion.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/accordion/accordion-item/AccordionItem.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/accordion/accordion-item/AccordionItem.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/accordion/accordion-item/AccordionItem.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/accordion/accordion-item/AccordionItem.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/accordion/accordion-item/AccordionItem.tsx b/src/apps/admin/src/platform/skill-management/lib/components/accordion/accordion-item/AccordionItem.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/accordion/accordion-item/AccordionItem.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/accordion/accordion-item/AccordionItem.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/accordion/accordion-item/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/accordion/accordion-item/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/accordion/accordion-item/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/accordion/accordion-item/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/accordion/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/accordion/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/accordion/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/accordion/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/actions-menu/ActionsMenu.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/actions-menu/ActionsMenu.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/actions-menu/ActionsMenu.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/actions-menu/ActionsMenu.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/actions-menu/ActionsMenu.tsx b/src/apps/admin/src/platform/skill-management/lib/components/actions-menu/ActionsMenu.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/actions-menu/ActionsMenu.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/actions-menu/ActionsMenu.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/actions-menu/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/actions-menu/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/actions-menu/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/actions-menu/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/BulkEditor.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/BulkEditor.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/BulkEditor.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/BulkEditor.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/BulkEditor.tsx b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/BulkEditor.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/BulkEditor.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/BulkEditor.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/archive-skills-modal/ArchiveSkillsModal.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/archive-skills-modal/ArchiveSkillsModal.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/archive-skills-modal/ArchiveSkillsModal.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/archive-skills-modal/ArchiveSkillsModal.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/archive-skills-modal/ArchiveSkillsModal.tsx b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/archive-skills-modal/ArchiveSkillsModal.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/archive-skills-modal/ArchiveSkillsModal.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/archive-skills-modal/ArchiveSkillsModal.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/archive-skills-modal/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/archive-skills-modal/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/archive-skills-modal/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/archive-skills-modal/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/move-skills-modal/MoveSkillsModal.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/move-skills-modal/MoveSkillsModal.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/move-skills-modal/MoveSkillsModal.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/move-skills-modal/MoveSkillsModal.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/move-skills-modal/MoveSkillsModal.tsx b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/move-skills-modal/MoveSkillsModal.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/move-skills-modal/MoveSkillsModal.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/move-skills-modal/MoveSkillsModal.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/move-skills-modal/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/move-skills-modal/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/move-skills-modal/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/move-skills-modal/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/replace-skills-modal/ReplaceSkillsModal.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/replace-skills-modal/ReplaceSkillsModal.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/replace-skills-modal/ReplaceSkillsModal.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/replace-skills-modal/ReplaceSkillsModal.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/replace-skills-modal/ReplaceSkillsModal.tsx b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/replace-skills-modal/ReplaceSkillsModal.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/replace-skills-modal/ReplaceSkillsModal.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/replace-skills-modal/ReplaceSkillsModal.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/replace-skills-modal/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/replace-skills-modal/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/replace-skills-modal/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/replace-skills-modal/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/search-skill-input/SearchSkillInput.tsx b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/search-skill-input/SearchSkillInput.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/search-skill-input/SearchSkillInput.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/search-skill-input/SearchSkillInput.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/bulk-editor/search-skill-input/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/search-skill-input/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/bulk-editor/search-skill-input/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/bulk-editor/search-skill-input/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/categories-accordion/CategoriesAccordion.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/categories-accordion/CategoriesAccordion.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/categories-accordion/CategoriesAccordion.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/categories-accordion/CategoriesAccordion.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/categories-accordion/CategoriesAccordion.tsx b/src/apps/admin/src/platform/skill-management/lib/components/categories-accordion/CategoriesAccordion.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/categories-accordion/CategoriesAccordion.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/categories-accordion/CategoriesAccordion.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/categories-accordion/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/categories-accordion/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/categories-accordion/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/categories-accordion/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/category-modal/CategoryModal.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/category-modal/CategoryModal.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/category-modal/CategoryModal.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/category-modal/CategoryModal.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/category-modal/CategoryModal.tsx b/src/apps/admin/src/platform/skill-management/lib/components/category-modal/CategoryModal.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/category-modal/CategoryModal.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/category-modal/CategoryModal.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/category-modal/category-form.config.ts b/src/apps/admin/src/platform/skill-management/lib/components/category-modal/category-form.config.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/category-modal/category-form.config.ts rename to src/apps/admin/src/platform/skill-management/lib/components/category-modal/category-form.config.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/category-modal/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/category-modal/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/category-modal/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/category-modal/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/more-actions-menu/MoreActionsMenu.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/more-actions-menu/MoreActionsMenu.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/more-actions-menu/MoreActionsMenu.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/more-actions-menu/MoreActionsMenu.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/more-actions-menu/MoreActionsMenu.tsx b/src/apps/admin/src/platform/skill-management/lib/components/more-actions-menu/MoreActionsMenu.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/more-actions-menu/MoreActionsMenu.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/more-actions-menu/MoreActionsMenu.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/more-actions-menu/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/more-actions-menu/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/more-actions-menu/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/more-actions-menu/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/page-header/PageHeader.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/page-header/PageHeader.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/page-header/PageHeader.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/page-header/PageHeader.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/page-header/PageHeader.tsx b/src/apps/admin/src/platform/skill-management/lib/components/page-header/PageHeader.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/page-header/PageHeader.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/page-header/PageHeader.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/page-header/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/page-header/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/page-header/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/page-header/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/search-input/SearchInput.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/search-input/SearchInput.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/search-input/SearchInput.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/search-input/SearchInput.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/search-input/SearchInput.tsx b/src/apps/admin/src/platform/skill-management/lib/components/search-input/SearchInput.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/search-input/SearchInput.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/search-input/SearchInput.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/search-input/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/search-input/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/search-input/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/search-input/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/SkillModal.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/SkillModal.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/SkillModal.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/SkillModal.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/SkillModal.tsx b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/SkillModal.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/SkillModal.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/SkillModal.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/similar-skills-dropdown/SimilarSkillsDropdown.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/similar-skills-dropdown/SimilarSkillsDropdown.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/similar-skills-dropdown/SimilarSkillsDropdown.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/similar-skills-dropdown/SimilarSkillsDropdown.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/similar-skills-dropdown/SimilarSkillsDropdown.tsx b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/similar-skills-dropdown/SimilarSkillsDropdown.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/similar-skills-dropdown/SimilarSkillsDropdown.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/similar-skills-dropdown/SimilarSkillsDropdown.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/similar-skills-dropdown/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/similar-skills-dropdown/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/similar-skills-dropdown/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/similar-skills-dropdown/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/skill-form/SkillForm.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/skill-form/SkillForm.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/skill-form/SkillForm.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/skill-form/SkillForm.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/skill-form/SkillForm.tsx b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/skill-form/SkillForm.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/skill-form/SkillForm.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/skill-form/SkillForm.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/skill-modals/skill-form/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/skill-modals/skill-form/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skill-modals/skill-form/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/skill-modals/skill-form/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/components/skills-list/SkillsList.module.scss b/src/apps/admin/src/platform/skill-management/lib/components/skills-list/SkillsList.module.scss similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skills-list/SkillsList.module.scss rename to src/apps/admin/src/platform/skill-management/lib/components/skills-list/SkillsList.module.scss diff --git a/src/apps/skills-manager/src/skills-manager/components/skills-list/SkillsList.tsx b/src/apps/admin/src/platform/skill-management/lib/components/skills-list/SkillsList.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skills-list/SkillsList.tsx rename to src/apps/admin/src/platform/skill-management/lib/components/skills-list/SkillsList.tsx diff --git a/src/apps/skills-manager/src/skills-manager/components/skills-list/index.ts b/src/apps/admin/src/platform/skill-management/lib/components/skills-list/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/components/skills-list/index.ts rename to src/apps/admin/src/platform/skill-management/lib/components/skills-list/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/config/constants.ts b/src/apps/admin/src/platform/skill-management/lib/config/constants.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/config/constants.ts rename to src/apps/admin/src/platform/skill-management/lib/config/constants.ts diff --git a/src/apps/skills-manager/src/skills-manager/config/index.ts b/src/apps/admin/src/platform/skill-management/lib/config/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/config/index.ts rename to src/apps/admin/src/platform/skill-management/lib/config/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/context/index.ts b/src/apps/admin/src/platform/skill-management/lib/context/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/context/index.ts rename to src/apps/admin/src/platform/skill-management/lib/context/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/context/skills-manager.context.tsx b/src/apps/admin/src/platform/skill-management/lib/context/skills-manager.context.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/context/skills-manager.context.tsx rename to src/apps/admin/src/platform/skill-management/lib/context/skills-manager.context.tsx diff --git a/src/apps/skills-manager/src/skills-manager/context/use-skills-bulk-editor-context.tsx b/src/apps/admin/src/platform/skill-management/lib/context/use-skills-bulk-editor-context.tsx similarity index 100% rename from src/apps/skills-manager/src/skills-manager/context/use-skills-bulk-editor-context.tsx rename to src/apps/admin/src/platform/skill-management/lib/context/use-skills-bulk-editor-context.tsx diff --git a/src/apps/skills-manager/src/skills-manager/lib/index.ts b/src/apps/admin/src/platform/skill-management/lib/lib/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/lib/index.ts rename to src/apps/admin/src/platform/skill-management/lib/lib/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/lib/skills.utils.ts b/src/apps/admin/src/platform/skill-management/lib/lib/skills.utils.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/lib/skills.utils.ts rename to src/apps/admin/src/platform/skill-management/lib/lib/skills.utils.ts diff --git a/src/apps/skills-manager/src/skills-manager/services/index.ts b/src/apps/admin/src/platform/skill-management/lib/services/index.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/services/index.ts rename to src/apps/admin/src/platform/skill-management/lib/services/index.ts diff --git a/src/apps/skills-manager/src/skills-manager/services/skills-categories.service.ts b/src/apps/admin/src/platform/skill-management/lib/services/skills-categories.service.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/services/skills-categories.service.ts rename to src/apps/admin/src/platform/skill-management/lib/services/skills-categories.service.ts diff --git a/src/apps/skills-manager/src/skills-manager/services/skills.service.ts b/src/apps/admin/src/platform/skill-management/lib/services/skills.service.ts similarity index 100% rename from src/apps/skills-manager/src/skills-manager/services/skills.service.ts rename to src/apps/admin/src/platform/skill-management/lib/services/skills.service.ts diff --git a/src/apps/gamification-admin/src/GamificationAdmin.tsx b/src/apps/gamification-admin/src/GamificationAdmin.tsx deleted file mode 100644 index 956e8d21a..000000000 --- a/src/apps/gamification-admin/src/GamificationAdmin.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { FC, useContext } from 'react' -import { Outlet, Routes } from 'react-router-dom' -import { SWRConfig } from 'swr' - -import { ToolTitle } from '~/config' -import { routerContext, RouterContextData, xhrGetAsync } from '~/libs/core' - -export const toolTitle: string = ToolTitle.gamificationAdmin - -const GamificationAdmin: FC<{}> = () => { - - const { getChildRoutes }: RouterContextData = useContext(routerContext) - - return ( - xhrGetAsync(resource), - refreshInterval: 60000, // 1 min - }} - > - - - {getChildRoutes(toolTitle)} - - - ) -} - -export default GamificationAdmin diff --git a/src/apps/gamification-admin/src/game-lib/hooks/use-gamification-breadcrumb.hook.tsx b/src/apps/gamification-admin/src/game-lib/hooks/use-gamification-breadcrumb.hook.tsx deleted file mode 100644 index 4bcbae662..000000000 --- a/src/apps/gamification-admin/src/game-lib/hooks/use-gamification-breadcrumb.hook.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { BreadcrumbItemModel } from '~/libs/ui' - -import { toolTitle } from '../../GamificationAdmin' -import { rootRoute } from '../../gamification-admin.routes' - -export function useGamificationBreadcrumb(items: Array): Array { - - const breadcrumb: Array = [ - { - name: toolTitle, - url: rootRoute || '/', - }, - ...items, - ] - - return breadcrumb -} diff --git a/src/apps/gamification-admin/src/game-lib/index.ts b/src/apps/gamification-admin/src/game-lib/index.ts index f7cba96f4..dc15c5b7b 100644 --- a/src/apps/gamification-admin/src/game-lib/index.ts +++ b/src/apps/gamification-admin/src/game-lib/index.ts @@ -1,6 +1,5 @@ export * from './game-badge.model' export * from './hooks/use-get-game-badges-page.hook' -export * from './hooks/use-gamification-breadcrumb.hook' export * from './hooks/use-get-game-badge-details.hook' export * from './member-autocomplete' export * from './pagination' diff --git a/src/apps/gamification-admin/src/game-lib/modals/badge-created-modal/BadgeCreatedModal.tsx b/src/apps/gamification-admin/src/game-lib/modals/badge-created-modal/BadgeCreatedModal.tsx index bbfd48005..95ff0e600 100644 --- a/src/apps/gamification-admin/src/game-lib/modals/badge-created-modal/BadgeCreatedModal.tsx +++ b/src/apps/gamification-admin/src/game-lib/modals/badge-created-modal/BadgeCreatedModal.tsx @@ -12,6 +12,7 @@ export interface BadgeCreatedModalProps { badge: GameBadge isOpen: boolean onClose: () => void + rootPage: string; } const BadgeCreatedModal: FC = (props: BadgeCreatedModalProps) => { @@ -52,7 +53,7 @@ const BadgeCreatedModal: FC = (props: BadgeCreatedModalP label='View' primary size='lg' - to={badgeDetailPath(props.badge.id)} + to={badgeDetailPath(props.rootPage, props.badge.id)} />