Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
},
"dependencies": {
"@datadog/browser-logs": "^4.21.2",
"@hello-pangea/dnd": "^18.0.1",
"@heroicons/react": "^1.0.6",
"@hookform/resolvers": "^4.1.2",
"@popperjs/core": "^2.11.8",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ export const ScorecardDetails: FC<Props> = (props: Props) => {
(questionResult, question) => {
let questionPoint = 0
const initialAnswer
= mapingResult[question.id]
= mapingResult[question.id as string]
if (
question.type === 'YES_NO'
&& initialAnswer === 'Yes'
Expand Down Expand Up @@ -338,7 +338,7 @@ export const ScorecardDetails: FC<Props> = (props: Props) => {
) => {
const reviewItemInfo
= mappingReviewInfo[
question.id
question.id as string
]
if (
!reviewItemInfo
Expand Down
3 changes: 2 additions & 1 deletion src/apps/review/src/lib/models/ScorecardQuestion.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
* Scorecard question info
*/
export interface ScorecardQuestion {
id: string
id?: string
type: 'SCALE' | 'YES_NO' | 'TEST_CASE'
description: string
guidelines: string
weight: number
scaleMin: number
scaleMax: number
requiresUpload: boolean
sortOrder: number
}
2 changes: 1 addition & 1 deletion src/apps/review/src/lib/models/ScorecardSection.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { ScorecardQuestion } from './ScorecardQuestion.model'
* Scorcard section info
*/
export interface ScorecardSection {
id: string
id?: string
name: string
weight: number
sortOrder: number
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,10 @@
.headerArea {
background: #0F172A;
color: $tc-white;
.title {
display: flex;
align-items: center;
}

:global(.input-error) {
font-family: "Nunito Sans", sans-serif;
Expand Down Expand Up @@ -116,6 +120,11 @@
background: $teal-160;
color: $tc-white;

.title {
display: flex;
align-items: center;
}

:global(.input-error) {
font-family: "Nunito Sans", sans-serif;
background: #E2CBC0;
Expand Down Expand Up @@ -147,6 +156,11 @@
grid-template-columns: 1fr 7.85% 3.5%;
gap: $sp-4;

.title {
display: flex;
align-items: center;
}

:global(.main-group) {
grid-column: 1;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
/* eslint-disable import/no-extraneous-dependencies */
import * as yup from 'yup'
import { FC, useCallback, useEffect, useMemo, useState } from 'react'
import { FormProvider, useForm } from 'react-hook-form'
import { useNavigate, useParams } from 'react-router-dom'
import { toast } from 'react-toastify'

import { yupResolver } from '@hookform/resolvers/yup'
import { Button, LinkButton } from '~/libs/ui'
import { DragDropContext, DropResult } from '@hello-pangea/dnd'
import { yupResolver } from '@hookform/resolvers/yup'

import { PageWrapper } from '../../../lib'
import { useFetchScorecard } from '../../../lib/hooks/useFetchScorecard'
import { saveScorecard } from '../../../lib/services'
import { rootRoute } from '../../../config/routes.config'
import { PageWrapper } from '../../../lib'
import type { ScorecardQuestion, ScorecardSection } from '../../../lib/models'

import { getEmptyScorecard } from './utils'
import { EditScorecardPageContextProvider } from './EditScorecardPage.context'
Expand Down Expand Up @@ -50,7 +53,7 @@ const EditScorecardPage: FC = () => {
}
}, [scorecardQuery.scorecard, scorecardQuery.isValidating])

const handleSubmit = useCallback(async (value: any) => {
const handleSubmit = useCallback(async (value: any): Promise<void> => {
setSaving(true)
try {
const response = await saveScorecard(value)
Expand All @@ -60,12 +63,141 @@ const EditScorecardPage: FC = () => {
}
} catch (e: any) {
toast.error(`Couldn't save scorecard! ${e.message}`)
console.error('Couldn\'t save scorecard!', e)
console.error("Couldn't save scorecard!", e)
} finally {
setSaving(false)
}
}, [params.scorecardId, navigate])

const reorder = (list: any[], startIndex: number, endIndex: number): any[] => {
const result = Array.from(list)
const [removed] = result.splice(startIndex, 1)
result.splice(endIndex, 0, removed)
return result
}

const move = (
source: any[],
destination: any[],
sourceIndex: number,
destinationIndex: number,
): { source: any[]; destination: any[] } => {
const sourceClone = Array.from(source)
const destClone = Array.from(destination)
const [removed] = sourceClone.splice(sourceIndex, 1)
destClone.splice(destinationIndex, 0, removed)
return {
destination: destClone,
source: sourceClone,
}
}

function onDragEnd(result: DropResult): void {
if (!result.destination) return

const { source, destination, type }: DropResult<string> = result

if (type === 'group') {
const newGroups = reorder(editForm.getValues('scorecardGroups'), source.index, destination.index)
editForm.setValue('scorecardGroups', newGroups, { shouldDirty: true, shouldValidate: true })
} else if (type === 'section') {
const groups = editForm.getValues('scorecardGroups')
const sourceGroupIndex = Number(source.droppableId.split('.')[1])
const destGroupIndex = Number(destination.droppableId.split('.')[1])

if (sourceGroupIndex === destGroupIndex) {
const newSections = reorder(groups[sourceGroupIndex].sections, source.index, destination.index)
newSections.forEach((section, index) => {
section.sortOrder = index
})
groups[sourceGroupIndex].sections = newSections
} else {
const {
source: newSourceSections,
destination: newDestSections,
}: { source: ScorecardSection[], destination: ScorecardSection[]} = move(
groups[sourceGroupIndex].sections,
groups[destGroupIndex].sections,
source.index,
destination.index,
)

const movedSection = newDestSections[destination.index]
if (movedSection) {
delete movedSection.id

movedSection.questions.forEach((question: any) => {
delete question.id
})
}

newSourceSections.forEach((section, index) => {
section.sortOrder = index
})

newDestSections.forEach((section, index) => {
section.sortOrder = index
})

groups[sourceGroupIndex].sections = newSourceSections
groups[destGroupIndex].sections = newDestSections
}

editForm.setValue('scorecardGroups', groups, { shouldDirty: true, shouldValidate: true })
} else if (type === 'question') {
const groups = editForm.getValues('scorecardGroups')
const parseDroppableId = (id: string): { groupIndex: number; sectionIndex: number } => {
const parts = id.split('.')
return {
groupIndex: Number(parts[1]),
sectionIndex: Number(parts[3]),
}
}

const sourceIds = parseDroppableId(source.droppableId)
const destIds = parseDroppableId(destination.droppableId)

if (sourceIds.groupIndex === destIds.groupIndex && sourceIds.sectionIndex === destIds.sectionIndex) {
const questions = groups[sourceIds.groupIndex].sections[sourceIds.sectionIndex].questions
const newQuestions = reorder(questions, source.index, destination.index)
newQuestions.forEach((question, index) => {
question.sortOrder = index
})
groups[sourceIds.groupIndex].sections[sourceIds.sectionIndex].questions = newQuestions
} else {
const sourceQuestions = groups[sourceIds.groupIndex].sections[sourceIds.sectionIndex].questions
const destQuestions = groups[destIds.groupIndex].sections[destIds.sectionIndex].questions
const {
source: newSourceQuestions,
destination: newDestQuestions,
}: { source: ScorecardQuestion[], destination: ScorecardQuestion[]} = move(
sourceQuestions,
destQuestions,
source.index,
destination.index,
)

const movedQuestion = newDestQuestions[destination.index]
if (movedQuestion) {
delete movedQuestion.id
}

newSourceQuestions.forEach((question, index) => {
question.sortOrder = index
})

newDestQuestions.forEach((question, index) => {
question.sortOrder = index
})

groups[sourceIds.groupIndex].sections[sourceIds.sectionIndex].questions = newSourceQuestions
groups[destIds.groupIndex].sections[destIds.sectionIndex].questions = newDestQuestions
}

editForm.setValue('scorecardGroups', groups, { shouldDirty: true, shouldValidate: true })
}
}

if (scorecardQuery.isValidating) {
return <></>
}
Expand All @@ -78,12 +210,13 @@ const EditScorecardPage: FC = () => {
>
<form className={styles.pageContentWrap} onSubmit={editForm.handleSubmit(handleSubmit)}>
<FormProvider {...editForm}>
<DragDropContext onDragEnd={onDragEnd}>
<h3 className={styles.sectionTitle}>1. Scorecard Information</h3>
<ScorecardInfoForm />

<h3 className={styles.sectionTitle}>1. Scorecard Information</h3>
<ScorecardInfoForm />

<h3 className={styles.sectionTitle}>2. Evaluation Structure</h3>
<ScorecardGroupForm />
<h3 className={styles.sectionTitle}>2. Evaluation Structure</h3>
<ScorecardGroupForm />
</DragDropContext>

<div className={styles.bottomContainer}>
<hr />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react'

const DragIcon: React.FC = () => (
<svg
width='32'
height='32'
viewBox='0 0 32 32'
fill='currentColor'
xmlns='http://www.w3.org/2000/svg'
role='img'
aria-label='Drag handle'
style={{ cursor: 'grab' }}
>
<title>Draggable</title>
<rect x='10' y='6' width='4' height='4' />
<rect x='18' y='6' width='4' height='4' />
<rect x='10' y='14' width='4' height='4' />
<rect x='18' y='14' width='4' height='4' />
<rect x='10' y='22' width='4' height='4' />
<rect x='18' y='22' width='4' height='4' />
</svg>
)

export default DragIcon
Loading