Skip to content

Commit b1312ae

Browse files
authored
Merge pull request #1016 from topcoder-platform/diazz-challenge-30376220
Winner of Challenge: Topcoder Admin App - User Management
2 parents 764f178 + c6f04a8 commit b1312ae

File tree

99 files changed

+5322
-181
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

99 files changed

+5322
-181
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
"dependencies": {
2222
"@datadog/browser-logs": "^4.21.2",
2323
"@heroicons/react": "^1.0.6",
24+
"@hookform/resolvers": "^4.1.2",
2425
"@popperjs/core": "^2.11.8",
2526
"@sprig-technologies/sprig-browser": "^2.20.1",
2627
"@storybook/addon-actions": "7.6.10",
@@ -71,6 +72,7 @@
7172
"react-elastic-carousel": "^0.11.5",
7273
"react-gtm-module": "^2.0.11",
7374
"react-helmet": "^6.1.0",
75+
"react-hook-form": "^7.54.2",
7476
"react-markdown": "8.0.6",
7577
"react-otp-input": "^3.1.1",
7678
"react-popper": "^2.3.0",
@@ -101,7 +103,8 @@
101103
"tc-auth-lib": "topcoder-platform/tc-auth-lib#1.0.27",
102104
"typescript": "^4.8.4",
103105
"universal-navigation": "https://github.com/topcoder-platform/universal-navigation#9fc50d938be7182",
104-
"uuid": "^9.0.0"
106+
"uuid": "^9.0.0",
107+
"yup": "^1.6.1"
105108
},
106109
"devDependencies": {
107110
"@babel/core": "^7.19.3",

src/apps/admin/src/admin-app.routes.tsx

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { AppSubdomain, EnvironmentConfig, ToolTitle } from '~/config'
1+
import { AppSubdomain, ToolTitle } from '~/config'
22
import {
33
lazyLoad,
44
LazyLoadedComponent,
@@ -7,6 +7,13 @@ import {
77
UserRole,
88
} from '~/libs/core'
99

10+
import {
11+
manageChallengeRouteId,
12+
manageReviewRouteId,
13+
rootRoute,
14+
userManagementRouteId,
15+
} from './config/routes.config'
16+
1017
const AdminApp: LazyLoadedComponent = lazyLoad(() => import('./AdminApp'))
1118

1219
const ChallengeManagement: LazyLoadedComponent = lazyLoad(
@@ -20,7 +27,10 @@ const ManageUserPage: LazyLoadedComponent = lazyLoad(
2027
() => import('./challenge-management/ManageUserPage'),
2128
'ManageUserPage',
2229
)
23-
30+
const UserManagementPage: LazyLoadedComponent = lazyLoad(
31+
() => import('./user-management/UserManagementPage'),
32+
'UserManagementPage',
33+
)
2434
const ReviewManagement: LazyLoadedComponent = lazyLoad(
2535
() => import('./review-management/ReviewManagement'),
2636
)
@@ -34,13 +44,6 @@ const ManageReviewerPage: LazyLoadedComponent = lazyLoad(
3444
)
3545

3646
export const toolTitle: string = ToolTitle.admin
37-
export const rootRoute: string
38-
= EnvironmentConfig.SUBDOMAIN === AppSubdomain.admin
39-
? ''
40-
: `/${AppSubdomain.admin}`
41-
42-
export const manageChallengeRouteId = 'challenge-management'
43-
export const manageReviewRouteId = 'review-management'
4447

4548
export const adminRoutes: ReadonlyArray<PlatformRoute> = [
4649
// Admin App Root
@@ -69,6 +72,12 @@ export const adminRoutes: ReadonlyArray<PlatformRoute> = [
6972
id: manageChallengeRouteId,
7073
route: manageChallengeRouteId,
7174
},
75+
// User Management Module
76+
{
77+
element: <UserManagementPage />,
78+
id: userManagementRouteId,
79+
route: userManagementRouteId,
80+
},
7281
// Reviewer Management Module
7382
{
7483
children: [

src/apps/admin/src/challenge-management/ChallengeManagement.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ import { routerContext, RouterContextData } from '~/libs/core'
55

66
import { Layout } from '../lib/components'
77
import { ChallengeManagementContextProvider } from '../lib/contexts'
8-
import { adminRoutes, manageChallengeRouteId } from '../admin-app.routes'
8+
import { adminRoutes } from '../admin-app.routes'
9+
import { manageChallengeRouteId } from '../config/routes.config'
910

1011
/**
1112
* The router outlet with layout.

src/apps/admin/src/challenge-management/ManageUserPage/ManageUserPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ import {
3939
getChallengeByLegacyId,
4040
getChallengeResources,
4141
} from '../../lib/services'
42-
import { rootRoute } from '../../admin-app.routes'
4342
import { createChallengeQueryString, handleError } from '../../lib/utils'
4443
import { useEventCallback } from '../../lib/hooks'
44+
import { rootRoute } from '../../config/routes.config'
4545

4646
import styles from './ManageUserPage.module.scss'
4747

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
// eslint-disable-next-line max-len
2+
import { InputSelectOption } from '~/libs/ui/lib/components/form/form-groups/form-input/input-select-react/InputSelectReact'
3+
4+
/**
5+
* Common config for ui.
6+
*/
7+
const EMPTY_OPTION: InputSelectOption = { label: '', value: '' }
8+
export const USER_STATUS_SELECT_OPTIONS: InputSelectOption[] = [
9+
EMPTY_OPTION,
10+
{ label: 'active', value: 'active' },
11+
{ label: 'inactive', value: 'inactive' },
12+
]
13+
export const USER_STATUS_DETAIL_SELECT_OPTIONS: InputSelectOption[] = [
14+
{ label: 'Verified', value: 'A' },
15+
{ label: 'Inactive - Duplicate account', value: '5' },
16+
{ label: 'Inactive - Member wanted account removed', value: '4' },
17+
{ label: 'Inactive - Deactivated for cheating', value: '6' },
18+
]
19+
export const DICT_USER_STATUS = {
20+
4: 'Deactivated(User request)',
21+
5: 'Deactivated(Duplicate account)',
22+
6: 'Deactivated(Cheating account)',
23+
A: 'Verified',
24+
U: 'Unverified',
25+
}
26+
export const TABLE_DATE_FORMAT = 'MMM DD, YYYY HH:mm'
27+
export const TABLE_PAGINATION_ITEM_PER_PAGE = 25
28+
export const TABLE_USER_TEMRS_PAGINATION_ITEM_PER_PAGE = 10
29+
export const LABEL_EMAIL_STATUS_VERIFIED = 'Verified'
30+
export const LABEL_EMAIL_STATUS_UNVERIFIED = 'Unverified'
31+
export const MSG_NO_RECORD_FOUND = 'No record found.'
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Common config for routes in admin app.
3+
*/
4+
import { AppSubdomain, EnvironmentConfig } from '~/config'
5+
6+
export const rootRoute: string
7+
= EnvironmentConfig.SUBDOMAIN === AppSubdomain.admin
8+
? ''
9+
: `/${AppSubdomain.admin}`
10+
11+
export const manageChallengeRouteId = 'challenge-management'
12+
export const manageReviewRouteId = 'review-management'
13+
export const userManagementRouteId = 'user-management'

src/apps/admin/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
export { adminRoutes, rootRoute as adminRootRoute } from './admin-app.routes'
1+
export { adminRoutes } from './admin-app.routes'
2+
export { rootRoute as adminRootRoute } from './config/routes.config'
Lines changed: 1 addition & 0 deletions
Loading
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
@import "@libs/ui/styles/includes";
2+
3+
.copy-btn {
4+
line-height: 0;
5+
6+
padding: $sp-3 $sp-4;
7+
margin: 10;
8+
background: none;
9+
border: none;
10+
border-radius: inherit;
11+
12+
&:active {
13+
background-color: rgba(darken($blue-10, 25%), 0.25);
14+
}
15+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* Copy button ui.
3+
*/
4+
import * as React from 'react'
5+
import { toast } from 'react-toastify'
6+
import classNames from 'classnames'
7+
8+
import { Button, IconOutline, Tooltip } from '~/libs/ui'
9+
import { copyTextToClipboard } from '~/libs/shared'
10+
11+
import styles from './CopyButton.module.scss'
12+
13+
interface CopyButtonProps {
14+
className?: string
15+
text?: string
16+
}
17+
18+
export const CopyButton: React.FC<CopyButtonProps> = props => {
19+
function handleCopyClick(): void {
20+
copyTextToClipboard(props.text ?? '')
21+
.then(() => {
22+
toast.success('Copied', {
23+
toastId: 'CopyButton',
24+
})
25+
})
26+
}
27+
28+
return (
29+
<Tooltip content='Copy to clipboard'>
30+
<Button
31+
size='xl'
32+
className={classNames(styles['copy-btn'], props.className)}
33+
icon={IconOutline.DocumentDuplicateIcon}
34+
onClick={handleCopyClick}
35+
/>
36+
</Tooltip>
37+
)
38+
}
39+
40+
export default CopyButton
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default as CopyButton } from './CopyButton'
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.container {
2+
display: flex;
3+
flex-direction: column;
4+
gap: 20px;
5+
position: relative;
6+
}
7+
8+
.actionButtons {
9+
display: flex;
10+
justify-content: flex-end;
11+
gap: 6px;
12+
}
13+
14+
.dialogLoadingSpinnerContainer {
15+
position: absolute;
16+
width: 64px;
17+
display: flex;
18+
align-items: center;
19+
justify-content: center;
20+
bottom: 0;
21+
height: 64px;
22+
left: 0;
23+
24+
.spinner {
25+
background: none;
26+
}
27+
}

0 commit comments

Comments
 (0)