Better form control and profile page

This commit is contained in:
2026-04-04 23:11:51 -05:00
parent 33b47d7ffb
commit 163ce564e5
6 changed files with 319 additions and 17 deletions

View File

@@ -1,6 +1,7 @@
import { useState, useRef, useEffect } from "react";
import ExcelJS from "exceljs";
import { chemicalsApi } from "../lib/api";
import { validateCAS, validateNumber, validatePhoneOrEmail } from "../lib/validators";
import type { ChemicalInventory } from "../shared/types";
import { Card } from "./ui/card";
import { Button } from "./ui/button";
@@ -199,6 +200,30 @@ export function Inventory() {
setFormError("Please fill in all required fields.");
return;
}
if (!validateCAS(String(form.casNumber || ""))) {
setFormError("CAS # must be in the format ##-##-# (e.g. 67-56-1).");
return;
}
if (!validateNumber(form.numberOfContainers, { min: 1, integer: true })) {
setFormError("# of containers must be a whole number of 1 or more.");
return;
}
if (!validateNumber(form.amountPerContainer, { min: 0 })) {
setFormError("Amount per container must be a number.");
return;
}
if (form.molecularWeight && !validateNumber(form.molecularWeight, { min: 0 })) {
setFormError("Molecular weight must be a number.");
return;
}
if (form.percentageFull != null && !validateNumber(form.percentageFull, { min: 0, max: 100 })) {
setFormError("% full must be between 0 and 100.");
return;
}
if (form.contact && !validatePhoneOrEmail(String(form.contact))) {
setFormError("Contact must be a valid phone number or email address.");
return;
}
setFormError("");
setIsSaving(true);
try {
@@ -963,7 +988,14 @@ export function Inventory() {
<div className="space-y-1">
<Label className="text-xs">CAS # <span className="text-red-500">*</span></Label>
<Input value={form.casNumber || ""} onChange={e => setField("casNumber", e.target.value)} placeholder="e.g. 67-56-1" />
<Input
value={form.casNumber || ""}
onChange={e => setField("casNumber", e.target.value)}
placeholder="e.g. 67-56-1"
inputMode="numeric"
pattern="\d{2,7}-\d{2}-\d"
title="CAS format: digits-digits-digit (e.g. 67-56-1)"
/>
</div>
<div className="space-y-1">
@@ -1009,7 +1041,14 @@ export function Inventory() {
<div className="space-y-1">
<Label className="text-xs">Amount / Container <span className="text-red-500">*</span></Label>
<Input value={form.amountPerContainer || ""} onChange={e => setField("amountPerContainer", e.target.value)} placeholder="e.g. 500" />
<Input
type="number"
min={0}
step="any"
value={form.amountPerContainer || ""}
onChange={e => setField("amountPerContainer", e.target.value)}
placeholder="e.g. 500"
/>
</div>
<div className="space-y-1 col-span-2">
@@ -1045,7 +1084,14 @@ export function Inventory() {
</div>
<div className="space-y-1">
<Label className="text-xs">Molecular Weight</Label>
<Input value={form.molecularWeight || ""} onChange={e => setField("molecularWeight", e.target.value)} placeholder="g/mol" />
<Input
type="number"
min={0}
step="any"
value={form.molecularWeight || ""}
onChange={e => setField("molecularWeight", e.target.value)}
placeholder="g/mol"
/>
</div>
<div className="space-y-1">
<Label className="text-xs">Concentration</Label>
@@ -1077,7 +1123,11 @@ export function Inventory() {
</div>
<div className="space-y-1">
<Label className="text-xs">Contact</Label>
<Input value={form.contact || ""} onChange={e => setField("contact", e.target.value)} />
<Input
value={form.contact || ""}
onChange={e => setField("contact", e.target.value)}
placeholder="Phone (e.g. 555-123-4567) or email"
/>
</div>
<div className="space-y-1 col-span-2">
<Label className="text-xs">Comments</Label>