Skip to content

Commit

Permalink
Merge branch 'master' into sidebarDark
Browse files Browse the repository at this point in the history
  • Loading branch information
carkom authored Nov 9, 2023
2 parents 955ad65 + 199a9f8 commit b14432f
Show file tree
Hide file tree
Showing 17 changed files with 294 additions and 129 deletions.
1 change: 1 addition & 0 deletions packages/desktop-client/src/components/accounts/Account.js
Original file line number Diff line number Diff line change
Expand Up @@ -1201,6 +1201,7 @@ class AccountInternal extends PureComponent {
items={allTransactions}
fetchAllIds={this.fetchAllIds}
registerDispatch={dispatch => (this.dispatchSelected = dispatch)}
selectAllFilter={item => !item._unmatched && !item.is_parent}
>
<View style={styles.page}>
<AccountHeader
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { type ComponentProps } from 'react';

import useFeatureFlag from '../../hooks/useFeatureFlag';
import ArrowThinRight from '../../icons/v1/ArrowThinRight';
import { type CSSProperties } from '../../style';
import View from '../common/View';
Expand All @@ -11,6 +12,8 @@ import { makeAmountStyle } from './util';
type BalanceWithCarryoverProps = {
carryover: ComponentProps<typeof CellValue>['binding'];
balance: ComponentProps<typeof CellValue>['binding'];
goal?: ComponentProps<typeof CellValue>['binding'];
budgeted?: ComponentProps<typeof CellValue>['binding'];
disabled?: boolean;
style?: CSSProperties;
balanceStyle?: CSSProperties;
Expand All @@ -19,20 +22,30 @@ type BalanceWithCarryoverProps = {
export default function BalanceWithCarryover({
carryover,
balance,
goal,
budgeted,
disabled,
style,
balanceStyle,
carryoverStyle,
}: BalanceWithCarryoverProps) {
let carryoverValue = useSheetValue(carryover);
let balanceValue = useSheetValue(balance);

let goalValue = useSheetValue(goal);
let budgetedValue = useSheetValue(budgeted);
let isGoalTemplatesEnabled = useFeatureFlag('goalTemplatesEnabled');
return (
<View style={style}>
<CellValue
binding={balance}
type="financial"
getStyle={makeAmountStyle}
getStyle={value =>
makeAmountStyle(
value,
isGoalTemplatesEnabled ? goalValue : null,
budgetedValue,
)
}
style={{
textAlign: 'right',
...(!disabled && {
Expand All @@ -58,7 +71,7 @@ export default function BalanceWithCarryover({
<ArrowThinRight
width={7}
height={7}
style={makeAmountStyle(balanceValue)}
style={makeAmountStyle(balanceValue, goalValue, budgetedValue)}
/>
</View>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,8 @@ const ExpenseCategory = memo(function ExpenseCategory({
<BalanceWithCarryover
carryover={rolloverBudget.catCarryover(category.id)}
balance={rolloverBudget.catBalance(category.id)}
goal={reportBudget.catGoal(category.id)}
budgeted={reportBudget.catBudgeted(category.id)}
balanceStyle={{
...styles.smallText,
...styles.underlinedText,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -369,6 +369,8 @@ export const CategoryMonth = memo(function CategoryMonth({
disabled={category.is_income}
carryover={reportBudget.catCarryover(category.id)}
balance={reportBudget.catBalance(category.id)}
goal={reportBudget.catGoal(category.id)}
budgeted={reportBudget.catBudgeted(category.id)}
/>
</span>
{balanceTooltip.isOpen && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ export const ExpenseCategoryMonth = memo(function ExpenseCategoryMonth({
<BalanceWithCarryover
carryover={rolloverBudget.catCarryover(category.id)}
balance={rolloverBudget.catBalance(category.id)}
goal={rolloverBudget.catGoal(category.id)}
budgeted={rolloverBudget.catBudgeted(category.id)}
/>
</span>
{balanceTooltip.isOpen && (
Expand Down
23 changes: 17 additions & 6 deletions packages/desktop-client/src/components/budget/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,26 @@ export function makeAmountGrey(value: number | string) {
: null;
}

export function makeAmountStyle(value: number) {
const greyed = makeAmountGrey(value);
if (greyed) {
return greyed;
}

export function makeAmountStyle(
value: number,
goalValue?: number,
budgetedValue?: number,
) {
if (value < 0) {
return { color: theme.errorText };
}

if (goalValue == null) {
const greyed = makeAmountGrey(value);
if (greyed) {
return greyed;
}
} else {
if (budgetedValue < goalValue) {
return { color: theme.warningText };
}
return { color: theme.noticeText };
}
}

export function makeAmountFullStyle(value: number) {
Expand Down
23 changes: 21 additions & 2 deletions packages/desktop-client/src/hooks/useSelected.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export default function useSelected<T extends Item>(
name: string,
items: T[],
initialSelectedIds: string[],
selectAllFilter?: (T) => boolean,
) {
let [state, dispatch] = useReducer(
(state: State, action: Actions) => {
Expand Down Expand Up @@ -128,9 +129,20 @@ export default function useSelected<T extends Item>(
return { ...state, selectedItems: new Set<string>() };

case 'select-all':
let selectedItems: string[] = [];
if (action.ids && items && selectAllFilter) {
const idsToInclude = new Set(
items.filter(selectAllFilter).map(item => item.id),
);
selectedItems = action.ids.filter(id => idsToInclude.has(id));
} else if (items && selectAllFilter) {
selectedItems = items.filter(selectAllFilter).map(item => item.id);
} else {
selectedItems = action.ids || items.map(item => item.id);
}
return {
...state,
selectedItems: new Set(action.ids || items.map(item => item.id)),
selectedItems: new Set(selectedItems),
selectedRange:
action.ids && action.ids.length === 1
? { start: action.ids[0], end: null }
Expand Down Expand Up @@ -300,6 +312,7 @@ type SelectedProviderWithItemsProps<T extends Item> = {
initialSelectedIds: string[];
fetchAllIds: () => Promise<string[]>;
registerDispatch?: (dispatch: Dispatch<Actions>) => void;
selectAllFilter?: (T) => boolean;
children: ReactElement;
};

Expand All @@ -311,9 +324,15 @@ export function SelectedProviderWithItems<T extends Item>({
initialSelectedIds,
fetchAllIds,
registerDispatch,
selectAllFilter,
children,
}: SelectedProviderWithItemsProps<T>) {
let selected = useSelected<T>(name, items, initialSelectedIds);
let selected = useSelected<T>(
name,
items,
initialSelectedIds,
selectAllFilter,
);

useEffect(() => {
registerDispatch?.(selected.dispatch);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BEGIN TRANSACTION;

ALTER TABLE zero_budgets ADD column goal INTEGER DEFAULT null;
ALTER TABLE reflect_budgets ADD column goal INTEGER DEFAULT null;
ALTER TABLE categories ADD column goal_def TEXT DEFAULT null;

COMMIT;
14 changes: 10 additions & 4 deletions packages/loot-core/src/client/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,17 @@ export function getAccountFilter(accountId, field = 'account') {
if (accountId) {
if (accountId === 'budgeted') {
return {
[`${field}.offbudget`]: false,
[`${field}.closed`]: false,
$and: [
{ [`${field}.offbudget`]: false },
{ [`${field}.closed`]: false },
],
};
} else if (accountId === 'offbudget') {
return {
[`${field}.offbudget`]: true,
[`${field}.closed`]: false,
$and: [
{ [`${field}.offbudget`]: true },
{ [`${field}.closed`]: false },
],
};
} else if (accountId === 'uncategorized') {
return {
Expand Down Expand Up @@ -173,6 +177,7 @@ export const rolloverBudget = {
catSumAmount: id => `sum-amount-${id}`,
catBalance: id => `leftover-${id}`,
catCarryover: id => `carryover-${id}`,
catGoal: id => `goal-${id}`,
};

export const reportBudget = {
Expand All @@ -195,4 +200,5 @@ export const reportBudget = {
catSumAmount: id => `sum-amount-${id}`,
catBalance: id => `leftover-${id}`,
catCarryover: id => `carryover-${id}`,
catGoal: id => `goal-${id}`,
};
18 changes: 18 additions & 0 deletions packages/loot-core/src/server/budget/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,24 @@ export function setBudget({
});
}

export function setGoal({ month, category, goal }): Promise<void> {
const table = getBudgetTable();
let existing = db.firstSync(
`SELECT id FROM ${table} WHERE month = ? AND category = ?`,
[dbMonth(month), category],
);
if (existing) {
return db.update(table, {
id: existing.id,
goal: goal,
});
}
return db.insert(table, {
id: month,
goal: goal,
});
}

export function setBuffer(month: string, amount: unknown): Promise<void> {
let existing = db.firstSync(
`SELECT id FROM zero_budget_months WHERE id = ?`,
Expand Down
1 change: 1 addition & 0 deletions packages/loot-core/src/server/budget/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ function handleBudgetChange(budget) {
`${sheetName}!carryover-${budget.category}`,
budget.carryover === 1 ? true : false,
);
sheet.get().set(`${sheetName}!goal-${budget.category}`, budget.goal);
}
}

Expand Down
Loading

0 comments on commit b14432f

Please sign in to comment.