'use client'; import { useState, useEffect, Suspense, useRef } from 'react'; import { useRouter, useSearchParams } from 'next/navigation'; import Header from '@/components/Header'; import { ScanLine, Search, Check, Box, Layers, AlertCircle, X, History } 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 ItemCountingContent() { const router = useRouter(); const searchParams = useSearchParams(); const product_id = searchParams.get('product_id'); const warehouse = searchParams.get('warehouse'); const [user, setUser] = useState(null); const [settings, setSettings] = useState({}); const [loading, setLoading] = useState(true); // We fetch product details based on product_id from query const [productName, setProductName] = useState(''); const [oldCount, setOldCount] = useState(null); const [newCount, setNewCount] = useState(''); const [shelfCode, setShelfCode] = useState(''); const [submitLoading, setSubmitLoading] = useState(false); const [history, setHistory] = useState([]); const [cameraEnabled, setCameraEnabled] = useState(true); const [camError, setCamError] = useState(''); const [errorMsg, setErrorMsg] = useState(''); const inputRef = useRef(null); useEffect(() => { const userData = localStorage.getItem('user'); if (userData) setUser(JSON.parse(userData)); fetchSettings(); fetchInitialItemData(); window.addEventListener('online', syncOfflineCounts); return () => window.removeEventListener('online', syncOfflineCounts); }, []); const fetchSettings = async () => { try { const res = await fetch('/api/settings'); if (res.ok) setSettings(await res.json()); } catch (e) {} }; const fetchInitialItemData = async () => { if (!product_id) { router.push('/dashboard'); return; } try { const nameRes = await fetch('/api/hesabfa', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: product_id, type: 'name' }) }); const nameData = await nameRes.json(); if (!nameData?.Result?.Name || nameData?.Result?.Name === 'نامشخص') { setErrorMsg('کالا یافت نشد.'); } else { setProductName(nameData.Result.Name); } const qRes = await fetch('/api/hesabfa', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ code: product_id, type: 'quantity' }) }); const qData = await qRes.json(); const productInfo = qData?.Result?.[0]; let foundStock = 0; if (productInfo) { if (productInfo.StockByWarehouse && Array.isArray(productInfo.StockByWarehouse)) { const wInfo = productInfo.StockByWarehouse.find(w => w.WarehouseCode === Number(warehouse) || w.Code === Number(warehouse)); if (wInfo) foundStock = wInfo.Stock || wInfo.Quantity || 0; else foundStock = productInfo.Stock || productInfo.Quantity || 0; } else if (productInfo.Warehouse && Array.isArray(productInfo.Warehouse)) { const wInfo = productInfo.Warehouse.find(w => w.Code === Number(warehouse)); foundStock = wInfo?.Quantity ?? productInfo.Stock ?? productInfo.Quantity ?? 0; } else { foundStock = productInfo.Stock ?? productInfo.Quantity ?? 0; } } setOldCount(foundStock); } catch (error) { setErrorMsg('خطا در دریافت اطلاعات کالا از سرور'); } finally { setLoading(false); } }; const handleScan = (detectedCodes) => { if (detectedCodes && detectedCodes.length > 0) { const scannedValue = detectedCodes[0].rawValue; // We do not close the camera! setShelfCode(scannedValue); setCamError(''); if (inputRef.current) setTimeout(() => inputRef.current.focus(), 100); } }; const handleError = (error) => { const msg = error?.message || error?.name || ''; if (msg.includes('Requested device not found')) setCamError('دوربینی یافت نشد.'); else setCamError('خطا در دسترسی به دوربین.'); }; const handleSubmitShelf = async () => { if (!shelfCode) { setErrorMsg('کد قفسه را وارد یا اسکن کنید'); return; } if (newCount === '' || newCount === null) { setErrorMsg('تعداد را وارد کنید'); return; } setSubmitLoading(true); setErrorMsg(''); const payload = { product_id: String(product_id), product_name: productName, warehouse: Number(warehouse), shelfCode: shelfCode.toUpperCase(), old_count: oldCount || 0, new_count: Number(newCount), user_id: user?.id, mode: 'ITEM' }; try { const res = await fetch('/api/counting', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) }); if (res.ok) { setHistory([{ shelf: shelfCode.toUpperCase(), count: newCount }, ...history]); setShelfCode(''); setNewCount(''); setErrorMsg(''); } else { const data = await res.json(); setErrorMsg(data.error || 'خطا در ثبت اطلاعات در سرور'); } } catch (err) { await saveCountOffline(payload); alert('ارتباط با سرور قطع است. اطلاعات ذخیره شد.'); setHistory([{ shelf: shelfCode.toUpperCase(), count: newCount, offline: true }, ...history]); setShelfCode(''); setNewCount(''); } finally { setSubmitLoading(false); } }; const handleCancelItem = async () => { const reason = window.prompt('لطفاً دلیل لغو انبارگردانی این کالا را وارد کنید:'); if (!reason) return; try { await fetch('/api/counting/cancel', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ product_id, warehouse, userId: user?.id, reason, mode: 'ITEM' }) }); router.push('/dashboard'); } catch (error) { alert('خطا در ارتباط با سرور'); } }; const isBlind = settings?.blind_counting && !hasRole(user?.roles, ['ADMIN', 'SUPERVISOR']); if (loading) { return (
); } return (
{/* Top Fixed Info Bar */}
{productName} آماده ثبت قفسه
{!isBlind && oldCount !== null && (
موجودی کل در سیستم: {oldCount}
)} {/* Continuous Scanner Area for Shelf */}
{camError ? (
{camError}
) : cameraEnabled ? ( <>
{/* Scanner Overlay UI */}
) : ( )}
{ setShelfCode(e.target.value); setErrorMsg(''); }} placeholder="کد قفسه..." className="flex-1 bg-gray-50 border border-gray-200 rounded-[14px] px-4 py-3 text-sm font-bold text-gray-800 uppercase focus:outline-none focus:border-teal-500 text-center placeholder:font-normal placeholder:normal-case" />
{/* Error Message */} {errorMsg && ( {errorMsg} )} {/* Count Input Box */}

ثبت موجودی در قفسه {shelfCode ? `«${shelfCode.toUpperCase()}»` : ''}

{ setNewCount(e.target.value); setErrorMsg(''); }} placeholder="0" className="w-full bg-gray-50 border-2 border-gray-200 rounded-[16px] p-4 text-center text-3xl font-black text-gray-900 focus:outline-none focus:border-teal-500 focus:bg-white transition-all placeholder:text-gray-300" />
{/* History of this session */} {history.length > 0 && (

قفسه‌های شمارش شده برای این کالا

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

{item.shelf}

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