139 lines
5.2 KiB
TypeScript
139 lines
5.2 KiB
TypeScript
'use client';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
import { useRouter } from 'next/navigation';
|
|
import { ChevronLeft, NotebookText } from 'lucide-react';
|
|
|
|
import Navbar from '@/components/Navbar';
|
|
import { api } from '@/lib/api';
|
|
import { WorkRecord } from '@/types';
|
|
|
|
const CURRENT_YEAR = new Date().getFullYear();
|
|
const YEAR_KEY = 'workRecordYear';
|
|
|
|
export default function WorkRecordsPage() {
|
|
const router = useRouter();
|
|
const [year, setYear] = useState<number>(() => {
|
|
if (typeof window !== 'undefined') {
|
|
return parseInt(localStorage.getItem(YEAR_KEY) || String(CURRENT_YEAR), 10);
|
|
}
|
|
return CURRENT_YEAR;
|
|
});
|
|
const [records, setRecords] = useState<WorkRecord[]>([]);
|
|
const [loading, setLoading] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
useEffect(() => {
|
|
localStorage.setItem(YEAR_KEY, String(year));
|
|
void fetchRecords();
|
|
}, [year]);
|
|
|
|
const fetchRecords = async () => {
|
|
setLoading(true);
|
|
setError(null);
|
|
try {
|
|
const res = await api.get(`/workrecords/?year=${year}`);
|
|
setRecords(res.data);
|
|
} catch (e) {
|
|
console.error(e);
|
|
setError('作業記録の読み込みに失敗しました。');
|
|
} finally {
|
|
setLoading(false);
|
|
}
|
|
};
|
|
|
|
const moveToSource = (record: WorkRecord) => {
|
|
if (record.spreading_session) {
|
|
router.push(`/fertilizer/spreading?session=${record.spreading_session}`);
|
|
return;
|
|
}
|
|
if (record.delivery_plan_id) {
|
|
router.push(`/distribution/${record.delivery_plan_id}/edit`);
|
|
}
|
|
};
|
|
|
|
const years = Array.from({ length: 5 }, (_, i) => CURRENT_YEAR + 1 - i);
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gray-50">
|
|
<Navbar />
|
|
<main className="mx-auto max-w-6xl px-4 py-8">
|
|
<div className="mb-6 flex items-center gap-3">
|
|
<button onClick={() => router.push('/fertilizer')} className="text-gray-500 hover:text-gray-700">
|
|
<ChevronLeft className="h-5 w-5" />
|
|
</button>
|
|
<NotebookText className="h-6 w-6 text-green-700" />
|
|
<h1 className="text-2xl font-bold text-gray-900">作業記録</h1>
|
|
</div>
|
|
|
|
<div className="mb-6 flex items-center gap-3">
|
|
<label className="text-sm font-medium text-gray-700">年度:</label>
|
|
<select
|
|
value={year}
|
|
onChange={(e) => setYear(Number(e.target.value))}
|
|
className="rounded-lg border border-gray-300 px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-green-500"
|
|
>
|
|
{years.map((y) => (
|
|
<option key={y} value={y}>
|
|
{y}年度
|
|
</option>
|
|
))}
|
|
</select>
|
|
</div>
|
|
|
|
{error && (
|
|
<div className="mb-4 rounded-lg border border-red-300 bg-red-50 px-4 py-3 text-sm text-red-700">
|
|
{error}
|
|
</div>
|
|
)}
|
|
|
|
<div className="overflow-hidden rounded-lg bg-white shadow-sm">
|
|
{loading ? (
|
|
<div className="px-5 py-8 text-sm text-gray-500">読み込み中...</div>
|
|
) : records.length === 0 ? (
|
|
<div className="px-5 py-8 text-sm text-gray-400">この年度の作業記録はまだありません。</div>
|
|
) : (
|
|
<table className="w-full text-sm">
|
|
<thead className="border-b bg-gray-50">
|
|
<tr>
|
|
<th className="px-4 py-3 text-left font-medium text-gray-700">作業日</th>
|
|
<th className="px-4 py-3 text-left font-medium text-gray-700">種別</th>
|
|
<th className="px-4 py-3 text-left font-medium text-gray-700">タイトル</th>
|
|
<th className="px-4 py-3 text-left font-medium text-gray-700">参照先</th>
|
|
<th className="px-4 py-3" />
|
|
</tr>
|
|
</thead>
|
|
<tbody className="divide-y divide-gray-100">
|
|
{records.map((record) => (
|
|
<tr key={record.id} className="hover:bg-gray-50">
|
|
<td className="px-4 py-3 text-gray-700">{record.work_date}</td>
|
|
<td className="px-4 py-3 text-gray-700">{record.work_type_display}</td>
|
|
<td className="px-4 py-3 font-medium text-gray-900">{record.title}</td>
|
|
<td className="px-4 py-3 text-gray-600">
|
|
{record.spreading_session
|
|
? `散布実績 #${record.spreading_session}`
|
|
: record.delivery_plan_name
|
|
? `${record.delivery_plan_name}`
|
|
: '-'}
|
|
</td>
|
|
<td className="px-4 py-3 text-right">
|
|
{(record.spreading_session || record.delivery_plan_id) && (
|
|
<button
|
|
onClick={() => moveToSource(record)}
|
|
className="rounded border border-gray-300 px-2.5 py-1.5 text-xs text-gray-700 hover:bg-gray-100"
|
|
>
|
|
開く
|
|
</button>
|
|
)}
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
)}
|
|
</div>
|
|
</main>
|
|
</div>
|
|
);
|
|
}
|