feat: add time
This commit is contained in:
@@ -170,6 +170,10 @@ export default function AccountingPage() {
|
|||||||
const [dateFrom, setDateFrom] = useState<string>('');
|
const [dateFrom, setDateFrom] = useState<string>('');
|
||||||
const [dateTo, setDateTo] = useState<string>('');
|
const [dateTo, setDateTo] = useState<string>('');
|
||||||
|
|
||||||
|
// Time range
|
||||||
|
const [timeFrom, setTimeFrom] = useState<string>('');
|
||||||
|
const [timeTo, setTimeTo] = useState<string>('');
|
||||||
|
|
||||||
// Status filter — both paid statuses selected by default
|
// Status filter — both paid statuses selected by default
|
||||||
const [statuses, setStatuses] = useState<number[]>([...PAID_STATUSES]);
|
const [statuses, setStatuses] = useState<number[]>([...PAID_STATUSES]);
|
||||||
|
|
||||||
@@ -259,14 +263,28 @@ export default function AccountingPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Date range (created_at is "Y-m-d H:i:s")
|
// Date range (created_at is "Y-m-d H:i:s")
|
||||||
if (dateFrom && p.created_at && p.created_at.slice(0, 10) < dateFrom) return false;
|
// When time is also selected, compare full datetime strings;
|
||||||
if (dateTo && p.created_at && p.created_at.slice(0, 10) > dateTo) return false;
|
// otherwise compare only the date portion (YYYY-MM-DD).
|
||||||
|
const created = p.created_at ?? '';
|
||||||
|
if (dateFrom) {
|
||||||
|
const datePart = created.slice(0, 10);
|
||||||
|
if (timeFrom) {
|
||||||
|
// Full datetime comparison: "YYYY-MM-DD HH:mm:ss"
|
||||||
|
if (created < `${dateFrom} ${timeFrom}`) return false;
|
||||||
|
} else if (datePart < dateFrom) return false;
|
||||||
|
}
|
||||||
|
if (dateTo) {
|
||||||
|
const datePart = created.slice(0, 10);
|
||||||
|
if (timeTo) {
|
||||||
|
if (created > `${dateTo} ${timeTo}`) return false;
|
||||||
|
} else if (datePart > dateTo) return false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
setResult(computeAccounting(filtered, myket, cafe, fee));
|
setResult(computeAccounting(filtered, myket, cafe, fee));
|
||||||
}, [allPurchases, statuses, selectedProductId, selectedPackageName, dateFrom, dateTo, myketRate, cafeRate, transactionFee]);
|
}, [allPurchases, statuses, selectedProductId, selectedPackageName, dateFrom, dateTo, timeFrom, timeTo, myketRate, cafeRate, transactionFee]);
|
||||||
|
|
||||||
// Recompute on filter/rate changes (no refetch needed once data is cached)
|
// Recompute on filter/rate changes (no refetch needed once data is cached)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -278,6 +296,8 @@ export default function AccountingPage() {
|
|||||||
setSelectedProductId('');
|
setSelectedProductId('');
|
||||||
setDateFrom('');
|
setDateFrom('');
|
||||||
setDateTo('');
|
setDateTo('');
|
||||||
|
setTimeFrom('');
|
||||||
|
setTimeTo('');
|
||||||
setStatuses([...PAID_STATUSES]);
|
setStatuses([...PAID_STATUSES]);
|
||||||
setMyketRate('85');
|
setMyketRate('85');
|
||||||
setCafeRate('85');
|
setCafeRate('85');
|
||||||
@@ -323,7 +343,7 @@ export default function AccountingPage() {
|
|||||||
}}
|
}}
|
||||||
className="bg-white dark:bg-gray-900 ring-1 ring-gray-200 dark:ring-gray-800 rounded-2xl p-5 sm:p-6 mb-6 shadow-sm"
|
className="bg-white dark:bg-gray-900 ring-1 ring-gray-200 dark:ring-gray-800 rounded-2xl p-5 sm:p-6 mb-6 shadow-sm"
|
||||||
>
|
>
|
||||||
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4">
|
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-6">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor="package_name" className={labelClass}>پکیج</label>
|
<label htmlFor="package_name" className={labelClass}>پکیج</label>
|
||||||
<select
|
<select
|
||||||
@@ -368,6 +388,18 @@ export default function AccountingPage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="time_from" className={labelClass}>از ساعت</label>
|
||||||
|
<input
|
||||||
|
type="time"
|
||||||
|
id="time_from"
|
||||||
|
value={timeFrom}
|
||||||
|
onChange={(e) => setTimeFrom(e.target.value)}
|
||||||
|
className={inputClass}
|
||||||
|
placeholder="۰۰:۰۰"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<PersianDatePicker
|
<PersianDatePicker
|
||||||
id="date_to"
|
id="date_to"
|
||||||
@@ -377,6 +409,18 @@ export default function AccountingPage() {
|
|||||||
onChange={setDateTo}
|
onChange={setDateTo}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label htmlFor="time_to" className={labelClass}>تا ساعت</label>
|
||||||
|
<input
|
||||||
|
type="time"
|
||||||
|
id="time_to"
|
||||||
|
value={timeTo}
|
||||||
|
onChange={(e) => setTimeTo(e.target.value)}
|
||||||
|
className={inputClass}
|
||||||
|
placeholder="۲۳:۵۹"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Status checkboxes */}
|
{/* Status checkboxes */}
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
getPurchaseStatusLabel,
|
getPurchaseStatusLabel,
|
||||||
} from '@/types/purchase';
|
} from '@/types/purchase';
|
||||||
import { PackageName } from '@/types/package';
|
import { PackageName } from '@/types/package';
|
||||||
import { formatPrice, formatDate, getProductTypeLabel, getPurchaseFinalPrice } from '@/lib/utils';
|
import { formatPrice, formatDate, formatTime, getProductTypeLabel, getPurchaseFinalPrice } from '@/lib/utils';
|
||||||
import { MagnifyingGlassIcon, ArrowPathIcon } from '@heroicons/react/24/outline';
|
import { MagnifyingGlassIcon, ArrowPathIcon } from '@heroicons/react/24/outline';
|
||||||
|
|
||||||
const statusBadgeClass = (status: number): string => {
|
const statusBadgeClass = (status: number): string => {
|
||||||
@@ -212,7 +212,7 @@ export default function PurchasesPage() {
|
|||||||
<th className="px-4 py-3">قیمت نهایی</th>
|
<th className="px-4 py-3">قیمت نهایی</th>
|
||||||
<th className="px-4 py-3">منبع پرداخت</th>
|
<th className="px-4 py-3">منبع پرداخت</th>
|
||||||
<th className="px-4 py-3">وضعیت</th>
|
<th className="px-4 py-3">وضعیت</th>
|
||||||
<th className="px-4 py-3">تاریخ</th>
|
<th className="px-4 py-3">تاریخ و ساعت</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-gray-200 dark:divide-gray-800">
|
<tbody className="divide-y divide-gray-200 dark:divide-gray-800">
|
||||||
@@ -254,7 +254,7 @@ export default function PurchasesPage() {
|
|||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3.5 text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
|
<td className="px-4 py-3.5 text-xs text-gray-500 dark:text-gray-400 whitespace-nowrap">
|
||||||
{formatDate(purchase.created_at)}
|
{formatDate(purchase.created_at)} {formatTime(purchase.created_at)}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|||||||
Reference in New Issue
Block a user