Skip to content

[JDDEV-51] Feat: 실제 공고 지원 플로우 연결 (~자소서 입력) #58

Merged
minnngo merged 5 commits into
developfrom
feature/JDDEV-51-mock_question_input-ui-feat
May 21, 2026
Merged

[JDDEV-51] Feat: 실제 공고 지원 플로우 연결 (~자소서 입력) #58
minnngo merged 5 commits into
developfrom
feature/JDDEV-51-mock_question_input-ui-feat

Conversation

@minnngo
Copy link
Copy Markdown
Collaborator

@minnngo minnngo commented May 21, 2026

🔗 관련 이슈

  • JDDEV-51

📝 개요

  • 실제 공고 지원 플로우에 문항 선택 및 자소서 입력 단계를 연결했습니다.
  • 공통 모달, 푸터, 입력 필드, 헤더 단계 표시 등 디자인/동작 이슈를 함께 정리했습니다.

⌨️ 작업 상세 내용

  • 실제 공고 플로우 연결: /mock-application/jd-review → /mock-application/questions → /mock-application/write
  • SelectQuestion에 onQuestionsChange 콜백 추가
  • InputSection 신규 추가 및 저장된 문항 기반 자소서 입력 UI 연결
  • 문항 추가 모달 입력값 존재 시 primary border 표시
  • 이미지/링크 처리 모달 디자인 및 경고 아이콘 세부 스타일 조정
  • 이미지 읽기 모달 취소 시 모달 닫기 및 fullscreen 해제 처리

Summary by CodeRabbit

  • New Features

    • Added persistent storage of selected questions and answers during the application process.
    • Modals can now be dismissed by clicking outside the content area.
  • Bug Fixes

    • Fixed character count validation for response answers to properly enforce minimum thresholds.
    • Improved URL format validation for document uploads.
  • UI/UX Improvements

    • Enhanced visual feedback for completed application questions.
    • Refined navigation flow and button styling across application steps.
    • Better alignment of form elements and spacing adjustments.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR implements the question selection and answer-input flow for the interview application by exporting the Question type, wiring sessionStorage persistence, rewriting InputSection to manage answers with normalized question models, refactoring page navigation, updating header/footer event handling, and refining modal and input component behaviors.

Changes

Question Selection and Answer Input Interview Flow

Layer / File(s) Summary
Question Type Export and Selection Sync
src/components/apply/SelectQuestion.tsx, src/components/common/chips/ChipQnumber.tsx
Question interface exported; onQuestionsChange callback wired to call on selection changes; notification helper filters selected questions and invokes both selection callbacks; layout and styling updated.
Questions Page Selection Persistence
src/app/apply/virtual/[id]/questions/page.tsx
Imports exported Question type; persists selectedQuestions to sessionStorage in handleConfirm before navigating to write page; footer back action route changed to jd-review.
InputSection Answer Management Component
src/components/apply/InputSection.tsx
Exports StoredQuestion interface; loads from sessionStorage with configurable storageKey and falls back to Korean defaults; normalizes/validates questions; tracks per-question answers in answersById map; computes completion via answer-length thresholds; provides imperative handle for validation; renders chip-based question selector with constrained multiline input.
Write Page Answer Validation and InputSection Integration
src/app/apply/virtual/[id]/write/page.tsx
Integrates InputSection component; handleSubmit checks hasUnderThreshold and returns early to show insufficient-length modal before navigating to result; modal description reformatted to multiline literal.
Header Navigation and Progress Step Styling
src/components/common/header/Header.tsx
Imports useRouter and adds MOCK_APPLICATION_HOME_PATH constant; implements handleLeftActionClick wrapper to conditionally navigate home when click is not prevented; replaces "reached" with "isCurrent" step comparison; applies active styling only for current step; wires left action with wrapper and right action with explicit disabled state.
Footer Event Handling and Layout Restructure
src/components/common/footer/Footer.tsx
Refactors handleBack/handleCta to respect event.defaultPrevented; changes wrapper layout to full-width centered relative/translate with w-screen; updates inner container to mx-auto/flex with max-width/items-start/justify-between; replaces conditional back-button mounting with aria-hidden placeholder; adds !gap-0.5 to back button when shown.
ApplyType Routing and Layout Standardization
src/app/apply/apply-type/ApplyTypePageClient.tsx
Routes handleSubmit based on selectedType to /apply/virtual/new/jd-input for "real" or /apply/virtual/new/jd for "virtual"; changes outer container to h-dvh/pt-6 with overflow-hidden; removes explicit onClick from Header leftAction.
InputMultiLine1000 Configurable Max Length
src/components/common/input/InputMultiLine1000.tsx
Replaces fixed MAX_LENGTH with DEFAULT_MAX_LENGTH constant; adds optional maxLength prop; defaults to DEFAULT_MAX_LENGTH; updates isError calculation and counter display to use dynamic maxLength.
InputSingleLine Active State Derivation
src/components/common/input/InputSingleLine.tsx
Derives isActive boolean from focused state or non-empty value; passes isActive to getWrapperClass instead of separate focused argument.
Modal Outside-Click Closing and Refinements
src/components/common/modal/ModalAdd.tsx, src/components/common/modal/ModalNotice.tsx
ModalAdd: imports useRef/useOutsideClick, creates modalRef, wires outside-click close, adds focusedBorder prop to InputSingleLine. ModalNotice: adds "use client" directive, destructures onClose directly, implements same outside-click pattern with modalRef.
ModalInput Rendering Restructure and Icon Replacement
src/components/common/modal/ModalInput.tsx
Updates imports to Button/IconBox/LoadMotionModal/InputMain; replaces warning icon with internal ModalWarningIcon SVG; changes loading default to false; adds derived render flags (isAlertModal, modalTitle, showLoadingMotion, hasMethodActions); conditionally renders icons/title/description/input; rebuilds footer for methodActions, alert two-button layout, or single submit button.
IconBox className Styling with clsx
src/components/common/icons/IconBox.tsx
Wraps Icon className in clsx(...) combining computed icon color styles with optional iconClassName.
JdInputPageClient URL Validation and Modal Flow
src/app/apply/virtual/[id]/(jd)/jd-input/JdInputPageClient.tsx
Refactors isUrlFormat with clearer early-return control flow; reorganizes handleCtaClick; changes modal close handlers to explicit setters; introduces cancelImageReading to close modals, reset image step, and exit fullscreen; updates submitLinkInput with early guards; rewires reading modal callbacks to use cancelImageReading.
Navigation Path Routing Updates
src/components/common/lnb/Lnb.tsx, src/components/mock-application/MockApplicationHomePageClient.tsx
Lnb updates "모의서류지원" href from /mock-application to /apply. MockApplicationHomePageClient updates button navigation from /apply/virtual to /apply/apply-type.
Disabled Fill Color Theme Update
src/styles/color.css
Updates --color-fill-disabled CSS variable from var(--color-gray-200) to literal hex value #ebebef.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • JobDri-Developer/FrontEnd#53: Introduces the same virtual flow pages and updates Footer component, directly overlapping with questions/page.tsx and write/page.tsx changes.
  • JobDri-Developer/FrontEnd#57: Implements the question selection→write flow with sessionStorage persistence in SelectQuestion/questions/page.tsx and answer input handling in InputSection/write/page.tsx.

Poem

🐰 A bunny hops through questions bright,
Selects them all with pure delight,
Stores answers safe in session's keep,
Then validates before the leap—
Hop, hop, input complete! 🌟

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title references JDDEV-51 and mentions connecting the real job posting application flow through to cover-letter input, which accurately reflects the changeset's main objective of connecting multiple application steps and implementing UI/UX updates.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/JDDEV-51-mock_question_input-ui-feat

Comment @coderabbitai help to get the list of available commands and usage tips.

@minnngo minnngo changed the title Feature/jddev 51 mock question input UI feat [JDDEV-51] Feat: 실제 공고 지원 플로우 연결 (~자소서 입력) May 21, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
jobdri/src/components/common/input/InputMultiLine1000.tsx (1)

35-42: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Enforce maxLength instead of only flagging overflow.

The component currently marks over-limit input as error but still accepts it. That breaks the max-length contract.

💡 Suggested patch
   const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
     const next = e.target.value;
-    // 여기서 return을 안 하니까 복붙해도 그대로 다 들어갑니다.
+    if (next.length > maxLength) return;
     setInternalValue(next);
     onChange?.(next);
   };
@@
         <textarea
@@
           rows={rows}
+          maxLength={maxLength}
         />

Also applies to: 55-70, 78-78

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jobdri/src/components/common/input/InputMultiLine1000.tsx` around lines 35 -
42, handleChange currently flags overflow via isError but still accepts input
beyond maxLength; change handleChange to enforce maxLength by truncating
e.target.value to maxLength before calling setInternalValue and onChange (i.e.,
compute const next = e.target.value.slice(0, maxLength) or similar), and apply
the same enforcement wherever value updates occur in this component (other
handlers around lines 55-70 and the place at 78) so the component never sets or
emits a value longer than maxLength while preserving existing error logic using
isError (value.length > maxLength || !!error).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@jobdri/src/app/apply/virtual/`[id]/questions/page.tsx:
- Around line 17-19: The saveSelectedQuestions function uses a global
sessionStorage key "selectedQuestions" which causes collisions across virtual
IDs; update saveSelectedQuestions to derive a flow- and route-scoped storage key
(e.g., include the virtual [id] and a flow identifier like
"selectedQuestions:{id}:{flowName}") and store selectedQuestions under that
scoped key, then ensure the write page/InputSection receives the exact same
scoped key (via prop or route state) so reads/writes use the same namespaced key
(refer to saveSelectedQuestions, selectedQuestions, and the InputSection
prop/state passing in this file).

In `@jobdri/src/app/mock-application/questions/page.tsx`:
- Around line 12-14: The code currently writes selectedQuestions to
sessionStorage under the global key "selectedQuestions" in
saveSelectedQuestions(), which collides with other flows; change the flow to use
a namespaced key (or a prop-provided key) so each page uses its own storage
key—update saveSelectedQuestions() to set sessionStorage with a unique key like
"mockApplication:selectedQuestions" (or accept a key parameter) and update the
write page to pass that same key into InputSection so both pages read/write the
same namespaced key instead of the shared "selectedQuestions".

In `@jobdri/src/components/apply/InputSection.tsx`:
- Around line 47-50: Validate item.maxLength before using it: replace the
current numeric-only check with a guard that accepts only a finite positive
integer (e.g., Number.isFinite + Number.isInteger + > 0) and otherwise falls
back to DEFAULT_MAX_LENGTH; update the normalization around maxLength in
InputSection (where item.maxLength and DEFAULT_MAX_LENGTH are referenced) so
values like 0, negatives, NaN, Infinity, or non-integers are rejected and
DEFAULT_MAX_LENGTH is used.

In `@jobdri/src/components/common/header/Header.tsx`:
- Around line 69-76: The handler handleLeftActionClick currently always
navigates to MOCK_APPLICATION_HOME_PATH after invoking leftActionOnClick which
forces navigation even when a custom handler exists; change the logic so
navigation only happens when there is no custom leftActionOnClick provided
(i.e., call router.push(MOCK_APPLICATION_HOME_PATH) only if leftActionOnClick is
undefined), updating the handleLeftActionClick implementation to guard the
router.push call accordingly (references: handleLeftActionClick,
leftActionOnClick, router.push, MOCK_APPLICATION_HOME_PATH).

In `@jobdri/src/components/common/icons/IconBox.tsx`:
- Around line 93-96: The lookup into iconColorStyles in IconBox uses state as
"primary" | "secondary" but state can be "danger", causing undefined in the
non-TRASH path; update the className construction (the clsx(...) expression in
IconBox) to guard/normalize state before indexing iconColorStyles (e.g., map
"danger" to a valid bucket or fall back to "primary"/"secondary" based on
background) so iconColorStyles[state][background] is never accessed with
"danger" and iconClassName still applies.

In `@jobdri/src/components/common/modal/ModalInput.tsx`:
- Around line 189-194: In ModalInput, the alert-mode cancel Button is always
rendered with the optional prop onCancel, so ensure it always invokes a working
handler by wiring a fallback: change the Button onClick to call onCancel if
provided, otherwise call the component's close handler (e.g., handleClose /
onClose / onDismiss) or another internal close function; update the Button usage
in the ModalInput component so the cancel button never becomes a no-op by
falling back to that close handler.

---

Outside diff comments:
In `@jobdri/src/components/common/input/InputMultiLine1000.tsx`:
- Around line 35-42: handleChange currently flags overflow via isError but still
accepts input beyond maxLength; change handleChange to enforce maxLength by
truncating e.target.value to maxLength before calling setInternalValue and
onChange (i.e., compute const next = e.target.value.slice(0, maxLength) or
similar), and apply the same enforcement wherever value updates occur in this
component (other handlers around lines 55-70 and the place at 78) so the
component never sets or emits a value longer than maxLength while preserving
existing error logic using isError (value.length > maxLength || !!error).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a36fc09d-a04f-425d-b3d8-b710477992d7

📥 Commits

Reviewing files that changed from the base of the PR and between 93eba7e and f71877a.

📒 Files selected for processing (19)
  • jobdri/src/app/apply-type/ApplyTypePageClient.tsx
  • jobdri/src/app/apply/virtual/[id]/questions/page.tsx
  • jobdri/src/app/apply/virtual/[id]/write/page.tsx
  • jobdri/src/app/mock-application/jd-input/JdInputPageClient.tsx
  • jobdri/src/app/mock-application/jd-review/JdReviewPageClient.tsx
  • jobdri/src/app/mock-application/questions/page.tsx
  • jobdri/src/app/mock-application/write/page.tsx
  • jobdri/src/components/apply/InputSection.tsx
  • jobdri/src/components/apply/SelectQuestion.tsx
  • jobdri/src/components/common/chips/ChipQnumber.tsx
  • jobdri/src/components/common/footer/Footer.tsx
  • jobdri/src/components/common/header/Header.tsx
  • jobdri/src/components/common/icons/IconBox.tsx
  • jobdri/src/components/common/input/InputMultiLine1000.tsx
  • jobdri/src/components/common/input/InputSingleLine.tsx
  • jobdri/src/components/common/modal/ModalAdd.tsx
  • jobdri/src/components/common/modal/ModalInput.tsx
  • jobdri/src/components/common/modal/ModalNotice.tsx
  • jobdri/src/styles/color.css

Comment on lines +17 to +19
const saveSelectedQuestions = () => {
sessionStorage.setItem("selectedQuestions", JSON.stringify(selectedQuestions));
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use a flow- and route-scoped storage key to prevent data collision.

Line 18 writes to a global key ("selectedQuestions"). This collides with mock-application and other virtual IDs in the same browser session, so users can land on the write page with another flow’s questions.

Suggested direction
+const STORAGE_KEY = `selectedQuestions:virtual:${id}`;
+
 const saveSelectedQuestions = () => {
-  sessionStorage.setItem("selectedQuestions", JSON.stringify(selectedQuestions));
+  sessionStorage.setItem(STORAGE_KEY, JSON.stringify(selectedQuestions));
 };

Then pass the same key to the write page InputSection via prop/route state so read/write stay aligned.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jobdri/src/app/apply/virtual/`[id]/questions/page.tsx around lines 17 - 19,
The saveSelectedQuestions function uses a global sessionStorage key
"selectedQuestions" which causes collisions across virtual IDs; update
saveSelectedQuestions to derive a flow- and route-scoped storage key (e.g.,
include the virtual [id] and a flow identifier like
"selectedQuestions:{id}:{flowName}") and store selectedQuestions under that
scoped key, then ensure the write page/InputSection receives the exact same
scoped key (via prop or route state) so reads/writes use the same namespaced key
(refer to saveSelectedQuestions, selectedQuestions, and the InputSection
prop/state passing in this file).

Comment thread jobdri/src/app/mock-application/questions/page.tsx Outdated
Comment on lines +47 to +50
maxLength:
typeof item.maxLength === "number"
? item.maxLength
: DEFAULT_MAX_LENGTH,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Validate maxLength as a finite positive integer before accepting persisted data.

Current normalization accepts any numeric maxLength. Values like 0, negative, or non-finite numbers can produce invalid input constraints and incorrect completion status.

Proposed patch
 maxLength:
-  typeof item.maxLength === "number"
-    ? item.maxLength
+  Number.isFinite(item.maxLength) && item.maxLength > 0
+    ? Math.floor(item.maxLength)
     : DEFAULT_MAX_LENGTH,
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
maxLength:
typeof item.maxLength === "number"
? item.maxLength
: DEFAULT_MAX_LENGTH,
maxLength:
Number.isFinite(item.maxLength) && item.maxLength > 0
? Math.floor(item.maxLength)
: DEFAULT_MAX_LENGTH,
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jobdri/src/components/apply/InputSection.tsx` around lines 47 - 50, Validate
item.maxLength before using it: replace the current numeric-only check with a
guard that accepts only a finite positive integer (e.g., Number.isFinite +
Number.isInteger + > 0) and otherwise falls back to DEFAULT_MAX_LENGTH; update
the normalization around maxLength in InputSection (where item.maxLength and
DEFAULT_MAX_LENGTH are referenced) so values like 0, negatives, NaN, Infinity,
or non-integers are rejected and DEFAULT_MAX_LENGTH is used.

Comment on lines +69 to +76
const handleLeftActionClick: ButtonHTMLAttributes<
HTMLButtonElement
>["onClick"] = (event) => {
leftActionOnClick?.(event);

if (!event.defaultPrevented) {
router.push(MOCK_APPLICATION_HOME_PATH);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid forcing home navigation when a custom left action exists.

On Line 74, router.push("/mock-application") still runs after leftAction.onClick unless the handler explicitly calls preventDefault(). That can break existing consumers expecting full control of navigation.

Suggested fix
   const handleLeftActionClick: ButtonHTMLAttributes<
     HTMLButtonElement
   >["onClick"] = (event) => {
-    leftActionOnClick?.(event);
-
-    if (!event.defaultPrevented) {
+    if (leftActionOnClick) {
+      leftActionOnClick(event);
+      return;
+    }
+    if (!event.defaultPrevented) {
       router.push(MOCK_APPLICATION_HOME_PATH);
     }
   };
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jobdri/src/components/common/header/Header.tsx` around lines 69 - 76, The
handler handleLeftActionClick currently always navigates to
MOCK_APPLICATION_HOME_PATH after invoking leftActionOnClick which forces
navigation even when a custom handler exists; change the logic so navigation
only happens when there is no custom leftActionOnClick provided (i.e., call
router.push(MOCK_APPLICATION_HOME_PATH) only if leftActionOnClick is undefined),
updating the handleLeftActionClick implementation to guard the router.push call
accordingly (references: handleLeftActionClick, leftActionOnClick, router.push,
MOCK_APPLICATION_HOME_PATH).

Comment on lines +93 to +96
className={clsx(
iconColorStyles[state as "primary" | "secondary"][background],
iconClassName,
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard "danger" state in non-TRASH path to prevent runtime crashes.

state allows "danger", but these lookups are indexed as "primary" | "secondary". In non-TRASH cases, "danger" can resolve to undefined and break rendering.

💡 Suggested patch
 export default function IconBox({
@@
 }: IconBoxProps) {
+  const paletteState = state === "danger" ? "secondary" : state;
+
   if (type === "TRASH") {
@@
       className={clsx(
         "flex shrink-0 items-center justify-center gap-2.5 rounded-icon-default",
         sizeStyles[size],
-        bgStyles[state as "primary" | "secondary"][background],
+        bgStyles[paletteState][background],
         className,
       )}
     >
       <Icon
         type={type}
         className={clsx(
-          iconColorStyles[state as "primary" | "secondary"][background],
+          iconColorStyles[paletteState][background],
           iconClassName,
         )}
       />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
className={clsx(
iconColorStyles[state as "primary" | "secondary"][background],
iconClassName,
)}
export default function IconBox({
state,
type,
size,
background,
icon: Icon,
iconClassName,
className,
}: IconBoxProps) {
const paletteState = state === "danger" ? "secondary" : state;
if (type === "TRASH") {
return (
<div
className={clsx(
"flex shrink-0 items-center justify-center gap-2.5 rounded-icon-default",
sizeStyles[size],
bgStyles[paletteState][background],
className,
)}
>
<Icon
type={type}
className={clsx(
iconColorStyles[paletteState][background],
iconClassName,
)}
/>
</div>
);
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jobdri/src/components/common/icons/IconBox.tsx` around lines 93 - 96, The
lookup into iconColorStyles in IconBox uses state as "primary" | "secondary" but
state can be "danger", causing undefined in the non-TRASH path; update the
className construction (the clsx(...) expression in IconBox) to guard/normalize
state before indexing iconColorStyles (e.g., map "danger" to a valid bucket or
fall back to "primary"/"secondary" based on background) so
iconColorStyles[state][background] is never accessed with "danger" and
iconClassName still applies.

Comment on lines +189 to +194
<Button
label="취소하기"
size="large"
styleType="quaternary"
onClick={onCancel}
className="h-[46px] flex-1 !text-text-system-fail"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Ensure alert-mode cancel always has a working handler.

onCancel is optional, but the cancel button is always rendered in this branch. When onCancel is omitted, the button is a no-op.

💡 Suggested patch
               <Button
                 label="취소하기"
                 size="large"
                 styleType="quaternary"
-                onClick={onCancel}
+                onClick={onCancel ?? onClose}
                 className="h-[46px] flex-1 !text-text-system-fail"
               />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<Button
label="취소하기"
size="large"
styleType="quaternary"
onClick={onCancel}
className="h-[46px] flex-1 !text-text-system-fail"
<Button
label="취소하기"
size="large"
styleType="quaternary"
onClick={onCancel ?? onClose}
className="h-[46px] flex-1 !text-text-system-fail"
/>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@jobdri/src/components/common/modal/ModalInput.tsx` around lines 189 - 194, In
ModalInput, the alert-mode cancel Button is always rendered with the optional
prop onCancel, so ensure it always invokes a working handler by wiring a
fallback: change the Button onClick to call onCancel if provided, otherwise call
the component's close handler (e.g., handleClose / onClose / onDismiss) or
another internal close function; update the Button usage in the ModalInput
component so the cancel button never becomes a no-op by falling back to that
close handler.

@minnngo minnngo merged commit 6b1da3c into develop May 21, 2026
1 check was pending
@minnngo minnngo deleted the feature/JDDEV-51-mock_question_input-ui-feat branch May 26, 2026 07:03
@minnngo minnngo restored the feature/JDDEV-51-mock_question_input-ui-feat branch May 26, 2026 07:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant