diff --git a/package-lock.json b/package-lock.json index 59af41e..35f0715 100644 --- a/package-lock.json +++ b/package-lock.json @@ -109,6 +109,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -262,29 +263,6 @@ "node": ">=6.9.0" } }, - "node_modules/@emnapi/core": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.1.tgz", - "integrity": "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.1.tgz", - "integrity": "sha512-vgj7R3y3Wgx24IQaGPA/R6YFXLHVMOZ0uVEyIQPaWs+rd1AzfEMXlAC22FYwO1XkKR6NPsq7mUandH8oIRdZFw==", - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", @@ -292,7 +270,6 @@ "dev": true, "license": "MIT", "optional": true, - "peer": true, "dependencies": { "tslib": "^2.4.0" } @@ -355,6 +332,7 @@ "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -398,6 +376,7 @@ "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.18.3", "@emotion/babel-plugin": "^11.13.5", @@ -1213,6 +1192,7 @@ "resolved": "https://registry.npmjs.org/@mui/material/-/material-9.1.1.tgz", "integrity": "sha512-Wv+gInjrpf99l1Q0oHe0eOWGTnlbkzs5nowClX65KCT/2fyPMwcbFEEkUsOHdpcHhB5UAbz/d7jlwt5ajWVvlA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.29.2", "@mui/core-downloads-tracker": "^9.1.1", @@ -1329,6 +1309,7 @@ "resolved": "https://registry.npmjs.org/@mui/system/-/system-9.1.1.tgz", "integrity": "sha512-q+aqNa58QZUwmmyUvJKKrStrej+4BcWFw4M0Ug+zRylPIQgR64cqvBnE3QTfLZm4OXulydp8Hl3zwKxMayrdsA==", "license": "MIT", + "peer": true, "dependencies": { "@babel/runtime": "^7.29.2", "@mui/private-theming": "^9.1.1", @@ -2122,6 +2103,7 @@ "integrity": "sha512-mKq3jQFhjvko5LTJFHGilsuQs+W+T3Gm451NzuTDGQxwCzwXHYnIu2zGkRoW+Exq3Rob7yp2MfzSrdIiZVhrBg==", "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "engines": { "node": ">=18.18" }, @@ -2504,6 +2486,7 @@ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.17.tgz", "integrity": "sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==", "license": "MIT", + "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2578,6 +2561,7 @@ "integrity": "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.61.0", "@typescript-eslint/types": "8.61.0", @@ -3192,6 +3176,7 @@ "integrity": "sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -4198,7 +4183,8 @@ "version": "1.11.21", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/debug": { "version": "4.4.3", @@ -4665,6 +4651,7 @@ "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -4838,6 +4825,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -6343,6 +6331,7 @@ "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", "devOptional": true, "license": "MIT", + "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -6910,6 +6899,7 @@ "resolved": "https://registry.npmjs.org/next/-/next-15.5.19.tgz", "integrity": "sha512-xNOW6tYshGX1/Oi3F8uuk4gpDeWsSUE/1Z0G5uUMekIxaQ0xc03UXd9II0VQHYMWviMeA0OHpJFAKsHf8bTYVg==", "license": "MIT", + "peer": true, "dependencies": { "@next/env": "15.5.19", "@swc/helpers": "0.5.15", @@ -7516,6 +7506,7 @@ "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.2.tgz", "integrity": "sha512-7tNmwg/7mzzAoB/8kSg6Hl37JraAZw3Z3A0JSY7VXlZwo82Xn0G7wKbNNs2qoF4ZEEsQGTwDAroNdqKs1ofJxQ==", "license": "MIT", + "peer": true, "funding": { "type": "opencollective", "url": "https://opencollective.com/preact" @@ -7578,6 +7569,7 @@ "devOptional": true, "hasInstallScript": true, "license": "Apache-2.0", + "peer": true, "dependencies": { "@prisma/config": "6.19.3", "@prisma/engines": "6.19.3" @@ -7728,6 +7720,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.7.tgz", "integrity": "sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==", "license": "MIT", + "peer": true, "engines": { "node": ">=0.10.0" } @@ -7737,6 +7730,7 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.7.tgz", "integrity": "sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==", "license": "MIT", + "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -7749,6 +7743,7 @@ "resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.79.0.tgz", "integrity": "sha512-mhYp/MTmXvzYX6AJcJVko0rktoIhhmRnEouObj4wF5i/tCttgJvnp1+9wRkpITZjDTqpo4IOSJqu0dBlPlV/Lw==", "license": "MIT", + "peer": true, "engines": { "node": ">=18.0.0" }, @@ -7764,13 +7759,15 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/react-redux": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.3.0.tgz", "integrity": "sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==", "license": "MIT", + "peer": true, "dependencies": { "@types/use-sync-external-store": "^0.0.6", "use-sync-external-store": "^1.4.0" @@ -7853,7 +7850,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz", "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==", - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/redux-thunk": { "version": "3.1.0", @@ -8090,6 +8088,7 @@ "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", "license": "MIT", + "peer": true, "dependencies": { "chokidar": "^5.0.0", "immutable": "^5.1.5", @@ -8766,6 +8765,7 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=12" }, @@ -8939,6 +8939,7 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "devOptional": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" diff --git a/public/images/characters/character-blocked.png b/public/images/characters/character-blocked.png deleted file mode 100644 index 2d90003..0000000 Binary files a/public/images/characters/character-blocked.png and /dev/null differ diff --git a/public/images/characters/character-blocked.svg b/public/images/characters/character-blocked.svg new file mode 100644 index 0000000..fbe3060 --- /dev/null +++ b/public/images/characters/character-blocked.svg @@ -0,0 +1,9 @@ + diff --git a/public/images/characters/character-case.png b/public/images/characters/character-case.png deleted file mode 100644 index 41588cf..0000000 Binary files a/public/images/characters/character-case.png and /dev/null differ diff --git a/public/images/characters/character-case.svg b/public/images/characters/character-case.svg new file mode 100644 index 0000000..d796f8b --- /dev/null +++ b/public/images/characters/character-case.svg @@ -0,0 +1,9 @@ + diff --git a/public/images/characters/character-closed.png b/public/images/characters/character-closed.png deleted file mode 100644 index 785586f..0000000 Binary files a/public/images/characters/character-closed.png and /dev/null differ diff --git a/public/images/characters/character-closed.svg b/public/images/characters/character-closed.svg new file mode 100644 index 0000000..6fe8f53 --- /dev/null +++ b/public/images/characters/character-closed.svg @@ -0,0 +1,9 @@ + diff --git a/public/images/characters/character-gift.png b/public/images/characters/character-gift.png deleted file mode 100644 index 154f48a..0000000 Binary files a/public/images/characters/character-gift.png and /dev/null differ diff --git a/public/images/characters/character-gift.svg b/public/images/characters/character-gift.svg new file mode 100644 index 0000000..b4067e0 --- /dev/null +++ b/public/images/characters/character-gift.svg @@ -0,0 +1,9 @@ + diff --git a/public/images/characters/character-home.png b/public/images/characters/character-home.png deleted file mode 100644 index a9d1c05..0000000 Binary files a/public/images/characters/character-home.png and /dev/null differ diff --git a/public/images/characters/character-home.svg b/public/images/characters/character-home.svg new file mode 100644 index 0000000..2f776a9 --- /dev/null +++ b/public/images/characters/character-home.svg @@ -0,0 +1,9 @@ + diff --git a/public/images/characters/character-loading.png b/public/images/characters/character-loading.png deleted file mode 100644 index 5139c8a..0000000 Binary files a/public/images/characters/character-loading.png and /dev/null differ diff --git a/public/images/characters/character-loading.svg b/public/images/characters/character-loading.svg new file mode 100644 index 0000000..8274449 --- /dev/null +++ b/public/images/characters/character-loading.svg @@ -0,0 +1,9 @@ + diff --git a/public/images/characters/character-welcome.png b/public/images/characters/character-welcome.png deleted file mode 100644 index 764f6bc..0000000 Binary files a/public/images/characters/character-welcome.png and /dev/null differ diff --git a/public/images/characters/character-welcome.svg b/public/images/characters/character-welcome.svg new file mode 100644 index 0000000..f1d2422 --- /dev/null +++ b/public/images/characters/character-welcome.svg @@ -0,0 +1,9 @@ + diff --git a/public/images/common/favicon.svg b/public/images/common/favicon.svg new file mode 100644 index 0000000..385a9b0 --- /dev/null +++ b/public/images/common/favicon.svg @@ -0,0 +1,15 @@ + diff --git a/public/images/common/login_character.png b/public/images/common/login_character.png deleted file mode 100644 index 2262227..0000000 Binary files a/public/images/common/login_character.png and /dev/null differ diff --git a/public/images/common/login_character.svg b/public/images/common/login_character.svg new file mode 100644 index 0000000..97e74ff --- /dev/null +++ b/public/images/common/login_character.svg @@ -0,0 +1,9 @@ + diff --git a/public/images/common/logo.png b/public/images/common/logo.png deleted file mode 100644 index 2542702..0000000 Binary files a/public/images/common/logo.png and /dev/null differ diff --git a/public/images/common/logo.svg b/public/images/common/logo.svg new file mode 100644 index 0000000..9eb87a9 --- /dev/null +++ b/public/images/common/logo.svg @@ -0,0 +1,6 @@ + diff --git a/public/images/common/logo_kakao.svg b/public/images/common/logo_kakao.svg new file mode 100644 index 0000000..06c11ee --- /dev/null +++ b/public/images/common/logo_kakao.svg @@ -0,0 +1,3 @@ + diff --git a/public/images/common/ogimg.jpg b/public/images/common/ogimg.jpg new file mode 100644 index 0000000..bcce82f Binary files /dev/null and b/public/images/common/ogimg.jpg differ diff --git a/public/images/common/thumbnail-default.png b/public/images/common/thumbnail-default.png deleted file mode 100644 index f4d0ae4..0000000 Binary files a/public/images/common/thumbnail-default.png and /dev/null differ diff --git a/public/images/common/thumbnail-default.svg b/public/images/common/thumbnail-default.svg new file mode 100644 index 0000000..f1fa36d --- /dev/null +++ b/public/images/common/thumbnail-default.svg @@ -0,0 +1,10 @@ + diff --git a/src/app/(page)/disputes/[id]/page.tsx b/src/app/(page)/disputes/[id]/page.tsx index 98b7faa..9624f0c 100644 --- a/src/app/(page)/disputes/[id]/page.tsx +++ b/src/app/(page)/disputes/[id]/page.tsx @@ -1,142 +1,153 @@ -'use client' +'use client'; -import React from 'react' -import Image from 'next/image' -import { useRouter } from 'next/navigation' -import { useQueryClient } from '@tanstack/react-query' -import AutorenewRoundedIcon from '@mui/icons-material/AutorenewRounded' -import CircularProgress from '@mui/material/CircularProgress' -import Header from '@/components/layout/Header' -import Button from '@/components/ui/Button' -import Tabs from '@/components/ui/Tabs' -import Tab from '@/components/ui/Tab' -import Spinner from '@/components/ui/Spinner' -import StatusBadge from '@/components/ui/StatusBadge' -import CategoryIcon from '@/components/ui/CategoryIcon' -import InviteChoiceModal from '@/components/room/InviteChoiceModal' -import JudgmentResult from '@/components/judgement/JudgmentResult' -import JudgmentTypeResult from '@/components/judgement/JudgmentTypeResult' -import { useDispute, useRequestJudgment, useCloseDispute, disputeKeys } from '@/domains/dispute/dispute.hooks' -import { useJudgment } from '@/domains/judgement/judgement.hooks' -import { useUserMe } from '@/domains/user/hooks' -import { useToastStore } from '@/stores/toastStore' -import styles from './DisputePage.module.scss' +import React from 'react'; +import Image from 'next/image'; +import { useRouter } from 'next/navigation'; +import { useQueryClient } from '@tanstack/react-query'; +import AutorenewRoundedIcon from '@mui/icons-material/AutorenewRounded'; +import CircularProgress from '@mui/material/CircularProgress'; +import Header from '@/components/layout/Header'; +import Button from '@/components/ui/Button'; +import Tabs from '@/components/ui/Tabs'; +import Tab from '@/components/ui/Tab'; +import Spinner from '@/components/ui/Spinner'; +import StatusBadge from '@/components/ui/StatusBadge'; +import CategoryIcon from '@/components/ui/CategoryIcon'; +import InviteChoiceModal from '@/components/room/InviteChoiceModal'; +import JudgmentResult from '@/components/judgement/JudgmentResult'; +import JudgmentTypeResult from '@/components/judgement/JudgmentTypeResult'; +import { + useDispute, + useRequestJudgment, + useCloseDispute, + disputeKeys, +} from '@/domains/dispute/dispute.hooks'; +import { useJudgment } from '@/domains/judgement/judgement.hooks'; +import { useUserMe } from '@/domains/user/hooks'; +import { useToastStore } from '@/stores/toastStore'; +import styles from './DisputePage.module.scss'; -const COMPLETED_STATUSES = ['judged', 'closed'] as const +const COMPLETED_STATUSES = ['judged', 'closed'] as const; const TABS = [ { id: 'statement', label: '진술' }, { id: 'judgement', label: '판결' }, -] +]; export default function DisputePage({ params }: { params: Promise<{ id: string }> }) { - const { id } = React.use(params) - const router = useRouter() - const queryClient = useQueryClient() + const { id } = React.use(params); + const router = useRouter(); + const queryClient = useQueryClient(); - const pollCountRef = React.useRef(0) - const MAX_POLL = 15 - const [pollExhausted, setPollExhausted] = React.useState(false) + const pollCountRef = React.useRef(0); + const MAX_POLL = 15; + const [pollExhausted, setPollExhausted] = React.useState(false); const { data: dispute, isLoading: fetchLoading } = useDispute(id, { refetchInterval: (query) => { - const d = query.state.data - if (!d) return false - const hasStatement = d.statements?.some((s) => s.role === 'role_a' && s.content) - const isTerminal = (COMPLETED_STATUSES as readonly string[]).includes(d.status) + const d = query.state.data; + if (!d) return false; + const hasStatement = d.statements?.some((s) => s.role === 'role_a' && s.content); + const isTerminal = (COMPLETED_STATUSES as readonly string[]).includes(d.status); if (d.title === '새 사건' && hasStatement && !isTerminal) { if (pollCountRef.current >= MAX_POLL) { - setPollExhausted(true) - return false + setPollExhausted(true); + return false; } - pollCountRef.current += 1 - return 2000 + pollCountRef.current += 1; + return 2000; } - pollCountRef.current = 0 - return false + pollCountRef.current = 0; + return false; }, - }) - const { mutate: requestJudgment, isPending: isJudging } = useRequestJudgment(id) - const { mutate: closeDispute, isPending: isClosing } = useCloseDispute(id) - const { data: userMe } = useUserMe() + }); + const { mutate: requestJudgment, isPending: isJudging } = useRequestJudgment(id); + const { mutate: closeDispute, isPending: isClosing } = useCloseDispute(id); + const { data: userMe } = useUserMe(); // judged(판결완료) + closed(종료) 모두 판결 결과 탭 노출 - const isCompleted = !!dispute && (COMPLETED_STATUSES as readonly string[]).includes(dispute.status) + const isCompleted = + !!dispute && (COMPLETED_STATUSES as readonly string[]).includes(dispute.status); const isExtractingMeta = !!dispute && dispute.title === '새 사건' && dispute.statements?.some((s) => s.role === 'role_a' && s.content) && !isCompleted && - !pollExhausted + !pollExhausted; const META_MESSAGES = [ '사건 정보를 분석하고 있어요', 'AI가 핵심 쟁점을 파악하고 있어요', '진술 내용을 정리하고 있어요', '거의 다 됐어요, 잠시만요', - ] - const [metaMsgIdx, setMetaMsgIdx] = React.useState(0) + ]; + const [metaMsgIdx, setMetaMsgIdx] = React.useState(0); React.useEffect(() => { - if (!isExtractingMeta) return + if (!isExtractingMeta) return; const timer = setInterval(() => { - setMetaMsgIdx((i) => (i + 1) % META_MESSAGES.length) - }, 2500) - return () => clearInterval(timer) - }, [isExtractingMeta]) + setMetaMsgIdx((i) => (i + 1) % META_MESSAGES.length); + }, 2500); + return () => clearInterval(timer); + }, [isExtractingMeta]); // 판결 완료/종료 상태일 때만 fetch — 불필요한 API 호출 방지 - const { data: judgment, isLoading: judgmentLoading, isError: judgmentError } = useJudgment(id, isCompleted) + const { + data: judgment, + isLoading: judgmentLoading, + isError: judgmentError, + } = useJudgment(id, isCompleted); - const showToast = useToastStore((s) => s.show) + const showToast = useToastStore((s) => s.show); - const [activeTab, setActiveTab] = React.useState('statement') - const [judgmentSubTab, setJudgmentSubTab] = React.useState<'verdict' | 'type'>('verdict') - const [showSoloModal, setShowSoloModal] = React.useState(false) - const [isInviting, setIsInviting] = React.useState(false) - const [isRefreshing, setIsRefreshing] = React.useState(false) + const [activeTab, setActiveTab] = React.useState('statement'); + const [judgmentSubTab, setJudgmentSubTab] = React.useState<'verdict' | 'type'>('verdict'); + const [showSoloModal, setShowSoloModal] = React.useState(false); + const [isInviting, setIsInviting] = React.useState(false); + const [isRefreshing, setIsRefreshing] = React.useState(false); const handleRefresh = async () => { - setIsRefreshing(true) + setIsRefreshing(true); try { - await queryClient.invalidateQueries({ queryKey: disputeKeys.detail(id) }) + await queryClient.invalidateQueries({ queryKey: disputeKeys.detail(id) }); } finally { - setIsRefreshing(false) + setIsRefreshing(false); } - } + }; - const isSolo = dispute !== undefined && dispute.participants.length === 1 - const roleAStatement = dispute?.statements?.find((s) => s.role === 'role_a') - const roleBStatement = dispute?.statements?.find((s) => s.role === 'role_b') - const canJudge = (isSolo && !!roleAStatement?.content) || dispute?.status === 'both_submitted' + const isSolo = dispute !== undefined && dispute.participants.length === 1; + const roleAStatement = dispute?.statements?.find((s) => s.role === 'role_a'); + const roleBStatement = dispute?.statements?.find((s) => s.role === 'role_b'); + const canJudge = (isSolo && !!roleAStatement?.content) || dispute?.status === 'both_submitted'; const handleInvite = async () => { - if (isInviting || !dispute) return - setIsInviting(true) - setShowSoloModal(false) + if (isInviting || !dispute) return; + setIsInviting(true); + setShowSoloModal(false); try { - const res = await fetch(`/api/rooms/${dispute.roomId}/invite`, { method: 'POST' }) - const data = await res.json() + const res = await fetch(`/api/rooms/${dispute.roomId}/invite`, { method: 'POST' }); + const data = await res.json(); if (!res.ok) { - showToast('초대 링크 발급에 실패했어요.') - return + showToast('초대 링크 발급에 실패했어요.'); + return; } - await navigator.clipboard.writeText(data.data.inviteUrl) - showToast('초대 링크가 복사되었어요!') + await navigator.clipboard.writeText(data.data.inviteUrl); + showToast('초대 링크가 복사되었어요!'); } catch { - showToast('초대 링크 발급에 실패했어요.') + showToast('초대 링크 발급에 실패했어요.'); } finally { - setIsInviting(false) + setIsInviting(false); } - } + }; const runJudge = () => { - setShowSoloModal(false) + setShowSoloModal(false); requestJudgment(undefined, { onSuccess: () => window.location.reload(), - onError: (error) => showToast(error instanceof Error ? error.message : 'AI 판결 요청에 실패했습니다.'), - }) - } + onError: (error) => + showToast(error instanceof Error ? error.message : 'AI 판결 요청에 실패했습니다.'), + }); + }; - if (fetchLoading) return null + if (fetchLoading) return null; if (isExtractingMeta) { return ( @@ -146,7 +157,7 @@ export default function DisputePage({ params }: { params: Promise<{ id: string }
{META_MESSAGES[metaMsgIdx]}
- ) + ); } if (isJudging) { @@ -157,7 +168,7 @@ export default function DisputePage({ params }: { params: Promise<{ id: string }{'작성한 진술서를 바탕으로\n분석중이에요'}
- ) + ); } if (!dispute) { @@ -166,10 +177,10 @@ export default function DisputePage({ params }: { params: Promise<{ id: string }사건을 찾을 수 없습니다.
- ) + ); } - const formattedDate = dispute.createdAt.slice(2, 10) + const formattedDate = dispute.createdAt.slice(2, 10); return ({dispute.description}
- )} + {dispute.description &&{dispute.description}
}