Skip to content

Commit

Permalink
Merge branch 'master' into matiss/upgrade-yarn
Browse files Browse the repository at this point in the history
  • Loading branch information
MatissJanis committed Nov 14, 2023
2 parents 4a27a66 + a399558 commit c88e9b9
Show file tree
Hide file tree
Showing 23 changed files with 740 additions and 29 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions packages/desktop-client/e2e/page-models/mobile-navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,17 @@ export class MobileNavigation {
}

async goToSettingsPage() {
await this.dragNavbarUp();

const link = this.page.getByRole('link', { name: 'Settings' });
await link.click();

return new SettingsPage(this.page);
}

async dragNavbarUp() {
await this.page
.getByRole('navigation')
.dragTo(this.page.getByTestId('budget-table'));
}
}
1 change: 1 addition & 0 deletions packages/desktop-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@types/react-router-dom": "^5.3.3",
"@types/uuid": "^9.0.2",
"@types/webpack-bundle-analyzer": "^4.6.0",
"@use-gesture/react": "^10.3.0",
"chokidar": "^3.5.3",
"cross-env": "^7.0.3",
"date-fns": "^2.29.3",
Expand Down
2 changes: 1 addition & 1 deletion packages/desktop-client/src/components/ScrollProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function ScrollProvider({ children }: ScrollProviderProps) {
setIsBottomReached(
e.target?.scrollHeight - e.target?.scrollTop <= e.target?.clientHeight,
);
}, 20);
}, 10);

window.addEventListener('scroll', listenToScroll, {
capture: true,
Expand Down
198 changes: 174 additions & 24 deletions packages/desktop-client/src/components/mobile/MobileNavTabs.tsx
Original file line number Diff line number Diff line change
@@ -1,53 +1,200 @@
import React, { type ComponentType, useMemo } from 'react';
import React, { type ComponentType, useEffect } from 'react';
import { NavLink } from 'react-router-dom';
import { useSpring, animated, config } from 'react-spring';

import { useDrag } from '@use-gesture/react';

import usePrevious from '../../hooks/usePrevious';
import Add from '../../icons/v1/Add';
import Cog from '../../icons/v1/Cog';
import PiggyBank from '../../icons/v1/PiggyBank';
import StoreFront from '../../icons/v1/StoreFront';
import Tuning from '../../icons/v1/Tuning';
import Wallet from '../../icons/v1/Wallet';
import Calendar from '../../icons/v2/Calendar';
import { useResponsive } from '../../ResponsiveProvider';
import { theme, styles } from '../../style';
import { theme, styles, type CSSProperties } from '../../style';
import View from '../common/View';
import { useScroll } from '../ScrollProvider';

const height = 70;
const ROW_HEIGHT = 70;
const COLUMN_COUNT = 3;

export default function MobileNavTabs() {
const { isNarrowWidth } = useResponsive();
const { scrollY, isBottomReached } = useScroll();
const { scrollY } = useScroll();

const navTabStyle = {
flex: `1 1 ${100 / COLUMN_COUNT}%`,
height: ROW_HEIGHT,
padding: 10,
};

const navTabs = [
{
name: 'Budget',
path: '/budget',
style: navTabStyle,
icon: Wallet,
},
{
name: 'Transaction',
path: '/transactions/new',
style: navTabStyle,
icon: Add,
},
{
name: 'Accounts',
path: '/accounts',
style: navTabStyle,
icon: PiggyBank,
},
{
name: 'Schedules (Soon)',
path: '/schedules/soon',
style: navTabStyle,
icon: Calendar,
},
{
name: 'Payees (Soon)',
path: '/payees/soon',
style: navTabStyle,
icon: StoreFront,
},
{
name: 'Rules (Soon)',
path: '/rules/soon',
style: navTabStyle,
icon: Tuning,
},
{
name: 'Settings',
path: '/settings',
style: navTabStyle,
icon: Cog,
},
].map(tab => <NavTab key={tab.path} {...tab} />);

const bufferTabsCount = COLUMN_COUNT - (navTabs.length % COLUMN_COUNT);
const bufferTabs = Array.from({ length: bufferTabsCount }).map((_, idx) => (
<div key={idx} style={navTabStyle} />
));

const totalHeight = ROW_HEIGHT * COLUMN_COUNT;
const openY = 0;
const closeY = totalHeight - ROW_HEIGHT;
const hiddenY = totalHeight;

const [{ y }, api] = useSpring(() => ({ y: totalHeight }));

const open = ({ canceled }) => {
// when cancel is true, it means that the user passed the upwards threshold
// so we change the spring config to create a nice wobbly effect
api.start({
y: openY,
immediate: false,
config: canceled ? config.wobbly : config.stiff,
});
};

const close = (velocity = 0) => {
api.start({
y: closeY,
immediate: false,
config: { ...config.stiff, velocity },
});
};

const hide = (velocity = 0) => {
api.start({
y: hiddenY,
immediate: false,
config: { ...config.stiff, velocity },
});
};

const previousScrollY = usePrevious(scrollY);

const isVisible = useMemo(
() =>
previousScrollY === undefined ||
(!isBottomReached && previousScrollY > scrollY) ||
previousScrollY < 0,
[scrollY],
useEffect(() => {
if (
scrollY &&
previousScrollY &&
scrollY > previousScrollY &&
previousScrollY !== 0
) {
hide();
} else {
close();
}
}, [scrollY]);

const bind = useDrag(
({
last,
velocity: [, vy],
direction: [, dy],
offset: [, oy],
cancel,
canceled,
}) => {
// if the user drags up passed a threshold, then we cancel
// the drag so that the sheet resets to its open position
if (oy < 0) {
cancel();
}

// when the user releases the sheet, we check whether it passed
// the threshold for it to close, or if we reset it to its open position
if (last) {
if (oy > ROW_HEIGHT * 0.5 || (vy > 0.5 && dy > 0)) {
close(vy);
} else {
open({ canceled });
}
} else {
// when the user keeps dragging, we just move the sheet according to
// the cursor position
api.start({ y: oy, immediate: true });
}
},
{
from: () => [0, y.get()],
filterTaps: true,
bounds: { top: -totalHeight, bottom: totalHeight - ROW_HEIGHT },
axis: 'y',
rubberband: true,
},
);

return (
<div
<animated.div
role="navigation"
{...bind()}
style={{
y,
touchAction: 'pan-x',
backgroundColor: theme.mobileNavBackground,
borderTop: `1px solid ${theme.menuBorder}`,
...styles.shadow,
display: isNarrowWidth ? 'flex' : 'none',
height,
justifyContent: 'space-around',
paddingTop: 10,
paddingBottom: 10,
height: totalHeight,
width: '100%',
position: 'fixed',
zIndex: 100,
bottom: isVisible ? 0 : -height,
transition: 'bottom 0.2s ease-out',
bottom: 0,
...(!isNarrowWidth && { display: 'none' }),
}}
>
<NavTab name="Budget" path="/budget" icon={Wallet} />
<NavTab name="Accounts" path="/accounts" icon={PiggyBank} />
<NavTab name="Transaction" path="/transactions/new" icon={Add} />
<NavTab name="Settings" path="/settings" icon={Cog} />
</div>
<View
style={{
flexDirection: 'row',
flexWrap: 'wrap',
height: totalHeight,
width: '100%',
}}
>
{[navTabs, bufferTabs]}
</View>
</animated.div>
);
}

Expand All @@ -60,9 +207,10 @@ type NavTabProps = {
name: string;
path: string;
icon: ComponentType<NavTabIconProps>;
style?: CSSProperties;
};

function NavTab({ icon: TabIcon, name, path }: NavTabProps) {
function NavTab({ icon: TabIcon, name, path, style }: NavTabProps) {
return (
<NavLink
to={path}
Expand All @@ -73,6 +221,8 @@ function NavTab({ icon: TabIcon, name, path }: NavTabProps) {
display: 'flex',
flexDirection: 'column',
textDecoration: 'none',
textAlign: 'center',
...style,
})}
>
<TabIcon width={22} height={22} />
Expand Down
51 changes: 47 additions & 4 deletions packages/desktop-client/src/components/reports/Overview.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import categorySpendingSpreadsheet from './graphs/category-spending-spreadsheet'
import CategorySpendingGraph from './graphs/CategorySpendingGraph';
import netWorthSpreadsheet from './graphs/net-worth-spreadsheet';
import NetWorthGraph from './graphs/NetWorthGraph';
import sankeySpreadsheet from './graphs/sankey-spreadsheet';
import SankeyGraph from './graphs/SankeyGraph';
import Tooltip from './Tooltip';
import useReport from './useReport';

Expand Down Expand Up @@ -325,10 +327,46 @@ function CategorySpendingCard() {
);
}

function SankeyCard() {
const { grouped: categoryGroups } = useCategories();
const end = monthUtils.currentMonth();
const start = monthUtils.subMonths(end, 5);

const params = useMemo(
() => sankeySpreadsheet(start, end, categoryGroups),
[start, end, categoryGroups],
);
const data = useReport('sankey', params);

return (
<Card flex={1} to="/reports/sankey">
<View style={{ flexDirection: 'row', padding: 20 }}>
<View style={{ flex: 1 }}>
<Block
style={{ ...styles.mediumText, fontWeight: 500, marginBottom: 5 }}
role="heading"
>
Sankey
</Block>
<DateRange start={start} end={end} />
</View>
</View>
<View style={{ flex: 1 }}>
{data ? (
<SankeyGraph data={data} compact={true} />
) : (
<LoadingIndicator />
)}
</View>
</Card>
);
}

export default function Overview() {
let categorySpendingReportFeatureFlag = useFeatureFlag(
'categorySpendingReport',
);
let sankeyFeatureFlag = useFeatureFlag('sankeyReport');

let accounts = useSelector(state => state.queries.accounts);
return (
Expand All @@ -348,16 +386,21 @@ export default function Overview() {
<CashFlowCard />
</View>

{categorySpendingReportFeatureFlag && (
{(sankeyFeatureFlag || categorySpendingReportFeatureFlag) && (
<View
style={{
flex: '0 0 auto',
flexDirection: 'row',
}}
>
<CategorySpendingCard />
<div style={{ flex: 1 }} />
<div style={{ flex: 1 }} />
{categorySpendingReportFeatureFlag && <CategorySpendingCard />}
{sankeyFeatureFlag && <SankeyCard />}
{(!categorySpendingReportFeatureFlag || !sankeyFeatureFlag) && (
<>
<div style={{ flex: 1 }} />
<div style={{ flex: 1 }} />
</>
)}
</View>
)}
</View>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import CashFlow from './CashFlow';
import CategorySpending from './CategorySpending';
import NetWorth from './NetWorth';
import Overview from './Overview';
import Sankey from './Sankey';

export function ReportRouter() {
return (
Expand All @@ -13,6 +14,7 @@ export function ReportRouter() {
<Route path="/net-worth" element={<NetWorth />} />
<Route path="/cash-flow" element={<CashFlow />} />
<Route path="/category-spending" element={<CategorySpending />} />
<Route path="/sankey" element={<Sankey />} />
</Routes>
);
}
Loading

0 comments on commit c88e9b9

Please sign in to comment.