Skip to content
Merged
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
28 changes: 28 additions & 0 deletions src/components/ui/Input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,35 @@ export const Input: React.FC<InputProps> = ({
rightIcon,
className = '',
id,
type,
value,
onChange,
onBlur,
onFocus,
...props
}) => {
const inputId = id || `input-${Math.random().toString(36).substr(2, 9)}`;
const { language } = useUiStore();
const isUrdu = language === 'ur';

const isNumber = type === 'number';
const [buffer, setBuffer] = React.useState<string | null>(null);
const displayValue = isNumber ? (buffer ?? (value === 0 || value == null ? '' : String(value))) : value;

const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (isNumber) setBuffer(e.target.value); // remember the literal text
onChange?.(e); // still call the parent's onChange
};

const handleBlur = (e: React.FocusEvent<HTMLInputElement>) => {
if (isNumber) setBuffer(null); // done typing → show clean number
onBlur?.(e);
};

const handleFocus = (e: React.FocusEvent<HTMLInputElement>) => {
if (isNumber) e.target.select(); // highlight the whole number
onFocus?.(e); // still call any parent onFocus
};
return (
<div className="w-full space-y-1.5">
{label && (
Expand All @@ -42,6 +65,11 @@ export const Input: React.FC<InputProps> = ({
<div className="relative flex-1">
<input
id={inputId}
type= {type}
value={displayValue}
onChange={handleChange}
onBlur={handleBlur}
onFocus={handleFocus}
className={`
w-full h-[46px] bg-background border rounded-xl py-3 ${isUrdu ? "text-xs" : "text-sm"} transition-all outline-none
focus:ring-4
Expand Down
14 changes: 8 additions & 6 deletions src/modules/deliveryChallan/CreateDeliveryChallanModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { useTranslation } from "react-i18next";
import { CreateProductModal } from "../../components/modals/CreateProductModal";
import { CreateCustomerModal } from "../../components/modals/CreateCustomerModal";
import { useUiStore } from "../../store/uiStore";
import { Input } from "../../components/ui/Input";

type ChallanItem = {
product_id: number;
Expand All @@ -41,7 +42,7 @@ export function CreateDeliveryChallanModule() {
const [selectedCustomer, setSelectedCustomer] = useState<Customer | null>(null);
const [challanItems, setChallanItems] = useState<ChallanItem[]>([]);
const [selectedProduct, setSelectedProduct] = useState<Product | null>(null);
const [quantity, setQuantity] = useState(1);
const [quantity, setQuantity] = useState(0);
const [previewExpanded, setPreviewExpanded] = useState(false);

const CUSTOM_FIELDS_KEY = 'teebot_challan_custom_fields';
Expand Down Expand Up @@ -167,7 +168,7 @@ export function CreateDeliveryChallanModule() {
}]);
}
setSelectedProduct(null);
setQuantity(1);
setQuantity(0);
};

const handleUpdateItemQty = (productId: number, delta: number) => {
Expand All @@ -185,7 +186,7 @@ export function CreateDeliveryChallanModule() {
};

const handleSetItemQty = (productId: number, newQty: number) => {
if (isNaN(newQty) || newQty < 1) return;
if (isNaN(newQty) || newQty < 0) return;
setChallanItems(items =>
items.map(item => {
if (item.product_id !== productId) return item;
Expand Down Expand Up @@ -419,7 +420,7 @@ export function CreateDeliveryChallanModule() {
/>
{selectedProduct && (
<div className="mt-3 flex gap-2">
<input
<Input
type="number"
value={quantity}
onChange={(e) => setQuantity(Number(e.target.value))}
Expand All @@ -441,9 +442,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}
<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); }}
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
2 changes: 1 addition & 1 deletion src/modules/inventory/InventoryModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export function InventoryModule() {
<input
type="number"
required
value={stockAdjustment.quantity_change}
value={stockAdjustment.quantity_change === 0 ? "" : stockAdjustment.quantity_change}
onChange={(e) => setStockAdjustment({ ...stockAdjustment, quantity_change: parseInt(e.target.value) || 0 })}
Comment thread
AteebNoOne marked this conversation as resolved.
placeholder={t("adjust_placeholder")}
className="w-full"
Expand Down
9 changes: 5 additions & 4 deletions src/modules/invoices/CreateInvoiceModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -507,18 +507,19 @@ export function CreateInvoiceModule() {
</div>
</td>
<td className="px-4 py-4">
<input
<input
type="number"
value={item.quantity}
value={item.quantity === 0 ? '' : item.quantity}
onChange={(e) => updateItem(idx, 'quantity', Number(e.target.value))}
onBlur={() => { if (item.quantity < 1) updateItem(idx, 'quantity', 1); }}
className="w-full h-8 bg-surface border border-border rounded px-2 text-sm font-bold"
/>
<div className="text-[9px] text-text-muted mt-1 truncate">{item.uom}</div>
</td>
<td className="px-4 py-4">
<input
<input
type="number"
value={item.unit_price}
value={item.unit_price === 0 ? '' : item.unit_price}
onChange={(e) => updateItem(idx, 'unit_price', Number(e.target.value))}
className="w-full h-8 bg-surface border border-border rounded px-2 text-sm font-bold"
/>
Expand Down
10 changes: 8 additions & 2 deletions src/modules/quotations/CreateQuotationModule.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,16 @@ export function CreateQuotationModule() {
<div className="flex items-center gap-4">
<div className="flex items-center border border-border rounded-lg overflow-hidden bg-surface/30">
<button onClick={() => handleUpdateItemQty(item.product_id!, -1)} className="h-7 w-7 flex items-center justify-center text-text-muted hover:bg-surface"><Minus className="h-2.5 w-2.5" /></button>
<input type="number" value={item.quantity} onChange={(e) => {
<input type="number" value={item.quantity === 0 ? '' : item.quantity} onChange={(e) => {
const newItems = [...quotationItems];
newItems[idx].quantity = parseInt(e.target.value) || 1;
newItems[idx].quantity = parseInt(e.target.value) || 0;
setQuotationItems(newItems);
}} onBlur={() => {
if (item.quantity < 1) {
const newItems = [...quotationItems];
newItems[idx].quantity = 1;
setQuotationItems(newItems);
}
}} className="w-12 text-center text-[11px] font-black tabular-nums bg-transparent outline-none" />
<button onClick={() => handleUpdateItemQty(item.product_id!, 1)} className="h-7 w-7 flex items-center justify-center text-text-muted hover:bg-surface"><Plus className="h-2.5 w-2.5" /></button>
</div>
Expand Down
Loading