remove PriceListSheet component and integrate new price list creation page
This commit is contained in:
@@ -26,6 +26,7 @@ import {
|
||||
rides as ridesApi,
|
||||
items as itemsApi,
|
||||
users as usersApi,
|
||||
priceLists as priceListsApi,
|
||||
getApiError,
|
||||
getPaginatedItems,
|
||||
} from '@/lib/api/index'
|
||||
@@ -83,6 +84,8 @@ export default function NewSalePage() {
|
||||
})
|
||||
|
||||
const watchedItems = useWatch({ control: form.control, name: 'items' })
|
||||
const watchedStoreId = useWatch({ control: form.control, name: 'storeId' })
|
||||
const watchedSaleDate = useWatch({ control: form.control, name: 'saleDate' })
|
||||
const itemsById = useMemo(
|
||||
() => new Map(itemsList.map((item) => [item.id, item])),
|
||||
[itemsList]
|
||||
@@ -91,6 +94,38 @@ export default function NewSalePage() {
|
||||
() => watchedItems.reduce((sum, item) => sum + (Number(item.quantity) || 0) * (Number(item.unitPrice) || 0), 0),
|
||||
[watchedItems]
|
||||
)
|
||||
const [priceMinByIndex, setPriceMinByIndex] = useState<Record<number, number | null>>({})
|
||||
const [priceRetailByIndex, setPriceRetailByIndex] = useState<Record<number, number | null>>({})
|
||||
|
||||
async function resolveAndSetPrice(index: number, itemId: string) {
|
||||
const item = itemsById.get(itemId)
|
||||
if (watchedStoreId && watchedSaleDate) {
|
||||
try {
|
||||
const resolution = await priceListsApi.resolve({ itemId, storeId: watchedStoreId, saleDate: watchedSaleDate })
|
||||
form.setValue(`items.${index}.unitPrice`, resolution.price, { shouldValidate: true })
|
||||
setPriceMinByIndex((prev) => ({ ...prev, [index]: resolution.minPrice }))
|
||||
setPriceRetailByIndex((prev) => ({ ...prev, [index]: resolution.retailPrice }))
|
||||
return
|
||||
} catch {
|
||||
// No resolvable price for this store/date (e.g. store/item not found) — fall back below.
|
||||
}
|
||||
}
|
||||
if (item) {
|
||||
form.setValue(`items.${index}.unitPrice`, item.salePrice, { shouldValidate: true })
|
||||
setPriceMinByIndex((prev) => ({ ...prev, [index]: null }))
|
||||
setPriceRetailByIndex((prev) => ({ ...prev, [index]: null }))
|
||||
}
|
||||
}
|
||||
|
||||
// Re-resolve every already-selected line's price whenever the store or sale date changes,
|
||||
// since the applicable price list is scoped by the store's region and the sale date.
|
||||
useEffect(() => {
|
||||
if (!watchedStoreId || !watchedSaleDate) return
|
||||
watchedItems.forEach((line, index) => {
|
||||
if (line.itemId) resolveAndSetPrice(index, line.itemId)
|
||||
})
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [watchedStoreId, watchedSaleDate])
|
||||
|
||||
useEffect(() => {
|
||||
Promise.all([
|
||||
@@ -291,10 +326,7 @@ export default function NewSalePage() {
|
||||
value={field.value as string}
|
||||
onValueChange={(value) => {
|
||||
field.onChange(value)
|
||||
const nextItem = value ? itemsById.get(value) : undefined
|
||||
if (nextItem) {
|
||||
form.setValue(`items.${index}.unitPrice`, nextItem.salePrice, { shouldValidate: true })
|
||||
}
|
||||
if (value) resolveAndSetPrice(index, value)
|
||||
}}
|
||||
>
|
||||
<SelectTrigger>
|
||||
@@ -359,6 +391,16 @@ export default function NewSalePage() {
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
{priceMinByIndex[index] != null && (
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
Negotiable down to {fmtAmount(priceMinByIndex[index]!)}
|
||||
</p>
|
||||
)}
|
||||
{priceRetailByIndex[index] != null && (
|
||||
<p className="mt-1 text-xs text-muted-foreground">
|
||||
Retail price: {fmtAmount(priceRetailByIndex[index]!)}
|
||||
</p>
|
||||
)}
|
||||
</td>
|
||||
|
||||
<td className="px-3 py-2 text-right font-medium">{fmtAmount(lineTotal)}</td>
|
||||
|
||||
Reference in New Issue
Block a user