From 28899ea0a93532fa71851613c21fdf86635c8dc6 Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Sun, 30 Jul 2023 10:25:32 -0500 Subject: [PATCH 01/49] first pass at progress bar --- .../budget/rollover/rollover-components.tsx | 343 ++++++++++-------- 1 file changed, 182 insertions(+), 161 deletions(-) diff --git a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx index 7f9c192f9a1..e514ff7c317 100644 --- a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx +++ b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx @@ -330,184 +330,205 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({ setHover(true)} - onMouseLeave={() => { - setHover(false); + '& .hover-visible': { + opacity: 0, + transition: 'opacity .25s', + }, + '&:hover .hover-visible': { + opacity: 1, + }, }} > - {!editing && (hover || menuOpen) ? ( - - - {menuOpen && ( - setMenuOpen(false)} + + {menuOpen && ( + setMenuOpen(false)} + > + { + onBudgetAction(monthIndex, type, { + category: category.id, + }); + setMenuOpen(false); + }} + items={[ + { + name: 'copy-single-last', + text: 'Copy last month’s budget', + }, + { + name: 'set-single-3-avg', + text: 'Set to 3 month average', + }, + { + name: 'set-single-6-avg', + text: 'Set to 6 month average', + }, + { + name: 'set-single-12-avg', + text: 'Set to yearly average', + }, + isGoalTemplatesEnabled && { + name: 'apply-single-category-template', + text: 'Apply budget template', + }, + ]} + /> + + )} + + ) : null} + onEdit(category.id, monthIndex)} + style={[editing && { zIndex: 100 }, styles.tnum]} + textAlign="right" + valueStyle={[ + { + cursor: 'default', + margin: 1, + padding: '0 4px', + borderRadius: 4, }, - }, - ]} - valueProps={{ - binding: rolloverBudget.catBudgeted(category.id), - type: 'financial', - getValueStyle: makeAmountGrey, - formatExpr: expr => { - return integerToCurrency(expr); - }, - unformatExpr: expr => { - return amountToInteger(evalArithmetic(expr, 0)); - }, - }} - inputProps={{ - onBlur: () => { - onEdit(null); - }, - }} - onSave={amount => { - onBudgetAction(monthIndex, 'budget-amount', { - category: category.id, - amount, - }); - }} - /> - - - onShowActivity(category.name, category.id, monthIndex)} - > - { + return integerToCurrency(expr); + }, + unformatExpr: expr => { + return amountToInteger(evalArithmetic(expr, 0)); + }, + }} + inputProps={{ + onBlur: () => { + onEdit(null); + }, + }} + onSave={amount => { + onBudgetAction(monthIndex, 'budget-amount', { + category: category.id, + amount, + }); }} /> - - - + + + onShowActivity(category.name, category.id, monthIndex) + } + > + + + + + + + + {balanceTooltip.isOpen && ( + + )} + + + - - - - {balanceTooltip.isOpen && ( - - )} - + + {' '} + + ); }); From 8622b77404fb6159005bde23fd859a46f91085fa Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Mon, 31 Jul 2023 21:50:32 -0500 Subject: [PATCH 02/49] db migration / enter goal in db --- .../1688941238000_add_goal_targets.sql | 5 ++ .../loot-core/src/server/budget/actions.ts | 17 ++++ .../src/server/budget/goaltemplates.ts | 81 +++++++++++++++---- 3 files changed, 87 insertions(+), 16 deletions(-) create mode 100644 packages/loot-core/migrations/1688941238000_add_goal_targets.sql diff --git a/packages/loot-core/migrations/1688941238000_add_goal_targets.sql b/packages/loot-core/migrations/1688941238000_add_goal_targets.sql new file mode 100644 index 00000000000..1f868b9524d --- /dev/null +++ b/packages/loot-core/migrations/1688941238000_add_goal_targets.sql @@ -0,0 +1,5 @@ +BEGIN TRANSACTION; + +ALTER TABLE zero_budgets ADD column goal INTEGER DEFAULT 0; + +COMMIT; diff --git a/packages/loot-core/src/server/budget/actions.ts b/packages/loot-core/src/server/budget/actions.ts index 0dd5a735b94..178c60b21d9 100644 --- a/packages/loot-core/src/server/budget/actions.ts +++ b/packages/loot-core/src/server/budget/actions.ts @@ -85,6 +85,23 @@ export function setBudget({ category, month, amount }) { }); } +export function setGoal({ month, category, goal }) { + let existing = db.firstSync( + `SELECT id FROM zero_budgets WHERE month = ? AND category = ?`, + [dbMonth(month), category], + ); + if (existing) { + return db.update('zero_budgets', { + id: existing.id, + goal: goal, + }); + } + return db.insert('zero_budgets', { + id: month, + goal: goal, + }); +} + export function setBuffer(month, amount) { let existing = db.firstSync( `SELECT id FROM zero_budget_months WHERE id = ?`, diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index 6ed7cd47c84..84950983405 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -9,7 +9,13 @@ import * as db from '../db'; import { getRuleForSchedule, getNextDate } from '../schedules/app'; import { batchMessages } from '../sync'; -import { setBudget, setZero, getSheetValue, isReflectBudget } from './actions'; +import { + setBudget, + setZero, + getSheetValue, + isReflectBudget, + setGoal, +} from './actions'; import { parse } from './goal-template.pegjs'; export async function applyTemplate({ month }) { @@ -63,12 +69,24 @@ async function setGoalBudget({ month, templateBudget }) { }); } +async function setCategoryTargets({ month, idealTemplate }) { + await batchMessages(async () => { + idealTemplate.forEach(element => { + setGoal({ + category: element.category, + goal: element.amount, + month: month, + }); + }); + }); +} + async function processTemplate(month, force, category_templates) { - let templateBudget = []; let num_applied = 0; let errors = []; let lowestPriority = 0; let originalCategoryBalance = []; + let idealTemplate = []; let categories = await db.all( 'SELECT * FROM v_categories WHERE tombstone = 0', @@ -140,6 +158,7 @@ async function processTemplate(month, force, category_templates) { ? await getSheetValue(sheetName, `total-saved`) : await getSheetValue(sheetName, `to-budget`); for (let priority = 0; priority <= lowestPriority; priority++) { + let templateBudget = []; // setup scaling for remainder let remainder_scale = 1; if (priority === lowestPriority) { @@ -195,24 +214,39 @@ async function processTemplate(month, force, category_templates) { sheetName, `budget-${category.id}`, ); - let { amount: to_budget, errors: applyErrors } = - await applyCategoryTemplate( - category, - template, - month, - priority, - remainder_scale, - available_start, - available_remaining, - prev_budgeted, - force, - ); + let { + amount: to_budget, + errors: applyErrors, + idealTarget, + } = await applyCategoryTemplate( + category, + template, + month, + priority, + remainder_scale, + available_start, + available_remaining, + prev_budgeted, + force, + ); if (to_budget != null) { num_applied++; templateBudget.push({ category: category.id, amount: to_budget + prev_budgeted, }); + if ( + idealTemplate.filter(c => c.category === category.id).length > 0 + ) { + idealTemplate.filter( + c => c.category === category.id, + )[0].amount += idealTarget; + } else { + idealTemplate.push({ + category: category.id, + amount: idealTarget, + }); + } available_remaining -= to_budget; } if (applyErrors != null) { @@ -226,7 +260,7 @@ async function processTemplate(month, force, category_templates) { } await setGoalBudget({ month, templateBudget }); } - + await setCategoryTargets({ month, idealTemplate }); if (!force) { //if overwrite is not preferred, set cell to original value for (let l = 0; l < originalCategoryBalance.length; l++) { @@ -388,6 +422,7 @@ async function applyCategoryTemplate( let to_budget = 0; let limit; let hold; + let idealTarget; let last_month_balance = balance - spent - budgeted; let remainder = 0; for (let l = 0; l < template_lines.length; l++) { @@ -413,7 +448,9 @@ async function applyCategoryTemplate( } if (increment < budgetAvailable || !priority) { to_budget += increment; + idealTarget = to_budget; } else { + idealTarget = to_budget + increment; if (budgetAvailable > 0) to_budget += budgetAvailable; errors.push(`Insufficient funds.`); } @@ -453,7 +490,9 @@ async function applyCategoryTemplate( if (diff >= 0) { if (to_budget + diff < budgetAvailable || !priority) { to_budget += diff; + idealTarget = to_budget; } else { + idealTarget = to_budget + diff; if (budgetAvailable > 0) to_budget += budgetAvailable; errors.push(`Insufficient funds.`); } @@ -483,7 +522,9 @@ async function applyCategoryTemplate( if (w >= current_month) { if (to_budget + amount < budgetAvailable || !priority) { to_budget += amount; + idealTarget = to_budget; } else { + idealTarget = to_budget + budgetAvailable; if (budgetAvailable > 0) to_budget += budgetAvailable; errors.push(`Insufficient funds.`); } @@ -545,7 +586,9 @@ async function applyCategoryTemplate( } if (increment < budgetAvailable || !priority) { to_budget = increment; + idealTarget = to_budget; } else { + idealTarget = increment; if (budgetAvailable > 0) to_budget = budgetAvailable; errors.push(`Insufficient funds.`); } @@ -601,7 +644,9 @@ async function applyCategoryTemplate( ); if (increment < budgetAvailable || !priority) { to_budget = increment; + idealTarget = to_budget; } else { + idealTarget = increment; if (budgetAvailable > 0) to_budget = budgetAvailable; errors.push(`Insufficient funds.`); } @@ -682,7 +727,9 @@ async function applyCategoryTemplate( ) { to_budget += diff; if (l === template_lines.length - 1) to_budget -= spent; + idealTarget = to_budget; } else { + idealTarget = to_budget + diff; if (budgetAvailable > 0) to_budget = budgetAvailable; errors.push(`Insufficient funds.`); } @@ -698,9 +745,11 @@ async function applyCategoryTemplate( // can over budget with the rounding, so checking that if (to_budget >= budgetAvailable) { to_budget = budgetAvailable; + idealTarget = to_budget; // check if there is 1 cent leftover from rounding } else if (budgetAvailable - to_budget === 1) { to_budget = to_budget + 1; + idealTarget = budgetAvailable; } } break; @@ -735,7 +784,7 @@ async function applyCategoryTemplate( integerToAmount(last_month_balance + to_budget); str += ' ' + template_lines.map(x => x.line).join('\n'); console.log(str); - return { amount: to_budget, errors }; + return { amount: to_budget, errors, idealTarget: idealTarget }; } } From cad101c72b73b8e27bc79c9bffbdcb20d41ee63e Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Mon, 31 Jul 2023 22:12:34 -0500 Subject: [PATCH 03/49] add getGoal function --- .../components/budget/rollover/rollover-components.tsx | 7 ++++++- packages/loot-core/src/server/budget/actions.ts | 9 +++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx index e514ff7c317..7c68a2b4c8f 100644 --- a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx +++ b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx @@ -1,6 +1,7 @@ import React, { type ComponentProps, memo, useContext, useState } from 'react'; import { rolloverBudget } from 'loot-core/src/client/queries'; +import { getGoal } from 'loot-core/src/server/budget/actions'; import evalArithmetic from 'loot-core/src/shared/arithmetic'; import { integerToCurrency, amountToInteger } from 'loot-core/src/shared/util'; @@ -326,6 +327,10 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({ const [hover, setHover] = useState(false); const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled'); + getGoal({ category, monthIndex }); + + //const percentProgress = Math.round((amount * 100) / goal); + const percentProgress = 50; return ( - + {' '} diff --git a/packages/loot-core/src/server/budget/actions.ts b/packages/loot-core/src/server/budget/actions.ts index 178c60b21d9..11ddccb672f 100644 --- a/packages/loot-core/src/server/budget/actions.ts +++ b/packages/loot-core/src/server/budget/actions.ts @@ -66,6 +66,15 @@ export function getBudget({ category, month }) { return existing ? existing.amount || 0 : 0; } +export function getGoal({ category, month }) { + let table = getBudgetTable(); + let existing = db.firstSync( + `SELECT * FROM ${table} WHERE month = ? AND category = ?`, + [dbMonth(month), category], + ); + return { goal: existing.goal, amount: existing.amount }; +} + export function setBudget({ category, month, amount }) { amount = safeNumber(typeof amount === 'number' ? amount : 0); const table = getBudgetTable(); From f1a9aebae7daaab2b97939a6bfbffcd6361bbdc3 Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Tue, 1 Aug 2023 05:38:07 -0500 Subject: [PATCH 04/49] stabilize --- .../budget/rollover/rollover-components.tsx | 351 ++++++++---------- .../loot-core/src/server/budget/actions.ts | 9 - 2 files changed, 163 insertions(+), 197 deletions(-) diff --git a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx index 7c68a2b4c8f..e4fbcb884d9 100644 --- a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx +++ b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx @@ -1,7 +1,6 @@ import React, { type ComponentProps, memo, useContext, useState } from 'react'; import { rolloverBudget } from 'loot-core/src/client/queries'; -import { getGoal } from 'loot-core/src/server/budget/actions'; import evalArithmetic from 'loot-core/src/shared/arithmetic'; import { integerToCurrency, amountToInteger } from 'loot-core/src/shared/util'; @@ -326,214 +325,190 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({ const [menuOpen, setMenuOpen] = useState(false); const [hover, setHover] = useState(false); const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled'); - - getGoal({ category, monthIndex }); - - //const percentProgress = Math.round((amount * 100) / goal); - const percentProgress = 50; return ( setHover(true)} + onMouseLeave={() => { + setHover(false); }} > - setHover(true)} - onMouseLeave={() => { - setHover(false); - }} - > - {!editing && (hover || menuOpen) ? ( - + + {menuOpen && ( + setMenuOpen(false)} > - { + onBudgetAction(monthIndex, type, { + category: category.id, + }); + setMenuOpen(false); + }} + items={[ + { + name: 'copy-single-last', + text: 'Copy last month’s budget', + }, + { + name: 'set-single-3-avg', + text: 'Set to 3 month average', + }, + { + name: 'set-single-6-avg', + text: 'Set to 6 month average', + }, + { + name: 'set-single-12-avg', + text: 'Set to yearly average', + }, + isGoalTemplatesEnabled && { + name: 'apply-single-category-template', + text: 'Apply budget template', + }, + ]} /> - - {menuOpen && ( - setMenuOpen(false)} - > - { - onBudgetAction(monthIndex, type, { - category: category.id, - }); - setMenuOpen(false); - }} - items={[ - { - name: 'copy-single-last', - text: 'Copy last month’s budget', - }, - { - name: 'set-single-3-avg', - text: 'Set to 3 month average', - }, - { - name: 'set-single-6-avg', - text: 'Set to 6 month average', - }, - { - name: 'set-single-12-avg', - text: 'Set to yearly average', - }, - isGoalTemplatesEnabled && { - name: 'apply-single-category-template', - text: 'Apply budget template', - }, - ]} - /> - - )} - - ) : null} - onEdit(category.id, monthIndex)} - style={[editing && { zIndex: 100 }, styles.tnum]} - textAlign="right" - valueStyle={[ - { - cursor: 'default', - margin: 1, - padding: '0 4px', - borderRadius: 4, - }, - { - ':hover': { - boxShadow: 'inset 0 0 0 1px ' + colors.n7, - backgroundColor: 'white', - }, - }, - ]} - valueProps={{ - binding: rolloverBudget.catBudgeted(category.id), - type: 'financial', - getValueStyle: makeAmountGrey, - formatExpr: expr => { - return integerToCurrency(expr); - }, - unformatExpr: expr => { - return amountToInteger(evalArithmetic(expr, 0)); - }, - }} - inputProps={{ - onBlur: () => { - onEdit(null); + + )} + + ) : null} + onEdit(category.id, monthIndex)} + style={[editing && { zIndex: 100 }, styles.tnum]} + textAlign="right" + valueStyle={[ + { + cursor: 'default', + margin: 1, + padding: '0 4px', + borderRadius: 4, + }, + { + ':hover': { + boxShadow: 'inset 0 0 0 1px ' + colors.n7, + backgroundColor: 'white', }, - }} - onSave={amount => { - onBudgetAction(monthIndex, 'budget-amount', { - category: category.id, - amount, - }); + }, + ]} + valueProps={{ + binding: rolloverBudget.catBudgeted(category.id), + type: 'financial', + getValueStyle: makeAmountGrey, + formatExpr: expr => { + return integerToCurrency(expr); + }, + unformatExpr: expr => { + return amountToInteger(evalArithmetic(expr, 0)); + }, + }} + inputProps={{ + onBlur: () => { + onEdit(null); + }, + }} + onSave={amount => { + onBudgetAction(monthIndex, 'budget-amount', { + category: category.id, + amount, + }); + }} + /> + + + onShowActivity(category.name, category.id, monthIndex)} + > + - - - - onShowActivity(category.name, category.id, monthIndex) - } - > - - - - - - - - {balanceTooltip.isOpen && ( - - )} - - - + + - - {' '} - - + + + + {balanceTooltip.isOpen && ( + + )} + ); }); diff --git a/packages/loot-core/src/server/budget/actions.ts b/packages/loot-core/src/server/budget/actions.ts index 11ddccb672f..178c60b21d9 100644 --- a/packages/loot-core/src/server/budget/actions.ts +++ b/packages/loot-core/src/server/budget/actions.ts @@ -66,15 +66,6 @@ export function getBudget({ category, month }) { return existing ? existing.amount || 0 : 0; } -export function getGoal({ category, month }) { - let table = getBudgetTable(); - let existing = db.firstSync( - `SELECT * FROM ${table} WHERE month = ? AND category = ?`, - [dbMonth(month), category], - ); - return { goal: existing.goal, amount: existing.amount }; -} - export function setBudget({ category, month, amount }) { amount = safeNumber(typeof amount === 'number' ? amount : 0); const table = getBudgetTable(); From 2c8c5a6cfc4e084008958debc80103cadfa7e587 Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Tue, 1 Aug 2023 06:06:10 -0500 Subject: [PATCH 05/49] whoops --- packages/loot-core/src/server/budget/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/loot-core/src/server/budget/actions.ts b/packages/loot-core/src/server/budget/actions.ts index 1e23c3b6b92..800e6faf00e 100644 --- a/packages/loot-core/src/server/budget/actions.ts +++ b/packages/loot-core/src/server/budget/actions.ts @@ -130,7 +130,7 @@ export function setGoal({ month, category, goal }) { }); } -export function setBuffer(month, amount) { +export function setBuffer(month: string, amount: unknown): Promise { let existing = db.firstSync( `SELECT id FROM zero_budget_months WHERE id = ?`, [month], From 756e73f2e25516e667bd23646563de5106389dda Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Tue, 1 Aug 2023 06:11:36 -0500 Subject: [PATCH 06/49] TS --- packages/loot-core/src/server/budget/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/loot-core/src/server/budget/actions.ts b/packages/loot-core/src/server/budget/actions.ts index 800e6faf00e..60664879b26 100644 --- a/packages/loot-core/src/server/budget/actions.ts +++ b/packages/loot-core/src/server/budget/actions.ts @@ -113,7 +113,7 @@ export function setBudget({ }); } -export function setGoal({ month, category, goal }) { +export function setGoal({ month, category, goal }): Promise { let existing = db.firstSync( `SELECT id FROM zero_budgets WHERE month = ? AND category = ?`, [dbMonth(month), category], From 66fc6a625df8fa649d12e2366d8c4ca125d7b338 Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Tue, 1 Aug 2023 08:01:02 -0500 Subject: [PATCH 07/49] reset goal in db if no template found --- .../loot-core/src/server/budget/goaltemplates.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index 84950983405..3276e012100 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -70,6 +70,18 @@ async function setGoalBudget({ month, templateBudget }) { } async function setCategoryTargets({ month, idealTemplate }) { + let categories = await db.all('SELECT * FROM zero_budgets WHERE month = ?', [ + parseInt(month.replace('-', '')), + ]); + + //clear set values + for (let cat of categories) { + await setGoal({ + category: cat.category, + goal: 0, + month: month, + }); + } await batchMessages(async () => { idealTemplate.forEach(element => { setGoal({ From 19064b8e21322596677b5899023ec81da25c109b Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:43:00 -0500 Subject: [PATCH 08/49] reconfirm --- .../src/server/budget/goaltemplates.ts | 39 +++++++------------ .../src/server/budget/types/handlers.d.ts | 8 ++-- 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index 3c112a3b857..a1c61cd1ee6 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -61,18 +61,6 @@ async function setGoalBudget({ month, templateBudget }) { } async function setCategoryTargets({ month, idealTemplate }) { - let categories = await db.all('SELECT * FROM zero_budgets WHERE month = ?', [ - parseInt(month.replace('-', '')), - ]); - - //clear set values - for (let cat of categories) { - await setGoal({ - category: cat.category, - goal: 0, - month: month, - }); - } await batchMessages(async () => { idealTemplate.forEach(element => { setGoal({ @@ -84,7 +72,11 @@ async function setCategoryTargets({ month, idealTemplate }) { }); } -async function processTemplate(month, force, category_templates) { +async function processTemplate( + month, + force, + category_templates, +): Promise { let num_applied = 0; let errors = []; let lowestPriority = 0; @@ -447,7 +439,7 @@ async function applyCategoryTemplate( let to_budget = 0; let limit; let hold; - let idealTarget; + let idealTarget = 0; let last_month_balance = balance - spent - budgeted; let remainder = 0; for (let l = 0; l < template_lines.length; l++) { @@ -473,12 +465,11 @@ async function applyCategoryTemplate( } if (to_budget + increment < budgetAvailable || !priority) { to_budget += increment; - idealTarget = to_budget; } else { - idealTarget = to_budget + increment; if (budgetAvailable > 0) to_budget += budgetAvailable; errors.push(`Insufficient funds.`); } + idealTarget += increment; break; } case 'by': { @@ -515,13 +506,12 @@ async function applyCategoryTemplate( if (diff >= 0) { if (to_budget + diff < budgetAvailable || !priority) { to_budget += diff; - idealTarget = to_budget; } else { - idealTarget = to_budget + diff; if (budgetAvailable > 0) to_budget += budgetAvailable; errors.push(`Insufficient funds.`); } } + idealTarget += diff; } else { errors.push(`by templates are not supported in Report budgets`); } @@ -547,15 +537,15 @@ async function applyCategoryTemplate( if (w >= current_month) { if (to_budget + amount < budgetAvailable || !priority) { to_budget += amount; - idealTarget = to_budget; } else { - idealTarget = to_budget + budgetAvailable; if (budgetAvailable > 0) to_budget += budgetAvailable; errors.push(`Insufficient funds.`); } + idealTarget += amount; } w = monthUtils.addWeeks(w, weeks); } + break; } case 'spend': { @@ -611,12 +601,11 @@ async function applyCategoryTemplate( } if (increment < budgetAvailable || !priority) { to_budget = increment; - idealTarget = to_budget; } else { - idealTarget = increment; if (budgetAvailable > 0) to_budget = budgetAvailable; errors.push(`Insufficient funds.`); } + idealTarget = increment; break; } case 'percentage': { @@ -670,10 +659,10 @@ async function applyCategoryTemplate( if (increment + to_budget <= budgetAvailable || !priority) { to_budget += increment; } else { - idealTarget = increment; if (budgetAvailable > 0) to_budget = budgetAvailable; errors.push(`Insufficient funds.`); } + idealTarget += increment; break; } case 'schedule': { @@ -832,6 +821,7 @@ async function applyCategoryTemplate( to_budget = budgetAvailable; errors.push(`Insufficient funds.`); } + idealTarget += diff; } break; } @@ -844,12 +834,11 @@ async function applyCategoryTemplate( // can over budget with the rounding, so checking that if (to_budget >= budgetAvailable) { to_budget = budgetAvailable; - idealTarget = to_budget; // check if there is 1 cent leftover from rounding } else if (budgetAvailable - to_budget === 1) { to_budget = to_budget + 1; - idealTarget = budgetAvailable; } + idealTarget = to_budget; } break; } diff --git a/packages/loot-core/src/server/budget/types/handlers.d.ts b/packages/loot-core/src/server/budget/types/handlers.d.ts index 3c44a0a4ba3..bb3f6964080 100644 --- a/packages/loot-core/src/server/budget/types/handlers.d.ts +++ b/packages/loot-core/src/server/budget/types/handlers.d.ts @@ -15,11 +15,13 @@ export interface BudgetHandlers { 'budget/check-templates': () => Promise; - 'budget/apply-goal-template': (arg: { month: string }) => Promise; + 'budget/apply-goal-template': (arg: { + month: string; + }) => Promise; 'budget/overwrite-goal-template': (arg: { month: string; - }) => Promise; + }) => Promise; 'budget/cleanup-goal-template': (arg: { month: string; @@ -40,7 +42,7 @@ export interface BudgetHandlers { 'budget/apply-single-template': (arg: { month: string; category: string; //category id - }) => Promise; + }) => Promise; 'budget/set-n-month-avg': (arg: { month: string; From 58aa791221cc58d47b607e4cf88f9e2da7743e45 Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:53:25 -0500 Subject: [PATCH 09/49] release note --- upcoming-release-notes/1682.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 upcoming-release-notes/1682.md diff --git a/upcoming-release-notes/1682.md b/upcoming-release-notes/1682.md new file mode 100644 index 00000000000..0c34178f1a4 --- /dev/null +++ b/upcoming-release-notes/1682.md @@ -0,0 +1,6 @@ +--- +category: Enhancement +authors: [shall0pass] +--- + +Goals: Add database entry for ideal monthly target From fd423a93ffce267cd39a2cbb8356df68fae3589b Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Sun, 10 Sep 2023 20:54:13 -0500 Subject: [PATCH 10/49] typo --- upcoming-release-notes/1682.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/upcoming-release-notes/1682.md b/upcoming-release-notes/1682.md index 0c34178f1a4..dc76a840e8a 100644 --- a/upcoming-release-notes/1682.md +++ b/upcoming-release-notes/1682.md @@ -1,5 +1,5 @@ --- -category: Enhancement +category: Enhancements authors: [shall0pass] --- From 425a6ca7dade9042db49c57ada809fe017cb34a5 Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Mon, 11 Sep 2023 08:24:10 -0500 Subject: [PATCH 11/49] rename migration --- .../src/components/budget/rollover/rollover-components.tsx | 1 + ...8000_add_goal_targets.sql => 1694438606_add_goal_targets.sql} | 0 2 files changed, 1 insertion(+) rename packages/loot-core/migrations/{1688941238000_add_goal_targets.sql => 1694438606_add_goal_targets.sql} (100%) diff --git a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx index 8ac22528ff3..3549fcf20f5 100644 --- a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx +++ b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx @@ -320,6 +320,7 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({ const [menuOpen, setMenuOpen] = useState(false); const [hover, setHover] = useState(false); const isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled'); + return ( Date: Mon, 11 Sep 2023 08:26:54 -0500 Subject: [PATCH 12/49] to ms --- ...06_add_goal_targets.sql => 1694438752000_add_goal_targets.sql} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/loot-core/migrations/{1694438606_add_goal_targets.sql => 1694438752000_add_goal_targets.sql} (100%) diff --git a/packages/loot-core/migrations/1694438606_add_goal_targets.sql b/packages/loot-core/migrations/1694438752000_add_goal_targets.sql similarity index 100% rename from packages/loot-core/migrations/1694438606_add_goal_targets.sql rename to packages/loot-core/migrations/1694438752000_add_goal_targets.sql From b00fc8e94251cf6240e7f09934a3311f3b65ac6b Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Mon, 11 Sep 2023 14:49:39 -0500 Subject: [PATCH 13/49] move priority logic, consistent variable names, --- .../budget/rollover/rollover-components.tsx | 4 +- .../src/server/budget/goaltemplates.ts | 165 +++++++----------- 2 files changed, 67 insertions(+), 102 deletions(-) diff --git a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx index 3549fcf20f5..298a1837af6 100644 --- a/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx +++ b/packages/desktop-client/src/components/budget/rollover/rollover-components.tsx @@ -380,9 +380,7 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({ > { - onBudgetAction(monthIndex, type, { - category: category.id, - }); + onBudgetAction(monthIndex, type, { category: category.id }); setMenuOpen(false); }} items={[ diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index a1c61cd1ee6..61945ab6efe 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -148,7 +148,7 @@ async function processTemplate( let sheetName = monthUtils.sheetForMonth(month); let available_start = await getSheetValue(sheetName, `to-budget`); - let available_remaining = isReflectBudget() + let budgetAvailable = isReflectBudget() ? await getSheetValue(sheetName, `total-saved`) : await getSheetValue(sheetName, `to-budget`); for (let priority = 0; priority <= lowestPriority; priority++) { @@ -162,20 +162,20 @@ async function processTemplate( for (let c = 0; c < categories.length; c++) { let category = categories[c]; - let template = category_templates[category.id]; - if (template) { + let template_lines = category_templates[category.id]; + if (template_lines) { //check that all schedule and by lines have the same priority level let skipSchedule = false; let isScheduleOrBy = false; let priorityCheck = 0; if ( - template.filter( + template_lines.filter( t => (t.type === 'schedule' || t.type === 'by') && t.priority === priority, ).length > 0 ) { - template = template.filter( + template_lines = template_lines.filter( t => (t.priority === priority && (t.type !== 'schedule' || t.type !== 'by')) || @@ -183,7 +183,7 @@ async function processTemplate( t.type === 'by', ); let { lowPriority, errorNotice } = await checkScheduleTemplates( - template, + template_lines, ); priorityCheck = lowPriority; skipSchedule = priorityCheck !== priority ? true : false; @@ -198,11 +198,13 @@ async function processTemplate( } if (!skipSchedule) { if (!isScheduleOrBy) { - template = template.filter(t => t.priority === priority); + template_lines = template_lines.filter( + t => t.priority === priority, + ); } - if (template.length > 0) { + if (template_lines.length > 0) { errors = errors.concat( - template + template_lines .filter(t => t.type === 'error') .map(({ line, error }) => [ @@ -218,40 +220,48 @@ async function processTemplate( sheetName, `budget-${category.id}`, ); - let { - amount: to_budget, - errors: applyErrors, - idealTarget, - } = await applyCategoryTemplate( - category, - template, - month, - priority, - remainder_scale, - available_start, - available_remaining, - prev_budgeted, - force, - ); + let { amount: to_budget, errors: applyErrors } = + await applyCategoryTemplate( + category, + template_lines, + month, + remainder_scale, + available_start, + budgetAvailable, + prev_budgeted, + force, + ); if (to_budget != null) { num_applied++; - templateBudget.push({ - category: category.id, - amount: to_budget + prev_budgeted, - }); if ( idealTemplate.filter(c => c.category === category.id).length > 0 ) { idealTemplate.filter( c => c.category === category.id, - )[0].amount += idealTarget; + )[0].amount += to_budget; } else { idealTemplate.push({ category: category.id, - amount: idealTarget, + amount: to_budget, }); + if (to_budget <= budgetAvailable || !priority) { + templateBudget.push({ + category: category.id, + amount: to_budget + prev_budgeted, + }); + } else if ( + to_budget > budgetAvailable && + budgetAvailable >= 0 + ) { + to_budget = budgetAvailable; + errors.push(`Insufficient funds.`); + templateBudget.push({ + category: category.id, + amount: to_budget + prev_budgeted, + }); + } } - available_remaining -= to_budget; + budgetAvailable -= to_budget; } if (applyErrors != null) { errors = errors.concat( @@ -292,7 +302,6 @@ async function processTemplate( } } } - if (num_applied === 0) { if (errors.length) { return { @@ -355,11 +364,10 @@ async function applyCategoryTemplate( category, template_lines, month, - priority, remainder_scale, available_start, budgetAvailable, - budgeted, + prev_budgeted, force, ) { let current_month = `${month}-01`; @@ -437,10 +445,10 @@ async function applyCategoryTemplate( let spent = await getSheetValue(sheetName, `sum-amount-${category.id}`); let balance = await getSheetValue(sheetName, `leftover-${category.id}`); let to_budget = 0; - let limit; - let hold; - let idealTarget = 0; - let last_month_balance = balance - spent - budgeted; + let limit = 0; + let hold = false; + let limitCheck = false; + let last_month_balance = balance - spent - prev_budgeted; let remainder = 0; for (let l = 0; l < template_lines.length; l++) { let template = template_lines[l]; @@ -448,10 +456,11 @@ async function applyCategoryTemplate( case 'simple': { // simple has 'monthly' and/or 'limit' params if (template.limit != null) { - if (limit != null) { + if (limitCheck) { errors.push(`More than one “up to” limit found.`); return { errors }; } else { + limitCheck = true; limit = amountToInteger(template.limit.amount); hold = template.limit.hold; } @@ -463,13 +472,7 @@ async function applyCategoryTemplate( } else { increment = limit; } - if (to_budget + increment < budgetAvailable || !priority) { - to_budget += increment; - } else { - if (budgetAvailable > 0) to_budget += budgetAvailable; - errors.push(`Insufficient funds.`); - } - idealTarget += increment; + to_budget += increment; break; } case 'by': { @@ -501,17 +504,9 @@ async function applyCategoryTemplate( target = 0; remainder = Math.abs(remainder); } - let diff = + let increment = num_months >= 0 ? Math.round(target / (num_months + 1)) : 0; - if (diff >= 0) { - if (to_budget + diff < budgetAvailable || !priority) { - to_budget += diff; - } else { - if (budgetAvailable > 0) to_budget += budgetAvailable; - errors.push(`Insufficient funds.`); - } - } - idealTarget += diff; + to_budget += increment; } else { errors.push(`by templates are not supported in Report budgets`); } @@ -526,6 +521,7 @@ async function applyCategoryTemplate( errors.push(`More than one “up to” limit found.`); return { errors }; } else { + limitCheck = true; limit = amountToInteger(template.limit.amount); hold = template.limit.hold; } @@ -535,17 +531,10 @@ async function applyCategoryTemplate( while (w < next_month) { if (w >= current_month) { - if (to_budget + amount < budgetAvailable || !priority) { - to_budget += amount; - } else { - if (budgetAvailable > 0) to_budget += budgetAvailable; - errors.push(`Insufficient funds.`); - } - idealTarget += amount; + to_budget += amount; } w = monthUtils.addWeeks(w, weeks); } - break; } case 'spend': { @@ -599,13 +588,7 @@ async function applyCategoryTemplate( (target - already_budgeted) / (num_months + 1), ); } - if (increment < budgetAvailable || !priority) { - to_budget = increment; - } else { - if (budgetAvailable > 0) to_budget = budgetAvailable; - errors.push(`Insufficient funds.`); - } - idealTarget = increment; + to_budget = increment; break; } case 'percentage': { @@ -656,13 +639,7 @@ async function applyCategoryTemplate( 0, Math.round(monthlyIncome * (percent / 100)), ); - if (increment + to_budget <= budgetAvailable || !priority) { - to_budget += increment; - } else { - if (budgetAvailable > 0) to_budget = budgetAvailable; - errors.push(`Insufficient funds.`); - } - idealTarget += increment; + to_budget += increment; break; } case 'schedule': { @@ -740,7 +717,7 @@ async function applyCategoryTemplate( t = t.filter(t => t.completed === 0); t = t.sort((a, b) => b.target - a.target); - let diff = 0; + let increment = 0; if (balance >= totalScheduledGoal) { for (let ll = 0; ll < t.length; ll++) { if (t[ll].num_months < 0) { @@ -754,11 +731,11 @@ async function applyCategoryTemplate( t[ll].target_frequency === 'weekly' || t[ll].target_frequency === 'daily' ) { - diff += t[ll].target; + increment += t[ll].target; } else if (t[ll].template.full && t[ll].num_months > 0) { - diff += 0; + increment += 0; } else { - diff += t[ll].target / t[ll].target_interval; + increment += t[ll].target / t[ll].target_interval; } } } else if (balance < totalScheduledGoal) { @@ -802,26 +779,17 @@ async function applyCategoryTemplate( t[ll].target_frequency === 'weekly' || t[ll].target_frequency === 'daily' ) { - diff += tg; + increment += tg; } else if (t[ll].template.full && t[ll].num_months > 0) { - diff += 0; + increment += 0; } else { - diff += tg / (t[ll].num_months + 1); + increment += tg / (t[ll].num_months + 1); } } } } - diff = Math.round(diff); - if ((diff > 0 && to_budget + diff <= budgetAvailable) || !priority) { - to_budget += diff; - } else if ( - to_budget + diff > budgetAvailable && - budgetAvailable >= 0 - ) { - to_budget = budgetAvailable; - errors.push(`Insufficient funds.`); - } - idealTarget += diff; + increment = Math.round(increment); + to_budget += increment; } break; } @@ -838,7 +806,6 @@ async function applyCategoryTemplate( } else if (budgetAvailable - to_budget === 1) { to_budget = to_budget + 1; } - idealTarget = to_budget; } break; } @@ -848,7 +815,7 @@ async function applyCategoryTemplate( } } - if (limit != null) { + if (limitCheck) { if (hold && balance > limit) { to_budget = 0; } else if (to_budget + balance > limit) { @@ -872,7 +839,7 @@ async function applyCategoryTemplate( integerToAmount(last_month_balance + to_budget); str += ' ' + template_lines.map(x => x.line).join('\n'); console.log(str); - return { amount: to_budget, errors, idealTarget: idealTarget }; + return { amount: to_budget, errors }; } } From ac4c3ebc2c6b6682bd22b3f1ec506e54032769f9 Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Mon, 11 Sep 2023 15:46:34 -0500 Subject: [PATCH 14/49] fixup --- .../src/server/budget/goaltemplates.ts | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index 61945ab6efe..7ecf4658984 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -244,22 +244,19 @@ async function processTemplate( category: category.id, amount: to_budget, }); - if (to_budget <= budgetAvailable || !priority) { - templateBudget.push({ - category: category.id, - amount: to_budget + prev_budgeted, - }); - } else if ( - to_budget > budgetAvailable && - budgetAvailable >= 0 - ) { - to_budget = budgetAvailable; - errors.push(`Insufficient funds.`); - templateBudget.push({ - category: category.id, - amount: to_budget + prev_budgeted, - }); - } + } + if (to_budget <= budgetAvailable || !priority) { + templateBudget.push({ + category: category.id, + amount: to_budget + prev_budgeted, + }); + } else if (to_budget > budgetAvailable && budgetAvailable >= 0) { + to_budget = budgetAvailable; + errors.push(`Insufficient funds.`); + templateBudget.push({ + category: category.id, + amount: to_budget + prev_budgeted, + }); } budgetAvailable -= to_budget; } From 2c9d33f671519333a25eca05866567d063e8aaa4 Mon Sep 17 00:00:00 2001 From: shall0pass <20625555+shall0pass@users.noreply.github.com> Date: Fri, 15 Sep 2023 15:15:46 -0500 Subject: [PATCH 15/49] clear goal if template removed --- .../src/server/budget/goaltemplates.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/loot-core/src/server/budget/goaltemplates.ts b/packages/loot-core/src/server/budget/goaltemplates.ts index 7ecf4658984..1498fc91a4d 100644 --- a/packages/loot-core/src/server/budget/goaltemplates.ts +++ b/packages/loot-core/src/server/budget/goaltemplates.ts @@ -11,11 +11,13 @@ import { parse } from './goal-template.pegjs'; export async function applyTemplate({ month }) { let category_templates = await getCategoryTemplates(null); + await resetCategoryTargets({ month }); return processTemplate(month, false, category_templates); } export async function overwriteTemplate({ month }) { let category_templates = await getCategoryTemplates(null); + await resetCategoryTargets({ month }); return processTemplate(month, true, category_templates); } @@ -72,6 +74,21 @@ async function setCategoryTargets({ month, idealTemplate }) { }); } +async function resetCategoryTargets({ month }) { + let categories = await db.all( + 'SELECT * FROM v_categories WHERE tombstone = 0 AND hidden = 0', + ); + await batchMessages(async () => { + categories.forEach(element => { + setGoal({ + category: element.id, + goal: 0, + month: month, + }); + }); + }); +} + async function processTemplate( month, force, From c55797b8cf4644c7632f6a0c32f653b0e947d7f4 Mon Sep 17 00:00:00 2001 From: youngcw Date: Sat, 16 Sep 2023 16:25:13 -0700 Subject: [PATCH 16/49] Visual goals (#40) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 🔥 removing privacyMode feature flag (#1688) * :art: fix multiline label in schedules modal (#1687) * Update Visual Regression README File (#1689) * Fix typo in GoCardlessLink.js (#1684) happend -> happened * queried cleared balance for tooltip (#1678) * Dark Theme Reports/Settings (#1512) * :bug: Mobile account transaction list: Fix sticky date section headers (#1698) * :construction_worker: do not cancel github ci jobs on master branch (#1692) * Sidebar Account Fix (#1703) * Dark Theme Final (#1513) * Category autocomplete should only search selectable categories (#1681) * set colors based on a goal value * extra comment --------- Co-authored-by: Matiss Janis Aboltins Co-authored-by: Crazypkr1099 Co-authored-by: Ikko Eltociear Ashimine Co-authored-by: Shaan Khosla <35707672+shaankhosla@users.noreply.github.com> Co-authored-by: Neil <55785687+carkom@users.noreply.github.com> Co-authored-by: Trevor Farlow --- .eslintrc.js | 58 +--------- .github/workflows/build.yml | 2 +- .github/workflows/check.yml | 2 +- .github/workflows/codeql.yml | 2 +- .github/workflows/electron.yml | 2 +- packages/desktop-client/README.md | 9 +- .../src/components/LoggedInUser.tsx | 4 +- .../src/components/MobileWebMessage.tsx | 6 +- .../src/components/NotesButton.tsx | 18 +-- .../src/components/Notifications.tsx | 34 ++++-- .../desktop-client/src/components/Page.tsx | 6 +- .../src/components/PrivacyFilter.tsx | 4 +- .../src/components/Titlebar.tsx | 19 +-- .../src/components/UpdateNotification.tsx | 18 ++- .../src/components/accounts/Header.js | 4 +- .../src/components/accounts/Reconcile.js | 13 ++- .../autocomplete/CategoryAutocomplete.tsx | 3 +- .../budget/BalanceWithCarryover.tsx | 11 +- .../src/components/budget/BudgetCategories.js | 9 +- .../src/components/budget/BudgetTotals.js | 11 +- .../src/components/budget/ExpenseGroup.js | 4 +- .../src/components/budget/IncomeGroup.js | 4 +- .../src/components/budget/MobileBudget.js | 3 +- .../components/budget/MobileBudgetTable.js | 68 ++++++----- .../src/components/budget/MobileTable.tsx | 4 +- .../components/budget/MonthCountSelector.tsx | 6 +- .../src/components/budget/MonthPicker.js | 14 ++- .../src/components/budget/RenderMonths.js | 4 +- .../src/components/budget/SidebarCategory.js | 8 +- .../src/components/budget/SidebarGroup.js | 8 +- .../src/components/budget/constants.js | 4 - .../budget/report/BudgetSummary.tsx | 41 ++++--- .../components/budget/report/components.tsx | 34 +++--- .../budget/rollover/BudgetSummary.tsx | 27 ++--- .../budget/rollover/rollover-components.tsx | 35 +++--- .../src/components/budget/util.js | 34 +++++- .../src/components/common/Card.tsx | 6 +- .../src/components/common/ExternalLink.tsx | 6 +- .../src/components/common/Label.tsx | 4 +- .../components/gocardless/GoCardlessLink.js | 2 +- .../src/components/mobile/MobileForms.js | 9 +- .../src/components/modals/BudgetSummary.js | 5 +- .../src/components/reports/CashFlow.js | 6 +- .../src/components/reports/Change.js | 7 +- .../src/components/reports/DateRange.js | 4 +- .../src/components/reports/Header.js | 2 - .../src/components/reports/NetWorth.js | 4 +- .../src/components/reports/Overview.js | 15 ++- .../src/components/reports/Tooltip.js | 8 +- .../src/components/reports/chart-theme.js | 17 ++- .../reports/graphs/CashFlowGraph.tsx | 13 +-- .../reports/graphs/CategorySpendingGraph.tsx | 4 +- .../reports/graphs/NetWorthGraph.tsx | 8 +- .../src/components/reports/graphs/common.tsx | 10 +- .../src/components/schedules/EditSchedule.js | 16 +-- .../src/components/settings/Encryption.tsx | 4 +- .../src/components/settings/Experimental.tsx | 18 ++- .../src/components/settings/FixSplits.tsx | 4 +- .../src/components/settings/Global.tsx | 4 +- .../src/components/settings/UI.tsx | 8 +- .../src/components/settings/index.tsx | 16 ++- .../src/components/sidebar/Account.tsx | 2 +- .../src/components/spreadsheet/CellValue.tsx | 6 +- .../transactions/MobileTransaction.js | 109 ++++++++++-------- .../transactions/TransactionsTable.js | 28 ++--- .../transactions/TransactionsTable.test.js | 11 +- .../src/hooks/useFeatureFlag.ts | 1 - packages/desktop-client/src/style/styles.ts | 1 + .../desktop-client/src/style/themes/dark.ts | 20 ++++ .../src/style/themes/development.ts | 20 ++++ .../desktop-client/src/style/themes/light.ts | 36 +++++- packages/loot-core/src/client/queries.ts | 2 + packages/loot-core/src/types/prefs.d.ts | 1 - upcoming-release-notes/1512.md | 5 + upcoming-release-notes/1513.md | 5 + upcoming-release-notes/1678.md | 6 + upcoming-release-notes/1681.md | 6 + upcoming-release-notes/1687.md | 6 + upcoming-release-notes/1688.md | 6 + upcoming-release-notes/1692.md | 6 + upcoming-release-notes/1698.md | 6 + upcoming-release-notes/1703.md | 6 + 82 files changed, 590 insertions(+), 432 deletions(-) delete mode 100644 packages/desktop-client/src/components/budget/constants.js create mode 100644 upcoming-release-notes/1512.md create mode 100644 upcoming-release-notes/1513.md create mode 100644 upcoming-release-notes/1678.md create mode 100644 upcoming-release-notes/1681.md create mode 100644 upcoming-release-notes/1687.md create mode 100644 upcoming-release-notes/1688.md create mode 100644 upcoming-release-notes/1692.md create mode 100644 upcoming-release-notes/1698.md create mode 100644 upcoming-release-notes/1703.md diff --git a/.eslintrc.js b/.eslintrc.js index b10db2ff9c5..ef5d7e4e2a8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -216,63 +216,9 @@ module.exports = { rules: { 'import/no-unused-modules': 'off' }, }, { - //This is temporary. We will remove these as dark theme gets ported files: [ - './packages/desktop-client/src/components/LoggedInUser.*', - './packages/desktop-client/src/components/MobileWebMessage.*', - './packages/desktop-client/src/components/NotesButton.*', - './packages/desktop-client/src/components/Notifications.*', - './packages/desktop-client/src/components/Page.*', - './packages/desktop-client/src/components/Titlebar.*', - './packages/desktop-client/src/components/UpdateNotification.*', - './packages/desktop-client/src/components/accounts/Header.*', - './packages/desktop-client/src/components/alerts.*', - './packages/desktop-client/src/components/budget/BudgetCategories.*', - './packages/desktop-client/src/components/budget/BudgetTotals.*', - './packages/desktop-client/src/components/budget/ExpenseGroup.*', - './packages/desktop-client/src/components/budget/IncomeGroup.*', - './packages/desktop-client/src/components/budget/MobileBudget.*', - './packages/desktop-client/src/components/budget/MobileBudgetTable.*', - './packages/desktop-client/src/components/budget/MobileTable.*', - './packages/desktop-client/src/components/budget/MonthCountSelector.*', - './packages/desktop-client/src/components/budget/MonthPicker.*', - './packages/desktop-client/src/components/budget/RenderMonths.*', - './packages/desktop-client/src/components/budget/SidebarCategory.*', - './packages/desktop-client/src/components/budget/SidebarGroup.*', - './packages/desktop-client/src/components/budget/constants.*', - './packages/desktop-client/src/components/budget/report/BudgetSummary.*', - './packages/desktop-client/src/components/budget/report/components.*', - './packages/desktop-client/src/components/budget/rollover/BudgetSummary.*', - './packages/desktop-client/src/components/budget/rollover/rollover-components.*', - './packages/desktop-client/src/components/budget/util.*', - './packages/desktop-client/src/components/common.*', - './packages/desktop-client/src/components/common/Card.*', - './packages/desktop-client/src/components/common/Label.*', - './packages/desktop-client/src/components/common/View.*', - './packages/desktop-client/src/components/common/ExternalLink.*', - './packages/desktop-client/src/components/modals/BudgetSummary.*', - './packages/desktop-client/src/components/payees/index.*', - './packages/desktop-client/src/components/reports/CashFlow.*', - './packages/desktop-client/src/components/reports/Change.*', - './packages/desktop-client/src/components/reports/DateRange.*', - './packages/desktop-client/src/components/reports/Header.*', - './packages/desktop-client/src/components/reports/NetWorth.*', - './packages/desktop-client/src/components/reports/Overview.*', - './packages/desktop-client/src/components/reports/Tooltip.*', - './packages/desktop-client/src/components/reports/chart-theme.*', - './packages/desktop-client/src/components/reports/graphs/CashFlowGraph.*', - './packages/desktop-client/src/components/reports/graphs/NetWorthGraph.*', - './packages/desktop-client/src/components/settings/Encryption.*', - './packages/desktop-client/src/components/settings/Experimental.*', - './packages/desktop-client/src/components/settings/FixSplits.*', - './packages/desktop-client/src/components/settings/Format.*', - './packages/desktop-client/src/components/settings/Global.*', - './packages/desktop-client/src/components/settings/UI.*', - './packages/desktop-client/src/components/settings/index.*', - './packages/desktop-client/src/components/transactions/MobileTransaction.*', - './packages/desktop-client/src/components/transactions/TransactionsTable.*', - './packages/desktop-client/src/components/util/AmountInput.*', - './packages/desktop-client/src/style/*', + './packages/desktop-client/src/style/index.*', + './packages/desktop-client/src/style/palette.*', ], rules: { 'no-restricted-imports': ['off', { patterns: restrictedImportColors }], diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b18dc0ff39a..6636d56d741 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: api: diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index 6e00fcb98f9..f10284c1d8e 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -8,7 +8,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: lint: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index ee9383aa9f1..efb3ea85c2e 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -9,7 +9,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: analyze: diff --git a/.github/workflows/electron.yml b/.github/workflows/electron.yml index 5bf0c521843..8b90d41a995 100644 --- a/.github/workflows/electron.yml +++ b/.github/workflows/electron.yml @@ -15,7 +15,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} jobs: build: diff --git a/packages/desktop-client/README.md b/packages/desktop-client/README.md index 3228051f1d4..834b79b486a 100644 --- a/packages/desktop-client/README.md +++ b/packages/desktop-client/README.md @@ -37,15 +37,20 @@ First start the dev server: ```sh HTTPS=true yarn start ``` - -Next, run the standartised docker container and launch the visual regression tests from within it. +Next, navigate to the root of your project folder, run the standartised docker container, and launch the visual regression tests from within it. ```sh # Run docker container docker run --rm --network host -v $(pwd):/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.37.0-jammy /bin/bash + # If you recieve an error such as "docker: invalid reference format", please instead use the following command: + docker run --rm --network host -v ${pwd}:/work/ -w /work/ -it mcr.microsoft.com/playwright:v1.37.0-jammy /bin/bash + # Run the VRT tests: important - they MUST be ran against a HTTPS server E2E_START_URL=https://192.168.0.178:3001 yarn vrt + + # To update snapshots, use the following command: + E2E_START_URL=https://192.168.0.178:3001 yarn vrt --update-snapshots ``` #### Running against a remote server diff --git a/packages/desktop-client/src/components/LoggedInUser.tsx b/packages/desktop-client/src/components/LoggedInUser.tsx index 4f432c8077f..7e81e9a732d 100644 --- a/packages/desktop-client/src/components/LoggedInUser.tsx +++ b/packages/desktop-client/src/components/LoggedInUser.tsx @@ -2,7 +2,7 @@ import React, { useState, useEffect } from 'react'; import { useSelector } from 'react-redux'; import { useActions } from '../hooks/useActions'; -import { colors, styles, type CSSProperties } from '../style'; +import { theme, styles, type CSSProperties } from '../style'; import Button from './common/Button'; import Menu from './common/Menu'; @@ -78,7 +78,7 @@ export default function LoggedInUser({ return ( diff --git a/packages/desktop-client/src/components/Notifications.tsx b/packages/desktop-client/src/components/Notifications.tsx index 368d095563c..f61552521e2 100644 --- a/packages/desktop-client/src/components/Notifications.tsx +++ b/packages/desktop-client/src/components/Notifications.tsx @@ -11,7 +11,7 @@ import type { NotificationWithId } from 'loot-core/src/client/state-types/notifi import { useActions } from '../hooks/useActions'; import AnimatedLoading from '../icons/AnimatedLoading'; import Delete from '../icons/v0/Delete'; -import { styles, colors, type CSSProperties } from '../style'; +import { styles, theme, type CSSProperties } from '../style'; import Button, { ButtonWithLoading } from './common/Button'; import ExternalLink from './common/ExternalLink'; @@ -107,7 +107,11 @@ function Notification({ @@ -200,7 +212,7 @@ function Notification({ left: 0, right: 0, bottom: 0, - backgroundColor: 'rgba(250, 250, 250, .75)', + backgroundColor: theme.tableBackground, alignItems: 'center', justifyContent: 'center', }} diff --git a/packages/desktop-client/src/components/Page.tsx b/packages/desktop-client/src/components/Page.tsx index b6ac595eaee..1971861caaf 100644 --- a/packages/desktop-client/src/components/Page.tsx +++ b/packages/desktop-client/src/components/Page.tsx @@ -1,7 +1,7 @@ import React, { type ReactNode } from 'react'; import { useResponsive } from '../ResponsiveProvider'; -import { colors, styles, type CSSProperties } from '../style'; +import { theme, styles, type CSSProperties } from '../style'; import Text from './common/Text'; import View from './common/View'; @@ -20,8 +20,8 @@ function PageTitle({ {Children.toArray(children)} ) : ( diff --git a/packages/desktop-client/src/components/Titlebar.tsx b/packages/desktop-client/src/components/Titlebar.tsx index fab82dbe3ab..3e449defd85 100644 --- a/packages/desktop-client/src/components/Titlebar.tsx +++ b/packages/desktop-client/src/components/Titlebar.tsx @@ -21,7 +21,7 @@ import SvgEye from '../icons/v2/Eye'; import SvgEyeSlashed from '../icons/v2/EyeSlashed'; import NavigationMenu from '../icons/v2/NavigationMenu'; import { useResponsive } from '../ResponsiveProvider'; -import { colors, type CSSProperties } from '../style'; +import { theme, type CSSProperties } from '../style'; import AccountSyncCheck from './accounts/AccountSyncCheck'; import AnimatedRefresh from './AnimatedRefresh'; @@ -72,7 +72,9 @@ function UncategorizedButton() { {count} uncategorized {count === 1 ? 'transaction' : 'transactions'} @@ -148,19 +150,19 @@ export function SyncButton({ style, isMobile = false }: SyncButtonProps) { const mobileColor = syncState === 'error' - ? colors.r7 + ? theme.alt4ErrorText : syncState === 'disabled' || syncState === 'offline' || syncState === 'local' - ? colors.n9 + ? theme.sidebarItemText : style.color; const desktopColor = syncState === 'error' - ? colors.r4 + ? theme.alt2ErrorText : syncState === 'disabled' || syncState === 'offline' || syncState === 'local' - ? colors.n6 + ? theme.altTableText : null; const activeStyle = isMobile @@ -296,7 +298,6 @@ export default function Titlebar({ style }) { state => state.prefs.global.floatingSidebar, ); - let privacyModeFeatureFlag = useFeatureFlag('privacyMode'); let themesFlag = useFeatureFlag('themes'); return isNarrowWidth ? null : ( @@ -338,7 +339,7 @@ export default function Titlebar({ style }) { > )} @@ -369,7 +370,7 @@ export default function Titlebar({ style }) { {themesFlag && } - {privacyModeFeatureFlag && } + {serverURL ? : null} diff --git a/packages/desktop-client/src/components/UpdateNotification.tsx b/packages/desktop-client/src/components/UpdateNotification.tsx index df42cc420b5..7e844e02999 100644 --- a/packages/desktop-client/src/components/UpdateNotification.tsx +++ b/packages/desktop-client/src/components/UpdateNotification.tsx @@ -3,7 +3,7 @@ import { useSelector } from 'react-redux'; import { useActions } from '../hooks/useActions'; import Close from '../icons/v1/Close'; -import { colors } from '../style'; +import { theme } from '../style'; import Button from './common/Button'; import LinkButton from './common/LinkButton'; @@ -36,8 +36,8 @@ export default function UpdateNotification() { bottom: 0, right: 0, margin: '15px 17px', - backgroundColor: colors.p6, - color: 'white', + backgroundColor: theme.altPageTextPositive, + color: theme.tableBackground, padding: '7px 10px', borderRadius: 4, zIndex: 10000, @@ -53,13 +53,19 @@ export default function UpdateNotification() { Restart {' '} ( window.Actual.openURLInBrowser( 'https://actualbudget.org/docs/releases', @@ -74,7 +80,7 @@ export default function UpdateNotification() { style={{ display: 'inline', padding: '1px 7px 2px 7px' }} onClick={() => closeNotification(setAppState)} > - + diff --git a/packages/desktop-client/src/components/accounts/Header.js b/packages/desktop-client/src/components/accounts/Header.js index eb180b07adf..e6dcfe54942 100644 --- a/packages/desktop-client/src/components/accounts/Header.js +++ b/packages/desktop-client/src/components/accounts/Header.js @@ -7,7 +7,7 @@ import ArrowsExpand3 from '../../icons/v2/ArrowsExpand3'; import ArrowsShrink3 from '../../icons/v2/ArrowsShrink3'; import DownloadThickBottom from '../../icons/v2/DownloadThickBottom'; import Pencil1 from '../../icons/v2/Pencil1'; -import { colors, styles } from '../../style'; +import { theme, styles } from '../../style'; import AnimatedRefresh from '../AnimatedRefresh'; import Button from '../common/Button'; import InitialFocus from '../common/InitialFocus'; @@ -170,7 +170,7 @@ export function AccountHeader({ style={{ width: 11, height: 11, - color: colors.n8, + color: theme.altButtonBareText, }} /> diff --git a/packages/desktop-client/src/components/accounts/Reconcile.js b/packages/desktop-client/src/components/accounts/Reconcile.js index 92615a9630c..0b684d640a5 100644 --- a/packages/desktop-client/src/components/accounts/Reconcile.js +++ b/packages/desktop-client/src/components/accounts/Reconcile.js @@ -96,7 +96,12 @@ export function ReconcilingMessage({ } export function ReconcileTooltip({ account, onReconcile, onClose }) { - let balance = useSheetValue(queries.accountBalance(account)); + let balanceQuery = queries.accountBalance(account); + let clearedBalance = useSheetValue({ + name: balanceQuery.name + '-cleared', + value: null, + query: balanceQuery.query.filter({ cleared: true }), + }); let format = useFormat(); function onSubmit(e) { @@ -104,7 +109,7 @@ export function ReconcileTooltip({ account, onReconcile, onClose }) { let input = e.target.elements[0]; let amount = currencyToInteger(input.value); if (amount != null) { - onReconcile(amount == null ? balance : amount); + onReconcile(amount == null ? clearedBalance : amount); onClose(); } else { input.select(); @@ -119,10 +124,10 @@ export function ReconcileTooltip({ account, onReconcile, onClose }) { reconcile with:
- {balance != null && ( + {clearedBalance != null && ( diff --git a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx index 99041a45872..9d23862b8e9 100644 --- a/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx +++ b/packages/desktop-client/src/components/autocomplete/CategoryAutocomplete.tsx @@ -202,8 +202,7 @@ export default function CategoryAutocomplete({ return suggestions.filter(suggestion => { return ( suggestion.id === 'split' || - defaultFilterSuggestion(suggestion, value) || - suggestion.groupName.toLowerCase().includes(value.toLowerCase()) + defaultFilterSuggestion(suggestion, value) ); }); }} diff --git a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx index 93d1df5312e..aab6fc2329c 100644 --- a/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx +++ b/packages/desktop-client/src/components/budget/BalanceWithCarryover.tsx @@ -5,27 +5,32 @@ import View from '../common/View'; import CellValue from '../spreadsheet/CellValue'; import useSheetValue from '../spreadsheet/useSheetValue'; -import { makeAmountStyle } from './util'; +import { makeAmountStyle, makeAmountStyleGoal } from './util'; type BalanceWithCarryoverProps = { carryover: ComponentProps['binding']; balance: ComponentProps['binding']; + goal: ComponentProps['binding']; disabled?: boolean; }; export default function BalanceWithCarryover({ carryover, balance, + goal, disabled, }: BalanceWithCarryoverProps) { let carryoverValue = useSheetValue(carryover); let balanceValue = useSheetValue(balance); + //let goalValue = useSheetValue(goal); + let goalValue = '5000'; //TODO: figure out how to actually get this value for realzies return ( <> )} diff --git a/packages/desktop-client/src/components/budget/BudgetCategories.js b/packages/desktop-client/src/components/budget/BudgetCategories.js index cfec40f1c42..bab700c8494 100644 --- a/packages/desktop-client/src/components/budget/BudgetCategories.js +++ b/packages/desktop-client/src/components/budget/BudgetCategories.js @@ -1,11 +1,10 @@ import React, { memo, useState, useMemo } from 'react'; -import { colors } from '../../style'; +import { theme, styles } from '../../style'; import View from '../common/View'; import { DropHighlightPosContext } from '../sort'; import { Row } from '../table'; -import { INCOME_HEADER_HEIGHT, MONTH_BOX_SHADOW } from './constants'; import ExpenseCategory from './ExpenseCategory'; import ExpenseGroup from './ExpenseGroup'; import IncomeCategory from './IncomeCategory'; @@ -152,7 +151,7 @@ const BudgetCategories = memo( marginBottom: 10, backgroundColor: 'white', overflow: 'hidden', - boxShadow: MONTH_BOX_SHADOW, + boxShadow: styles.cardShadow, borderRadius: '0 0 4px 4px', flex: 1, }} @@ -162,7 +161,7 @@ const BudgetCategories = memo( switch (item.type) { case 'new-group': content = ( - + diff --git a/packages/desktop-client/src/components/budget/BudgetTotals.js b/packages/desktop-client/src/components/budget/BudgetTotals.js index 2132d0e0bb5..3a811461fec 100644 --- a/packages/desktop-client/src/components/budget/BudgetTotals.js +++ b/packages/desktop-client/src/components/budget/BudgetTotals.js @@ -1,13 +1,12 @@ import React, { memo, useState } from 'react'; import DotsHorizontalTriple from '../../icons/v1/DotsHorizontalTriple'; -import { colors } from '../../style'; +import { theme, styles } from '../../style'; import Button from '../common/Button'; import Menu from '../common/Menu'; import View from '../common/View'; import { Tooltip } from '../tooltips'; -import { MONTH_BOX_SHADOW } from './constants'; import RenderMonths from './RenderMonths'; import { getScrollbarWidth } from './util'; @@ -25,17 +24,17 @@ const BudgetTotals = memo(function BudgetTotals({ backgroundColor: 'white', flexDirection: 'row', flexShrink: 0, - boxShadow: MONTH_BOX_SHADOW, + boxShadow: styles.cardShadow, marginLeft: 5, marginRight: 5 + getScrollbarWidth(), borderRadius: '4px 4px 0 0', - borderBottom: '1px solid ' + colors.border, + borderBottom: '1px solid ' + theme.tableBorder, }} > {menuOpen && ( {dragState && !dragState.preview && dragState.type === 'group' && ( diff --git a/packages/desktop-client/src/components/budget/IncomeGroup.js b/packages/desktop-client/src/components/budget/IncomeGroup.js index 38cbd53cbcf..f7d260fff54 100644 --- a/packages/desktop-client/src/components/budget/IncomeGroup.js +++ b/packages/desktop-client/src/components/budget/IncomeGroup.js @@ -1,6 +1,6 @@ import React from 'react'; -import { colors } from '../../style'; +import { theme } from '../../style'; import { Row } from '../table'; import RenderMonths from './RenderMonths'; @@ -19,7 +19,7 @@ function IncomeGroup({ return ( @@ -386,7 +393,7 @@ class TotalsRow extends PureComponent { style={{ flexDirection: 'row', alignItems: 'center', - backgroundColor: colors.n11, + backgroundColor: theme.tableHeaderBackground, }} data-testid="totals" > @@ -564,7 +571,7 @@ class IncomeCategory extends PureComponent { // flexDirection: 'row', // justifyContent: 'flex-end', // alignItems: 'stretch', -// backgroundColor: colors.n10, +// backgroundColor: colorsm.tableBackground, // padding: 5, // height: 45 // }} @@ -718,7 +725,9 @@ class IncomeBudgetGroup extends Component { } nameTextStyle={{ fontWeight: '500' }} amountTextStyle={{ fontWeight: '500' }} - style={{ backgroundColor: colors.n11 }} + style={{ + backgroundColor: theme.altTableBackground, + }} /> {group.categories.map((category, index) => { @@ -883,7 +892,7 @@ export function BudgetTable(props) { paddingRight: 14, backgroundColor: 'white', borderBottomWidth: 1, - borderColor: colors.n9, + borderColor: theme.tableBorder, }} > {type === 'report' ? ( @@ -905,22 +914,25 @@ export function BudgetTable(props) { margin: '0 -8px', background: showBudgetedCol && !show3Cols - ? `linear-gradient(-45deg, ${colors.p5} 8px, transparent 0)` + ? `linear-gradient(-45deg, ${theme.formInputBackgroundSelection} 8px, transparent 0)` : !show3Cols - ? `linear-gradient(45deg, ${colors.p5} 8px, transparent 0)` + ? `linear-gradient(45deg, ${theme.formInputBackgroundSelection} 8px, transparent 0)` : null, // 45deg to flip it to the lower left corner }} > {show3Cols || showBudgetedCol ? ( - - {!editMode ? ( // {!editMode && ( @@ -1093,7 +1104,11 @@ function BudgetHeader({ padding: '5px 30px 5px 0', }} > - + )} - {serverURL && ( { style={{ height: ROW_HEIGHT, borderBottomWidth: 1, - borderColor: colors.border, + borderColor: theme.tableBorder, flexDirection: 'row', alignItems: 'center', paddingLeft: 10, diff --git a/packages/desktop-client/src/components/budget/MonthCountSelector.tsx b/packages/desktop-client/src/components/budget/MonthCountSelector.tsx index d5bba0f3a20..d3baecf087b 100644 --- a/packages/desktop-client/src/components/budget/MonthCountSelector.tsx +++ b/packages/desktop-client/src/components/budget/MonthCountSelector.tsx @@ -1,7 +1,7 @@ import React from 'react'; import CalendarIcon from '../../icons/v2/Calendar'; -import { colors } from '../../style'; +import { theme } from '../../style'; import View from '../common/View'; import { useBudgetMonthCount } from './BudgetMonthCountContext'; @@ -42,7 +42,9 @@ export function MonthCountSelector({ calendars.push( = i ? colors.n5 : colors.n8} + color={ + maxMonths >= i ? theme.altpageTextSubdued : theme.altButtonBareText + } onClick={() => onChange(i)} />, ); diff --git a/packages/desktop-client/src/components/budget/MonthPicker.js b/packages/desktop-client/src/components/budget/MonthPicker.js index 390f8e77bcf..4466edb38df 100644 --- a/packages/desktop-client/src/components/budget/MonthPicker.js +++ b/packages/desktop-client/src/components/budget/MonthPicker.js @@ -3,7 +3,7 @@ import { useState } from 'react'; import * as monthUtils from 'loot-core/src/shared/months'; import useResizeObserver from '../../hooks/useResizeObserver'; -import { styles, colors } from '../../style'; +import { styles, theme } from '../../style'; import View from '../common/View'; export const MonthPicker = ({ @@ -102,12 +102,12 @@ export const MonthPicker = ({ border: 'none', ...(!isMonthBudgeted && { textDecoration: 'line-through', - color: colors.n7, + color: theme.pageTextSubdued, }), ...styles.smallText, ...(selected && { - backgroundColor: colors.p6, - color: 'white', + backgroundColor: theme.tableBorderHover, + color: theme.buttonPrimaryText, }), ...((hovered || selected) && { borderRadius: 0, @@ -119,7 +119,7 @@ export const MonthPicker = ({ }), ...(hovered && selected && { - backgroundColor: colors.p7, + backgroundColor: theme.tableBorderHover, }), ...((idx === firstSelectedIndex || (idx === hoverId && !selected)) && { @@ -146,7 +146,9 @@ export const MonthPicker = ({ left: 0, fontSize: 10, fontWeight: 'bold', - color: isMonthBudgeted ? '#272630' : colors.n7, + color: isMonthBudgeted + ? theme.pageText + : theme.pageTextSubdued, }} > {year} diff --git a/packages/desktop-client/src/components/budget/RenderMonths.js b/packages/desktop-client/src/components/budget/RenderMonths.js index f563d859fe5..044f2ca702d 100644 --- a/packages/desktop-client/src/components/budget/RenderMonths.js +++ b/packages/desktop-client/src/components/budget/RenderMonths.js @@ -2,7 +2,7 @@ import React, { useContext } from 'react'; import * as monthUtils from 'loot-core/src/shared/months'; -import { colors } from '../../style'; +import { theme } from '../../style'; import View from '../common/View'; import NamespaceContext from '../spreadsheet/NamespaceContext'; @@ -22,7 +22,7 @@ function RenderMonths({ component: Component, editingIndex, args, style }) { diff --git a/packages/desktop-client/src/components/budget/SidebarCategory.js b/packages/desktop-client/src/components/budget/SidebarCategory.js index 3ccebb13a3b..cee13b3924f 100644 --- a/packages/desktop-client/src/components/budget/SidebarCategory.js +++ b/packages/desktop-client/src/components/budget/SidebarCategory.js @@ -1,7 +1,7 @@ import React, { useState } from 'react'; import CheveronDown from '../../icons/v1/CheveronDown'; -import { colors } from '../../style'; +import { theme } from '../../style'; import Button from '../common/Button'; import Menu from '../common/Menu'; import View from '../common/View'; @@ -16,7 +16,7 @@ function SidebarCategory({ dragging, editing, style, - borderColor = colors.border, + borderColor = theme.tableBorder, isLast, onDragChange, onEditMonth, @@ -110,9 +110,9 @@ function SidebarCategory({ '& button': { display: 'none' }, ...(!dragging && !dragPreview && { - '&:hover button': { display: 'flex', color: colors.n1 }, + '&:hover button': { display: 'flex', color: theme.tableTextHover }, }), - ...(dragging && { color: colors.n8 }), + ...(dragging && { color: theme.formInputTextPlaceholderSelected }), // The zIndex here forces the the view on top of a row below // it that may be "collapsed" and show a border on top ...(dragPreview && { diff --git a/packages/desktop-client/src/components/budget/SidebarGroup.js b/packages/desktop-client/src/components/budget/SidebarGroup.js index 2273dac88a9..f470ebb31ce 100644 --- a/packages/desktop-client/src/components/budget/SidebarGroup.js +++ b/packages/desktop-client/src/components/budget/SidebarGroup.js @@ -2,7 +2,7 @@ import React, { useState } from 'react'; import ExpandArrow from '../../icons/v0/ExpandArrow'; import CheveronDown from '../../icons/v1/CheveronDown'; -import { colors } from '../../style'; +import { theme } from '../../style'; import Button from '../common/Button'; import Menu from '../common/Menu'; import Text from '../common/Text'; @@ -18,7 +18,7 @@ function SidebarGroup({ dragPreview, innerRef, style, - borderColor = colors.border, + borderColor = theme.tableBorder, onEdit, onSave, onDelete, @@ -124,9 +124,9 @@ function SidebarGroup({ style={{ ...style, width: 200, - backgroundColor: colors.n11, + backgroundColor: theme.altTableBackground, '& button': { display: 'none' }, - '&:hover button': { display: 'flex', color: colors.n1 }, + '&:hover button': { display: 'flex', color: theme.tableTextHover }, ...(dragPreview && { paddingLeft: 10, zIndex: 10000, diff --git a/packages/desktop-client/src/components/budget/constants.js b/packages/desktop-client/src/components/budget/constants.js deleted file mode 100644 index d0ac62ba30e..00000000000 --- a/packages/desktop-client/src/components/budget/constants.js +++ /dev/null @@ -1,4 +0,0 @@ -export const INCOME_HEADER_HEIGHT = 70; -export const MONTH_BOX_SHADOW = - '0 1px 3px rgba(0,0,0,0.12), 0 1px 2px rgba(0,0,0,0.24)'; -export const MONTH_RIGHT_PADDING = 5; diff --git a/packages/desktop-client/src/components/budget/report/BudgetSummary.tsx b/packages/desktop-client/src/components/budget/report/BudgetSummary.tsx index 82c5cc0f2fe..ebf6d1c782c 100644 --- a/packages/desktop-client/src/components/budget/report/BudgetSummary.tsx +++ b/packages/desktop-client/src/components/budget/report/BudgetSummary.tsx @@ -15,7 +15,7 @@ import useFeatureFlag from '../../../hooks/useFeatureFlag'; import DotsHorizontalTriple from '../../../icons/v1/DotsHorizontalTriple'; import ArrowButtonDown1 from '../../../icons/v2/ArrowButtonDown1'; import ArrowButtonUp1 from '../../../icons/v2/ArrowButtonUp1'; -import { colors, type CSSProperties, styles } from '../../../style'; +import { theme, type CSSProperties, styles } from '../../../style'; import AlignedText from '../../common/AlignedText'; import Button from '../../common/Button'; import HoverTarget from '../../common/HoverTarget'; @@ -30,7 +30,6 @@ import NamespaceContext from '../../spreadsheet/NamespaceContext'; import useFormat from '../../spreadsheet/useFormat'; import useSheetValue from '../../spreadsheet/useSheetValue'; import { Tooltip } from '../../tooltips'; -import { MONTH_BOX_SHADOW } from '../constants'; import { makeAmountFullStyle } from '../util'; import { useReport } from './ReportContext'; @@ -100,8 +99,8 @@ function IncomeProgress({ current, target }: IncomeProgressProps) { return ( ); @@ -133,8 +132,8 @@ function ExpenseProgress({ current, target }: ExpenseProgressProps) { return ( ); @@ -168,12 +167,12 @@ function BudgetTotal({ - {title} + {title} - + {' of '} {projected ? ( - Projected Savings: + Projected Savings: ) : ( - + {isNegative ? 'Overspent:' : 'Saved:'} )} @@ -280,7 +279,11 @@ function Saved({ projected, style }: SavedProps) { className={`${css([ { fontSize: 25, - color: projected ? colors.y3 : isNegative ? colors.r4 : colors.p5, + color: projected + ? theme.alt2WarningText + : isNegative + ? theme.alt2ErrorText + : theme.altUpcomingText, }, ])}`} > @@ -320,8 +323,8 @@ export function BudgetSummary({ month }: BudgetSummaryProps) { return ( @@ -397,7 +400,7 @@ export function BudgetSummary({ month }: BudgetSummaryProps) { width={15} height={15} tooltipPosition="bottom-right" - defaultColor={colors.n6} + defaultColor={theme.pageTextSubdued} // notes page color /> @@ -405,7 +408,7 @@ export function BudgetSummary({ month }: BudgetSummaryProps) { {menuOpen && ( @@ -452,7 +455,7 @@ export function BudgetSummary({ month }: BudgetSummaryProps) { spacing={2} style={{ alignSelf: 'center', - backgroundColor: colors.n11, + backgroundColor: theme.tableRowHeaderBackground, borderRadius: 4, padding: '10px 15px', marginTop: 13, @@ -469,8 +472,8 @@ export function BudgetSummary({ month }: BudgetSummaryProps) { alignItems: 'center', padding: '10px 20px', justifyContent: 'space-between', - backgroundColor: colors.n11, - borderTop: '1px solid ' + colors.n10, + backgroundColor: theme.tableRowHeaderBackground, + borderTop: '1px solid ' + theme.tableRowHeaderText, }} > = currentMonth} /> diff --git a/packages/desktop-client/src/components/budget/report/components.tsx b/packages/desktop-client/src/components/budget/report/components.tsx index a4b1de57d66..8255a06d43e 100644 --- a/packages/desktop-client/src/components/budget/report/components.tsx +++ b/packages/desktop-client/src/components/budget/report/components.tsx @@ -6,7 +6,7 @@ import { integerToCurrency, amountToInteger } from 'loot-core/src/shared/util'; import useFeatureFlag from '../../../hooks/useFeatureFlag'; import CheveronDown from '../../../icons/v1/CheveronDown'; -import { styles, colors, type CSSProperties } from '../../../style'; +import { styles, theme, type CSSProperties } from '../../../style'; import Button from '../../common/Button'; import Menu from '../../common/Menu'; import Text from '../../common/Text'; @@ -17,7 +17,6 @@ import useSheetValue from '../../spreadsheet/useSheetValue'; import { Field, SheetCell } from '../../table'; import { Tooltip, useTooltip } from '../../tooltips'; import BalanceWithCarryover from '../BalanceWithCarryover'; -import { MONTH_RIGHT_PADDING } from '../constants'; import { makeAmountGrey } from '../util'; export { BudgetSummary } from './BudgetSummary'; @@ -27,7 +26,6 @@ let headerLabelStyle: CSSProperties = { padding: '0 5px', textAlign: 'right', }; - export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() { const format = useFormat(); return ( @@ -35,36 +33,36 @@ export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() { style={{ flex: 1, flexDirection: 'row', - marginRight: MONTH_RIGHT_PADDING, + marginRight: styles.monthRightPadding, paddingTop: 10, paddingBottom: 10, }} > - Budgeted + Budgeted { return format(parseFloat(value || '0'), 'financial'); }} /> - Spent + Spent - Balance + Balance @@ -76,15 +74,15 @@ export function IncomeHeaderMonth() { - Budgeted + Budgeted - Received + Received ); @@ -125,7 +123,7 @@ export const GroupMonth = memo(function GroupMonth({ group }: GroupMonthProps) { textAlign="right" style={{ fontWeight: 600, - paddingRight: MONTH_RIGHT_PADDING, + paddingRight: styles.monthRightPadding, ...styles.tnum, }} valueProps={{ @@ -133,7 +131,7 @@ export const GroupMonth = memo(function GroupMonth({ group }: GroupMonthProps) { type: 'financial', privacyFilter: { style: { - paddingRight: MONTH_RIGHT_PADDING, + paddingRight: styles.monthRightPadding, }, }, }} @@ -309,8 +307,8 @@ export const CategoryMonth = memo(function CategoryMonth({ padding: '0 4px', borderRadius: 4, ':hover': { - boxShadow: 'inset 0 0 0 1px ' + colors.n7, - backgroundColor: 'white', + boxShadow: 'inset 0 0 0 1px ' + theme.mobileAccountShadow, + backgroundColor: theme.tableBackground, }, }} valueProps={{ @@ -363,7 +361,7 @@ export const CategoryMonth = memo(function CategoryMonth({ @@ -366,7 +367,7 @@ export function BudgetSummary({ width={15} height={15} tooltipPosition="bottom-right" - defaultColor={colors.n6} + defaultColor={theme.altTableText} /> @@ -374,7 +375,7 @@ export function BudgetSummary({ {menuOpen && ( @@ -426,8 +427,8 @@ export function BudgetSummary({ alignItems: 'center', padding: '10px 20px', justifyContent: 'space-between', - backgroundColor: colors.n11, - borderTop: '1px solid ' + colors.n10, + backgroundColor: theme.tableHeaderBackground, + borderTop: '1px solid ' + theme.tableBorder, }} > ); } - let headerLabelStyle: CSSProperties = { flex: 1, padding: '0 5px', @@ -197,36 +195,36 @@ export const BudgetTotalsMonth = memo(function BudgetTotalsMonth() { style={{ flex: 1, flexDirection: 'row', - marginRight: MONTH_RIGHT_PADDING, + marginRight: styles.monthRightPadding, paddingTop: 10, paddingBottom: 10, }} > - Budgeted + Budgeted { return format(-parseFloat(value || '0'), 'financial'); }} /> - Spent + Spent - Balance + Balance @@ -237,7 +235,7 @@ export function IncomeHeaderMonth() { return ( {balanceTooltip.isOpen && ( @@ -504,7 +503,7 @@ export function IncomeGroupMonth() { textAlign="right" style={{ fontWeight: 600, - paddingRight: MONTH_RIGHT_PADDING, + paddingRight: styles.monthRightPadding, ...styles.tnum, }} valueProps={{ @@ -512,7 +511,7 @@ export function IncomeGroupMonth() { type: 'financial', privacyFilter: { style: { - paddingRight: MONTH_RIGHT_PADDING, + paddingRight: styles.monthRightPadding, }, }, }} @@ -539,7 +538,7 @@ export function IncomeCategoryMonth({ name="received" width="flex" style={{ - paddingRight: MONTH_RIGHT_PADDING, + paddingRight: styles.monthRightPadding, textAlign: 'right', ...(isLast && { borderBottomWidth: 0 }), }} diff --git a/packages/desktop-client/src/components/budget/util.js b/packages/desktop-client/src/components/budget/util.js index 9fed886012b..6a1c52b6817 100644 --- a/packages/desktop-client/src/components/budget/util.js +++ b/packages/desktop-client/src/components/budget/util.js @@ -1,4 +1,4 @@ -import { styles, colors } from '../../style'; +import { styles, theme } from '../../style'; export function addToBeBudgetedGroup(groups) { return [ @@ -20,7 +20,7 @@ export function separateGroups(categoryGroups) { export function makeAmountGrey(value) { return value === 0 || value === '0' || value === '' - ? { color: colors.n10 } + ? { color: theme.altMenuItemText } : null; } @@ -31,13 +31,39 @@ export function makeAmountStyle(value) { } if (value < 0) { - return { color: colors.r4 }; + return { color: theme.errorText }; } } +export function makeAmountStyleGoal(value, goal) { + const greyed = makeAmountGrey(value); + if (greyed) { + return greyed; + } + + if (goal) { + if ( goal>=0 ) { + if(value( marginLeft: 5, marginRight: 5, borderRadius: 6, - backgroundColor: 'white', - borderColor: colors.p3, + backgroundColor: theme.cardBackground, + borderColor: theme.cardBorder, boxShadow: '0 1px 2px #9594A8', ...props.style, }} diff --git a/packages/desktop-client/src/components/common/ExternalLink.tsx b/packages/desktop-client/src/components/common/ExternalLink.tsx index e4fa656b5c7..6c37ea5825a 100644 --- a/packages/desktop-client/src/components/common/ExternalLink.tsx +++ b/packages/desktop-client/src/components/common/ExternalLink.tsx @@ -1,10 +1,10 @@ import React, { type ReactNode, forwardRef } from 'react'; -import { colors } from '../../style'; +import { theme } from '../../style'; let externalLinkColors = { - purple: colors.p4, - blue: colors.b4, + purple: theme.pageTextPositive, + blue: theme.pageTextLink, muted: 'inherit', }; type ExternalLinkProps = { diff --git a/packages/desktop-client/src/components/common/Label.tsx b/packages/desktop-client/src/components/common/Label.tsx index 85ef99ce403..a540214a53e 100644 --- a/packages/desktop-client/src/components/common/Label.tsx +++ b/packages/desktop-client/src/components/common/Label.tsx @@ -1,6 +1,6 @@ import { type ReactNode } from 'react'; -import { type CSSProperties, colors, styles } from '../../style'; +import { type CSSProperties, theme, styles } from '../../style'; import Text from './Text'; @@ -14,7 +14,7 @@ export default function Label({ title, style }: LabelProps) { Please wait... - The window should close automatically. If nothing happend you can + The window should close automatically. If nothing happened you can close this window or tab. diff --git a/packages/desktop-client/src/components/mobile/MobileForms.js b/packages/desktop-client/src/components/mobile/MobileForms.js index 4114b2571fc..21ebbc657a3 100644 --- a/packages/desktop-client/src/components/mobile/MobileForms.js +++ b/packages/desktop-client/src/components/mobile/MobileForms.js @@ -2,13 +2,12 @@ import { forwardRef } from 'react'; import { css } from 'glamor'; -import { theme } from '../../style'; +import { theme, styles } from '../../style'; import Button from '../common/Button'; import Input from '../common/Input'; import Text from '../common/Text'; import View from '../common/View'; -export const EDITING_PADDING = 12; const FIELD_HEIGHT = 40; export function FieldLabel({ title, flush, style }) { @@ -19,7 +18,7 @@ export function FieldLabel({ title, flush, style }) { marginTop: flush ? 0 : 25, fontSize: 13, color: theme.tableRowHeaderText, - paddingLeft: EDITING_PADDING, + paddingLeft: styles.mobileEditingPadding, textTransform: 'uppercase', userSelect: 'none', ...style, @@ -36,7 +35,7 @@ const valueStyle = { marginLeft: -1, marginRight: -1, height: FIELD_HEIGHT, - paddingHorizontal: EDITING_PADDING, + paddingHorizontal: styles.mobileEditingPadding, }; export const InputField = forwardRef(function InputField( @@ -119,7 +118,7 @@ export function BooleanField({ checked, onUpdate, style }) { onChange={e => onUpdate(e.target.checked)} className={`${css([ { - marginInline: EDITING_PADDING, + marginInline: styles.mobileEditingPadding, }, style, ])}`} diff --git a/packages/desktop-client/src/components/modals/BudgetSummary.js b/packages/desktop-client/src/components/modals/BudgetSummary.js index 3adf6022358..d4f3a82cba6 100644 --- a/packages/desktop-client/src/components/modals/BudgetSummary.js +++ b/packages/desktop-client/src/components/modals/BudgetSummary.js @@ -3,7 +3,7 @@ import React from 'react'; import { rolloverBudget } from 'loot-core/src/client/queries'; import * as monthUtils from 'loot-core/src/shared/months'; -import { colors, styles } from '../../style'; +import { theme, styles } from '../../style'; import Button from '../common/Button'; import Modal from '../common/Modal'; import Text from '../common/Text'; @@ -26,7 +26,7 @@ function ToBudget({ toBudget }) { ...styles.text, fontWeight: '600', fontSize: 22, - color: budgetAmount < 0 ? colors.r4 : colors.n1, + color: budgetAmount < 0 ? theme.errorText : theme.formInputText, }} > {format(budgetAmount, 'financial')} @@ -90,7 +90,6 @@ function BudgetSummary({ month, modalProps }) { For Next Month - {amount >= 0 ? '+' : ''} {integerToCurrency(amount)} diff --git a/packages/desktop-client/src/components/reports/DateRange.js b/packages/desktop-client/src/components/reports/DateRange.js index 927d5784ee4..2e2ba1234e5 100644 --- a/packages/desktop-client/src/components/reports/DateRange.js +++ b/packages/desktop-client/src/components/reports/DateRange.js @@ -2,7 +2,7 @@ import React from 'react'; import * as d from 'date-fns'; -import { colors } from '../../style'; +import { theme } from '../../style'; import Block from '../common/Block'; function DateRange({ start, end }) { @@ -26,7 +26,7 @@ function DateRange({ start, end }) { content = d.format(end, 'MMMM yyyy'); } - return {content}; + return {content}; } export default DateRange; diff --git a/packages/desktop-client/src/components/reports/Header.js b/packages/desktop-client/src/components/reports/Header.js index 2973e17d40a..dca96e47e9b 100644 --- a/packages/desktop-client/src/components/reports/Header.js +++ b/packages/desktop-client/src/components/reports/Header.js @@ -97,7 +97,6 @@ function Header({ }} > onChangeDates(...validateEnd(allMonths, start, newValue)) } diff --git a/packages/desktop-client/src/components/reports/NetWorth.js b/packages/desktop-client/src/components/reports/NetWorth.js index 294e3b8c083..5c9a8acbe6c 100644 --- a/packages/desktop-client/src/components/reports/NetWorth.js +++ b/packages/desktop-client/src/components/reports/NetWorth.js @@ -8,7 +8,7 @@ import * as monthUtils from 'loot-core/src/shared/months'; import { integerToCurrency } from 'loot-core/src/shared/util'; import useFilters from '../../hooks/useFilters'; -import { styles } from '../../style'; +import { theme, styles } from '../../style'; import Paragraph from '../common/Paragraph'; import View from '../common/View'; import PrivacyFilter from '../PrivacyFilter'; @@ -101,7 +101,7 @@ export default function NetWorth() { @@ -181,7 +181,7 @@ function CashFlowCard() { @@ -192,10 +192,10 @@ function CashFlowCard() { {(width, height, portalHost) => ( ), labelPosition: 'right', - fill: theme.colors.red, }, ]} labels={d => d.premadeLabel} diff --git a/packages/desktop-client/src/components/reports/Tooltip.js b/packages/desktop-client/src/components/reports/Tooltip.js index 966e2233a51..4ee6b07e744 100644 --- a/packages/desktop-client/src/components/reports/Tooltip.js +++ b/packages/desktop-client/src/components/reports/Tooltip.js @@ -4,7 +4,7 @@ import ReactDOM from 'react-dom'; import { css, before } from 'glamor'; import { VictoryTooltip } from 'victory'; -import { colors } from '../../style'; +import { theme } from '../../style'; class Tooltip extends Component { static defaultEvents = VictoryTooltip.defaultEvents; @@ -57,8 +57,8 @@ class Tooltip extends Component { borderRadius: 2, boxShadow: light ? 'none' : '0 1px 6px rgba(0, 0, 0, .20)', // TODO: Transparent background - backgroundColor: light ? 'transparent' : colors.n1, - color: light ? 'inherit' : 'white', + backgroundColor: light ? 'transparent' : theme.alt2MenuBackground, + color: light ? 'inherit' : theme.alt2MenuItemText, padding: 10, }, !light && @@ -68,7 +68,7 @@ class Tooltip extends Component { borderTop: '7px solid transparent', borderBottom: '7px solid transparent', [position === 'right' ? 'borderRight' : 'borderLeft']: - '7px solid ' + colors.n1, + '7px solid ' + theme.alt2MenuBackground, [position === 'right' ? 'left' : 'right']: -6, top: 'calc(50% - 7px)', // eslint-disable-next-line rulesdir/typography diff --git a/packages/desktop-client/src/components/reports/chart-theme.js b/packages/desktop-client/src/components/reports/chart-theme.js index fb30df44a4a..b8e1c2bd9ef 100644 --- a/packages/desktop-client/src/components/reports/chart-theme.js +++ b/packages/desktop-client/src/components/reports/chart-theme.js @@ -1,4 +1,4 @@ -import { colors } from '../../style'; +import { theme } from '../../style'; let colorFades = { blueFadeStart: 'rgba(229, 245, 255, 1)', @@ -18,7 +18,7 @@ const baseLabelStyles = { fontFamily: sansSerif, fontSize, letterSpacing, - fill: colors.n1, + fill: theme.reportsLabel, stroke: 'transparent', }; @@ -41,17 +41,17 @@ const axisBaseStyles = { tickLabels: baseLabelStyles, }; -const theme = { +export const chartTheme = { colors: { ...colorFades, - red: colors.r7, - blue: colors.b6, + red: theme.reportsRed, + blue: theme.reportsBlue, }, area: { style: { labels: baseLabelStyles, data: { - stroke: colors.b6, + stroke: theme.reportsBlue, strokeWidth: 2, strokeLinejoin: 'round', strokeLinecap: 'round', @@ -82,7 +82,7 @@ const theme = { bar: { style: { labels: baseLabelStyles, - data: { fill: colors.b6, stroke: 'none' }, + data: { fill: theme.reportsBlue, stroke: 'none' }, }, }, line: { @@ -90,7 +90,7 @@ const theme = { labels: baseLabelStyles, data: { fill: 'none', - stroke: colors.b6, + stroke: theme.reportsBlue, strokeWidth: 2, strokeLinejoin: 'round', strokeLinecap: 'round', @@ -111,4 +111,3 @@ const theme = { }, }, }; -export default theme; diff --git a/packages/desktop-client/src/components/reports/graphs/CashFlowGraph.tsx b/packages/desktop-client/src/components/reports/graphs/CashFlowGraph.tsx index a83abe5252f..51263a18a8e 100644 --- a/packages/desktop-client/src/components/reports/graphs/CashFlowGraph.tsx +++ b/packages/desktop-client/src/components/reports/graphs/CashFlowGraph.tsx @@ -10,8 +10,8 @@ import { VictoryGroup, } from 'victory'; -import { colors } from '../../../style'; -import theme from '../chart-theme'; +import { theme } from '../../../style'; +import { chartTheme } from '../chart-theme'; import Container from '../Container'; import Tooltip from '../Tooltip'; @@ -26,7 +26,7 @@ function CashFlowGraph({ graphData, isConcise }: CashFlowGraphProps) { graphData && ( - + } labels={x => x.premadeLabel} style={{ - data: { stroke: colors.n5 }, + data: { stroke: theme.altpageTextSubdued }, }} /> ( diff --git a/packages/desktop-client/src/components/reports/graphs/NetWorthGraph.tsx b/packages/desktop-client/src/components/reports/graphs/NetWorthGraph.tsx index ff8b4687def..5c58527bd1a 100644 --- a/packages/desktop-client/src/components/reports/graphs/NetWorthGraph.tsx +++ b/packages/desktop-client/src/components/reports/graphs/NetWorthGraph.tsx @@ -11,7 +11,7 @@ import { } from 'victory'; import { type CSSProperties } from '../../../style'; -import theme from '../chart-theme'; +import { chartTheme } from '../chart-theme'; import Container from '../Container'; import Tooltip from '../Tooltip'; @@ -36,7 +36,7 @@ function NetWorthGraph({ style, graphData, compact }: NetWorthGraphProps) { graphData && ( {!compact && ( d.format(x, "MMM ''yy")} tickValues={graphData.data.map(item => item.x)} diff --git a/packages/desktop-client/src/components/reports/graphs/common.tsx b/packages/desktop-client/src/components/reports/graphs/common.tsx index c88ccd2327b..1c983ebdc5a 100644 --- a/packages/desktop-client/src/components/reports/graphs/common.tsx +++ b/packages/desktop-client/src/components/reports/graphs/common.tsx @@ -1,6 +1,6 @@ import * as d from 'date-fns'; -import theme from '../chart-theme'; +import { chartTheme } from '../chart-theme'; type AreaProps = { start: string; @@ -47,8 +47,8 @@ export function Area({ start, end, scale, range }: AreaProps) { x2={0} y2={zero} > - - + + - - + + diff --git a/packages/desktop-client/src/components/schedules/EditSchedule.js b/packages/desktop-client/src/components/schedules/EditSchedule.js index 506c34eb642..132362b606e 100644 --- a/packages/desktop-client/src/components/schedules/EditSchedule.js +++ b/packages/desktop-client/src/components/schedules/EditSchedule.js @@ -527,8 +527,8 @@ export default function ScheduleDetails({ modalProps, actions, id }) { - - + + {repeats ? ( - + {!adding && state.schedule.rule && ( - + {state.isCustom && ( )} - + diff --git a/packages/desktop-client/src/components/settings/Encryption.tsx b/packages/desktop-client/src/components/settings/Encryption.tsx index 3eed3bc9548..f67beb47032 100644 --- a/packages/desktop-client/src/components/settings/Encryption.tsx +++ b/packages/desktop-client/src/components/settings/Encryption.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { useActions } from '../../hooks/useActions'; -import { colors } from '../../style'; +import { theme } from '../../style'; import Button from '../common/Button'; import ExternalLink from '../common/ExternalLink'; import Text from '../common/Text'; @@ -26,7 +26,7 @@ export default function EncryptionSettings() { primaryAction={} > - + End-to-end Encryption is turned on. {' '} Your data is encrypted with a key that only you have before sending it diff --git a/packages/desktop-client/src/components/settings/Experimental.tsx b/packages/desktop-client/src/components/settings/Experimental.tsx index 37ea3ac5d89..2a4a5646ee3 100644 --- a/packages/desktop-client/src/components/settings/Experimental.tsx +++ b/packages/desktop-client/src/components/settings/Experimental.tsx @@ -5,7 +5,7 @@ import type { FeatureFlag } from 'loot-core/src/types/prefs'; import { useActions } from '../../hooks/useActions'; import useFeatureFlag from '../../hooks/useFeatureFlag'; -import { colors, useTheme } from '../../style'; +import { theme, useTheme } from '../../style'; import LinkButton from '../common/LinkButton'; import Text from '../common/Text'; import View from '../common/View'; @@ -41,10 +41,19 @@ function FeatureToggle({ }} disabled={disableToggle} /> - + {children} {disableToggle && ( - {error} + + {error} + )} @@ -99,7 +108,6 @@ export default function ExperimentalFeatures() { Goal templates - Privacy mode Experimental OFX parser @@ -112,7 +120,7 @@ export default function ExperimentalFeatures() { style={{ flexShrink: 0, alignSelf: 'flex-start', - color: colors.p4, + color: theme.pageTextPositive, }} > I understand the risks, show experimental features diff --git a/packages/desktop-client/src/components/settings/FixSplits.tsx b/packages/desktop-client/src/components/settings/FixSplits.tsx index 936ded3f718..7b3ca97e280 100644 --- a/packages/desktop-client/src/components/settings/FixSplits.tsx +++ b/packages/desktop-client/src/components/settings/FixSplits.tsx @@ -3,7 +3,7 @@ import React, { useState } from 'react'; import { send } from 'loot-core/src/platform/client/fetch'; import { type Handlers } from 'loot-core/src/types/handlers'; -import { colors } from '../../style'; +import { theme } from '../../style'; import { ButtonWithLoading } from '../common/Button'; import Paragraph from '../common/Paragraph'; import Text from '../common/Text'; @@ -39,7 +39,7 @@ function renderResults(results: Results) { return ( { { style={{ flexShrink: 0, alignSelf: 'flex-start', - color: colors.p4, + color: theme.pageTextPositive, marginBottom: 25, }} > diff --git a/packages/desktop-client/src/components/settings/index.tsx b/packages/desktop-client/src/components/settings/index.tsx index ab6e8884a53..2ac16726a9b 100644 --- a/packages/desktop-client/src/components/settings/index.tsx +++ b/packages/desktop-client/src/components/settings/index.tsx @@ -11,7 +11,7 @@ import useFeatureFlag from '../../hooks/useFeatureFlag'; import useLatestVersion, { useIsOutdated } from '../../hooks/useLatestVersion'; import { useSetThemeColor } from '../../hooks/useSetThemeColor'; import { useResponsive } from '../../ResponsiveProvider'; -import { colors, theme } from '../../style'; +import { theme } from '../../style'; import tokens from '../../tokens'; import Button from '../common/Button'; import ExternalLink from '../common/ExternalLink'; @@ -67,7 +67,7 @@ function About() { New version available: {latestVersion} ) : ( - + You’re up to date! )} @@ -100,7 +100,7 @@ function AdvancedAbout() { Budget ID: {budgetId} - + Sync ID: {groupId || '(none)'} {/* low priority todo: eliminate some or all of these, or decide when/if to show them */} @@ -146,8 +146,8 @@ export default function Settings() { titleStyle={ isNarrowWidth ? { - backgroundColor: colors.n11, - color: colors.n1, + backgroundColor: theme.menuItemBackground, + color: theme.menuItemText, } : undefined } @@ -160,7 +160,11 @@ export default function Settings() { {/* The only spot to close a budget on mobile */} - + diff --git a/packages/desktop-client/src/components/sidebar/Account.tsx b/packages/desktop-client/src/components/sidebar/Account.tsx index f836dea8301..e3b0539eb35 100644 --- a/packages/desktop-client/src/components/sidebar/Account.tsx +++ b/packages/desktop-client/src/components/sidebar/Account.tsx @@ -125,7 +125,7 @@ function Account({ height: 5, borderRadius: 5, backgroundColor: failed - ? theme.errorBackground + ? theme.sidebarItemBackgroundFailed : theme.sidebarItemBackgroundPositive, marginLeft: 2, transition: 'transform .3s', diff --git a/packages/desktop-client/src/components/spreadsheet/CellValue.tsx b/packages/desktop-client/src/components/spreadsheet/CellValue.tsx index 969003ba5a0..63cee3bb134 100644 --- a/packages/desktop-client/src/components/spreadsheet/CellValue.tsx +++ b/packages/desktop-client/src/components/spreadsheet/CellValue.tsx @@ -15,16 +15,18 @@ import { type Binding } from '.'; type CellValueProps = { binding: string | Binding; + goalValue?: string | Binding; type?: string; formatter?: (value) => ReactNode; style?: CSSProperties; - getStyle?: (value) => CSSProperties; + getStyle?: (value,modifier?) => CSSProperties; privacyFilter?: ConditionalPrivacyFilterProps['privacyFilter']; ['data-testid']?: string; }; function CellValue({ binding, + goalValue, type, formatter, style, @@ -51,7 +53,7 @@ function CellValue({ style={{ ...(type === 'financial' && styles.tnum), ...style, - ...(getStyle && getStyle(sheetValue)), + ...(getStyle && getStyle(sheetValue, goalValue)), }} data-testid={testId || fullSheetName} data-cellname={fullSheetName} diff --git a/packages/desktop-client/src/components/transactions/MobileTransaction.js b/packages/desktop-client/src/components/transactions/MobileTransaction.js index e5d7b45b352..893cbf6cdbe 100644 --- a/packages/desktop-client/src/components/transactions/MobileTransaction.js +++ b/packages/desktop-client/src/components/transactions/MobileTransaction.js @@ -52,7 +52,7 @@ import SvgTrash from '../../icons/v1/Trash'; import ArrowsSynchronize from '../../icons/v2/ArrowsSynchronize'; import CheckCircle1 from '../../icons/v2/CheckCircle1'; import SvgPencilWriteAlternate from '../../icons/v2/PencilWriteAlternate'; -import { styles, colors, theme } from '../../style'; +import { styles, theme } from '../../style'; import Button from '../common/Button'; import Text from '../common/Text'; import TextOneLine from '../common/TextOneLine'; @@ -63,7 +63,6 @@ import { TapField, InputField, BooleanField, - EDITING_PADDING, } from '../mobile/MobileForms'; const zIndices = { SECTION_HEADING: 10 }; @@ -138,12 +137,14 @@ export function DateHeader({ date }) { - + {monthUtils.format(date, 'MMMM dd, yyyy')} @@ -155,13 +156,13 @@ function Status({ status }) { switch (status) { case 'missed': - color = colors.r3; + color = theme.alt3ErrorText; break; case 'due': - color = colors.y3; + color = theme.alt2WarningText; break; case 'upcoming': - color = colors.n4; + color = theme.alt2TableText; break; default: } @@ -345,13 +346,13 @@ class TransactionEditInner extends PureComponent { style={{ margin: 10, marginTop: 3, - backgroundColor: colors.n11, + backgroundColor: theme.tableHeaderBackground, flex: 1, borderRadius: 4, // This shadow make the card "pop" off of the screen below // it - shadowColor: colors.n3, + shadowColor: theme.cardShadow, shadowOffset: { width: 0, height: 0 }, shadowRadius: 4, shadowOpacity: 1, @@ -368,8 +369,8 @@ class TransactionEditInner extends PureComponent { Back @@ -428,7 +433,6 @@ class TransactionEditInner extends PureComponent { automaticallyAdjustContentInsets={false} keyboardShouldPersistTaps="always" style={{ - backgroundColor: colors.n11, flexGrow: 1, overflow: 'hidden', }} @@ -517,7 +521,7 @@ class TransactionEditInner extends PureComponent { data-testid="category-field" /> ) : ( - + Split transaction editing is not supported on mobile at this time. @@ -592,8 +596,8 @@ class TransactionEditInner extends PureComponent { style={{ borderWidth: 0, paddingVertical: 5, - marginLeft: EDITING_PADDING, - marginRight: EDITING_PADDING, + marginLeft: styles.mobileEditingPadding, + marginRight: styles.mobileEditingPadding, marginTop: 20, marginBottom: 15, backgroundColor: 'transparent', @@ -603,11 +607,11 @@ class TransactionEditInner extends PureComponent { {adding ? (