Skip to content

Commit

Permalink
Mobile budget file quick switch mode
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-jeremy committed Mar 25, 2024
1 parent c54cfaf commit b849021
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 79 deletions.
5 changes: 5 additions & 0 deletions packages/desktop-client/src/components/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { useSyncServerStatus } from '../hooks/useSyncServerStatus';

import { AccountAutocompleteModal } from './modals/AccountAutocompleteModal';
import { AccountMenuModal } from './modals/AccountMenuModal';
import { BudgetListModal } from './modals/BudgetListModal';
import { BudgetMenuModal } from './modals/BudgetMenuModal';
import { CategoryAutocompleteModal } from './modals/CategoryAutocompleteModal';
import { CategoryGroupMenuModal } from './modals/CategoryGroupMenuModal';
Expand Down Expand Up @@ -597,12 +598,16 @@ export function Modals() {
<BudgetMenuModal
modalProps={modalProps}
month={options.month}
onSwitchBudgetFile={options.onSwitchBudgetFile}
onToggleHiddenCategories={options.onToggleHiddenCategories}
onSwitchBudgetType={options.onSwitchBudgetType}
/>
</NamespaceContext.Provider>
);

case 'budget-list':
return <BudgetListModal key={name} modalProps={modalProps} />;

default:
console.error('Unknown modal:', name);
return null;
Expand Down
216 changes: 137 additions & 79 deletions packages/desktop-client/src/components/manager/BudgetList.jsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,20 @@
import React, { useState, useRef } from 'react';
import { useSelector } from 'react-redux';
import { useDispatch, useSelector } from 'react-redux';

import * as actions from 'loot-core/src/client/actions';
import {
closeAndDownloadBudget,
closeAndLoadBudget,
createBudget,
downloadBudget,
getUserData,
loadAllFiles,
loadBudget,
pushModal,
} from 'loot-core/client/actions';
import { isNonProductionEnvironment } from 'loot-core/src/shared/environment';

import { useActions } from '../../hooks/useActions';
import { useInitialMount } from '../../hooks/useInitialMount';
import { useLocalPref } from '../../hooks/useLocalPref';
import { AnimatedLoading } from '../../icons/AnimatedLoading';
import {
SvgCloudCheck,
Expand All @@ -13,6 +23,7 @@ import {
SvgFileDouble,
} from '../../icons/v1';
import { SvgCloudUnknown, SvgKey, SvgRefreshArrow } from '../../icons/v2';
import { useResponsive } from '../../ResponsiveProvider';
import { styles, theme } from '../../style';
import { tokens } from '../../tokens';
import { Button } from '../common/Button';
Expand Down Expand Up @@ -52,11 +63,27 @@ function FileMenu({ onDelete, onClose }) {
}

const items = [{ name: 'delete', text: 'Delete' }];
const { isNarrowWidth } = useResponsive();

const defaultMenuItemStyle = isNarrowWidth
? {
...styles.mobileMenuItem,
color: theme.menuItemText,
borderRadius: 0,
borderTop: `1px solid ${theme.pillBorder}`,
}
: {};

return <Menu onMenuSelect={onMenuSelect} items={items} />;
return (
<Menu
getItemStyle={() => defaultMenuItemStyle}
onMenuSelect={onMenuSelect}
items={items}
/>
);
}

function DetailButton({ state, onDelete }) {
function FileMenuButton({ state, onDelete }) {
const [menuOpen, setMenuOpen] = useState(false);

return (
Expand Down Expand Up @@ -136,7 +163,7 @@ function FileState({ file }) {
);
}

function File({ file, onSelect, onDelete }) {
function File({ file, quickSwitchMode, onSelect, onDelete }) {
const selecting = useRef(false);

async function _onSelect(file) {
Expand Down Expand Up @@ -191,13 +218,15 @@ function File({ file, onSelect, onDelete }) {
/>
)}

<DetailButton state={file.state} onDelete={() => onDelete(file)} />
{!quickSwitchMode && (
<FileMenuButton state={file.state} onDelete={() => onDelete(file)} />
)}
</View>
</View>
);
}

function BudgetTable({ files, onSelect, onDelete }) {
function BudgetTable({ files, quickSwitchMode, onSelect, onDelete }) {
return (
<View
style={{
Expand All @@ -214,6 +243,7 @@ function BudgetTable({ files, onSelect, onDelete }) {
<File
key={file.id || file.cloudFileId}
file={file}
quickSwitchMode={quickSwitchMode}
onSelect={onSelect}
onDelete={onDelete}
/>
Expand All @@ -222,7 +252,7 @@ function BudgetTable({ files, onSelect, onDelete }) {
);
}

function RefreshButton({ onRefresh }) {
function RefreshButton({ style, onRefresh }) {
const [loading, setLoading] = useState(false);

async function _onRefresh() {
Expand All @@ -237,118 +267,146 @@ function RefreshButton({ onRefresh }) {
<Button
type="bare"
aria-label="Refresh"
style={{ padding: 10, marginRight: 5 }}
style={{ padding: 10, ...style }}
onClick={_onRefresh}
>
<Icon style={{ width: 18, height: 18 }} />
</Button>
);
}

export function BudgetList() {
const files = useSelector(state => state.budgets.allFiles || []);
function BudgetListHeader({ quickSwitchMode, onRefresh }) {
return (
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
margin: 20,
}}
>
<Text
style={{
...styles.veryLargeText,
}}
>
Files
</Text>
{!quickSwitchMode && <RefreshButton onRefresh={onRefresh} />}
</View>
);
}

export function BudgetList({ showHeader = true, quickSwitchMode = false }) {
const dispatch = useDispatch();
const allFiles = useSelector(state => state.budgets.allFiles || []);
const [id] = useLocalPref('id');

const {
getUserData,
loadAllFiles,
pushModal,
loadBudget,
createBudget,
downloadBudget,
} = useActions();
const files = allFiles.filter(f => f.id !== id);

const [creating, setCreating] = useState(false);

const onCreate = ({ testMode } = {}) => {
if (!creating) {
setCreating(true);
createBudget({ testMode });
dispatch(createBudget({ testMode }));
}
};

const refresh = () => {
dispatch(getUserData());
dispatch(loadAllFiles());
};

const initialMount = useInitialMount();
if (initialMount && quickSwitchMode) {
refresh();
}

return (
<View
style={{
flex: 1,
justifyContent: 'center',
marginInline: -20,
marginTop: 20,
width: '100vw',
...(!quickSwitchMode && {
marginTop: 20,
width: '100vw',
}),
[`@media (min-width: ${tokens.breakpoint_small})`]: {
maxWidth: tokens.breakpoint_small,
width: '100%',
},
}}
>
<View>
<Text style={{ ...styles.veryLargeText, margin: 20 }}>Files</Text>
<View
style={{
position: 'absolute',
right: 0,
top: 0,
bottom: 0,
justifyContent: 'center',
marginRight: 5,
}}
>
<RefreshButton
onRefresh={() => {
getUserData();
loadAllFiles();
}}
/>
</View>
</View>
{showHeader && (
<BudgetListHeader
quickSwitchMode={quickSwitchMode}
onRefresh={refresh}
/>
)}
<BudgetTable
files={files}
actions={actions}
quickSwitchMode={quickSwitchMode}
onSelect={file => {
if (file.state === 'remote') {
downloadBudget(file.cloudFileId);
} else {
loadBudget(file.id);
if (!id) {
if (file.state === 'remote') {
dispatch(downloadBudget(file.cloudFileId));
} else {
dispatch(loadBudget(file.id));
}
} else if (file.id !== id) {
if (file.state === 'remote') {
dispatch(closeAndDownloadBudget(file.cloudFileId));
} else {
dispatch(closeAndLoadBudget(file.id));
}
}
}}
onDelete={file => pushModal('delete-budget', { file })}
onDelete={file => dispatch(pushModal('delete-budget', { file }))}
/>
<View
style={{
flexDirection: 'row',
justifyContent: 'flex-end',
padding: 25,
paddingLeft: 5,
}}
>
<Button
type="bare"
{!quickSwitchMode && (
<View
style={{
marginLeft: 10,
color: theme.pageTextLight,
}}
onClick={e => {
e.preventDefault();
pushModal('import');
flexDirection: 'row',
justifyContent: 'flex-end',
alignItems: 'center',
padding: 25,
}}
>
Import file
</Button>

<Button type="primary" onClick={onCreate} style={{ marginLeft: 15 }}>
Create new file
</Button>
<Button
type="bare"
style={{
height: styles.mobileMinHeight,
marginLeft: 10,
color: theme.pageTextLight,
}}
onClick={e => {
e.preventDefault();
dispatch(pushModal('import'));
}}
>
Import file
</Button>

{isNonProductionEnvironment() && (
<Button
type="primary"
isSubmit={false}
onClick={() => onCreate({ testMode: true })}
style={{ marginLeft: 15 }}
onClick={onCreate}
style={{ height: styles.mobileMinHeight, marginLeft: 10 }}
>
Create test file
Create new file
</Button>
)}
</View>

{isNonProductionEnvironment() && (
<Button
type="primary"
isSubmit={false}
onClick={() => onCreate({ testMode: true })}
style={{ height: styles.mobileMinHeight, marginLeft: 10 }}
>
Create test file
</Button>
)}
</View>
)}
</View>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -375,11 +375,16 @@ function BudgetInner(props: BudgetInnerProps) {
dispatch(collapseModals('budget-menu'));
};

const onSwitchBudgetFile = () => {
dispatch(pushModal('budget-list'));
};

const onOpenBudgetActionMenu = month => {
dispatch(
pushModal('budget-menu', {
month,
onToggleHiddenCategories,
onSwitchBudgetFile,
onSwitchBudgetType: _onSwitchBudgetType,
}),
);
Expand Down
Loading

0 comments on commit b849021

Please sign in to comment.