Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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: 0 additions & 1 deletion src/app/(page)/disputes/[id]/DisputePage.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,6 @@
.statementCardEditable {
cursor: pointer;

&:hover,
&:focus {
border-color: v.$color-primary-500;
outline: none;
Expand Down
30 changes: 26 additions & 4 deletions src/app/(page)/disputes/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,15 @@ export default function DisputePage({ params }: { params: Promise<{ id: string }
'진술 내용을 정리하고 있어요',
'거의 다 됐어요, 잠시만요',
];
const JUDGING_MESSAGES = [
'작성한 진술서를 바탕으로\n분석중이에요',
'AI가 양측 진술을\n검토하고 있어요',
'핵심 쟁점을\n파악하고 있어요',
'공정한 판결을\n준비하고 있어요',
'거의 다 됐어요,\n잠시만요',
];
const [metaMsgIdx, setMetaMsgIdx] = React.useState(0);
const [judgingMsgIdx, setJudgingMsgIdx] = React.useState(0);
React.useEffect(() => {
if (!isExtractingMeta) return;
const timer = setInterval(() => {
Expand All @@ -96,13 +104,23 @@ export default function DisputePage({ params }: { params: Promise<{ id: string }
return () => clearInterval(timer);
}, [isExtractingMeta]);

React.useEffect(() => {
if (!isJudging) return;
const timer = setInterval(() => {
setJudgingMsgIdx((i) => (i + 1) % JUDGING_MESSAGES.length);
}, 2500);
return () => clearInterval(timer);
}, [isJudging]);

// 판결 완료/종료 상태일 때만 fetch — 불필요한 API 호출 방지
const isJudged = !!dispute && dispute.status === 'judged';

const {
data: judgment,
isLoading: judgmentLoading,
isError: judgmentError,
error: judgmentErrorData,
} = useJudgment(id, isCompleted);
} = useJudgment(id, isJudged);
Comment on lines 115 to +123

Copy link
Copy Markdown
Contributor

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

closed 상태에서 판결 결과 조회가 막히는 회귀가 있습니다.

판결 탭은 judged/closed 모두에서 노출되는데, 현재 조회 조건이 status === 'judged'로 제한되어 closed 사건은 useJudgment가 실행되지 않습니다. 완료 상태 전체와 조회 조건을 일치시켜야 합니다.

제안 패치 예시
- // 판결 완료/종료 상태일 때만 fetch — 불필요한 API 호출 방지
- const isJudged = !!dispute && dispute.status === 'judged';
+ // 판결 완료/종료 상태에서 결과 조회
+ const shouldFetchJudgment =
+   !!dispute && (dispute.status === 'judged' || dispute.status === 'closed');

 ...
- } = useJudgment(id, isJudged);
+ } = useJudgment(id, shouldFetchJudgment);
📝 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
// 판결 완료/종료 상태일 때만 fetch — 불필요한 API 호출 방지
const isJudged = !!dispute && dispute.status === 'judged';
const {
data: judgment,
isLoading: judgmentLoading,
isError: judgmentError,
error: judgmentErrorData,
} = useJudgment(id, isCompleted);
} = useJudgment(id, isJudged);
// 판결 완료/종료 상태에서 결과 조회
const shouldFetchJudgment =
!!dispute && (dispute.status === 'judged' || dispute.status === 'closed');
const {
data: judgment,
isLoading: judgmentLoading,
isError: judgmentError,
error: judgmentErrorData,
} = useJudgment(id, shouldFetchJudgment);
🤖 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 `@src/app/`(page)/disputes/[id]/page.tsx around lines 115 - 123, The condition
determining when to fetch judgment data only checks for `dispute.status ===
'judged'`, but the judgment tab should be visible and data should be fetched for
both `judged` and `closed` dispute statuses. Update the `isJudged` condition to
include both completed states so that the `useJudgment` hook is triggered
whenever the dispute status is either `judged` or `closed`, not just when it is
`judged` alone.


const showToast = useToastStore((s) => s.show);

Expand Down Expand Up @@ -187,7 +205,7 @@ export default function DisputePage({ params }: { params: Promise<{ id: string }
<div className={styles.judgingScreen}>
<div className={styles.judgingContent}>
<Spinner />
<p className={styles.judgingText}>{'작성한 진술서를 바탕으로\n분석중이에요'}</p>
<p className={styles.judgingText}>{JUDGING_MESSAGES[judgingMsgIdx]}</p>
</div>
</div>
);
Expand Down Expand Up @@ -347,10 +365,14 @@ export default function DisputePage({ params }: { params: Promise<{ id: string }
<div className={styles.judgementPlaceholder}>
<p className={styles.empty}>판결 결과를 불러올 수 없습니다.</p>
</div>
) : !judgment ? (
<div className={styles.judgementPlaceholder}>
<p className={styles.empty}>판결 결과를 불러올 수 없습니다.</p>
</div>
) : judgmentSubTab === 'verdict' ? (
<JudgmentResult disputeId={id} />
<JudgmentResult judgment={judgment} participants={dispute.participants} />
) : (
<JudgmentTypeResult disputeId={id} />
<JudgmentTypeResult judgment={judgment} participants={dispute.participants} />
)}
</>
)}
Expand Down
155 changes: 155 additions & 0 deletions src/app/(page)/rooms/[roomId]/statement/StatementPage.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
@use '@/styles/abstracts/variables' as v;
@use '@/styles/abstracts/functions' as fn;
@use '@/styles/abstracts/mixins' as m;

.page {
display: flex;
flex-direction: column;
background-color: var(--bg-page);
}

.content {
padding: fn.r(16) fn.r(20) fn.r(100);
display: flex;
flex-direction: column;
gap: fn.r(16);
}

.section {
display: flex;
flex-direction: column;
gap: fn.r(16);
}

.label {
@include m.text-body-s;

color: v.$color-black;
margin: 0;
}

.categories {
display: flex;
flex-direction: row;
}

.categoryItem {
display: flex;
flex-direction: column;
align-items: center;
gap: fn.r(4);
width: fn.r(44);
}

.categoryIcon {
display: flex;
align-items: center;
justify-content: center;
width: fn.r(44);
height: fn.r(44);
border-radius: fn.r(8);
background-color: var(--bg-surface);
border: 1px solid var(--border-brand);
}

.categoryLabel {
@include m.text-caption;
font-weight: v.$font-weight-bold;
color: var(--text-primary);
Comment on lines +55 to +58

Copy link
Copy Markdown
Contributor

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

Stylelint 공백 규칙을 맞춰 주세요.

Line 57, Line 106에서 @include 뒤 선언 전에 빈 줄이 없어 declaration-empty-line-before가 실패합니다.

수정 예시
 .categoryLabel {
   `@include` m.text-caption;
+
   font-weight: v.$font-weight-bold;
   color: var(--text-primary);
   white-space: nowrap;
 }
@@
 .modalText {
   `@include` m.text-body-m;
+
   color: var(--text-primary);
   margin: 0;
   text-align: center;
 }

Also applies to: 104-106

🧰 Tools
🪛 Stylelint (17.13.0)

[error] 57-57: Expected empty line before declaration (declaration-empty-line-before)

(declaration-empty-line-before)

🤖 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 `@src/app/`(page)/rooms/[roomId]/statement/StatementPage.module.scss around
lines 55 - 58, The stylelint rule `declaration-empty-line-before` requires a
blank line before property declarations that follow an `@include` statement. In
the .categoryLabel class, add a blank line between the `@include
m.text-caption;` statement and the `font-weight` property declaration. Apply the
same fix to the similar issue mentioned at lines 104-106 where an `@include`
statement should be separated from following properties by a blank line.

Source: Linters/SAST tools

white-space: nowrap;
}

.statementGroup {
display: flex;
flex-direction: column;
gap: fn.r(8);
}

.textarea {
min-height: fn.r(350);
}

.footer {
padding: 0 fn.r(20) fn.r(40);
background-color: var(--bg-page);
}

.footerRow {
display: flex;
gap: fn.r(8);
}

.modalOverlay {
position: fixed;
inset: 0;
background-color: rgba(0, 0, 0, 0.4);
display: flex;
align-items: center;
justify-content: center;
z-index: 100;
padding: fn.r(20);
}

.modal {
background-color: var(--bg-page);
border-radius: fn.r(16);
padding: fn.r(24) fn.r(20);
width: 100%;
max-width: fn.r(320);
display: flex;
flex-direction: column;
gap: fn.r(20);
}

.modalText {
@include m.text-body-m;
color: var(--text-primary);
margin: 0;
text-align: center;
}

.modalSubText {
@include m.text-body-s;

color: var(--text-secondary);
margin: fn.r(-12) 0 0;
text-align: center;
}

.modalActions {
display: flex;
flex-direction: column;
gap: fn.r(8);
}

// ===========================
// Saving (로딩 화면)
// ===========================

.savingScreen {
position: fixed;
inset: 0;
background: linear-gradient(180deg, #{v.$color-primary-200} 0%, #{v.$color-white} 50%);
display: flex;
align-items: center;
justify-content: center;
z-index: 200;
}

.savingContent {
display: flex;
flex-direction: column;
align-items: center;
gap: fn.r(24);
width: fn.r(362);
}

.savingText {
font-family: v.$font-family-base;
font-size: v.$font-size-title-m;
font-weight: v.$font-weight-semibold;
color: v.$color-black;
text-align: center;
white-space: pre-line;
line-height: 1.5;
}
Loading