Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ (dashboards) ability to save net-worth widget details #3364

Merged
merged 16 commits into from
Sep 9, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 43 additions & 29 deletions packages/desktop-client/src/components/common/Button2.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { forwardRef, type ComponentPropsWithoutRef } from 'react';
import React, {
forwardRef,
type ComponentPropsWithoutRef,
type ComponentType,
type ReactNode,
type SVGProps,
} from 'react';
import {
type ButtonRenderProps as ReactAriaButtonRenderProps,
Button as ReactAriaButton,
Expand Down Expand Up @@ -121,13 +127,21 @@ const _getActiveStyles = (
type ButtonProps = ComponentPropsWithoutRef<typeof ReactAriaButton> & {
variant?: ButtonVariant;
bounce?: boolean;
Icon?: ComponentType<SVGProps<SVGElement>>;
children?: ReactNode;
};

type ButtonVariant = 'normal' | 'primary' | 'bare' | 'menu' | 'menuSelected';

export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
(props, ref) => {
const { children, variant = 'normal', bounce = true, ...restProps } = props;
const {
children,
variant = 'normal',
bounce = true,
Icon,
...restProps
} = props;

const variantWithDisabled: ButtonVariant | `${ButtonVariant}Disabled` =
props.isDisabled ? `${variant}Disabled` : variant;
Expand Down Expand Up @@ -161,6 +175,7 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
...styles.smallText,
...(renderProps.isDisabled ? {} : { ':hover': hoveredStyle }),
...(renderProps.isDisabled ? {} : { ':active': activeStyle }),
...(Icon ? { paddingLeft: 0 } : {}),
}),
);

Expand All @@ -177,6 +192,9 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
`${renderProps.defaultClassName} ${defaultButtonClassName(renderProps)} ${buttonClassName(renderProps)}`
}
>
{Icon && (
<Icon style={{ height: 15, paddingLeft: 5, paddingRight: 3 }} />
)}
{children}
</ReactAriaButton>
);
Expand All @@ -203,34 +221,30 @@ export const ButtonWithLoading = forwardRef<
...(typeof style === 'function' ? style(buttonRenderProps) : style),
})}
>
{renderProps => (
<>
{isLoading && (
<View
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center',
}}
>
<AnimatedLoading style={{ width: 20, height: 20 }} />
</View>
)}
<View
style={{
opacity: isLoading ? 0 : 1,
flexDirection: 'row',
alignItems: 'center',
}}
>
{typeof children === 'function' ? children(renderProps) : children}
</View>
</>
{isLoading && (
<View
style={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
alignItems: 'center',
justifyContent: 'center',
}}
>
<AnimatedLoading style={{ width: 20, height: 20 }} />
</View>
)}
<View
style={{
opacity: isLoading ? 0 : 1,
flexDirection: 'row',
alignItems: 'center',
}}
>
{children}
</View>
</Button>
);
});
Expand Down
49 changes: 39 additions & 10 deletions packages/desktop-client/src/components/reports/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useLocation } from 'react-router-dom';

import * as monthUtils from 'loot-core/src/shared/months';

import { SvgPause, SvgPlay } from '../../icons/v1';
import { useResponsive } from '../../ResponsiveProvider';
import { Button } from '../common/Button2';
import { Select } from '../common/Select';
Expand All @@ -19,6 +20,7 @@ import {
export function Header({
start,
end,
mode,
show1Month,
allMonths,
onChangeDates,
Expand All @@ -28,7 +30,6 @@ export function Header({
onUpdateFilter,
onDeleteFilter,
onConditionsOpChange,
headerPrefixItems,
children,
}) {
const location = useLocation();
Expand All @@ -52,7 +53,21 @@ export function Header({
gap: 15,
}}
>
{headerPrefixItems}
{mode && (
<Button
variant={mode === 'static' ? 'normal' : 'primary'}
onPress={() =>
onChangeDates(
start,
end,
mode === 'static' ? 'sliding-window' : 'static',
)
}
Icon={mode === 'static' ? SvgPause : SvgPlay}
>
{mode === 'static' ? 'Paused' : 'Live'}
</Button>
)}

<View
style={{
Expand Down Expand Up @@ -90,15 +105,16 @@ export function Header({
options={allMonths.map(({ name, pretty }) => [name, pretty])}
buttonStyle={{ marginRight: 10 }}
/>
{filters && (
<FilterButton
compact={isNarrowWidth}
onApply={onApply}
type="accounts"
/>
)}
</View>

{filters && (
<FilterButton
compact={isNarrowWidth}
onApply={onApply}
type="accounts"
/>
)}

<View
style={{
flexDirection: 'row',
Expand Down Expand Up @@ -144,7 +160,20 @@ export function Header({
All Time
</Button>
</View>
{children || <View style={{ flex: 1 }} />}

{children ? (
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
{children}
</View>
) : (
<View style={{ flex: 1 }} />
)}
</View>
)}
{filters && filters.length > 0 && (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,7 @@ export function Overview() {
<div key={item.i}>
{item.type === 'net-worth-card' ? (
<NetWorthCard
widgetId={item.i}
isEditing={isEditing}
accounts={accounts}
meta={item.meta}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export function ReportRouter() {
<Routes>
<Route path="/" element={<Overview />} />
<Route path="/net-worth" element={<NetWorth />} />
<Route path="/net-worth/:id" element={<NetWorth />} />
<Route path="/cash-flow" element={<CashFlow />} />
<Route path="/custom" element={<CustomReport />} />
<Route path="/spending" element={<Spending />} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import React, { useMemo, useRef, useState, type ComponentProps } from 'react';
import * as monthUtils from 'loot-core/src/shared/months';
import { type CategoryEntity } from 'loot-core/types/models/category';
import { type CategoryGroupEntity } from 'loot-core/types/models/category-group';
import { type TimeFrame } from 'loot-core/types/models/dashboard';
import { type CustomReportEntity } from 'loot-core/types/models/reports';
import { type SyncedPrefs } from 'loot-core/types/prefs';

Expand Down Expand Up @@ -44,7 +45,11 @@ type ReportSidebarProps = {
setShowUncategorized: (value: boolean) => void;
setIncludeCurrentInterval: (value: boolean) => void;
setSelectedCategories: (value: CategoryEntity[]) => void;
onChangeDates: (dateStart: string, dateEnd: string) => void;
onChangeDates: (
dateStart: string,
dateEnd: string,
mode: TimeFrame['mode'],
) => void;
onReportChange: ({
savedReport,
type,
Expand Down Expand Up @@ -420,6 +425,7 @@ export function ReportSidebar({
onChangeDates(
customReportItems.startDate,
customReportItems.endDate,
'static',
);
}}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as monthUtils from 'loot-core/src/shared/months';
import { type TimeFrame } from 'loot-core/types/models';
import { type SyncedPrefs } from 'loot-core/types/prefs';

import { ReportOptions } from './ReportOptions';
Expand All @@ -9,7 +10,7 @@ export function getLiveRange(
earliestTransaction: string,
includeCurrentInterval: boolean,
firstDayOfWeekIdx?: SyncedPrefs['firstDayOfWeekIdx'],
): [string, string] {
): [string, string, TimeFrame['mode']] {
let dateStart = earliestTransaction;
let dateEnd = monthUtils.currentDay();
const rangeName = ReportOptions.dateRangeMap.get(cond);
Expand Down Expand Up @@ -50,5 +51,5 @@ export function getLiveRange(
}
}

return [dateStart, dateEnd];
return [dateStart, dateEnd, 'sliding-window'];
}
42 changes: 30 additions & 12 deletions packages/desktop-client/src/components/reports/reportRanges.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as monthUtils from 'loot-core/src/shared/months';
import { type TimeFrame } from 'loot-core/types/models';
import { type SyncedPrefs } from 'loot-core/types/prefs';

export function validateStart(
Expand All @@ -7,9 +8,9 @@ export function validateStart(
end: string,
interval?: string,
firstDayOfWeekIdx?: SyncedPrefs['firstDayOfWeekIdx'],
): [string, string] {
let addDays;
let dateStart;
): [string, string, TimeFrame['mode']] {
let addDays: number;
let dateStart: string;
switch (interval) {
case 'Monthly':
dateStart = start + '-01';
Expand Down Expand Up @@ -47,9 +48,9 @@ export function validateEnd(
end: string,
interval?: string,
firstDayOfWeekIdx?: SyncedPrefs['firstDayOfWeekIdx'],
): [string, string] {
let subDays;
let dateEnd;
): [string, string, TimeFrame['mode']] {
let subDays: number;
let dateEnd: string;
switch (interval) {
case 'Monthly':
dateEnd = monthUtils.getMonthEnd(end + '-01');
Expand Down Expand Up @@ -98,8 +99,8 @@ function boundedRange(
end: string,
interval?: string,
firstDayOfWeekIdx?: SyncedPrefs['firstDayOfWeekIdx'],
): [string, string] {
let latest;
): [string, string, 'static'] {
let latest: string;
switch (interval) {
case 'Daily':
latest = monthUtils.currentDay();
Expand All @@ -124,7 +125,7 @@ function boundedRange(
if (start < earliest) {
start = earliest;
}
return [start, end];
return [start, end, 'static'];
}

export function getSpecificRange(
Expand All @@ -150,16 +151,33 @@ export function getSpecificRange(
);
}

return [dateStart, dateEnd];
return [dateStart, dateEnd, 'static'];
}

export function getFullRange(start: string) {
const end = monthUtils.currentMonth();
return [start, end];
return [start, end, 'full'];
}

export function getLatestRange(offset: number) {
const end = monthUtils.currentMonth();
const start = monthUtils.subMonths(end, offset);
return [start, end];
return [start, end, 'sliding-window'];
}

export function calculateTimeRange(
{ start, end, mode }: TimeFrame = {
start: monthUtils.subMonths(monthUtils.currentMonth(), 5),
end: monthUtils.currentMonth(),
mode: 'sliding-window',
},
) {
if (mode === 'full') {
return getFullRange(start);
}
if (mode === 'sliding-window') {
return getLatestRange(monthUtils.differenceInCalendarMonths(end, start));
}

return [start, end, 'static'];
}
Original file line number Diff line number Diff line change
Expand Up @@ -134,19 +134,11 @@ export function CashFlow() {
onDeleteFilter={onDeleteFilter}
conditionsOp={conditionsOp}
onConditionsOpChange={onConditionsOpChange}
headerPrefixItems={undefined}
mode={undefined}
>
<View
style={{
flex: 1,
flexDirection: 'row',
justifyContent: 'flex-end',
}}
>
<Button onPress={() => setShowBalance(state => !state)}>
{showBalance ? 'Hide balance' : 'Show balance'}
</Button>
</View>
<Button onPress={() => setShowBalance(state => !state)}>
{showBalance ? 'Hide balance' : 'Show balance'}
</Button>
</Header>
<View
style={{
Expand Down
Loading
Loading