Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions src/components/ui/NumberField.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import React from "react";

interface NumberFieldProps
extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'value' | 'onchange'>{
value : number
onCommit : (n:number) => void
fallback ?: number
allowNegative ? :boolean
Comment on lines +3 to +8

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== NumberField ==\n'
sed -n '1,220p' src/components/ui/NumberField.tsx

printf '\n== DeliveryChallan usage ==\n'
sed -n '430,470p' src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx

printf '\n== Inventory usage ==\n'
sed -n '220,255p' src/modules/inventory/InventoryModule.tsx

printf '\n== Invoice usage ==\n'
sed -n '500,545p' src/modules/invoices/CreateInvoiceModule.tsx

Repository: iTeebot/flow

Length of output: 9237


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== NumberField references ==\n'
rg -n "NumberField|allowNegative|fallback|onCommit|type=\"number\"|required" src/components/ui/NumberField.tsx src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx src/modules/inventory/InventoryModule.tsx src/modules/invoices/CreateInvoiceModule.tsx

Repository: iTeebot/flow

Length of output: 2746


Forward native input props from NumberField. The component drops caller-supplied props because it never captures or spreads the rest of React.InputHTMLAttributes, so required, placeholder, className, and similar attributes never reach the DOM input. type="number" is also ignored because the field is hardcoded to type="text" for draft editing.

  • src/components/ui/NumberField.tsx: fix the prop type omit to use onChange (not onchange), capture the remaining input props, and spread them onto <input />.
  • Keep the internal text-based draft behavior, but make the unsupported type prop explicit or remove it from callers that expect native number input behavior.
📍 Affects 4 files
  • src/components/ui/NumberField.tsx#L3-L8 (this comment)
  • src/components/ui/NumberField.tsx#L11-L13
  • src/components/ui/NumberField.tsx#L36-L43
  • src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx#L446-L449
  • src/modules/inventory/InventoryModule.tsx#L236-L241
  • src/modules/invoices/CreateInvoiceModule.tsx#L521-L524
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ui/NumberField.tsx` around lines 3 - 8, Update
src/components/ui/NumberField.tsx at lines 3-8, 11-13, and 36-43: omit onChange
with the correct casing, capture remaining native input props, and spread them
onto the internal input while preserving text-based draft behavior; explicitly
exclude or override the unsupported type prop. Review callers at
src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx lines 446-449,
src/modules/inventory/InventoryModule.tsx lines 236-241, and
src/modules/invoices/CreateInvoiceModule.tsx lines 521-524, removing
type="number" where callers require native number behavior or otherwise aligning
them with NumberField’s text input contract.

}

export const NumberField : React.FC<NumberFieldProps> = ({
value, onCommit, fallback, allowNegative
}) => {
const [draft,setDraft] = React.useState<string | null> (null)

const pattern = allowNegative ? /^-?\d*\.?\d*$/ : /^\d*\.?\d*$/;

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const text = e.target.value
if(!pattern.test(text)) return
setDraft(text)
const n = Number(text)
if(text != '' && !isNaN(n)) onCommit(n);
Comment on lines +22 to +23

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and inspect the file in question.
git ls-files src/components/ui/NumberField.tsx
wc -l src/components/ui/NumberField.tsx
cat -n src/components/ui/NumberField.tsx | sed -n '1,220p'

Repository: iTeebot/flow

Length of output: 1804


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find local usages of NumberField and inspect the call sites.
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
  'NumberField' src

# Also inspect the component's immediate neighbors for context if any.
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
  'onCommit\(|fallback|allowNegative|inputMode="decimal"' src/components src | sed -n '1,200p'

Repository: iTeebot/flow

Length of output: 3087


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for local call sites to understand whether Infinity would affect money/quantity flows.
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
  '<NumberField|NumberField\\s*\\(' src

# Show surrounding lines for each hit.
for f in $(rg -l --hidden --glob '!node_modules' --glob '!dist' --glob '!build' \
  '<NumberField|NumberField\\s*\\(' src); do
  echo "===== $f ====="
  cat -n "$f" | sed -n '1,240p'
done

Repository: iTeebot/flow

Length of output: 263


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Probe the number semantics that drive the bug claim.
node - <<'JS'
const samples = [
  '9'.repeat(307),
  '9'.repeat(308),
  '1e309',
  '',
  '123.45',
  '-123',
  'abc',
];
for (const s of samples) {
  const n = Number(s);
  console.log(JSON.stringify({s, n, isNaN: isNaN(n), finite: Number.isFinite(n)}));
}
JS

# Find every local reference to NumberField to understand impact.
rg -n --hidden --glob '!node_modules' --glob '!dist' --glob '!build' 'NumberField' src

Repository: iTeebot/flow

Length of output: 1873


🏁 Script executed:

#!/bin/bash
set -euo pipefail

node - <<'JS'
for (const len of [308, 309, 310, 320]) {
  const s = '9'.repeat(len);
  const n = Number(s);
  console.log(len, String(n), Number.isFinite(n), isNaN(n));
}
JS

Repository: iTeebot/flow

Length of output: 247


Reject non-finite numeric values. Number(text) overflows to Infinity for very long digit strings, and isNaN(Infinity) still passes. That can commit non-finite values into quantities and amounts; use Number.isFinite(n) here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/ui/NumberField.tsx` around lines 22 - 23, Update the commit
validation in the NumberField input handler to use Number.isFinite(n) instead of
the global isNaN check, while retaining the existing non-empty text requirement
and onCommit behavior for valid finite numbers.

}
const handleBlur = () =>{
const n = Number(draft ?? '')
if( draft == '' || draft == null || isNaN(n)){
if(fallback !== undefined){
onCommit(fallback)
}
}

setDraft(null);
}

return(
<input
type="text"
inputMode="decimal"
onChange={handleChange}
onBlur={handleBlur}
value={draft ?? (value === 0 ? '' : String(value))}
/>

)
}
9 changes: 5 additions & 4 deletions src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { CreateProductModal } from "../../components/modals/CreateProductModal";
import { CreateCustomerModal } from "../../components/modals/CreateCustomerModal";
import { useUiStore } from "../../store/uiStore";
import { Input } from "../../components/ui/Input";
import { NumberField } from "../../components/ui/NumberField";

type ChallanItem = {
product_id: number;
Expand Down Expand Up @@ -442,10 +443,10 @@ export function CreateDeliveryChallanModule() {
</div>
<div className="flex items-center gap-0 border border-border rounded-lg overflow-hidden bg-background">
<button onClick={() => handleUpdateItemQty(item.product_id, -1)} className="h-6 w-6 flex items-center justify-center border-r border-border hover:bg-surface"><Minus className="h-2.5 w-2.5" /></button>
<input
value={item.quantity === 0 ? '' : item.quantity}
onChange={e => handleSetItemQty(item.product_id, Number(e.target.value))}
onBlur={() => { if (item.quantity < 1) handleSetItemQty(item.product_id, 1); }}
<NumberField
value={item.quantity}
onCommit={(n) => handleSetItemQty(item.product_id, n)}
fallback={1}
Comment on lines +446 to +449

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant files and inspect the shared component plus the caller.
git ls-files 'src/components/ui/NumberField.tsx' 'src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx'

echo
echo '--- NumberField outline ---'
ast-grep outline src/components/ui/NumberField.tsx --view expanded || true

echo
echo '--- CreateDeliveryChallanModule outline (focused) ---'
ast-grep outline src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx --view expanded | sed -n '1,220p'

echo
echo '--- NumberField source ---'
wc -l src/components/ui/NumberField.tsx
cat -n src/components/ui/NumberField.tsx

echo
echo '--- Caller lines around usage ---'
sed -n '430,470p' src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx

Repository: iTeebot/flow

Length of output: 5341


Forward native input props in NumberField
NumberField accepts InputHTMLAttributes, but the props are never spread onto the <input>, so caller-supplied attributes like className are ignored. Pass the remaining props through in src/components/ui/NumberField.tsx.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx` around lines 446
- 449, Update the NumberField component to forward its remaining
InputHTMLAttributes onto the underlying input element, preserving its existing
value, commit handling, and fallback behavior so caller-supplied props such as
className are applied.

className="w-10 h-6 text-center text-[10px] font-black border-0 bg-transparent focus:ring-0"
/>
<button onClick={() => handleUpdateItemQty(item.product_id, 1)} className="h-6 w-6 flex items-center justify-center border-l border-border hover:bg-surface"><Plus className="h-2.5 w-2.5" /></button>
Expand Down
8 changes: 5 additions & 3 deletions src/modules/inventory/InventoryModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { Input } from "../../components/ui/Input";
import { ModulePage } from "../../components/ModulePage";
import { DataTable } from "../../components/DataTable";
import { useUiStore } from "../../store/uiStore";
import { NumberField } from "../../components/ui/NumberField";

export function InventoryModule() {
const { t } = useTranslation("inventory");
Expand Down Expand Up @@ -232,11 +233,12 @@ export function InventoryModule() {
<form onSubmit={handleStockAdjustment} className="flex flex-col sm:flex-row gap-4">
<div className="flex-1">
<label className="block text-[10px] font-black uppercase text-text-muted mb-1 ml-1">{t("adjust_qty_change")}</label>
<input
<NumberField
type="number"
required
value={stockAdjustment.quantity_change === 0 ? "" : stockAdjustment.quantity_change}
onChange={(e) => setStockAdjustment({ ...stockAdjustment, quantity_change: parseInt(e.target.value) || 0 })}
value={stockAdjustment.quantity_change}
onCommit={(n) => setStockAdjustment({ ...stockAdjustment, quantity_change: Math.trunc(n)})}
allowNegative
placeholder={t("adjust_placeholder")}
className="w-full"
/>
Expand Down
7 changes: 4 additions & 3 deletions src/modules/invoices/CreateInvoiceModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Input } from "../../components/ui/Input";
import { SearchableSelect } from "../../components/ui/SearchableSelect";
import { Select } from "../../components/ui/Select";
import { formatCurrency } from "../../lib/utils";
import { NumberField } from "../../components/ui/NumberField";

const PROVINCES = ["Sindh", "Punjab", "Khyber Pakhtunkhwa", "Balochistan", "Islamabad Capital Territory", "Gilgit-Baltistan", "Azad Kashmir"];
const REGISTRATION_TYPES = ["Registered", "Unregistered"];
Expand Down Expand Up @@ -517,10 +518,10 @@ export function CreateInvoiceModule() {
<div className="text-[9px] text-text-muted mt-1 truncate">{item.uom}</div>
</td>
<td className="px-4 py-4">
<input
<NumberField
type="number"
value={item.unit_price === 0 ? '' : item.unit_price}
onChange={(e) => updateItem(idx, 'unit_price', Number(e.target.value))}
value={item.unit_price}
onCommit={(n) => updateItem(idx, 'unit_price',n)}
className="w-full h-8 bg-surface border border-border rounded px-2 text-sm font-bold"
/>
</td>
Expand Down
Loading