Skip to content

Commit

Permalink
Sortable mobile accounts
Browse files Browse the repository at this point in the history
  • Loading branch information
joel-jeremy committed Jan 20, 2024
1 parent dbb777e commit 68f2163
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 24 deletions.
158 changes: 135 additions & 23 deletions packages/desktop-client/src/components/accounts/MobileAccounts.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,27 @@
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';

import {
DndContext,
MouseSensor,
TouchSensor,
closestCenter,
useSensor,
useSensors,
} from '@dnd-kit/core';
import {
restrictToParentElement,
restrictToVerticalAxis,
} from '@dnd-kit/modifiers';
import {
SortableContext,
useSortable,
verticalListSortingStrategy,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';

import * as queries from 'loot-core/src/client/queries';
import { send } from 'loot-core/src/platform/client/fetch';

import { useActions } from '../../hooks/useActions';
import { useCategories } from '../../hooks/useCategories';
Expand All @@ -16,6 +36,7 @@ import { View } from '../common/View';
import { Page } from '../Page';
import { PullToRefresh } from '../responsive/PullToRefresh';
import { CellValue } from '../spreadsheet/CellValue';
import { findSortDown, getDropPosition } from '../util/sort';

function AccountHeader({ name, amount, style = {} }) {
return (
Expand Down Expand Up @@ -52,8 +73,26 @@ function AccountHeader({ name, amount, style = {} }) {
}

function AccountCard({ account, updated, getBalanceQuery, onSelect }) {
const {
isDragging,
attributes,
listeners,
setNodeRef,
transform,
transition,
} = useSortable({ id: account.id });

const dndStyle = {
opacity: isDragging ? 0.5 : undefined,
transform: CSS.Transform.toString(transform),
transition,
};

return (
<View
innerRef={setNodeRef}
{...attributes}
{...listeners}
style={{
flex: 1,
flexDirection: 'row',
Expand All @@ -63,20 +102,18 @@ function AccountCard({ account, updated, getBalanceQuery, onSelect }) {
marginTop: 10,
marginRight: 10,
width: '100%',
...dndStyle,
}}
data-testid="account"
>
<Button
onMouseDown={() => onSelect(account.id)}
onClick={() => onSelect(account.id)}
style={{
flexDirection: 'row',
border: '1px solid ' + theme.pillBorder,
flex: 1,
alignItems: 'center',
borderRadius: 6,
'&:active': {
opacity: 0.1,
},
}}
>
<View
Expand Down Expand Up @@ -149,6 +186,7 @@ function AccountList({
onAddAccount,
onSelectAccount,
onSync,
onReorder,
}) {
const budgetedAccounts = accounts.filter(account => account.offbudget === 0);
const offbudgetAccounts = accounts.filter(account => account.offbudget === 1);
Expand All @@ -157,6 +195,41 @@ function AccountList({
color: 'white',
};

const sensors = useSensors(
useSensor(TouchSensor, {
activationConstraint: {
delay: 250,
tolerance: 5,
},
}),
useSensor(MouseSensor, {
activationConstraint: {
distance: 10,
},
}),
);

const [isDragging, setIsDragging] = useState(false);

const onDragStart = e => {
setIsDragging(true);
};

const onDragEnd = e => {
const { active, over } = e;

if (active.id !== over.id) {
const dropPos = getDropPosition(
active.rect.current.translated,
active.rect.current.initial,
);

onReorder(active.id, dropPos, over.id);
}

setIsDragging(false);
};

return (
<Page
title="Accounts"
Expand All @@ -178,20 +251,35 @@ function AccountList({
style={{ flex: 1, backgroundColor: theme.mobilePageBackground }}
>
{accounts.length === 0 && <EmptyMessage />}
<PullToRefresh onRefresh={onSync}>
<PullToRefresh isPullable={!isDragging} onRefresh={onSync}>
<View style={{ margin: 10 }}>
{budgetedAccounts.length > 0 && (
<AccountHeader name="For Budget" amount={getOnBudgetBalance()} />
)}
{budgetedAccounts.map(acct => (
<AccountCard
account={acct}
key={acct.id}
updated={updatedAccounts.includes(acct.id)}
getBalanceQuery={getBalanceQuery}
onSelect={onSelectAccount}
/>
))}
<View>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
modifiers={[restrictToVerticalAxis, restrictToParentElement]}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
>
<SortableContext
items={budgetedAccounts}
strategy={verticalListSortingStrategy}
>
{budgetedAccounts.map(acct => (
<AccountCard
account={acct}
key={acct.id}
updated={updatedAccounts.includes(acct.id)}
getBalanceQuery={getBalanceQuery}
onSelect={onSelectAccount}
/>
))}
</SortableContext>
</DndContext>
</View>

{offbudgetAccounts.length > 0 && (
<AccountHeader
Expand All @@ -200,15 +288,30 @@ function AccountList({
style={{ marginTop: 30 }}
/>
)}
{offbudgetAccounts.map(acct => (
<AccountCard
account={acct}
key={acct.id}
updated={updatedAccounts.includes(acct.id)}
getBalanceQuery={getBalanceQuery}
onSelect={onSelectAccount}
/>
))}
<View>
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
modifiers={[restrictToVerticalAxis, restrictToParentElement]}
onDragStart={onDragStart}
onDragEnd={onDragEnd}
>
<SortableContext
items={offbudgetAccounts}
strategy={verticalListSortingStrategy}
>
{offbudgetAccounts.map(acct => (
<AccountCard
account={acct}
key={acct.id}
updated={updatedAccounts.includes(acct.id)}
getBalanceQuery={getBalanceQuery}
onSelect={onSelectAccount}
/>
))}
</SortableContext>
</DndContext>
</View>
</View>
</PullToRefresh>
</Page>
Expand Down Expand Up @@ -244,6 +347,14 @@ export function Accounts() {
navigate(`/transaction/${transaction}`);
};

const onReorder = async (id, dropPos, targetId) => {
await send('account-move', {
id,
...findSortDown(accounts, dropPos, targetId),
});
await getAccounts();
};

useSetThemeColor(theme.mobileViewTheme);

return (
Expand All @@ -264,6 +375,7 @@ export function Accounts() {
onSelectAccount={onSelectAccount}
onSelectTransaction={onSelectTransaction}
onSync={syncAndDownload}
onReorder={onReorder}
/>
</View>
);
Expand Down
1 change: 0 additions & 1 deletion packages/desktop-client/src/components/sidebar/Account.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export function Account({
} = useSortable({ id: account?.id || `sortable-account-${name}` });

const dndStyle = {
touchAction: 'none',
opacity: isDragging ? 0.5 : undefined,
transform: CSS.Transform.toString(transform),
transition,
Expand Down

0 comments on commit 68f2163

Please sign in to comment.