Validate parsed dollar amount before submitting invoice form

Open Beginner friendly
#43 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
78/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
react, typescript

Research direction

Start in src/app/invoices/new/invoice-upload-form.tsx around lines 263 and 309-318, comparing the overwrite guard with onSubmit. Add coverage for empty, non-numeric, non-positive, and valid amounts, then run the relevant Vitest tests plus pnpm lint and pnpm typecheck. Done means invalid submissions show the specified toast without calling saveInvoice, while valid amounts still submit.

Written by the indexing model from the issue text.

Description

area:billing bug priority:medium tech-debt

Problem

In the invoice upload flow, the on-submit handler converts a string state (amountDollars) into cents via parseFloat, but does not validate the result before sending it to the server. If the user clears the dollar field after the form has been validated by Zod, or React Hook Form’s validation hasn't caught up, the request payload can carry amountCents = NaN. NaN then propagates into Drizzle inserts and breaks downstream period matching and ingestion logging.

Other entry points already guard the parse (e.g. the overwrite path on line 263, the input onChange on line 415, tools/[id]/tool-detail-client.tsx:185, claude/org-credits-panel.tsx:41, budget/[id]/budget-detail-client.tsx:177), so the protection is genuinely missing only at the on-submit path.

Evidence

src/app/invoices/new/invoice-upload-form.tsx:309-318:

const onSubmit = async (data: CreateInvoiceInput) => {
  // T018: Convert dollars to cents before saving
  const amountCents = Math.round(parseFloat(amountDollars) * 100);
  const submitData = { ...data, amountCents };

  const result = await saveInvoice(submitData);
  ...
};

For comparison, handleOverwriteDuplicate on line 263 does guard with Number.isFinite(parsedAmount) || parsedAmount <= 0. The on-submit path is the only one that skips this.

Proposed approach

  1. In onSubmit, replicate the guard from line 263:
    const parsedAmount = parseFloat(amountDollars);
    if (!Number.isFinite(parsedAmount) || parsedAmount <= 0) {
      toast.error(\"Please enter a valid positive amount.\");
      return;
    }
    const amountCents = Math.round(parsedAmount * 100);
    
  2. Optionally extract a small helper parseDollarsToCents(value: string): number | null in the same file (or in src/lib/utils.ts) and use it in both call sites to keep them in sync.
  3. Add a Vitest unit test that covers: empty string, \"abc\", \"-1\", \"0\", valid input.

Acceptance criteria

  • On-submit returns early with a toast when the parsed amount is NaN, <= 0, or empty.
  • No NaN ever reaches saveInvoice.
  • The overwrite path and on-submit path use the same validation logic (extracted helper).
  • Unit tests for the helper / on-submit guard.
  • pnpm lint && pnpm typecheck pass.

Verification

  1. pnpm dev (or PORT=3001 pnpm dev if 3000 is busy).
  2. Navigate to /invoices/new, upload a PDF, let extraction run, then clear the amount field and click submit.
  3. Expect a toast "Please enter a valid positive amount" and no network call.
  4. Re-enter a valid amount → submit succeeds.
Dominant language
HTML
Stars
0
Forks
0
PR merge metrics
No merged PRs in 30d

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from unic/ai-developer-hub

All issues in unic/ai-developer-hub

Similar issues

More Web Dev issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.