pre-launch hardening: Address Book type sort, Hot Desk proportions, TVA calculator, ROADMAP Phase 4B
- Address Book: type dropdown always sorted alphabetically (ro locale), including custom types - Hot Desk: window ~half height (top-[35%] bottom-[35%]), door ~double height (h-16) - Mini Utilities: TVA calculator (19%) with add/extract modes, RON formatting, copy buttons - ROADMAP: new Phase 4B Pre-Launch Hardening with 10 structured tasks - CLAUDE.md: bumped versions (Address Book 0.1.1, Mini Utilities 0.1.1, Hot Desk 0.1.1), Visual Copilot separate repo note
This commit is contained in:
@@ -16,6 +16,7 @@ import {
|
||||
CaseUpper,
|
||||
Palette,
|
||||
Upload,
|
||||
Receipt,
|
||||
} from "lucide-react";
|
||||
import { Button } from "@/shared/components/ui/button";
|
||||
import { Input } from "@/shared/components/ui/input";
|
||||
@@ -206,6 +207,103 @@ function PercentageCalculator() {
|
||||
);
|
||||
}
|
||||
|
||||
function TvaCalculator() {
|
||||
const TVA_RATE = 19; // Romania standard VAT
|
||||
const [amount, setAmount] = useState("");
|
||||
const [mode, setMode] = useState<"add" | "extract">("add");
|
||||
|
||||
const val = parseFloat(amount);
|
||||
const tvaMultiplier = TVA_RATE / 100;
|
||||
|
||||
const cuTva = !isNaN(val) && mode === "add" ? val * (1 + tvaMultiplier) : NaN;
|
||||
const faraTva =
|
||||
!isNaN(val) && mode === "extract" ? val / (1 + tvaMultiplier) : NaN;
|
||||
const tvaAmount = !isNaN(val)
|
||||
? mode === "add"
|
||||
? val * tvaMultiplier
|
||||
: val - val / (1 + tvaMultiplier)
|
||||
: NaN;
|
||||
|
||||
const fmt = (n: number) =>
|
||||
isNaN(n)
|
||||
? "—"
|
||||
: n.toLocaleString("ro-RO", {
|
||||
minimumFractionDigits: 2,
|
||||
maximumFractionDigits: 2,
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
variant={mode === "add" ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={() => setMode("add")}
|
||||
>
|
||||
Adaugă TVA
|
||||
</Button>
|
||||
<Button
|
||||
variant={mode === "extract" ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={() => setMode("extract")}
|
||||
>
|
||||
Extrage TVA
|
||||
</Button>
|
||||
</div>
|
||||
<div>
|
||||
<Label>{mode === "add" ? "Sumă fără TVA" : "Sumă cu TVA"}</Label>
|
||||
<div className="mt-1 flex gap-2">
|
||||
<Input
|
||||
type="number"
|
||||
value={amount}
|
||||
onChange={(e) => setAmount(e.target.value)}
|
||||
placeholder={mode === "add" ? "Ex: 1000" : "Ex: 1190"}
|
||||
className="flex-1"
|
||||
/>
|
||||
<span className="flex items-center text-sm text-muted-foreground">
|
||||
RON
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{!isNaN(val) && val > 0 && (
|
||||
<div className="rounded-md border bg-muted/30 p-4 space-y-2 text-sm">
|
||||
{mode === "add" ? (
|
||||
<>
|
||||
<p>
|
||||
Sumă fără TVA: <strong>{fmt(val)} RON</strong>
|
||||
</p>
|
||||
<p>
|
||||
TVA ({TVA_RATE}%): <strong>{fmt(tvaAmount)} RON</strong>
|
||||
<CopyButton text={fmt(tvaAmount)} />
|
||||
</p>
|
||||
<p className="text-base pt-1 border-t">
|
||||
Total cu TVA:{" "}
|
||||
<strong className="text-primary">{fmt(cuTva)} RON</strong>
|
||||
<CopyButton text={fmt(cuTva)} />
|
||||
</p>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<p>
|
||||
Sumă cu TVA: <strong>{fmt(val)} RON</strong>
|
||||
</p>
|
||||
<p>
|
||||
TVA ({TVA_RATE}%): <strong>{fmt(tvaAmount)} RON</strong>
|
||||
<CopyButton text={fmt(tvaAmount)} />
|
||||
</p>
|
||||
<p className="text-base pt-1 border-t">
|
||||
Sumă fără TVA:{" "}
|
||||
<strong className="text-primary">{fmt(faraTva)} RON</strong>
|
||||
<CopyButton text={fmt(faraTva)} />
|
||||
</p>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function AreaConverter() {
|
||||
const units = [
|
||||
{ key: "mp", label: "mp (m²)", factor: 1 },
|
||||
@@ -1207,6 +1305,9 @@ export function MiniUtilitiesModule() {
|
||||
<TabsTrigger value="percentage">
|
||||
<Percent className="mr-1 h-3.5 w-3.5" /> Procente
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="tva">
|
||||
<Receipt className="mr-1 h-3.5 w-3.5" /> TVA
|
||||
</TabsTrigger>
|
||||
<TabsTrigger value="area">
|
||||
<Ruler className="mr-1 h-3.5 w-3.5" /> Suprafețe
|
||||
</TabsTrigger>
|
||||
@@ -1263,6 +1364,16 @@ export function MiniUtilitiesModule() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
<TabsContent value="tva">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle className="text-base">Calculator TVA (19%)</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<TvaCalculator />
|
||||
</CardContent>
|
||||
</Card>
|
||||
</TabsContent>
|
||||
<TabsContent value="area">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
||||
Reference in New Issue
Block a user