Rename to Tally; add Beauty category, Housing -> Household

This commit is contained in:
2026-09-18 22:05:47 +00:00
parent b394fd85a9
commit edbd05a3c9
10 changed files with 33 additions and 17 deletions

View File

@@ -1,4 +1,4 @@
# Pin & Penny
# Tally
Daily, weekly and monthly expense tracking. Data is saved privately (local storage on web, on-device storage in the app). No account.
@@ -20,7 +20,7 @@ To use another port: `PORT=8080 python3 server.py`.
## Features
- **Sidebar views** — Daily, Weekly, Monthly and All expenses with live counts, each group with its own total.
- **Categories** — Food, Transport, Housing, Utilities, Shopping, Health, Entertainment, Other.
- **Categories** — Food, Transport, Household, Utilities, Shopping, Health, Beauty, Entertainment, Other.
- **Repeats** — mark an expense Daily, Weekly or Monthly. Repeating entries appear under “Repeating expenses” with the next due date and a one-click **Log next occurrence** button.
- **Summary** — totals plus a per-category spending breakdown for whatever is shown.
- **INR amounts** — everything is shown in rupees (₹) with Indian digit grouping.

16
app.js
View File

@@ -1,4 +1,4 @@
/* Pin & Penny: daily / weekly / monthly views + repeating expenses.
/* Tally: daily / weekly / monthly views + repeating expenses.
Stored privately in localStorage; no network calls. */
"use strict";
@@ -7,10 +7,11 @@
var CATS = {
Food: "#9ed6a4",
Transport: "#a9c8f0",
Housing: "#eab88f",
Household: "#eab88f",
Utilities: "#8fd8c4",
Shopping: "#f5b98a",
Health: "#f2a3a3",
Beauty: "#dba9e8",
Entertainment: "#f2cd88",
Other: "#c9c9c9"
};
@@ -110,7 +111,14 @@ function load() {
return seed;
}
var arr = JSON.parse(raw);
return Array.isArray(arr) ? arr : [];
if (!Array.isArray(arr)) return [];
/* Migrate the Housing -> Household rename in stored entries. */
var changed = false;
arr.forEach(function (e) {
if (e && e.category === "Housing") { e.category = "Household"; changed = true; }
});
if (changed) { try { save(arr); } catch (err) { /* keep the in-memory list */ } }
return arr;
} catch (e) {
return [];
}
@@ -138,7 +146,7 @@ function seedSamples() {
mk("New shoes", 79.99, "Shopping", addDaysStr(t, -8)),
mk("Team lunch", 13.4, "Food", addDaysStr(t, -9), "weekly"),
mk("Internet", 59.99, "Utilities", addDaysStr(t, -12), "monthly"),
mk("Rent", 1200.0, "Housing", first, "monthly"),
mk("Rent", 1200.0, "Household", first, "monthly"),
mk("Concert ticket", 45.0, "Entertainment", addDaysStr(t, -20)),
mk("Groceries", 62.1, "Food", addDaysStr(t, -33))
];

View File

@@ -156,7 +156,7 @@ export default function App() {
<ScrollView ref={scrollRef} style={s.scroll} contentContainerStyle={s.container}>
<View style={s.header}>
<View style={{ flexDirection: "row", justifyContent: "space-between", alignItems: "center" }}>
<Text style={s.headerTitle}>Pin & Penny</Text>
<Text style={s.headerTitle}>Tally</Text>
<Pressable onPress={() => setMenuOpen(!menuOpen)} accessibilityLabel={menuOpen ? "Close menu" : "Open records menu"}>
<Text style={[s.headerTotal, { fontSize: 20 }]}>{menuOpen ? "\u2715" : "\u2630"}</Text>
</Pressable>

View File

@@ -1,4 +1,4 @@
# Pin & Penny — Expo app (web + mobile from one codebase)
# Tally — Expo app (web + mobile from one codebase)
React Native (Expo SDK 57) version of the expense tracker. The same code runs as a
website, an iOS app and an Android app. Data is stored on-device with AsyncStorage,
@@ -11,8 +11,8 @@ working as before; this folder is the future-proof rewrite.
- **Daily / Weekly / Monthly tabs** — the same expenses regrouped by day, by week
(MondaySunday) or by month, each group with its own total.
- **Categories** — Food, Transport, Housing, Utilities, Shopping, Health,
Entertainment, Other.
- **Categories** — Food, Transport, Household, Utilities, Shopping, Health,
Beauty, Entertainment, Other.
- **Repeats** — mark an expense Daily, Weekly or Monthly. They appear under
“Repeating expenses” with the next due date and a **Log next occurrence** button.
- **Summary** — totals plus a per-category spending breakdown of whatever is shown.

View File

@@ -1,6 +1,6 @@
{
"expo": {
"name": "Pin & Penny",
"name": "Tally",
"slug": "expense-tracker",
"version": "1.0.0",
"orientation": "portrait",

View File

@@ -3,10 +3,11 @@
export const CATEGORIES = [
{ name: "Food", color: "#9ed6a4" },
{ name: "Transport", color: "#a9c8f0" },
{ name: "Housing", color: "#eab88f" },
{ name: "Household", color: "#eab88f" },
{ name: "Utilities", color: "#8fd8c4" },
{ name: "Shopping", color: "#f5b98a" },
{ name: "Health", color: "#f2a3a3" },
{ name: "Beauty", color: "#dba9e8" },
{ name: "Entertainment", color: "#f2cd88" },
{ name: "Other", color: "#c9c9c9" },
];

View File

@@ -176,7 +176,7 @@ export function seedSamples() {
mk("New shoes", 79.99, "Shopping", addDaysStr(t, -8)),
mk("Team lunch", 13.4, "Food", addDaysStr(t, -9), "weekly"),
mk("Internet", 59.99, "Utilities", addDaysStr(t, -12), "monthly"),
mk("Rent", 1200.0, "Housing", first, "monthly"),
mk("Rent", 1200.0, "Household", first, "monthly"),
mk("Concert ticket", 45.0, "Entertainment", addDaysStr(t, -20)),
mk("Groceries", 62.1, "Food", addDaysStr(t, -33)),
];

View File

@@ -14,7 +14,14 @@ export async function loadExpenses() {
return seed;
}
const arr = JSON.parse(raw);
return Array.isArray(arr) ? arr : [];
if (!Array.isArray(arr)) return [];
// Migrate the Housing -> Household rename in stored entries.
let changed = false;
arr.forEach((e) => {
if (e && e.category === "Housing") { e.category = "Household"; changed = true; }
});
if (changed) await saveExpenses(arr);
return arr;
} catch (e) {
return [];
}

View File

@@ -3,7 +3,7 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pin &amp; Penny — Daily, Weekly, Monthly</title>
<title>Tally — Daily, Weekly, Monthly</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Petit+Formal+Script&family=Shadows+Into+Light+Two&family=Style+Script&family=Waterfall&display=swap" rel="stylesheet">
@@ -14,7 +14,7 @@
<button type="button" id="btnMenu" class="menu-btn" aria-label="Open menu" aria-expanded="false">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-dasharray="0.1 5" aria-hidden="true"><path d="M4 7h16M4 12h16M4 17h16"/></svg>
</button>
<span class="topbar-brand">Pin &amp; Penny</span>
<span class="topbar-brand">Tally</span>
<span class="topbar-month" id="topMonth">$0.00</span>
</header>
<div class="backdrop" id="backdrop" hidden></div>

View File

@@ -13,7 +13,7 @@ handler = functools.partial(
)
server = http.server.ThreadingHTTPServer((HOST, PORT), handler)
print(
"Pin & Penny running at http://%s:%d (open http://localhost:%d in your browser)"
"Tally running at http://%s:%d (open http://localhost:%d in your browser)"
% (HOST, PORT, PORT),
flush=True,
)