Skip to content

Commit fc456ff

Browse files
authored
Merge pull request #202 from CSE-Shaco/develop
fix(manito): api 호출 오류 해결
2 parents 638ee0b + 6545afa commit fc456ff

File tree

1 file changed

+85
-95
lines changed

1 file changed

+85
-95
lines changed

src/app/manitto/page.jsx

Lines changed: 85 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
import {useEffect, useState} from 'react';
44
import {useSearchParams} from 'next/navigation';
55
import {Button, Card, CardBody, CardHeader, Divider, Input} from '@nextui-org/react';
6+
import {useAuthenticatedApi} from '@/hooks/useAuthenticatedApi';
67

78
export default function ManitoVerifyPage() {
89
const searchParams = useSearchParams();
10+
const {apiClient} = useAuthenticatedApi();
911

1012
const [sessionCode, setSessionCode] = useState('');
1113
const [studentId, setStudentId] = useState('');
@@ -58,7 +60,6 @@ export default function ManitoVerifyPage() {
5860

5961
const keyBytes = base64UrlToBytes(hashKey);
6062
if (keyBytes.length !== 32) {
61-
// 우리가 정의한 스펙: 32바이트 키
6263
console.warn('Unexpected key length:', keyBytes.length);
6364
return null;
6465
}
@@ -95,21 +96,9 @@ export default function ManitoVerifyPage() {
9596
try {
9697
setLoading(true);
9798

98-
const res = await fetch('/api/v1/manito/verify', {
99-
method: 'POST', headers: {
100-
'Content-Type': 'application/json',
101-
}, body: JSON.stringify({
102-
sessionCode, studentId, pin,
103-
}),
104-
});
105-
106-
if (!res.ok) {
107-
const body = await res.json().catch(() => null);
108-
const msg = body?.message || body?.error || `요청이 실패했습니다. (status ${res.status})`;
109-
throw new Error(msg);
110-
}
99+
const res = await apiClient.post('/manito/verify', {sessionCode, studentId, pin}, {},);
111100

112-
const body = await res.json();
101+
const body = res.data;
113102
const encrypted = body?.data?.encryptedManitto || '';
114103

115104
setCipher(encrypted);
@@ -120,12 +109,13 @@ export default function ManitoVerifyPage() {
120109
if (decoded) {
121110
setPlain(decoded);
122111
} else {
123-
// 해시는 있는데 복호화 실패 → 에러만 살짝 알려주고 암호문은 그대로 보여줌
124112
setError((prev) => (prev ? prev + '\n' : '') + '복호화에 실패했습니다. 해시 값이 올바른지 확인해 주세요.',);
125113
}
126114
}
127115
} catch (err) {
128-
setError(err.message || '알 수 없는 오류가 발생했습니다.');
116+
const res = err?.response;
117+
const msg = res?.data?.message || res?.data?.error || err?.message || '알 수 없는 오류가 발생했습니다.';
118+
setError(msg);
129119
} finally {
130120
setLoading(false);
131121
}
@@ -134,90 +124,90 @@ export default function ManitoVerifyPage() {
134124
const disabled = !sessionCode || !studentId;
135125

136126
return (<div className="dark min-h-[100svh] flex items-center justify-center bg-black px-4">
137-
<Card className="max-w-md w-full bg-zinc-900 border border-zinc-800">
138-
<CardHeader className="flex flex-col items-start gap-2">
139-
<h1 className="text-2xl font-bold text-white">마니또 확인</h1>
140-
<p className="text-sm text-zinc-400">
141-
전달받은 링크로 접속한 뒤, 본인이 설정한 PIN 4자리를 입력해 주세요.
142-
</p>
143-
</CardHeader>
144-
<Divider className="border-zinc-800"/>
145-
<CardBody className="flex flex-col gap-4 text-white">
146-
{/* 세션/학번 정보 표시 (읽기 전용) */}
147-
<div className="text-xs text-zinc-400 space-y-1">
148-
<div>
149-
<span className="font-semibold text-zinc-300">세션 코드: </span>
150-
<span>{sessionCode || '(없음)'}</span>
151-
</div>
152-
<div>
153-
<span className="font-semibold text-zinc-300">학번: </span>
154-
<span>{studentId || '(없음)'}</span>
155-
</div>
156-
{hash && (<div>
157-
<span className="font-semibold text-zinc-300">해시: </span>
158-
<span className="break-all">{hash}</span>
159-
</div>)}
127+
<Card className="max-w-md w-full bg-zinc-900 border border-zinc-800">
128+
<CardHeader className="flex flex-col items-start gap-2">
129+
<h1 className="text-2xl font-bold text-white">마니또 확인</h1>
130+
<p className="text-sm text-zinc-400">
131+
전달받은 링크로 접속한 뒤, 본인이 설정한 PIN 4자리를 입력해 주세요.
132+
</p>
133+
</CardHeader>
134+
<Divider className="border-zinc-800"/>
135+
<CardBody className="flex flex-col gap-4 text-white">
136+
{/* 세션/학번 정보 표시 (읽기 전용) */}
137+
<div className="text-xs text-zinc-400 space-y-1">
138+
<div>
139+
<span className="font-semibold text-zinc-300">세션 코드: </span>
140+
<span>{sessionCode || '(없음)'}</span>
160141
</div>
161-
162-
{disabled && (<p className="text-xs text-red-400">
163-
세션 코드 또는 학번 정보가 누락되었습니다. 링크를 다시 확인해 주세요.
164-
</p>)}
165-
166-
<form onSubmit={handleSubmit} className="flex flex-col gap-4 mt-2">
167-
<Input
168-
label="PIN (숫자 4자리)"
169-
type="password"
170-
variant="bordered"
171-
value={pin}
172-
maxLength={4}
173-
onChange={(e) => setPin(e.target.value.replace(/[^0-9]/g, '').slice(0, 4))}
174-
classNames={{
175-
label: 'text-zinc-300',
176-
input: 'text-white',
177-
inputWrapper: 'bg-zinc-900 border-zinc-700 group-data-[focus=true]:border-zinc-400',
178-
}}
179-
isDisabled={disabled || loading}
180-
/>
181-
182-
{error && (<p className="text-xs text-red-400 whitespace-pre-line">{error}</p>)}
183-
184-
<Button
185-
type="submit"
186-
color="primary"
187-
isLoading={loading}
188-
isDisabled={disabled || loading || !pin}
189-
className="font-semibold"
190-
>
191-
마니또 확인하기
192-
</Button>
193-
</form>
194-
195-
{/* 결과 영역 */}
196-
{(cipher || plain) && (<>
197-
<Divider className="border-zinc-800 my-2"/>
198-
<div className="space-y-2 text-sm">
199-
<p className="font-semibold text-zinc-200">결과</p>
200-
201-
{plain ? (<>
142+
<div>
143+
<span className="font-semibold text-zinc-300">학번: </span>
144+
<span>{studentId || '(없음)'}</span>
145+
</div>
146+
{hash && (<div>
147+
<span className="font-semibold text-zinc-300">해시: </span>
148+
<span className="break-all">{hash}</span>
149+
</div>)}
150+
</div>
151+
152+
{disabled && (<p className="text-xs text-red-400">
153+
세션 코드 또는 학번 정보가 누락되었습니다. 링크를 다시 확인해 주세요.
154+
</p>)}
155+
156+
<form onSubmit={handleSubmit} className="flex flex-col gap-4 mt-2">
157+
<Input
158+
label="PIN (숫자 4자리)"
159+
type="password"
160+
variant="bordered"
161+
value={pin}
162+
maxLength={4}
163+
onChange={(e) => setPin(e.target.value.replace(/[^0-9]/g, '').slice(0, 4))}
164+
classNames={{
165+
label: 'text-zinc-300',
166+
input: 'text-white',
167+
inputWrapper: 'bg-zinc-900 border-zinc-700 group-data-[focus=true]:border-zinc-400',
168+
}}
169+
isDisabled={disabled || loading}
170+
/>
171+
172+
{error && (<p className="text-xs text-red-400 whitespace-pre-line">{error}</p>)}
173+
174+
<Button
175+
type="submit"
176+
color="primary"
177+
isLoading={loading}
178+
isDisabled={disabled || loading || !pin}
179+
className="font-semibold"
180+
>
181+
마니또 확인하기
182+
</Button>
183+
</form>
184+
185+
{/* 결과 영역 */}
186+
{(cipher || plain) && (<>
187+
<Divider className="border-zinc-800 my-2"/>
188+
<div className="space-y-2 text-sm">
189+
<p className="font-semibold text-zinc-200">결과</p>
190+
191+
{plain ? (<>
202192
<pre
203193
className="text-xs bg-zinc-950 border border-zinc-800 rounded-lg p-3 overflow-x-auto">
204194
{JSON.stringify(plain, null, 2)}
205195
</pre>
206-
<p className="text-xs text-zinc-400">
207-
위 내용은 클라이언트에서 hash를 이용해 복호화한 결과입니다.
208-
</p>
209-
</>) : (<>
210-
<p className="text-xs text-zinc-400 mb-1">
211-
서버에서 받은 암호문(encryptedManitto)입니다.
212-
</p>
213-
<pre
214-
className="text-xs bg-zinc-950 border border-zinc-800 rounded-lg p-3 break-all">
196+
<p className="text-xs text-zinc-400">
197+
위 내용은 클라이언트에서 hash를 이용해 복호화한 결과입니다.
198+
</p>
199+
</>) : (<>
200+
<p className="text-xs text-zinc-400 mb-1">
201+
서버에서 받은 암호문(encryptedManitto)입니다.
202+
</p>
203+
<pre
204+
className="text-xs bg-zinc-950 border border-zinc-800 rounded-lg p-3 break-all">
215205
{cipher}
216206
</pre>
217-
</>)}
218-
</div>
219207
</>)}
220-
</CardBody>
221-
</Card>
222-
</div>);
208+
</div>
209+
</>)}
210+
</CardBody>
211+
</Card>
212+
</div>);
223213
}

0 commit comments

Comments
 (0)