113 lines
5.2 KiB
TypeScript
113 lines
5.2 KiB
TypeScript
import { useContext, useEffect, useRef, useState } from 'react';
|
|
import { faker } from '@faker-js/faker';
|
|
|
|
import { dateToOrdinal, ordinalToDate } from '@/app/lib/ordinalDate';
|
|
import { Product } from '@/app/lib/product.enum';
|
|
import { SupplyChainContext } from '@/app/lib/context/SupplyChain/SupplyChainContext';
|
|
import { ParsedBarcode, barcodeToProduct } from '@/app/lib/barcode';
|
|
|
|
import { BinnerContext } from '../../context/BinnerContext';
|
|
import { useGetProcessorByBarcodeId } from '../../hooks';
|
|
|
|
import styles from './ProductInfo.module.scss';
|
|
|
|
export function ProductInfo() {
|
|
const { item, setItem } = useContext(BinnerContext);
|
|
const { processors } = useContext(SupplyChainContext);
|
|
const [inputItem, setInputItem] = useState<Partial<ParsedBarcode> | null>(null);
|
|
const dateRef = useRef<HTMLInputElement>(null);
|
|
const weightRef = useRef<HTMLInputElement>(null);
|
|
const getProcessorByBarcodeId = useGetProcessorByBarcodeId();
|
|
|
|
const isCompleteItem = (item: Partial<ParsedBarcode> | null) => item && !!(item?.product && item?.date && item?.processor && item?.weight);
|
|
|
|
const [isEntryMode, setIsEntryMode] = useState(!isCompleteItem(item));
|
|
|
|
useEffect(() => {
|
|
setIsEntryMode(!isCompleteItem(item));
|
|
}, [item])
|
|
|
|
useEffect(() => {
|
|
if (isCompleteItem(inputItem)) {
|
|
setItem(barcodeToProduct(`${inputItem?.product}${inputItem?.date}${inputItem?.processor}${inputItem?.weight}`));
|
|
setInputItem(null);
|
|
}
|
|
setIsEntryMode(!isCompleteItem(inputItem));
|
|
}, [inputItem])
|
|
|
|
return (
|
|
<div className={styles.productInfo}>
|
|
<div className={styles.attributes}>
|
|
<div className={styles.card}>
|
|
<label htmlFor="product">Product</label>
|
|
{isEntryMode ? (
|
|
<select
|
|
id="product"
|
|
defaultValue=""
|
|
onChange={(e) => setInputItem({ ...inputItem || {}, product: e.currentTarget.value })}
|
|
>
|
|
<option value="">Select a product</option>
|
|
{Object.keys(Product).map((product) => (
|
|
<option key={product} value={Product[product]}>{product}</option>
|
|
))}
|
|
</select>
|
|
) : (
|
|
<input id="product" value={item?.product!} contentEditable={false} />
|
|
)}
|
|
</div>
|
|
<div className={styles.card}>
|
|
<label htmlFor="date">Packaged Date</label>
|
|
<input
|
|
id="date" value={!!item ? ordinalToDate(item.date).toDateString() : ''}
|
|
contentEditable={isEntryMode}
|
|
ref={dateRef}
|
|
onChange={(e) => {
|
|
dateRef.current.value = e.currentTarget.value;
|
|
setInputItem({ ...inputItem || {}, date: dateToOrdinal(new Date(e.currentTarget.value)) })
|
|
}}
|
|
/>
|
|
</div>
|
|
<div className={styles.card}>
|
|
<label htmlFor="processor">Processor</label>
|
|
{isEntryMode ? (
|
|
<select
|
|
id="processor"
|
|
defaultValue=""
|
|
onChange={(e) => setInputItem({ ...inputItem || {}, processor: e.currentTarget.value })}
|
|
>
|
|
<option value="">Select a processor</option>
|
|
{processors.map((processor) => (
|
|
<option key={processor._id} value={processor.barcode_id}>{processor.name}</option>
|
|
))}
|
|
</select>
|
|
) : (
|
|
<input id="processor" value={!!item ? (getProcessorByBarcodeId(item.processor)?.name ?? 'unknown/invalid processor') : ''} contentEditable={false} />
|
|
)}
|
|
</div>
|
|
<div className={styles.card}>
|
|
<label htmlFor="weight">Weight</label>
|
|
<div className={styles.inputWithButton}>
|
|
<input
|
|
id="weight"
|
|
value={!!item ? `${item.weight} lbs.` : ''}
|
|
contentEditable={false}
|
|
tabIndex={-1}
|
|
ref={weightRef}
|
|
/>
|
|
{isEntryMode && (
|
|
<button
|
|
onClick={(e) => {
|
|
const weight = faker.number.int({ min: 1000, max: 1999 });
|
|
weightRef.current.value = `${weight / 100} lbs`; setInputItem({ ...inputItem || {}, weight })
|
|
}}
|
|
tabIndex={0}
|
|
>
|
|
Weight from Scale
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |