Skip to content

Commit 6462088

Browse files
authored
Merge pull request #1182 from topcoder-platform/PM-1505_clone-scorecard
PM-1505 - clone scorecard
2 parents 96f77b1 + 05a2c77 commit 6462088

File tree

3 files changed

+53
-6
lines changed

3 files changed

+53
-6
lines changed

src/apps/review/src/lib/components/TableScorecards/TableScorecards.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*/
44
import { Dispatch, FC, SetStateAction, useMemo } from 'react'
55
import { Link } from 'react-router-dom'
6-
import { noop } from 'lodash'
6+
import { bind, noop } from 'lodash'
77
import classNames from 'classnames'
88

99
import { MobileTableColumn } from '~/apps/admin/src/lib/models/MobileTableColumn.model'
@@ -26,6 +26,7 @@ interface Props {
2626
totalPages: number
2727
page: number
2828
setPage: Dispatch<SetStateAction<number>>
29+
onClone: (scorecard: Scorecard) => unknown
2930
}
3031

3132
export const TableScorecards: FC<Props> = (props: Props) => {
@@ -87,13 +88,13 @@ export const TableScorecards: FC<Props> = (props: Props) => {
8788
{
8889
className: classNames(styles.tableCell, styles.tableCellCenter),
8990
label: 'Action',
90-
renderer: () => (
91+
renderer: (data: Scorecard) => (
9192
<div className={styles.action}>
9293
<div className={styles.actionItem}>
9394
<PencilIcon />
9495
<span>Edit</span>
9596
</div>
96-
<div className={styles.actionItem}>
97+
<div className={styles.actionItem} onClick={bind(props.onClone, this, data)}>
9798
<DuplicateIcon />
9899
<span>Clone</span>
99100
</div>
Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,26 @@
11
/**
22
* Scorecards service
33
*/
4+
import { xhrPostAsync } from '~/libs/core'
5+
import { EnvironmentConfig } from '~/config'
6+
47
import { MockScorecard } from '../../mock-datas'
5-
import { adjustScorecardInfo, ScorecardInfo } from '../models'
8+
import { adjustScorecardInfo, Scorecard, ScorecardInfo } from '../models'
9+
10+
const baseUrl = `${EnvironmentConfig.API.V6}/review/scorecards`
611

712
/**
813
* Fetch scorecard
914
* @returns resolves to the scorecard info
1015
*/
1116
export const fetchScorecards
1217
= async (): Promise<ScorecardInfo> => Promise.resolve(adjustScorecardInfo(MockScorecard) as ScorecardInfo)
18+
19+
/**
20+
* Clone scorecard
21+
* @param scorecard Scorecard to clone
22+
* @returns resolves to the cloned scorecard info
23+
*/
24+
export const cloneScorecard = async (scorecard: Pick<Scorecard, 'id'>): Promise<Scorecard> => (
25+
xhrPostAsync(`${baseUrl}/${scorecard.id}/clone`, {})
26+
)

src/apps/review/src/pages/scorecards/ScorecardsListPage/ScorecardsListPage.tsx

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1+
import { useNavigate } from 'react-router-dom'
12
import { FC, useCallback, useMemo, useState } from 'react'
3+
import { toast } from 'react-toastify'
24

3-
import { PageTitle } from '~/libs/ui'
5+
import { PageTitle, useConfirmationModal } from '~/libs/ui'
46
import { TableLoading } from '~/apps/admin/src/lib'
57

8+
import { Scorecard } from '../../../lib/models'
9+
import { cloneScorecard } from '../../../lib/services'
610
import { PageWrapper, ScorecardsFilter, TableNoRecord, TableScorecards } from '../../../lib'
711
import { ScorecardsResponse, useFetchScorecards } from '../../../lib/hooks'
812

913
import styles from './ScorecardsListPage.module.scss'
1014

1115
export const ScorecardsListPage: FC<{}> = () => {
16+
const navigate = useNavigate()
17+
const confirmation = useConfirmationModal()
18+
1219
const [filters, setFilters] = useState({
1320
category: '',
1421
name: '',
@@ -43,6 +50,30 @@ export const ScorecardsListPage: FC<{}> = () => {
4350
setPage(1)
4451
}, [])
4552

53+
const handleScorecardClone = useCallback(async (scorecard: Scorecard) => {
54+
if (!await confirmation.confirm({
55+
action: 'Clone',
56+
content: `Are you sure you want to clone "${scorecard.name}" scorecard?`,
57+
title: 'Clone Scorecard',
58+
})) {
59+
return
60+
}
61+
62+
try {
63+
const cloned = await cloneScorecard({ id: scorecard.id })
64+
if (!cloned || !cloned.id) {
65+
toast.error('Failed to clone scorecard!')
66+
return
67+
}
68+
69+
toast.success('Scorecard cloned successfully!')
70+
navigate(`${cloned.id}/details`)
71+
} catch (error) {
72+
toast.error('Failed to clone scorecard!')
73+
console.error('Failed to clone scorecard:', error)
74+
}
75+
}, [navigate, confirmation])
76+
4677
return (
4778
<PageWrapper
4879
pageTitle='Scorecards'
@@ -66,6 +97,7 @@ export const ScorecardsListPage: FC<{}> = () => {
6697
<TableNoRecord />
6798
) : (
6899
<TableScorecards
100+
onClone={handleScorecardClone}
69101
totalPages={metadata?.totalPages}
70102
page={page}
71103
setPage={setPage}
@@ -80,7 +112,7 @@ export const ScorecardsListPage: FC<{}> = () => {
80112

81113
</>
82114
)}
83-
115+
{confirmation.modal}
84116
</PageWrapper>
85117
)
86118

0 commit comments

Comments
 (0)