Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(fe): hand over only changed field in problem edit #2098

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
73 changes: 66 additions & 7 deletions apps/frontend/app/admin/problem/[id]/edit/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ import { ScrollArea, ScrollBar } from '@/components/ui/scroll-area'
import { UPDATE_PROBLEM } from '@/graphql/problem/mutations'
import { GET_PROBLEM } from '@/graphql/problem/queries'
import { useMutation, useQuery } from '@apollo/client'
import type { Template, Testcase, UpdateProblemInput } from '@generated/graphql'
import type {
GetProblemQuery,
Template,
Testcase,
UpdateProblemInput
} from '@generated/graphql'
import { zodResolver } from '@hookform/resolvers/zod'
import Link from 'next/link'
import { useRouter } from 'next/navigation'
Expand Down Expand Up @@ -38,17 +43,18 @@ export default function Page({ params }: { params: { id: string } }) {

const methods = useForm<UpdateProblemInput>({
resolver: zodResolver(editSchema),
defaultValues: {
template: []
}
defaultValues: { template: [] }
})

const { handleSubmit, setValue, getValues } = methods

const [blockEdit, setBlockEdit] = useState<boolean>(false)
const [showHint, setShowHint] = useState<boolean>(false)
const [showSource, setShowSource] = useState<boolean>(false)
const [isDialogOpen, setDialogOpen] = useState<boolean>(false)
const [dialogDescription, setDialogDescription] = useState<string>('')
const [initialData, setInitialData] =
useState<GetProblemQuery['getProblem']>()

useQuery(GET_PROBLEM, {
variables: {
Expand All @@ -57,6 +63,11 @@ export default function Page({ params }: { params: { id: string } }) {
},
onCompleted: (problemData) => {
const data = problemData.getProblem

if (data.submissionCount > 0) setBlockEdit(true)

setInitialData(data)

setValue('id', +id)
setValue('title', data.title)
setValue('isVisible', data.isVisible)
Expand Down Expand Up @@ -104,9 +115,57 @@ export default function Page({ params }: { params: { id: string } }) {
}
})

// TODO: refactor after discussing schema ProblemWithIsVisible and UpdateProblemInput
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const getChangedFields = (initial: any, current: any) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const changedFields: any = {}

// Define a map of fields that need to be renamed for comparison
const fieldMapping: Record<string, string> = {
testcases: 'testcase'
}

for (const key in current) {
const mappedKey = fieldMapping[key] || key
if (JSON.stringify(current[key]) !== JSON.stringify(initial[mappedKey])) {
changedFields[key] = current[key]
}
}
return changedFields
}

const [updateProblem, { error }] = useMutation(UPDATE_PROBLEM)

const onSubmit = async (input: UpdateProblemInput) => {
// TODO: need to check tags and templates from input
const currentValues = getValues()
const changedFields = getChangedFields(initialData, currentValues)

// remove id and __typename from testcases
if (changedFields.testcases) {
changedFields.testcases = changedFields.testcases.map(
({
id,
__typename,
...rest
}: {
id: number
__typename: string
input: string
output: string
isHidden: boolean
scoreWeight: number
}) => {
void id
void __typename
return rest
}
)
}

changedFields['id'] = Number(id)

const testcases = getValues('testcases') as Testcase[]
if (validateScoreWeight(testcases) === false) {
setDialogDescription(
Expand All @@ -127,7 +186,7 @@ export default function Page({ params }: { params: { id: string } }) {
await updateProblem({
variables: {
groupId: 1,
input
input: changedFields
}
})
if (error) {
Expand Down Expand Up @@ -193,10 +252,10 @@ export default function Page({ params }: { params: { id: string } }) {
</div>
</div>

{getValues('testcases') && <TestcaseField />}
{getValues('testcases') && <TestcaseField blockEdit={blockEdit} />}

<FormSection title="Limit">
<LimitForm />
<LimitForm blockEdit={blockEdit} />
</FormSection>
<TemplateField />
<SwitchField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ interface ExampleTextareaProps {
// TODO: any를 다른 type으로 대체
// eslint-disable-next-line @typescript-eslint/no-explicit-any
register: any
blockEdit?: boolean
}
export default function ExampleTextarea({
onRemove,
inputName,
outputName,
className,
register
register,
blockEdit
}: ExampleTextareaProps) {
return (
<div
Expand All @@ -30,11 +32,13 @@ export default function ExampleTextarea({
onClick={() => onRemove()}
/>
<Textarea
disabled={blockEdit}
placeholder="Input"
className="resize-none border-0 px-4 py-0 shadow-none focus-visible:ring-0"
{...register(inputName)}
/>
<Textarea
disabled={blockEdit}
placeholder="Output"
className="min-h-[120px] rounded-none border-l border-transparent border-l-gray-200 px-4 py-0 shadow-none focus-visible:ring-0"
{...register(outputName)}
Expand Down
4 changes: 3 additions & 1 deletion apps/frontend/app/admin/problem/_components/LimitForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { useFormContext } from 'react-hook-form'
import ErrorMessage from '../../_components/ErrorMessage'
import { inputStyle } from '../../utils'

export default function LimitForm() {
export default function LimitForm({ blockEdit }: { blockEdit?: boolean }) {
const {
formState: { errors },
register
Expand All @@ -15,6 +15,7 @@ export default function LimitForm() {
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<Input
disabled={blockEdit}
id="time"
type="number"
min={0}
Expand All @@ -32,6 +33,7 @@ export default function LimitForm() {
<div className="flex flex-col gap-1">
<div className="flex items-center gap-2">
<Input
disabled={blockEdit}
id="memory"
type="number"
min={0}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import AddBadge from './AddBadge'
import { CautionDialog } from './CautionDialog'
import TestcaseItem from './TestcaseItem'

export default function TestcaseField() {
export default function TestcaseField({ blockEdit }: { blockEdit?: boolean }) {
const {
formState: { errors },
getValues,
Expand Down Expand Up @@ -119,6 +119,7 @@ export default function TestcaseField() {
(item, index) =>
!item.isHidden && (
<TestcaseItem
blockEdit={blockEdit}
key={index}
index={index}
itemError={itemErrors}
Expand All @@ -134,6 +135,7 @@ export default function TestcaseField() {
(item, index) =>
item.isHidden && (
<TestcaseItem
blockEdit={blockEdit}
key={index}
index={index}
itemError={itemErrors}
Expand Down
4 changes: 4 additions & 0 deletions apps/frontend/app/admin/problem/_components/TestcaseItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import { isInvalid } from '../_libs/utils'
import ExampleTextarea from './ExampleTextarea'

interface TestcaseItemProps {
blockEdit?: boolean
index: number
itemError: FieldErrorsImpl | undefined
onRemove: () => void
}

export default function TestcaseItem({
blockEdit,
index,
itemError,
onRemove
Expand Down Expand Up @@ -77,6 +79,7 @@ export default function TestcaseItem({

<div>
<input
disabled={blockEdit}
{...register(`testcases.${index}.scoreWeight`, {
setValueAs: (value) => (isInvalid(value) ? null : Number(value))
})}
Expand All @@ -94,6 +97,7 @@ export default function TestcaseItem({
</div>
</div>
<ExampleTextarea
blockEdit={blockEdit}
onRemove={onRemove}
inputName={`testcases.${index}.input`}
outputName={`testcases.${index}.output`}
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/app/admin/problem/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export default function Page({
enableFilter={true}
enableDelete={true}
enablePagination={true}
defaultSortColumn={{ id: 'createTime', desc: true }}
defaultSortColumn={{ id: 'updateTime', desc: true }}
/>
)}
</div>
Expand Down
1 change: 1 addition & 0 deletions apps/frontend/graphql/problem/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const GET_PROBLEM = gql(`
description
inputDescription
outputDescription
submissionCount
testcase {
id
input
Expand Down
Loading