Initial commit: Voiced invoice desktop app

Offline-first invoicing app for Arun P, built by Bongbetic.

- Tauri v2 (Rust) + React/TypeScript + IBM Carbon Design System UI
- SQLite (rusqlite) storage with a persistent invoice-number series
- Guided first-run setup, pre-filled vendor/bank details
- Fixed-amount or rate x quantity line items (per sec/min/hour/session/unit)
- GST as CGST+SGST or IGST, Indian amount-in-words
- Optional signature, with a computer-generated note as fallback
- Print-ready PDF export via @react-pdf/renderer
- Windows cross-compile via cargo-xwin (NSIS installer)

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
This commit is contained in:
2026-10-03 23:07:51 +05:30
co-authored by CommandCodeBot
commit 3af9f3f66f
125 changed files with 13660 additions and 0 deletions
+42
View File
@@ -0,0 +1,42 @@
const PAN_RE = /^[A-Z]{5}[0-9]{4}[A-Z]$/;
const IFSC_RE = /^[A-Z]{4}0[A-Z0-9]{6}$/;
const GSTIN_RE = /^[0-9]{2}[A-Z]{5}[0-9]{4}[A-Z][1-9A-Z]Z[0-9A-Z]$/;
const EMAIL_RE = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const PHONE_RE = /^[0-9+\-()\s]{6,16}$/;
const norm = (v: string) => v.trim().toUpperCase();
export function panError(value: string): string | undefined {
if (!value.trim()) return undefined;
return PAN_RE.test(norm(value)) ? undefined : "Enter a valid PAN, e.g. CPOPP7388K";
}
export function ifscError(value: string): string | undefined {
if (!value.trim()) return undefined;
return IFSC_RE.test(norm(value)) ? undefined : "Enter a valid IFSC, e.g. SBIN0017060";
}
export function gstinError(value: string): string | undefined {
const v = norm(value);
if (!v || v === "NA") return undefined;
return GSTIN_RE.test(v) ? undefined : "Enter a valid 15-character GSTIN";
}
export function emailError(value: string): string | undefined {
if (!value.trim()) return undefined;
return EMAIL_RE.test(value.trim()) ? undefined : "Enter a valid email address";
}
export function phoneError(value: string): string | undefined {
if (!value.trim()) return undefined;
return PHONE_RE.test(value.trim()) ? undefined : "Enter a valid phone number";
}
export function accountError(value: string): string | undefined {
if (!value.trim()) return undefined;
return /^[0-9]{6,20}$/.test(value.trim()) ? undefined : "Account number should be 6–20 digits";
}
export const isPan = (v: string) => PAN_RE.test(norm(v));
export const isIfsc = (v: string) => IFSC_RE.test(norm(v));
export const isGstin = (v: string) => GSTIN_RE.test(norm(v));