Skip to content

Commit

Permalink
add categories to standing orders
Browse files Browse the repository at this point in the history
  • Loading branch information
konstantin-lukas committed Sep 9, 2024
1 parent ceb9b85 commit 8cb6ae2
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 51 deletions.
6 changes: 3 additions & 3 deletions forge.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const config: ForgeConfig = {
iconUrl: 'file:///' + __dirname + '/src/img/favicon.ico',
description: "Oslo is a personal finance app for keeping track of your savings. You can set up standing orders, manage multiple accounts and view your expenses over different time spans.",
name: "oslo",
version: "3.1.0"
version: "3.2.0"
}, ['win32']),
new MakerRpm({
options: {
Expand All @@ -35,7 +35,7 @@ const config: ForgeConfig = {
license: "MIT",
name: "oslo",
productName: "Oslo",
version: "3.1.0"
version: "3.2.0"
}
}, ['linux']),
new MakerDeb({
Expand All @@ -47,7 +47,7 @@ const config: ForgeConfig = {
homepage: "https://github.com/konstantin-lukas/oslo",
name: "oslo",
productName: "Oslo",
version: "3.1.0"
version: "3.2.0"
}
}, ['linux'])
],
Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "oslo",
"productName": "Open Source Ledger Oslo",
"version": "3.1.0",
"version": "3.2.0",
"description": "Oslo is a personal finance app for keeping track of your savings. You can set up standing orders, manage multiple accounts and view your expenses over different time spans.",
"main": ".webpack/main",
"scripts": {
Expand All @@ -10,7 +10,7 @@
"package": "electron-forge package",
"make": "electron-forge make",
"build": "npm run package && npm run make",
"lint": "eslint --ext .ts,.tsx .",
"lint": "eslint --ext .ts,.tsx .",
"test": "jest"
},
"keywords": [],
Expand Down
1 change: 1 addition & 0 deletions src/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ declare type Transaction = {
declare type StandingOrder = {
id: number,
title: string,
category: string,
sum: string,
exec_interval: number,
exec_on: number,
Expand Down
18 changes: 15 additions & 3 deletions src/components/StandingOrder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export default function StandingOrder({data, currency, intervalLabels, intervalV
const text = useContext(TextContext);
const [amount, setAmount] = useState(data.sum);
const [name, setName] = useState(data.title);
const [category, setCategory] = useState(data.category);
const [execOn, setExecOn] = useState(data.exec_on);
const [execInterval, setExecInterval] = useState(data.exec_interval);

Expand All @@ -45,6 +46,15 @@ export default function StandingOrder({data, currency, intervalLabels, intervalV
<label><span className="label_name">{text.amount_} ({currency})</span>
<CurrencyInput value={amount} setValue={setAmount}/>
</label>
<label className="label_name">
<span className="label_name">{text.category_}</span>
<Input
value={category}
onInput={e => {
setCategory((e.target as HTMLInputElement).value);
}}
/>
</label>
<label className="dot">
<span className="label_name">{text.day_of_execution_}</span>
<Dropdown
Expand All @@ -65,10 +75,11 @@ export default function StandingOrder({data, currency, intervalLabels, intervalV
</label>
<div className="contain_two">
<Button altColors={theme.neutral_color === '#ffffff'} onClick={() => {
api.db.patchStandingOrder(data.id, name, amount, execInterval, execOn).then(() => {
api.db.patchStandingOrder(data.id, name, category, amount, execInterval, execOn).then(() => {
alertCtx(
text.changes_saved_,
() => {}
() => {
}
);
});
}}>{text.save_}</Button>
Expand All @@ -82,7 +93,8 @@ export default function StandingOrder({data, currency, intervalLabels, intervalV
});
})
},
() => {}
() => {
}
);
}}>{text.delete_}</Button>
</div>
Expand Down
84 changes: 51 additions & 33 deletions src/components/StandingOrders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export default function StandingOrders({closeStandingOrders, openAccount}: {
const [addOrderState, setAddOrderState] = useReducer(addOrderReducer, {
name: text.new_standing_order_,
amount: getZeroValue(currency.decimalPlaces),
category: text.new_standing_order_,
first_execution: new Date().toISOString().split('T')[0],
exec_interval: 1,
exec_on_last_of_month: false
Expand Down Expand Up @@ -133,7 +134,7 @@ export default function StandingOrders({closeStandingOrders, openAccount}: {
setIsUsingDefaultName(false);
}
}}
value={addOrderState.name}/>
value={addOrderState.name}/>
</label>
<label className="export_label" id="amount_label">
<span className="label_name">{text.amount_}</span>
Expand All @@ -142,6 +143,15 @@ export default function StandingOrders({closeStandingOrders, openAccount}: {
value={addOrderState.amount}
/>
</label>
<label className="export_label" id="category_label">
<span className="label_name">{text.category_}</span>
<Input
onInput={e => {
setAddOrderState({type: 'category', payload: (e.target as HTMLInputElement).value});
}}
value={addOrderState.category}
/>
</label>
<label className="export_label" id="exec_date_label">
<span className="label_name">{text.first_execution_}</span>
<Input
Expand All @@ -162,46 +172,51 @@ export default function StandingOrders({closeStandingOrders, openAccount}: {
</label>
<label className="export_label" id="exec_on_last">
<Checkbox
onChange={() => setAddOrderState({type: 'exec_on_last_of_month', payload: !addOrderState.exec_on_last_of_month})}
onChange={() => setAddOrderState({
type: 'exec_on_last_of_month',
payload: !addOrderState.exec_on_last_of_month
})}
checked={addOrderState.exec_on_last_of_month}
label={text.exec_on_last_day_of_month_}
/>
</label>
<Button
altColors={theme.neutral_color === '#ffffff'}
onClick={() => {
const first_exec = addOrderState.first_execution;
const exec_on = addOrderState.exec_on_last_of_month
? 31
: parseInt(first_exec.substring(8));
let first_exec_date = new Date(first_exec);
if (addOrderState.exec_on_last_of_month)
first_exec_date = setDate(first_exec_date, lastDayOfMonth(first_exec_date).getDate());
let last_exec = sub(first_exec_date, {
months: addOrderState.exec_interval
});
if (addOrderState.exec_on_last_of_month) {
last_exec = lastDayOfMonth(last_exec);
}
const first_exec = addOrderState.first_execution;
const exec_on = addOrderState.exec_on_last_of_month
? 31
: parseInt(first_exec.substring(8));
let first_exec_date = new Date(first_exec);
if (addOrderState.exec_on_last_of_month)
first_exec_date = setDate(first_exec_date, lastDayOfMonth(first_exec_date).getDate());
let last_exec = sub(first_exec_date, {
months: addOrderState.exec_interval
});
if (addOrderState.exec_on_last_of_month) {
last_exec = lastDayOfMonth(last_exec);
}
api.db.postStandingOrder(
openAccount.id,
addOrderState.name,
addOrderState.amount,
addOrderState.exec_interval,
exec_on,
formatISO(last_exec, {representation: 'date'})
).then(() => {
api.db.executeStandingOrders().then(() => {
api.db.getStandingOrders(openAccount.id).then(res => {
setStandingOrders(res);
alertCtx(
text.changes_saved_,
() => {}
);
openAccount.id,
addOrderState.name,
addOrderState.category,
addOrderState.amount,
addOrderState.exec_interval,
exec_on,
formatISO(last_exec, {representation: 'date'})
).then(() => {
api.db.executeStandingOrders().then(() => {
api.db.getStandingOrders(openAccount.id).then(res => {
setStandingOrders(res);
alertCtx(
text.changes_saved_,
() => {
}
);
});
fetchCtx();
});
fetchCtx();
});
});
}}>{text.create_}</Button>
</div>
<div id="manage_orders" className="theme_background">
Expand All @@ -211,12 +226,15 @@ export default function StandingOrders({closeStandingOrders, openAccount}: {
</div>
<div className={(datePickerOpen ? 'left_open' : '') + " dateTimePickerContainer"}>
<DatePicker
onChange={() => {}}
onChange={() => {
}}
onSelect={(pickedDate) => {
setAddOrderState({type: 'first_execution', payload: pickedDate});
setDatePickerOpen(false);
}}
onClickOutside={() => {setDatePickerOpen(false)}}
onClickOutside={() => {
setDatePickerOpen(false)
}}
minDate={new Date()}
locale={lang.code}
selected={new Date(addOrderState.first_execution)}
Expand Down
14 changes: 8 additions & 6 deletions src/ipcMain/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ export async function executeStandingOrders() {
} catch (e) {
json = null;
}
const category = json?.category_ || 'Category';
// EXECUTE STANDING ORDERS
const db = await openDB();
try {
Expand All @@ -115,7 +114,7 @@ export async function executeStandingOrders() {
order.sum,
order.account,
formatISO(nextExecution, {representation: 'date'}) + ' 00:00:00',
category
order.category
);
} else {
break;
Expand Down Expand Up @@ -317,13 +316,14 @@ export default function registerDatabase() {
return;
}
});
ipcMain.handle('postStandingOrder', async (_, account, title, sum, exec_interval, exec_on, last_exec) => {
ipcMain.handle('postStandingOrder', async (_, account, title, category, sum, exec_interval, exec_on, last_exec) => {
try {
const db = await openDB();
await db.run(
'INSERT INTO "standing_order" ("account", "title", "sum", "exec_interval", "exec_on", "last_exec") VALUES (?, ?, ?, ?, ?, ?);',
'INSERT INTO "standing_order" ("account", "title", "category", "sum", "exec_interval", "exec_on", "last_exec") VALUES (?, ?, ?, ?, ?, ?, ?);',
account,
title,
category,
sum,
exec_interval,
exec_on,
Expand All @@ -342,6 +342,7 @@ export default function registerDatabase() {
'SELECT ' +
'"id", ' +
'"title", ' +
'"category", ' +
'"sum", ' +
'"exec_interval", ' +
'"exec_on", ' +
Expand All @@ -364,17 +365,18 @@ export default function registerDatabase() {
return;
}
});
ipcMain.handle('patchStandingOrder', async (_, id, title, sum, exec_interval, exec_on) => {
ipcMain.handle('patchStandingOrder', async (_, id, title, category, sum, exec_interval, exec_on) => {
try {
const db = await openDB();
await db.run(
'UPDATE "standing_order" ' +
'SET "title" = ?, ' +
'"category" = ?, ' +
'"sum" = ?, ' +
'"exec_interval" = ?, ' +
'"exec_on" = ? ' +
'WHERE "id" = ?;',
title, sum, exec_interval, exec_on, id
title, category, sum, exec_interval, exec_on, id
);
await db.close();
return
Expand Down
8 changes: 4 additions & 4 deletions src/ipcRenderer/database.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,17 +45,17 @@ const database = {
patchAccount: async (id: number, name: string, color: string, allow_overdrawing: boolean, interest_rate: number) => {
return await ipcRenderer.invoke('patchAccount', id, name, color, allow_overdrawing, interest_rate);
},
postStandingOrder: async (account: number, title: string, sum: string, exec_interval: number, exec_on: number, last_exec: string) => {
return await ipcRenderer.invoke('postStandingOrder', account, title, sum, exec_interval, exec_on, last_exec);
postStandingOrder: async (account: number, title: string, category: string, sum: string, exec_interval: number, exec_on: number, last_exec: string) => {
return await ipcRenderer.invoke('postStandingOrder', account, title, category, sum, exec_interval, exec_on, last_exec);
},
getStandingOrders: async (account: number) => {
return await ipcRenderer.invoke('getStandingOrders', account);
},
deleteStandingOrder: async (id: number) => {
return await ipcRenderer.invoke('deleteStandingOrder', id);
},
patchStandingOrder: async (id: number, title: string, sum: string, exec_interval: number, exec_on: number) => {
return await ipcRenderer.invoke('patchStandingOrder', id, title, sum, exec_interval, exec_on);
patchStandingOrder: async (id: number, title: string, category: string, sum: string, exec_interval: number, exec_on: number) => {
return await ipcRenderer.invoke('patchStandingOrder', id, title, category, sum, exec_interval, exec_on);
},
executeStandingOrders: async () => {
return await ipcRenderer.invoke('executeStandingOrders');
Expand Down
5 changes: 5 additions & 0 deletions src/migrations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ const migrations: {
await db.exec('drop table "transaction";');
await db.exec('alter table transaction_dg_tmp rename to "transaction";');
}
}, {
version: "3.2.0",
exec: async (db) => {
await db.exec('ALTER TABLE standing_order ADD category TEXT default \'\' NOT NULL;');
}
}];

export default async function createDatabase() {
Expand Down

0 comments on commit 8cb6ae2

Please sign in to comment.