Skip to content
Snippets Groups Projects
Unverified Commit a0ecd65e authored by Matiss Janis Aboltins's avatar Matiss Janis Aboltins Committed by GitHub
Browse files

:sparkles: (reports) add loading indicators (#1491)

* :sparkles: (reports) add loading indicators

* Release notes
parent 2ef0fc94
No related branches found
No related tags found
No related merge requests found
import React, { useState } from 'react';
import React, { Fragment, useState } from 'react';
import Eye from '../../icons/v2/Eye';
import EyeSlashed from '../../icons/v2/EyeSlashed';
......@@ -67,7 +67,7 @@ export default function CategorySelector({
),
);
return (
<>
<Fragment key={categoryGroup.id}>
<li
style={{
display:
......@@ -75,7 +75,6 @@ export default function CategorySelector({
marginBottom: 4,
flexDirection: 'row',
}}
key={categoryGroup.id}
>
<Checkbox
id={`form_${categoryGroup.id}`}
......@@ -162,7 +161,7 @@ export default function CategorySelector({
})}
</ul>
</li>
</>
</Fragment>
);
})}
</ul>
......
......@@ -8,6 +8,7 @@ import { integerToCurrency } from 'loot-core/src/shared/util';
import useCategories from '../../hooks/useCategories';
import useFeatureFlag from '../../hooks/useFeatureFlag';
import AnimatedLoading from '../../icons/AnimatedLoading';
import { colors, styles } from '../../style';
import AnchorLink from '../common/AnchorLink';
import Block from '../common/Block';
......@@ -63,6 +64,20 @@ function Card({ flex, to, style, children }) {
return content;
}
function LoadingIndicator() {
return (
<View
style={{
height: '100%',
alignItems: 'center',
justifyContent: 'center',
}}
>
<AnimatedLoading style={{ width: 25, height: 25 }} />
</View>
);
}
function NetWorthCard({ accounts }) {
const end = monthUtils.currentMonth();
const start = monthUtils.subMonths(end, 5);
......@@ -76,10 +91,6 @@ function NetWorthCard({ accounts }) {
);
const data = useReport('net_worth', params);
if (!data) {
return null;
}
return (
<Card flex={2} to="/reports/net-worth">
<View
......@@ -97,30 +108,39 @@ function NetWorthCard({ accounts }) {
</Block>
<DateRange start={start} end={end} />
</View>
<View style={{ textAlign: 'right' }}>
<Block
style={[styles.mediumText, { fontWeight: 500, marginBottom: 5 }]}
>
{data && (
<View style={{ textAlign: 'right' }}>
<Block
style={[
styles.mediumText,
{ fontWeight: 500, marginBottom: 5 },
]}
>
<PrivacyFilter activationFilters={[!isCardHovered]}>
{integerToCurrency(data.netWorth)}
</PrivacyFilter>
</Block>
<PrivacyFilter activationFilters={[!isCardHovered]}>
{integerToCurrency(data.netWorth)}
<Change
amount={data.totalChange}
style={{ color: colors.n6, fontWeight: 300 }}
/>
</PrivacyFilter>
</Block>
<PrivacyFilter activationFilters={[!isCardHovered]}>
<Change
amount={data.totalChange}
style={{ color: colors.n6, fontWeight: 300 }}
/>
</PrivacyFilter>
</View>
</View>
)}
</View>
<NetWorthGraph
start={start}
end={end}
graphData={data.graphData}
compact={true}
style={{ height: 'auto', flex: 1 }}
/>
{data ? (
<NetWorthGraph
start={start}
end={end}
graphData={data.graphData}
compact={true}
style={{ height: 'auto', flex: 1 }}
/>
) : (
<LoadingIndicator />
)}
</View>
</Card>
);
......@@ -136,13 +156,9 @@ function CashFlowCard() {
const onCardHover = useCallback(() => setIsCardHovered(true));
const onCardHoverEnd = useCallback(() => setIsCardHovered(false));
if (!data) {
return null;
}
const { graphData } = data;
const expense = -(graphData.expense || 0);
const income = graphData.income || 0;
const { graphData } = data || {};
const expense = -(graphData?.expense || 0);
const income = graphData?.income || 0;
return (
<Card flex={1} to="/reports/cash-flow">
......@@ -161,102 +177,108 @@ function CashFlowCard() {
</Block>
<DateRange start={start} end={end} />
</View>
<View style={{ textAlign: 'right' }}>
<PrivacyFilter activationFilters={[!isCardHovered]}>
<Change
amount={income - expense}
style={{ color: colors.n6, fontWeight: 300 }}
/>
</PrivacyFilter>
</View>
{data && (
<View style={{ textAlign: 'right' }}>
<PrivacyFilter activationFilters={[!isCardHovered]}>
<Change
amount={income - expense}
style={{ color: colors.n6, fontWeight: 300 }}
/>
</PrivacyFilter>
</View>
)}
</View>
<Container style={{ height: 'auto', flex: 1 }}>
{(width, height, portalHost) => (
<VictoryGroup
colorScale={[theme.colors.blue, theme.colors.red]}
width={100}
height={height}
theme={theme}
domain={{
x: [0, 100],
y: [0, Math.max(income, expense, 100)],
}}
containerComponent={
<VictoryVoronoiContainer voronoiDimension="x" />
}
labelComponent={
<Tooltip
portalHost={portalHost}
offsetX={(width - 100) / 2}
offsetY={y => (y + 40 > height ? height - 40 : y)}
light={true}
forceActive={true}
style={{
padding: 0,
}}
/>
}
padding={{
top: 0,
bottom: 0,
left: 0,
right: 0,
}}
>
<VictoryBar
barWidth={13}
data={[
{
x: 30,
y: Math.max(income, 5),
premadeLabel: (
<View style={{ textAlign: 'right' }}>
Income
<View>
<PrivacyFilter activationFilters={[!isCardHovered]}>
{integerToCurrency(income)}
</PrivacyFilter>
{data ? (
<Container style={{ height: 'auto', flex: 1 }}>
{(width, height, portalHost) => (
<VictoryGroup
colorScale={[theme.colors.blue, theme.colors.red]}
width={100}
height={height}
theme={theme}
domain={{
x: [0, 100],
y: [0, Math.max(income, expense, 100)],
}}
containerComponent={
<VictoryVoronoiContainer voronoiDimension="x" />
}
labelComponent={
<Tooltip
portalHost={portalHost}
offsetX={(width - 100) / 2}
offsetY={y => (y + 40 > height ? height - 40 : y)}
light={true}
forceActive={true}
style={{
padding: 0,
}}
/>
}
padding={{
top: 0,
bottom: 0,
left: 0,
right: 0,
}}
>
<VictoryBar
barWidth={13}
data={[
{
x: 30,
y: Math.max(income, 5),
premadeLabel: (
<View style={{ textAlign: 'right' }}>
Income
<View>
<PrivacyFilter activationFilters={[!isCardHovered]}>
{integerToCurrency(income)}
</PrivacyFilter>
</View>
</View>
</View>
),
labelPosition: 'left',
},
]}
labels={d => d.premadeLabel}
/>
<VictoryBar
barWidth={13}
data={[
{
x: 60,
y: Math.max(expense, 5),
premadeLabel: (
<View>
Expenses
),
labelPosition: 'left',
},
]}
labels={d => d.premadeLabel}
/>
<VictoryBar
barWidth={13}
data={[
{
x: 60,
y: Math.max(expense, 5),
premadeLabel: (
<View>
<PrivacyFilter activationFilters={[!isCardHovered]}>
{integerToCurrency(expense)}
</PrivacyFilter>
Expenses
<View>
<PrivacyFilter activationFilters={[!isCardHovered]}>
{integerToCurrency(expense)}
</PrivacyFilter>
</View>
</View>
</View>
),
labelPosition: 'right',
fill: theme.colors.red,
},
]}
labels={d => d.premadeLabel}
/>
</VictoryGroup>
)}
</Container>
),
labelPosition: 'right',
fill: theme.colors.red,
},
]}
labels={d => d.premadeLabel}
/>
</VictoryGroup>
)}
</Container>
) : (
<LoadingIndicator />
)}
</View>
</Card>
);
}
function CategorySpendingCard() {
const categories = useCategories();
const { list: categories = [] } = useCategories();
const end = monthUtils.currentDay();
const start = monthUtils.subMonths(end, 3);
......@@ -266,9 +288,7 @@ function CategorySpendingCard() {
start,
end,
3,
(categories.list || []).filter(
category => !category.is_income && !category.hidden,
),
categories.filter(category => !category.is_income && !category.hidden),
);
}, [start, end, categories]);
......@@ -289,13 +309,16 @@ function CategorySpendingCard() {
</View>
</View>
</View>
{!perCategorySpending ? null : (
{perCategorySpending ? (
<CategorySpendingGraph
start={start}
end={end}
graphData={perCategorySpending}
compact={true}
/>
) : (
<LoadingIndicator />
)}
</Card>
);
......
......@@ -52,7 +52,6 @@ export default function createSpreadsheet(
setData: (graphData: CategorySpendingGraphData) => void,
) => {
if (start === null || end === null || categories.length === 0) {
setData({ categories: [], tickValues: [], data: {} });
return;
}
......@@ -72,7 +71,6 @@ export default function createSpreadsheet(
.select('date'),
);
if (firstTransaction.data.length === 0) {
setData({ categories: [], tickValues: [], data: {} });
return;
}
......
......@@ -14,7 +14,7 @@ export function Area({ start, end, scale, range }: AreaProps) {
const startX = scale.x(d.parseISO(start + '-01'));
const endX = scale.x(d.parseISO(end + '-01'));
if (startX < 0 || endX < 0) {
if (startX < 0 || endX < 0 || startX === undefined || endX === undefined) {
return null;
}
......
---
category: Enhancements
authors: [MatissJanis]
---
Add loading indicators to reports page
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment