mirror of
https://github.com/actualbudget/actual.git
synced 2026-03-11 20:44:32 -05:00
upcoming schedule setting: move setting to modal (#4164)
* upcoming schedule setting: move setting to modal * note * change nomenclature * remove strict override
This commit is contained in:
@@ -74,6 +74,7 @@ import { DiscoverSchedules } from './schedules/DiscoverSchedules';
|
||||
import { PostsOfflineNotification } from './schedules/PostsOfflineNotification';
|
||||
import { ScheduleDetails } from './schedules/ScheduleDetails';
|
||||
import { ScheduleLink } from './schedules/ScheduleLink';
|
||||
import { UpcomingLength } from './schedules/UpcomingLength';
|
||||
import { NamespaceContext } from './spreadsheet/NamespaceContext';
|
||||
|
||||
export function Modals() {
|
||||
@@ -373,6 +374,9 @@ export function Modals() {
|
||||
case 'schedules-discover':
|
||||
return <DiscoverSchedules key={name} />;
|
||||
|
||||
case 'schedules-upcoming-length':
|
||||
return <UpcomingLength key={name} />;
|
||||
|
||||
case 'schedule-posts-offline-notification':
|
||||
return <PostsOfflineNotification key={name} />;
|
||||
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import React from 'react';
|
||||
import { Trans, useTranslation } from 'react-i18next';
|
||||
|
||||
import { type SyncedPrefs } from 'loot-core/types/prefs';
|
||||
|
||||
import { useSyncedPref } from '../../hooks/useSyncedPref';
|
||||
import { Modal, ModalCloseButton, ModalHeader } from '../common/Modal';
|
||||
import { Paragraph } from '../common/Paragraph';
|
||||
import { Select } from '../common/Select';
|
||||
import { View } from '../common/View';
|
||||
|
||||
function useUpcomingLengthOptions() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const upcomingLengthOptions: {
|
||||
value: SyncedPrefs['upcomingScheduledTransactionLength'];
|
||||
label: string;
|
||||
}[] = [
|
||||
{ value: '1', label: t('1 day') },
|
||||
{ value: '7', label: t('1 week') },
|
||||
{ value: '14', label: t('2 weeks') },
|
||||
{ value: '30', label: t('1 month') },
|
||||
];
|
||||
|
||||
return { upcomingLengthOptions };
|
||||
}
|
||||
|
||||
export function UpcomingLength() {
|
||||
const { t } = useTranslation();
|
||||
const [_upcomingLength, setUpcomingLength] = useSyncedPref(
|
||||
'upcomingScheduledTransactionLength',
|
||||
);
|
||||
|
||||
const { upcomingLengthOptions } = useUpcomingLengthOptions();
|
||||
|
||||
const upcomingLength = _upcomingLength || '7';
|
||||
|
||||
return (
|
||||
<Modal
|
||||
name="schedules-upcoming-length"
|
||||
containerProps={{ style: { width: 600 } }}
|
||||
>
|
||||
{({ state: { close } }) => (
|
||||
<>
|
||||
<ModalHeader
|
||||
title={t('Change upcoming length')}
|
||||
rightContent={<ModalCloseButton onPress={close} />}
|
||||
/>
|
||||
<Paragraph>
|
||||
<Trans>
|
||||
Change how many days in advance of the scheduled date a scheduled
|
||||
transaction appears in the account ledger as upcoming.
|
||||
</Trans>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Trans>
|
||||
This only affects how schedules are displayed and not how budget
|
||||
data is stored. It can be changed at any time.
|
||||
</Trans>
|
||||
</Paragraph>
|
||||
<Paragraph>
|
||||
<Trans>
|
||||
Only the first instance of a recurring transaction will be shown.
|
||||
</Trans>
|
||||
</Paragraph>
|
||||
<View>
|
||||
<Select
|
||||
options={upcomingLengthOptions.map(x => [
|
||||
x.value || '7',
|
||||
x.label,
|
||||
])}
|
||||
value={upcomingLength}
|
||||
onChange={newValue => setUpcomingLength(newValue)}
|
||||
/>
|
||||
</View>
|
||||
</>
|
||||
)}
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
@@ -7,13 +7,13 @@ import { useSchedules } from 'loot-core/src/client/data-hooks/schedules';
|
||||
import { send } from 'loot-core/src/platform/client/fetch';
|
||||
import { type ScheduleEntity } from 'loot-core/src/types/models';
|
||||
|
||||
import { useFeatureFlag } from '../../hooks/useFeatureFlag';
|
||||
import { useDispatch } from '../../redux';
|
||||
import { theme } from '../../style';
|
||||
import { Button } from '../common/Button2';
|
||||
import { Search } from '../common/Search';
|
||||
import { View } from '../common/View';
|
||||
import { Page } from '../Page';
|
||||
import { UpcomingLengthSettings } from '../settings/Upcoming';
|
||||
|
||||
import { type ScheduleItemAction, SchedulesTable } from './SchedulesTable';
|
||||
|
||||
@@ -23,6 +23,8 @@ export function Schedules() {
|
||||
const dispatch = useDispatch();
|
||||
const [filter, setFilter] = useState('');
|
||||
|
||||
const upcomingLengthEnabled = useFeatureFlag('upcomingLengthAdjustment');
|
||||
|
||||
const onEdit = useCallback(
|
||||
(id: ScheduleEntity['id']) => {
|
||||
dispatch(pushModal('schedule-edit', { id }));
|
||||
@@ -38,6 +40,10 @@ export function Schedules() {
|
||||
dispatch(pushModal('schedules-discover'));
|
||||
}, [dispatch]);
|
||||
|
||||
const onChangeUpcomingLength = useCallback(() => {
|
||||
dispatch(pushModal('schedules-upcoming-length'));
|
||||
}, [dispatch]);
|
||||
|
||||
const onAction = useCallback(
|
||||
async (name: ScheduleItemAction, id: ScheduleEntity['id']) => {
|
||||
switch (name) {
|
||||
@@ -84,15 +90,6 @@ export function Schedules() {
|
||||
padding: '0 0 15px',
|
||||
}}
|
||||
>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
padding: '15px 0 0',
|
||||
}}
|
||||
>
|
||||
<UpcomingLengthSettings />
|
||||
</View>
|
||||
<View
|
||||
style={{
|
||||
flex: 1,
|
||||
@@ -127,9 +124,22 @@ export function Schedules() {
|
||||
flexShrink: 0,
|
||||
}}
|
||||
>
|
||||
<Button onPress={onDiscover}>
|
||||
<Trans>Find schedules</Trans>
|
||||
</Button>
|
||||
<View
|
||||
style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: '1em',
|
||||
}}
|
||||
>
|
||||
<Button onPress={onDiscover}>
|
||||
<Trans>Find schedules</Trans>
|
||||
</Button>
|
||||
{upcomingLengthEnabled && (
|
||||
<Button onPress={onChangeUpcomingLength}>
|
||||
<Trans>Change upcoming length</Trans>
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
<Button variant="primary" onPress={onAdd}>
|
||||
<Trans>Add new schedule</Trans>
|
||||
</Button>
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useTranslation, Trans } from 'react-i18next';
|
||||
import { useLocation } from 'react-router-dom';
|
||||
|
||||
import { type SyncedPrefs } from 'loot-core/types/prefs';
|
||||
|
||||
import { useFeatureFlag } from '../../hooks/useFeatureFlag';
|
||||
import { useSyncedPref } from '../../hooks/useSyncedPref';
|
||||
import { Button } from '../common/Button2';
|
||||
import { InfoBubble } from '../common/InfoBubble';
|
||||
import { Select } from '../common/Select';
|
||||
import { Text } from '../common/Text';
|
||||
import { View } from '../common/View';
|
||||
|
||||
import { Setting } from './UI';
|
||||
|
||||
function useUpcomingLengthOptions() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const upcomingLengthOptions: {
|
||||
value: SyncedPrefs['upcomingScheduledTransactionLength'];
|
||||
label: string;
|
||||
}[] = [
|
||||
{ value: '1', label: t('1 day') },
|
||||
{ value: '7', label: t('1 week') },
|
||||
{ value: '14', label: t('2 weeks') },
|
||||
{ value: '30', label: t('1 month') },
|
||||
];
|
||||
|
||||
return { upcomingLengthOptions };
|
||||
}
|
||||
|
||||
export function UpcomingLengthSettings() {
|
||||
const { t } = useTranslation();
|
||||
const [_upcomingLength, setUpcomingLength] = useSyncedPref(
|
||||
'upcomingScheduledTransactionLength',
|
||||
);
|
||||
|
||||
const { upcomingLengthOptions } = useUpcomingLengthOptions();
|
||||
|
||||
const upcomingLength = _upcomingLength || '7';
|
||||
|
||||
const enabled = useFeatureFlag('upcomingLengthAdjustment');
|
||||
|
||||
const location = useLocation();
|
||||
const [expanded, setExpanded] = useState(location.hash === '#upcomingLength');
|
||||
|
||||
if (!enabled) return null;
|
||||
|
||||
return expanded ? (
|
||||
<Setting
|
||||
primaryAction={
|
||||
<View style={{ flexDirection: 'row', gap: '1em' }}>
|
||||
<View style={{ flexDirection: 'row', alignItems: 'center', gap: 20 }}>
|
||||
<View title={t('Upcoming Length')}>
|
||||
<Select
|
||||
options={upcomingLengthOptions.map(x => [
|
||||
x.value || '7',
|
||||
x.label,
|
||||
])}
|
||||
value={upcomingLength}
|
||||
onChange={newValue => setUpcomingLength(newValue)}
|
||||
/>
|
||||
</View>
|
||||
<InfoBubble
|
||||
label={t(
|
||||
'Only the first instance of a recurring transaction will be shown.',
|
||||
)}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
}
|
||||
>
|
||||
<View style={{ flexDirection: 'row', gap: 20 }}>
|
||||
<Text>
|
||||
<Trans>
|
||||
<strong>Upcoming Length</strong> does not affect how budget data is
|
||||
stored, and can be changed at any time.
|
||||
</Trans>
|
||||
</Text>
|
||||
<Button
|
||||
onPress={() => setExpanded(false)}
|
||||
aria-label="Close upcoming length settings"
|
||||
>
|
||||
<Trans>Close</Trans>
|
||||
</Button>
|
||||
</View>
|
||||
</Setting>
|
||||
) : (
|
||||
<View>
|
||||
<Button
|
||||
aria-label="Edit upcoming length settings"
|
||||
variant="primary"
|
||||
onPress={() => setExpanded(true)}
|
||||
>
|
||||
<Trans>Edit Upcoming Length</Trans> (
|
||||
{upcomingLengthOptions.find(x => x.value === upcomingLength)?.label ??
|
||||
t('1 week')}
|
||||
)
|
||||
</Button>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -181,6 +181,8 @@ type FinanceModals = {
|
||||
|
||||
'schedules-discover': null;
|
||||
|
||||
'schedules-upcoming-length': null;
|
||||
|
||||
'schedule-posts-offline-notification': null;
|
||||
'account-menu': {
|
||||
accountId: string;
|
||||
|
||||
6
upcoming-release-notes/4164.md
Normal file
6
upcoming-release-notes/4164.md
Normal file
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: Enhancements
|
||||
authors: [matt-fidd]
|
||||
---
|
||||
|
||||
Move upcoming schedule length setting
|
||||
Reference in New Issue
Block a user