Rename to Tally; add Beauty category, Housing -> Household
This commit is contained in:
@@ -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
16
app.js
@@ -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))
|
||||
];
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
|
||||
(Monday–Sunday) 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"expo": {
|
||||
"name": "Pin & Penny",
|
||||
"name": "Tally",
|
||||
"slug": "expense-tracker",
|
||||
"version": "1.0.0",
|
||||
"orientation": "portrait",
|
||||
|
||||
@@ -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" },
|
||||
];
|
||||
|
||||
@@ -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)),
|
||||
];
|
||||
|
||||
@@ -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 [];
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Pin & 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 & 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>
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user