feat: 일지 작성 화면
This commit is contained in:
118
src/app/debrief/page.tsx
Normal file
118
src/app/debrief/page.tsx
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { useRouter } from 'next/navigation';
|
||||||
|
import { getCurrentVoyage, saveToHistory, saveCurrentVoyage } from '@/lib/store';
|
||||||
|
import { Voyage, VoyageStatus } from '@/types';
|
||||||
|
|
||||||
|
export default function DebriefPage() {
|
||||||
|
const router = useRouter();
|
||||||
|
const [voyage, setVoyage] = useState<Voyage | null>(null);
|
||||||
|
|
||||||
|
const [status, setStatus] = useState<VoyageStatus | null>(null);
|
||||||
|
const [progress, setProgress] = useState('');
|
||||||
|
const [nextAction, setNextAction] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const current = getCurrentVoyage();
|
||||||
|
if (!current) {
|
||||||
|
router.replace('/');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setVoyage(current);
|
||||||
|
}, [router]);
|
||||||
|
|
||||||
|
const handleSave = () => {
|
||||||
|
if (!voyage || !status) return;
|
||||||
|
|
||||||
|
const finalVoyage: Voyage = {
|
||||||
|
...voyage,
|
||||||
|
status: status,
|
||||||
|
debriefProgress: progress,
|
||||||
|
nextAction: nextAction,
|
||||||
|
endedAt: voyage.endedAt || Date.now(), // Fallback if missed in flight
|
||||||
|
};
|
||||||
|
|
||||||
|
saveToHistory(finalVoyage);
|
||||||
|
saveCurrentVoyage(null);
|
||||||
|
router.push('/log');
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!voyage) return null;
|
||||||
|
|
||||||
|
const statusOptions: { value: VoyageStatus; label: string; desc: string }[] = [
|
||||||
|
{ value: 'completed', label: '✅ 계획대로', desc: '목표를 달성했습니다' },
|
||||||
|
{ value: 'partial', label: '🌓 부분 진행', desc: '절반의 성공입니다' },
|
||||||
|
{ value: 'reoriented', label: '🧭 방향 재설정', desc: '새로운 발견을 했습니다' },
|
||||||
|
];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col flex-1 p-6 max-w-2xl mx-auto w-full animate-in zoom-in-95 duration-500">
|
||||||
|
<header className="mb-8 text-center">
|
||||||
|
<h1 className="text-2xl font-bold text-white mb-2">무사히 궤도에 도착했습니다</h1>
|
||||||
|
<p className="text-slate-400">이번 항해를 짧게 기록하고 마무리하세요.</p>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div className="space-y-8 flex-1">
|
||||||
|
{/* Question 1: Status */}
|
||||||
|
<section>
|
||||||
|
<label className="block text-sm font-medium text-slate-300 mb-3">
|
||||||
|
항해 결과
|
||||||
|
</label>
|
||||||
|
<div className="grid grid-cols-1 sm:grid-cols-3 gap-3">
|
||||||
|
{statusOptions.map((opt) => (
|
||||||
|
<button
|
||||||
|
key={opt.value}
|
||||||
|
onClick={() => setStatus(opt.value)}
|
||||||
|
className={`p-4 rounded-xl border text-left transition-all ${
|
||||||
|
status === opt.value
|
||||||
|
? 'bg-indigo-900/40 border-indigo-500 ring-1 ring-indigo-500'
|
||||||
|
: 'bg-slate-900/50 border-slate-800 hover:bg-slate-800'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="font-bold text-slate-200 mb-1">{opt.label}</div>
|
||||||
|
<div className="text-xs text-slate-500">{opt.desc}</div>
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Question 2: Secured */}
|
||||||
|
<section>
|
||||||
|
<label className="block text-sm font-medium text-slate-300 mb-2">
|
||||||
|
이번 항해에서 확보한 것 (What)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={progress}
|
||||||
|
onChange={(e) => setProgress(e.target.value)}
|
||||||
|
placeholder="예: 기획안 목차 구성 완료"
|
||||||
|
className="w-full bg-slate-900/30 border border-slate-800 rounded-lg px-4 py-3 text-slate-200 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 outline-none transition-all"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
{/* Question 3: Next Action */}
|
||||||
|
<section>
|
||||||
|
<label className="block text-sm font-medium text-slate-300 mb-2">
|
||||||
|
다음 항해의 첫 행동 (Next)
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={nextAction}
|
||||||
|
onChange={(e) => setNextAction(e.target.value)}
|
||||||
|
placeholder="예: 본문 1챕터 초안 쓰기"
|
||||||
|
className="w-full bg-slate-900/30 border border-slate-800 rounded-lg px-4 py-3 text-slate-200 focus:border-indigo-500 focus:ring-1 focus:ring-indigo-500 outline-none transition-all"
|
||||||
|
/>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={handleSave}
|
||||||
|
disabled={!status}
|
||||||
|
className="w-full mt-10 py-4 bg-indigo-600 hover:bg-indigo-500 disabled:bg-slate-800 disabled:text-slate-500 text-white font-bold rounded-xl transition-all shadow-lg shadow-indigo-900/20"
|
||||||
|
>
|
||||||
|
항해일지 저장
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user