Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x | /**
* @file useQuantityAdjustFormQueries.ts
* @module dialogs/QuantityAdjustDialog/useQuantityAdjustFormQueries
*
* @summary
* Query management hook for quantity adjustment form.
* Handles data fetching: suppliers, items, and item details with intelligent effects.
*
* @enterprise
* - Separates query/fetch logic from state and form concerns
* - Intelligent effects reset form state on supplier changes
* - Pre-fills quantity field with current item quantity
* - Provides loading states for async data
* - Uses shared hooks for consistent caching and error handling
*/
import * as React from 'react';
import { useSuppliersQuery, useItemSearchQuery, useItemDetailsQuery } from '../../../../api/inventory/hooks/useInventoryData';
import { useItemPriceQuery } from './useItemPriceQuery';
import type { QuantityAdjustFormState, QuantityAdjustFormStateSetters } from './useQuantityAdjustFormState';
import type { UseFormSetValue } from 'react-hook-form';
import type { QuantityAdjustForm } from '../../../../api/inventory/validation';
/**
* Query results and data loading states.
*
* @interface QuantityAdjustFormQueries
* @property {Object[]} suppliers - Array of supplier options
* @property {boolean} suppliersLoading - Loading state for suppliers query
* @property {Object[]} items - Array of item options filtered by supplier
* @property {boolean} itemsLoading - Loading state for items query
* @property {number | null} effectiveCurrentQty - Current item quantity (from details or search)
* @property {number | null} effectiveCurrentPrice - Current item price (from trend or selected)
* @property {boolean} itemDetailsLoading - Loading state for item details query
*/
export interface QuantityAdjustFormQueries {
suppliers: ReturnType<typeof useSuppliersQuery>['data'];
suppliersLoading: boolean;
items: ReturnType<typeof useItemSearchQuery>['data'];
itemsLoading: boolean;
effectiveCurrentQty: number;
effectiveCurrentPrice: number | null;
itemDetailsLoading: boolean;
}
/**
* Query management hook for quantity adjustment form.
*
* Provides all query/fetch logic:
* - Suppliers list (shared hook)
* - Items filtered by supplier (shared hook)
* - Item details including current quantity (shared hook)
* - Item price trend (analytics API)
*
* Intelligent effects:
* - Reset item search/selection when supplier changes
* - Pre-fill quantity field with current item quantity
*
* @param state - Current form state (supplier/item selection)
* @param setters - State setter functions
* @param setValue - react-hook-form's setValue for syncing form state
* @param isDialogOpen - Whether dialog is open (disables queries when closed)
* @returns Query results and loading states
*
* @example
* ```ts
* const queries = useQuantityAdjustFormQueries(state, setters, setValue, open);
* return (
* <>
* <Suppliers data={queries.suppliers} loading={queries.suppliersLoading} />
* <Items data={queries.items} loading={queries.itemsLoading} />
* <CurrentQty>{queries.effectiveCurrentQty}</CurrentQty>
* </>
* );
* ```
*/
export const useQuantityAdjustFormQueries = (
state: QuantityAdjustFormState,
setters: QuantityAdjustFormStateSetters,
setValue: UseFormSetValue<QuantityAdjustForm>,
isDialogOpen: boolean
): QuantityAdjustFormQueries => {
// ================================
// Data Queries
// ================================
/**
* Load suppliers for dropdown.
* Uses shared hook for consistent caching and error handling.
*/
const suppliersQuery = useSuppliersQuery(isDialogOpen);
/**
* Load items based on selected supplier and search query.
* Uses shared hook with client-side supplier filtering.
*/
const itemsQuery = useItemSearchQuery(state.selectedSupplier, state.itemQuery);
/**
* Fetch full item details including current quantity when item is selected.
* Uses shared hook for consistent data fetching.
*/
const itemDetailsQuery = useItemDetailsQuery(state.selectedItem?.id);
/**
* Fetch current price for the selected item via specialized hook.
* Uses price trend API to get the most recent price.
*/
const itemPriceQuery = useItemPriceQuery(state.selectedItem, state.selectedSupplier?.id);
// ================================
// Effects
// ================================
// Destructure individual setters so the dependency array uses stable
// React useState setter references instead of the whole `setters` object
// (which is recreated on every render, causing the effect to fire every render).
const { setSelectedItem, setItemQuery, setFormError } = setters;
/**
* Reset item search when supplier changes.
* Prevents cross-supplier item selection errors.
*/
React.useEffect(() => {
setSelectedItem(null);
setItemQuery('');
setValue('itemId', '');
setValue('newQuantity', 0);
setFormError('');
}, [state.selectedSupplier, setValue, setSelectedItem, setItemQuery, setFormError]);
/**
* Update form value when item is selected.
* Use current quantity from selected item data.
*/
React.useEffect(() => {
if (state.selectedItem && itemDetailsQuery.data) {
setValue('itemId', state.selectedItem.id);
setValue('newQuantity', itemDetailsQuery.data.onHand);
}
}, [state.selectedItem, itemDetailsQuery.data, setValue]);
// ================================
// Derived Values
// ================================
/**
* Effective current quantity:
* - Prefer value from itemDetailsQuery (GET /api/inventory/{id})
* - Fall back to selectedItem.onHand (search placeholder) if details not loaded yet
*/
const effectiveCurrentQty = state.selectedItem
? itemDetailsQuery.data?.onHand ?? state.selectedItem.onHand ?? 0
: 0;
/**
* Effective current price:
* - Prefer value from itemPriceQuery (analytics API)
* - Fall back to selectedItem.price (search placeholder)
*/
const effectiveCurrentPrice =
itemPriceQuery.data !== null && itemPriceQuery.data !== undefined
? itemPriceQuery.data
: state.selectedItem?.price ?? null;
return {
suppliers: suppliersQuery.data,
suppliersLoading: suppliersQuery.isLoading,
items: itemsQuery.data,
itemsLoading: itemsQuery.isLoading,
effectiveCurrentQty,
effectiveCurrentPrice,
itemDetailsLoading: itemDetailsQuery.isLoading,
};
};
|