restructure project, add claudemd

This commit is contained in:
2026-07-08 16:36:17 -04:00
parent a7964f9410
commit 2a5fbffaa2
315 changed files with 81075 additions and 0 deletions

98
web/finance.ts Normal file
View File

@@ -0,0 +1,98 @@
// Format a number as USD currency.
// If `showChangeIfExists` is false, the cents value is only shown if there are leftover cents
// after converting to dollars (i.e. amount=1000 would be shown as $10, but amount=1001 would be
// shown as $10.01). If true, cents are always displayed.
export function formatCurrency(amount: number, showChangeIfExists: boolean = true): string {
const dollars = amount / 100;
return new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
trailingZeroDisplay: (showChangeIfExists ? "auto" : "stripIfInteger"),
useGrouping: false,
}).format(dollars);
}
// // Same as formatMoney() but with commas.
export function formatCurrencyWithCommas(amount: number, showChangeIfExists: boolean = true): string {
const dollars = amount / 100;
return new Intl.NumberFormat("en-US", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
trailingZeroDisplay: (showChangeIfExists ? "auto" : "stripIfInteger"),
}).format(dollars);
}
// takes a number such as 123456, and outputs (1234, 56) as strings
export function splitCurrency(amount: number): [string, string] {
// Calculate dollars as a string (without cents)
const dollars = Math.floor(amount / 100).toString();
// Calculate cents as a string with leading zero if necessary;
const cents = (amount % 100).toString().padStart(2, "0");
return [dollars, cents];
}
export function moneyToNumber(input: string): number {
if (!input.includes(".")) {
input += ".00";
} else if (input.split(".").length - 1 === 1) {
const digits = input.split(".");
if (digits[1].length === 1) {
input += "0";
}
}
let processed = input
.replaceAll(".", "")
.replaceAll(",", "")
.replaceAll(" ", "");
return parseInt(processed);
}
export function formatRate(rate: number): string {
return (rate / 1000).toFixed(3);
}
export function processDiscount(discount: string): number {
const discountFloat = parseFloat(discount);
if (discountFloat < 0) {
return 0;
} else if (discountFloat > 100) {
return 100;
}
return discountFloat;
}
// Takes days as an input and outputs the string representation of the number
// of days, months, or years in the term based on which unit is the best fit
// for the amount of days along with the corresponding unit string.
export function daysToRateTerm(days: number): [string, string] {
const years = Math.floor(days / 365);
const months = Math.floor((days - years*365) / 30);
const dayRemainder = days - years*365 - months*30;
if (days == 0) { // Return empty string for value
return ["", "days"];
} else if (days <= 270 || dayRemainder > 0) {
return [days.toString(), "days"]
} else if (months > 0) {
return [(months + years*12).toString(), "months"];
} else {
return [years.toString(), "years"];
}
}
export function rateTermToDays(value: string, unit: string): number {
const valueNum = parseInt(value);
switch (unit) {
case "months":
const years = Math.floor(valueNum / 12);
const months = valueNum % 12;
return years*365 + months*30;
case "years":
return valueNum * 365;
default: // case "days":
return valueNum;
}
}