'use client'; import { useState, useEffect, Suspense } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import Header from '@/components/Header'; import { Lock, Unlock, ScanLine, Search, Check, Box, Layers, AlertCircle, X } from 'lucide-react'; import { hasRole } from '@/lib/auth'; import { saveCountOffline, syncOfflineCounts } from '@/lib/offlineSync'; import dynamic from 'next/dynamic'; import { motion, AnimatePresence } from 'framer-motion'; const Scanner = dynamic(() => import('@yudiel/react-qr-scanner').then(mod => mod.Scanner), { ssr: false }); function ShelfCountingContent() { const router = useRouter(); const searchParams = useSearchParams(); const shelfCode = searchParams.get('code'); const warehouse = searchParams.get('warehouse'); const [user, setUser] = useState(null); const [settings, setSettings] = useState({}); const [loading, setLoading] = useState(true); // Item scanning state const [productCode, setProductCode] = useState(''); const [productName, setProductName] = useState(''); const [oldCount, setOldCount] = useState(null); const [newCount, setNewCount] = useState(''); const [itemLoading, setItemLoading] = useState(false); const [submitLoading, setSubmitLoading] = useState(false); const [errorMsg, setErrorMsg] = useState(''); const [cameraEnabled, setCameraEnabled] = useState(true); const [camError, setCamError] = useState(''); // History of scanned items in this session const [history, setHistory] = useState([]); useEffect(() => { const userData = localStorage.getItem('user'); if (userData) setUser(JSON.parse(userData)); fetchSettings(); window.addEventListener('online', syncOfflineCounts); return () => window.removeEventListener('online', syncOfflineCounts); }, []); const fetchSettings = async () => { try { const res = await fetch('/api/settings'); if (res.ok) { const data = await res.json(); setSettings(data); } } catch (e) { console.error(e); } finally { setLoading(false); } }; const handleFinishShelf = async () => { try { const token = localStorage.getItem('token'); await fetch('/api/locations/lock', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${token}` }, body: JSON.stringify({ shelfCode, action: 'UNLOCK' }) }); router.push('/dashboard'); } catch (error) { router.push('/dashboard'); } }; const fetchItemData = async (codeToFetch) => { const code = codeToFetch || productCode; if (!code) { setErrorMsg('کد کالا را وارد کنید'); return; } setErrorMsg(''); setItemLoading(true); setProductName(''); setOldCount(null); setNewCount(''); try { const nameRes = await fetch('/api/hesabfa', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code, type: 'name' }) }); const nameData = await nameRes.json(); if (!nameData?.Result?.Name || nameData?.Result?.Name === 'نامشخص' || nameData.error) { setErrorMsg('کالایی با این کد در حسابفا یافت نشد.'); setItemLoading(false); return; } setProductName(nameData.Result.Name); const qRes = await fetch('/api/hesabfa', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code, type: 'quantity' }) }); const qData = await qRes.json(); const productInfo = qData?.Result?.[0]; const wInfo = productInfo?.Warehouse?.find(w => w.Code === Number(warehouse)); setOldCount(wInfo?.Quantity ?? 0); } catch (error) { console.error(error); setErrorMsg('خطا در ارتباط با حسابفا'); } finally { setItemLoading(false); } }; const handleProductCodeChange = (e) => { setProductCode(e.target.value); setErrorMsg(''); setProductName(''); }; const handleProductCodeKeyDown = (e) => { if (e.key === 'Enter') { fetchItemData(); } }; const handleScan = (detectedCodes) => { if (detectedCodes && detectedCodes.length > 0) { const scannedValue = detectedCodes[0].rawValue; setProductCode(scannedValue); setCameraEnabled(false); setCamError(''); fetchItemData(scannedValue); } }; const handleError = (error) => { const msg = error?.message || error?.name || ''; if (msg.includes('Requested device not found')) { setCamError('دوربینی یافت نشد.'); } else { setCamError('خطا در دسترسی به دوربین.'); } }; const handleSubmitItem = async () => { if (!productName || errorMsg) { setErrorMsg('ابتدا از صحت کالا اطمینان حاصل کنید'); return; } if (newCount === '' || newCount === null) { setErrorMsg('لطفاً تعداد را وارد کنید'); return; } setSubmitLoading(true); const payload = { product_id: productCode, product_name: productName, warehouse, shelfCode: shelfCode.toUpperCase(), old_count: oldCount || 0, new_count: Number(newCount), user_id: user?.id, mode: 'SHELF' }; try { const res = await fetch('/api/counting', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (res.ok) { setHistory([{ code: productCode, name: productName, count: newCount }, ...history]); setProductCode(''); setProductName(''); setOldCount(null); setNewCount(''); setErrorMsg(''); } else { setErrorMsg('خطا در ثبت شمارش کالا در سرور'); } } catch (err) { // Network error (offline or server down) await saveCountOffline(payload); alert('ارتباط با سرور قطع است. اطلاعات در گوشی شما ذخیره شد و به محض اتصال ارسال می‌شود.'); setHistory([{ code: productCode, name: productName, count: newCount, offline: true }, ...history]); setProductCode(''); setProductName(''); setOldCount(null); setNewCount(''); setErrorMsg(''); } finally { setSubmitLoading(false); } }; const handleCancelShelf = async () => { const reason = window.prompt('لطفاً دلیل لغو انبارگردانی این قفسه را وارد کنید:'); if (!reason) return; try { await fetch('/api/counting/cancel', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ shelfCode, warehouse, userId: user?.id, reason, mode: 'SHELF' }) }); router.push('/dashboard'); } catch (error) { alert('خطا در لغو انبارگردانی'); } }; const isBlind = settings?.blind_counting && !hasRole(user?.roles, ['ADMIN', 'SUPERVISOR']); if (loading) { return (
); } return (
{/* Top Banner */}
در حال شمارش قفسه {shelfCode}
{/* Scanner Form */}

اسکن کالای جدید در این قفسه

{errorMsg && (
{errorMsg}
)}
fetchItemData()} disabled={itemLoading || !productCode} className="w-14 bg-indigo-50 text-indigo-600 rounded-[16px] flex items-center justify-center shrink-0 hover:bg-indigo-100 transition-colors border border-indigo-100 disabled:opacity-50" > {itemLoading ?
: }
setCameraEnabled(true)} className="w-14 bg-gray-900 text-white rounded-[16px] flex items-center justify-center shrink-0 shadow-md transition-colors" >
{cameraEnabled && ( {camError ? (
{camError}
) : (
)}
)}
{/* Product Details & Count input (only shown if valid product found) */} {productName && !itemLoading && (

{productName}

کد حسابفا: {productCode}

{!isBlind && oldCount !== null && (
{oldCount} موجودی سیستم
)}
{ setNewCount(e.target.value); setErrorMsg(''); }} placeholder="تعداد شمارش شده را وارد کنید..." className="w-full border-2 border-gray-200 bg-white rounded-[16px] p-4 text-center text-2xl font-black text-gray-800 focus:outline-none focus:border-indigo-500 transition-all placeholder:text-sm placeholder:font-medium placeholder:text-gray-300" />
)}
{/* History of this session */} {history.length > 0 && (

کالاهای ثبت شده تا الان

{history.map((item, idx) => (
{item.offline && (
)}

{item.name}

کد: {item.code}

شمارش شما {item.count}
))}
)}
); } export default function ShelfCountingPage() { return ( در حال بارگذاری...}> ); }