diff --git a/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.module.scss b/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.module.scss
index 995aeed6d..2d443acc9 100644
--- a/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.module.scss
+++ b/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.module.scss
@@ -82,12 +82,21 @@
.answerWrap {
display: flex;
align-items: center;
+ flex-wrap: wrap;
gap: $sp-4;
.answerInput {
width: 120px;
}
}
+.placementGuidelines {
+ flex-basis: 100%;
+ order: 1;
+ color: #767676;
+ font-size: 14px;
+ line-height: 20px;
+}
+
.responseTypeWrap {
width: 240px;
}
diff --git a/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.spec.tsx b/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.spec.tsx
new file mode 100644
index 000000000..44e7bb795
--- /dev/null
+++ b/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.spec.tsx
@@ -0,0 +1,174 @@
+/* eslint-disable import/no-extraneous-dependencies, ordered-imports/ordered-imports */
+import { FC, useMemo } from 'react'
+import { render, screen } from '@testing-library/react'
+import { useForm } from 'react-hook-form'
+
+import type {
+ ChallengeDetailContextModel,
+ FormReviews,
+ ReviewItemInfo,
+ ScorecardQuestion,
+} from '../../../../../models'
+import { ChallengeDetailContext } from '../../../../../contexts/ChallengeDetailContext'
+
+import ScorecardQuestionEdit from './ScorecardQuestionEdit'
+
+const mockUseScorecardViewerContext = jest.fn()
+
+jest.mock('../../ScorecardViewer.context', () => ({
+ useScorecardViewerContext: () => mockUseScorecardViewerContext(),
+}))
+
+jest.mock('../../../../../utils', () => ({
+ getScoreResponseOptions: () => [{
+ label: '10',
+ value: '10',
+ }],
+}))
+
+jest.mock('~/libs/ui', () => ({
+ IconOutline: {
+ ChevronDownIcon: () => ,
+ },
+}), { virtual: true })
+
+jest.mock('~/apps/review/src/lib/assets/icons', () => ({
+ IconComment: () => ,
+}), { virtual: true })
+
+jest.mock('../../../../FieldMarkdownEditor', () => ({
+ FieldMarkdownEditor: () => ,
+}))
+
+jest.mock('../../../../MarkdownReview', () => ({
+ MarkdownReview: () =>
,
+}))
+
+const submissionPlaceQuestion: ScorecardQuestion = {
+ description: 'Submission Place',
+ guidelines: '',
+ id: 'submission-place',
+ requiresUpload: false,
+ scaleMax: 10,
+ scaleMin: 1,
+ sortOrder: 0,
+ type: 'SCALE',
+ weight: 100,
+}
+
+const reviewItem: ReviewItemInfo = {
+ createdAt: '2026-07-30T00:00:00.000Z',
+ id: 'review-item-1',
+ initialAnswer: '10',
+ reviewItemComments: [],
+ scorecardQuestionId: 'submission-place',
+}
+
+interface QuestionHarnessProps {
+ question: ScorecardQuestion
+ trackName: string
+}
+
+/**
+ * Supplies the form, scorecard, and challenge contexts needed by an editable question.
+ *
+ * @param props.question scorecard question to render.
+ * @param props.trackName challenge track name exposed by the challenge context.
+ * @returns An editable scorecard question with realistic form state.
+ * @throws This test component does not throw.
+ */
+const QuestionHarness: FC = props => {
+ const form = useForm({
+ defaultValues: {
+ reviews: [{
+ comments: [],
+ id: reviewItem.id,
+ index: 0,
+ initialAnswer: reviewItem.initialAnswer!,
+ scorecardQuestionId: props.question.id!,
+ }],
+ },
+ })
+ const challengeContext = useMemo(
+ () => ({
+ challengeInfo: {
+ track: {
+ name: props.trackName,
+ },
+ },
+ } as unknown as ChallengeDetailContextModel),
+ [props.trackName],
+ )
+
+ mockUseScorecardViewerContext.mockReturnValue({
+ form,
+ formErrors: {},
+ formTrigger: form.trigger,
+ isTouched: {},
+ scoreMap: new Map([[props.question.id, 100]]),
+ setIsTouched: jest.fn(),
+ toggledItems: {},
+ toggleItem: jest.fn(),
+ })
+
+ return (
+
+
+
+ )
+}
+
+describe('ScorecardQuestionEdit placement guidelines', () => {
+ beforeEach(() => {
+ jest.clearAllMocks()
+ })
+
+ it('explains placement ratings for a design Submission Place question', () => {
+ render(
+ ,
+ )
+
+ const guidelines = screen.getByText(/10 - 1st place/i)
+
+ expect(guidelines.textContent)
+ .toContain('2 and 1 - no placement')
+ })
+
+ it('does not show placement ratings for a non-design challenge', () => {
+ render(
+ ,
+ )
+
+ expect(screen.queryByText(/10 - 1st place/i))
+ .toBeNull()
+ })
+
+ it('does not show placement ratings for another design scorecard question', () => {
+ render(
+ ,
+ )
+
+ expect(screen.queryByText(/10 - 1st place/i))
+ .toBeNull()
+ })
+})
diff --git a/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.tsx b/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.tsx
index 7bc225a88..8c366c8e0 100644
--- a/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.tsx
+++ b/src/apps/review/src/lib/components/Scorecard/ScorecardViewer/ScorecardQuestion/ScorecardQuestionEdit/ScorecardQuestionEdit.tsx
@@ -1,4 +1,9 @@
-import { FC, useCallback, useMemo } from 'react'
+import {
+ FC,
+ useCallback,
+ useContext,
+ useMemo,
+} from 'react'
import {
Controller,
ControllerRenderProps,
@@ -12,14 +17,19 @@ import classNames from 'classnames'
import { IconOutline } from '~/libs/ui'
import { IconComment } from '~/apps/review/src/lib/assets/icons'
-import { QUESTION_RESPONSE_OPTIONS } from '../../../../../../config/index.config'
+import {
+ DESIGN,
+ QUESTION_RESPONSE_OPTIONS,
+} from '../../../../../../config/index.config'
import { getScoreResponseOptions } from '../../../../../utils'
import {
+ ChallengeDetailContextModel,
FormReviews,
ReviewItemInfo,
ScorecardQuestion,
SelectOption,
} from '../../../../../models'
+import { ChallengeDetailContext } from '../../../../../contexts/ChallengeDetailContext'
import { FieldMarkdownEditor } from '../../../../FieldMarkdownEditor'
import { MarkdownReview } from '../../../../MarkdownReview'
import { ScorecardViewerContextValue, useScorecardViewerContext } from '../../ScorecardViewer.context'
@@ -37,6 +47,7 @@ interface ScorecardQuestionEditProps {
}
export const ScorecardQuestionEdit: FC = props => {
+ const { challengeInfo }: ChallengeDetailContextModel = useContext(ChallengeDetailContext)
const {
toggleItem,
toggledItems,
@@ -61,6 +72,13 @@ export const ScorecardQuestionEdit: FC = props => {
const responseOptions = useMemo(() => (
getScoreResponseOptions(props.question)
), [props.question])
+ const showPlacementGuidelines = (
+ challengeInfo?.track?.name?.trim()
+ .toLowerCase() === DESIGN.toLowerCase()
+ && props.question.type === 'SCALE'
+ && props.question.description.trim()
+ .toLowerCase() === 'submission place'
+ )
const {
fields,
@@ -205,6 +223,16 @@ export const ScorecardQuestionEdit: FC = props => {
isDisabled={props.disabled}
/>
+ {showPlacementGuidelines && (
+
+ 10 - 1st place, 9 - 2nd place, 8 - 3rd place,
+ {' '}
+ 7 - 4th place, 6 - 5th place, 5 - 6th place,
+ {' '}
+ 4 - 7th place, 3 - 8th place, 2 and 1 - no placement.
+
+ )}
+
{errorMessage && (
{errorMessage}