Skip to content

Commit 4c8760a

Browse files
committed
TCA-1179 - gamification admin linting
1 parent 37c58e2 commit 4c8760a

File tree

12 files changed

+170
-51
lines changed

12 files changed

+170
-51
lines changed

src-ts/tools/gamification-admin/game-lib/hooks/use-get-game-badge-assignees-page.hook.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@ export function useGetGameBadgeAssigneesPage(badge: GameBadge, sort: Sort): Infi
1919
order_type: sort.direction,
2020
}
2121

22-
const badgeEndpointUrl: URL = new URL(`${EnvironmentConfig.API.V5}/gamification/badges/${badge.id}/assignees?${new URLSearchParams(params)}`)
22+
const badgeEndpointUrl: URL = new URL(
23+
`${EnvironmentConfig.API.V5}/gamification/badges/${badge.id}/assignees?${new URLSearchParams(params)}`,
24+
)
2325

2426
return badgeEndpointUrl.toString()
2527
}

src-ts/tools/gamification-admin/game-lib/hooks/use-get-game-badges-page.hook.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ export function useGetGameBadgesPage(sort: Sort): InfinitePageHandler<GameBadge>
2020
organization_id: GamificationConfig.ORG_ID,
2121
}
2222

23-
const badgeEndpointUrl: URL = new URL(`${EnvironmentConfig.API.V5}/gamification/badges?${new URLSearchParams(params)}`)
23+
const badgeEndpointUrl: URL = new URL(
24+
`${EnvironmentConfig.API.V5}/gamification/badges?${new URLSearchParams(params)}`,
25+
)
2426

2527
return badgeEndpointUrl.toString()
2628
}

src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/AwardedMembersTab.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ export interface AwardedMembersTabProps {
1212
}
1313

1414
const AwardedMembersTab: FC<AwardedMembersTabProps> = (props: AwardedMembersTabProps) => {
15-
const [sort, setSort]: [Sort, Dispatch<SetStateAction<Sort>>] = useState<Sort>(tableGetDefaultSort(awardedMembersColumns))
15+
const [sort, setSort]: [Sort, Dispatch<SetStateAction<Sort>>]
16+
= useState<Sort>(tableGetDefaultSort(awardedMembersColumns))
1617

1718
const [columns]: [
1819
ReadonlyArray<TableColumn<MemberBadgeAward>>,

src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-action-renderer/MemberActionRenderer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* eslint-disable arrow-body-style */
1+
/* eslint-disable */
22
// TODO: enable when unassign feature is ready
33
// import { Button, ButtonProps, useCheckIsMobile } from '../../../../../../../lib'
44
import { MemberBadgeAward } from '../../../../../game-lib'

src-ts/tools/gamification-admin/pages/badge-detail/AwardedMembersTab/awarded-members-table/member-handle-renderer/MemberHandleRenderer.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,20 @@ import { MemberBadgeAward } from '../../../../../game-lib'
55
import styles from './MemberHandleRenderer.module.scss'
66

77
const MemberHandleRenderer: (memberAward: MemberBadgeAward) => JSX.Element
8-
= (memberAward: MemberBadgeAward): JSX.Element => (
8+
= (memberAward: MemberBadgeAward): JSX.Element => {
9+
function handleOpenLink(): void {
10+
window.open(`${EnvironmentConfig.TOPCODER_URLS.USER_PROFILE}/${memberAward.user_handle}`, '_blank')
11+
}
12+
13+
return (
914
<div className={styles.memberAward}>
1015
<p className={styles.memberHandle}>{memberAward.user_handle}</p>
1116
<IconOutline.ExternalLinkIcon
1217
className={styles.profileLink}
13-
onClick={() => window.open(`${EnvironmentConfig.TOPCODER_URLS.USER_PROFILE}/${memberAward.user_handle}`, '_blank')}
18+
onClick={handleOpenLink}
1419
/>
1520
</div>
1621
)
22+
}
1723

1824
export default MemberHandleRenderer

src-ts/tools/gamification-admin/pages/badge-detail/BadgeDetailPage.tsx

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
/* eslint-disable import/no-unresolved */
22
import { noop, trim } from 'lodash'
3-
import { ChangeEvent, createRef, Dispatch, FC, KeyboardEvent, RefObject, SetStateAction, useEffect, useState } from 'react'
3+
import {
4+
ChangeEvent,
5+
createRef,
6+
Dispatch,
7+
FC,
8+
KeyboardEvent,
9+
RefObject,
10+
SetStateAction,
11+
useEffect,
12+
useState,
13+
} from 'react'
414
import { Params, useLocation, useParams } from 'react-router-dom'
515
import { toast } from 'react-toastify'
616
import { KeyedMutator, useSWRConfig } from 'swr'
@@ -9,9 +19,29 @@ import ContentEditable from 'react-contenteditable'
919
import MarkdownIt from 'markdown-it'
1020
import sanitizeHtml from 'sanitize-html'
1121

12-
import { Breadcrumb, BreadcrumbItemModel, Button, ButtonProps, ContentLayout, IconOutline, IconSolid, LoadingSpinner, PageDivider, Sort, tableGetDefaultSort, TabsNavbar, TabsNavItem } from '../../../../lib'
22+
import {
23+
Breadcrumb,
24+
BreadcrumbItemModel,
25+
Button,
26+
ButtonProps,
27+
ContentLayout,
28+
IconOutline,
29+
IconSolid,
30+
LoadingSpinner,
31+
PageDivider,
32+
Sort,
33+
tableGetDefaultSort,
34+
TabsNavbar,
35+
TabsNavItem,
36+
} from '../../../../lib'
1337
import { GamificationConfig } from '../../game-config'
14-
import { BadgeDetailPageHandler, GameBadge, useGamificationBreadcrumb, useGetGameBadgeDetails, useGetGameBadgesPage } from '../../game-lib'
38+
import {
39+
BadgeDetailPageHandler,
40+
GameBadge,
41+
useGamificationBreadcrumb,
42+
useGetGameBadgeDetails,
43+
useGetGameBadgesPage,
44+
} from '../../game-lib'
1545
import { BadgeActivatedModal } from '../../game-lib/modals/badge-activated-modal'
1646
import { badgeListingColumns } from '../badge-listing/badge-listing-table'
1747

@@ -65,20 +95,26 @@ const BadgeDetailPage: FC = () => {
6595

6696
const fileInputRef: RefObject<HTMLInputElement> = createRef<HTMLInputElement>()
6797

68-
// eslint-disable-next-line no-null/no-null
69-
const [newImageFile, setNewImageFile]: [FileList | null, Dispatch<SetStateAction<FileList | null>>] = useState<FileList | null>(null)
98+
const [newImageFile, setNewImageFile]: [FileList | undefined, Dispatch<SetStateAction<FileList | undefined>>]
99+
= useState<FileList | undefined>(undefined)
70100

71-
const [fileDataURL, setFileDataURL]: [string | undefined, Dispatch<SetStateAction<string | undefined>>] = useState<string | undefined>()
101+
const [fileDataURL, setFileDataURL]: [string | undefined, Dispatch<SetStateAction<string | undefined>>]
102+
= useState<string | undefined>()
72103

73-
const [isBadgeDescEditingMode, setIsBadgeDescEditingMode]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
104+
const [isBadgeDescEditingMode, setIsBadgeDescEditingMode]: [boolean, Dispatch<SetStateAction<boolean>>]
105+
= useState<boolean>(false)
74106

75107
// badgeListingMutate will reset badge listing page cache when called
76108
const sort: Sort = tableGetDefaultSort(badgeListingColumns)
77109
const { mutate: badgeListingMutate }: { mutate: KeyedMutator<any> } = useGetGameBadgesPage(sort)
78110

79-
const [badgeNameErrorText, setBadgeNameErrorText]: [string | undefined, Dispatch<SetStateAction<string | undefined>>] = useState<string | undefined>()
111+
const [badgeNameErrorText, setBadgeNameErrorText]: [
112+
string | undefined,
113+
Dispatch<SetStateAction<string | undefined>>
114+
] = useState<string | undefined>()
80115

81-
const [showActivatedModal, setShowActivatedModal]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
116+
const [showActivatedModal, setShowActivatedModal]: [boolean, Dispatch<SetStateAction<boolean>>]
117+
= useState<boolean>(false)
82118

83119
const { cache, mutate }: FullConfiguration = useSWRConfig()
84120

@@ -135,6 +171,7 @@ const BadgeDetailPage: FC = () => {
135171
onClick: onActivateBadge,
136172
})
137173
break
174+
default: break
138175
}
139176
}
140177
}, [
@@ -256,6 +293,28 @@ const BadgeDetailPage: FC = () => {
256293
badgeListingMutate()
257294
}
258295

296+
function handleBadgeEditClick(): void {
297+
fileInputRef.current?.click()
298+
}
299+
300+
function cancelEditBadge(): void {
301+
setIsBadgeDescEditingMode(false)
302+
}
303+
304+
function hideActivateModal(): void {
305+
setShowActivatedModal(false)
306+
}
307+
308+
function handleContentEditFocus(): void {
309+
setIsBadgeDescEditingMode(true)
310+
}
311+
312+
function handleContentChange(): void {
313+
if (badgeNameErrorText) {
314+
setBadgeNameErrorText(undefined)
315+
}
316+
}
317+
259318
function validateFilePicked(e: ChangeEvent<HTMLInputElement>): void {
260319
if (e.target.files?.length) {
261320
if (GamificationConfig.ACCEPTED_BADGE_MIME_TYPES.includes(e.target.files[0].type)) {
@@ -327,9 +386,12 @@ const BadgeDetailPage: FC = () => {
327386
buttonStyle='icon'
328387
icon={IconOutline.PencilIcon}
329388
className={styles.filePickerPencil}
330-
onClick={() => fileInputRef.current?.click()}
389+
onClick={handleBadgeEditClick}
390+
/>
391+
<img
392+
src={fileDataURL || badgeDetailsHandler.data?.badge_image_url}
393+
alt='badge media preview'
331394
/>
332-
<img src={fileDataURL || badgeDetailsHandler.data?.badge_image_url} alt='badge media preview' />
333395
<input
334396
type='file'
335397
ref={fileInputRef}
@@ -343,7 +405,7 @@ const BadgeDetailPage: FC = () => {
343405
<ContentEditable
344406
innerRef={badgeNameRef}
345407
html={badgeDetailsHandler.data?.badge_name as string}
346-
onChange={() => (badgeNameErrorText ? setBadgeNameErrorText(undefined) : '')}
408+
onChange={handleContentChange}
347409
onKeyDown={onNameEditKeyDown}
348410
onBlur={onSaveBadgeName}
349411
onFocus={onBadgeNameEditFocus}
@@ -364,11 +426,17 @@ const BadgeDetailPage: FC = () => {
364426
html={
365427
isBadgeDescEditingMode
366428
? badgeDetailsHandler.data?.badge_description as string
367-
: md.render(badgeDetailsHandler.data?.badge_description as string)
429+
: md.render(
430+
badgeDetailsHandler.data?.badge_description as string,
431+
)
368432
}
369433
onChange={noop}
370-
onFocus={() => setIsBadgeDescEditingMode(true)}
371-
className={isBadgeDescEditingMode ? styles.badgeEditableMode : styles.badgeEditable}
434+
onFocus={handleContentEditFocus}
435+
className={
436+
isBadgeDescEditingMode
437+
? styles.badgeEditableMode
438+
: styles.badgeEditable
439+
}
372440
/>
373441
{
374442
isBadgeDescEditingMode && (
@@ -377,7 +445,7 @@ const BadgeDetailPage: FC = () => {
377445
label='Cancel'
378446
buttonStyle='secondary'
379447
size='xs'
380-
onClick={() => setIsBadgeDescEditingMode(false)}
448+
onClick={cancelEditBadge}
381449
/>
382450
<Button
383451
label='Save'
@@ -405,7 +473,7 @@ const BadgeDetailPage: FC = () => {
405473
&& (
406474
<BadgeActivatedModal
407475
isOpen={showActivatedModal}
408-
onClose={() => setShowActivatedModal(false)}
476+
onClose={hideActivateModal}
409477
badge={badgeDetailsHandler.data}
410478
/>
411479
)

src-ts/tools/gamification-admin/pages/badge-detail/BatchAwardTab/BatchAwardTab.tsx

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,19 @@ interface BatchAwardTabProps {
1414

1515
const BatchAwardTab: FC<BatchAwardTabProps> = (props: BatchAwardTabProps) => {
1616

17-
const [showBadgeAssigned, setShowBadgeAssigned]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
17+
const [showBadgeAssigned, setShowBadgeAssigned]: [
18+
boolean,
19+
Dispatch<SetStateAction<boolean>>
20+
] = useState<boolean>(false)
1821

19-
// eslint-disable-next-line no-null/no-null
20-
const [files, setFiles]: [FileList | null, Dispatch<SetStateAction<FileList | null>>] = useState<FileList | null>(null)
22+
const [files, setFiles]: [
23+
FileList | undefined,
24+
Dispatch<SetStateAction<FileList | undefined>>
25+
] = useState<FileList | undefined>(undefined)
2126

2227
const [errorText, setErrorText]: [string, Dispatch<SetStateAction<string>>] = useState<string>('')
2328

24-
function onFilePick(fileList: FileList | null): void {
29+
function onFilePick(fileList: FileList | undefined): void {
2530
if (fileList && fileList[0] && fileList[0].type !== 'text/csv') {
2631
setErrorText('Only CSV files are allowed.')
2732
} else {
@@ -34,7 +39,7 @@ const BatchAwardTab: FC<BatchAwardTabProps> = (props: BatchAwardTabProps) => {
3439
batchAssignRequestAsync(files?.item(0) as File)
3540
.then(() => {
3641
setShowBadgeAssigned(true)
37-
setFiles(null)
42+
setFiles(undefined)
3843
})
3944
.catch(e => {
4045
let message: string = e.message
@@ -46,13 +51,29 @@ const BatchAwardTab: FC<BatchAwardTabProps> = (props: BatchAwardTabProps) => {
4651
})
4752
}
4853

54+
function handleModalClose(): void {
55+
setShowBadgeAssigned(false)
56+
props.onBatchAssign()
57+
}
58+
4959
return (
5060
<div className={styles.tabWrap}>
5161
<h3>Batch Award</h3>
5262
<div className={styles.batchFormWrap}>
5363
<div>
54-
<p>If you would like to assign multiple people to multiple badges, this area is for you. Download the template below, populate the file with your data, and upload that file to the right once completed.</p>
55-
<a target='_blank' href='/gamification-admin/bulk.sample.csv' download='bulk.sample.csv' className={styles.templateLink}>Download template CSV</a>
64+
<p>
65+
If you would like to assign multiple people to multiple badges,
66+
this area is for you. Download the template below, populate the
67+
file with your data, and upload that file to the right once completed.
68+
</p>
69+
<a
70+
target='_blank'
71+
href='/gamification-admin/bulk.sample.csv'
72+
download='bulk.sample.csv'
73+
className={styles.templateLink}
74+
>
75+
Download template CSV
76+
</a>
5677
</div>
5778
<div className={styles.batchForm}>
5879
<InputFilePicker
@@ -84,10 +105,7 @@ const BatchAwardTab: FC<BatchAwardTabProps> = (props: BatchAwardTabProps) => {
84105
<BadgeAssignedModal
85106
badge={props.badge}
86107
isOpen={showBadgeAssigned}
87-
onClose={() => {
88-
setShowBadgeAssigned(false)
89-
props.onBatchAssign()
90-
}}
108+
onClose={handleModalClose}
91109
/>
92110
)
93111
}

src-ts/tools/gamification-admin/pages/badge-detail/ManualAwardTab/ManualAwardTab.tsx

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,21 @@ export interface ManualAwardTabProps {
1717

1818
const ManualAwardTab: FC<ManualAwardTabProps> = (props: ManualAwardTabProps) => {
1919

20-
const [selectedMembers, setSelectedMembers]: [Array<MembersAutocompeteResult>, Dispatch<SetStateAction<Array<MembersAutocompeteResult>>>]
20+
const [selectedMembers, setSelectedMembers]: [
21+
Array<MembersAutocompeteResult>,
22+
Dispatch<SetStateAction<Array<MembersAutocompeteResult>>>
23+
]
2124
= useState<Array<MembersAutocompeteResult>>([])
2225

23-
const [showBadgeAssigned, setShowBadgeAssigned]: [boolean, Dispatch<SetStateAction<boolean>>] = useState<boolean>(false)
26+
const [showBadgeAssigned, setShowBadgeAssigned]: [
27+
boolean,
28+
Dispatch<SetStateAction<boolean>>
29+
] = useState<boolean>(false)
2430

25-
const [badgeAssignError, setBadgeAssignError]: [string | undefined, Dispatch<SetStateAction<string | undefined>>] = useState<string | undefined>()
31+
const [badgeAssignError, setBadgeAssignError]: [
32+
string | undefined,
33+
Dispatch<SetStateAction<string | undefined>>
34+
] = useState<string | undefined>()
2635

2736
function onAward(): void {
2837
const csv: string = generateCSV(
@@ -37,19 +46,30 @@ const ManualAwardTab: FC<ManualAwardTabProps> = (props: ManualAwardTabProps) =>
3746
.catch(e => {
3847
let message: string = e.message
3948
if (e.errors && e.errors[0] && e.errors[0].path === 'user_id') {
40-
const handleOrId: string = find(selectedMembers, { userId: e.errors[0].value })?.handle || e.errors[0].value
49+
const handleOrId: string = find(
50+
selectedMembers,
51+
{ userId: e.errors[0].value },
52+
)?.handle || e.errors[0].value
4153
message = `Member ${handleOrId} already owns this badge.`
4254
}
4355

4456
setBadgeAssignError(message)
4557
})
4658
}
4759

60+
function handleModalClose(): void {
61+
setShowBadgeAssigned(false)
62+
props.onManualAssign()
63+
}
64+
4865
return (
4966
<div className={styles.tabWrap}>
5067
<h3>Manual Award</h3>
5168
<div className={styles.manualFormWrap}>
52-
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Neque ullamcorper neque sed orci, enim amet, sed.</p>
69+
<p>
70+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
71+
Neque ullamcorper neque sed orci, enim amet, sed.
72+
</p>
5373
<div className={styles.manualForm}>
5474
<InputHandleAutocomplete
5575
label='Select Member'
@@ -77,10 +97,7 @@ const ManualAwardTab: FC<ManualAwardTabProps> = (props: ManualAwardTabProps) =>
7797
<BadgeAssignedModal
7898
badge={props.badge}
7999
isOpen={showBadgeAssigned}
80-
onClose={() => {
81-
setShowBadgeAssigned(false)
82-
props.onManualAssign()
83-
}}
100+
onClose={handleModalClose}
84101
/>
85102
)
86103
}

0 commit comments

Comments
 (0)