Skip to content
Snippets Groups Projects
  • Joel Jeremy Marquez's avatar
    08cbdab2
    Hooks for frequently made operations (#2293) · 08cbdab2
    Joel Jeremy Marquez authored
    
    * Hooks for frequently made operations
    
    * Release notes
    
    * Fix typecheck errors
    
    * Remove useGlobalPrefs
    
    * Add null checks
    
    * Fix showCleared pref
    
    * Add loaded flag for categories, accounts and payees state
    
    * Refactor to reduce unnecessary states
    
    * Fix eslint errors
    
    * Fix hooks deps
    
    * Add useEffect
    
    * Fix typecheck error
    
    * Set local and global pref hooks
    
    * Fix lint error
    
    * VRT
    
    * Fix typecheck error
    
    * Remove eager loading
    
    * Fix typecheck error
    
    * Fix typo
    
    * Fix typecheck error
    
    * Update useTheme
    
    * Typecheck errors
    
    * Typecheck error
    
    * defaultValue
    
    * Explicitly check undefined
    
    * Remove useGlobalPref and useLocalPref defaults
    
    * Fix default prefs
    
    * Default value
    
    * Fix lint error
    
    * Set default theme
    
    * Default date format in Account
    
    * Update packages/desktop-client/src/style/theme.tsx
    
    Co-authored-by: default avatarMatiss Janis Aboltins <matiss@mja.lv>
    
    ---------
    
    Co-authored-by: default avatarMatiss Janis Aboltins <matiss@mja.lv>
    Hooks for frequently made operations (#2293)
    Joel Jeremy Marquez authored
    
    * Hooks for frequently made operations
    
    * Release notes
    
    * Fix typecheck errors
    
    * Remove useGlobalPrefs
    
    * Add null checks
    
    * Fix showCleared pref
    
    * Add loaded flag for categories, accounts and payees state
    
    * Refactor to reduce unnecessary states
    
    * Fix eslint errors
    
    * Fix hooks deps
    
    * Add useEffect
    
    * Fix typecheck error
    
    * Set local and global pref hooks
    
    * Fix lint error
    
    * VRT
    
    * Fix typecheck error
    
    * Remove eager loading
    
    * Fix typecheck error
    
    * Fix typo
    
    * Fix typecheck error
    
    * Update useTheme
    
    * Typecheck errors
    
    * Typecheck error
    
    * defaultValue
    
    * Explicitly check undefined
    
    * Remove useGlobalPref and useLocalPref defaults
    
    * Fix default prefs
    
    * Default value
    
    * Fix lint error
    
    * Set default theme
    
    * Default date format in Account
    
    * Update packages/desktop-client/src/style/theme.tsx
    
    Co-authored-by: default avatarMatiss Janis Aboltins <matiss@mja.lv>
    
    ---------
    
    Co-authored-by: default avatarMatiss Janis Aboltins <matiss@mja.lv>
Format.tsx 4.66 KiB
// @ts-strict-ignore
import React, { type ReactNode } from 'react';

import { numberFormats } from 'loot-core/src/shared/util';
import { type LocalPrefs } from 'loot-core/src/types/prefs';

import { useDateFormat } from '../../hooks/useDateFormat';
import { useLocalPref } from '../../hooks/useLocalPref';
import { tokens } from '../../tokens';
import { Button } from '../common/Button';
import { Select } from '../common/Select';
import { Text } from '../common/Text';
import { View } from '../common/View';
import { Checkbox } from '../forms';
import { useSidebar } from '../sidebar/SidebarProvider';

import { Setting } from './UI';

// Follows Pikaday 'firstDay' numbering
// https://github.com/Pikaday/Pikaday
const daysOfWeek: { value: LocalPrefs['firstDayOfWeekIdx']; label: string }[] =
  [
    { value: '0', label: 'Sunday' },
    { value: '1', label: 'Monday' },
    { value: '2', label: 'Tuesday' },
    { value: '3', label: 'Wednesday' },
    { value: '4', label: 'Thursday' },
    { value: '5', label: 'Friday' },
    { value: '6', label: 'Saturday' },
  ];

const dateFormats: { value: LocalPrefs['dateFormat']; label: string }[] = [
  { value: 'MM/dd/yyyy', label: 'MM/DD/YYYY' },
  { value: 'dd/MM/yyyy', label: 'DD/MM/YYYY' },
  { value: 'yyyy-MM-dd', label: 'YYYY-MM-DD' },
  { value: 'MM.dd.yyyy', label: 'MM.DD.YYYY' },
  { value: 'dd.MM.yyyy', label: 'DD.MM.YYYY' },
];

function Column({ title, children }: { title: string; children: ReactNode }) {
  return (
    <View
      style={{
        alignItems: 'flex-start',
        flexGrow: 1,
        gap: '0.5em',
        width: '100%',
      }}
    >
      <Text style={{ fontWeight: 500 }}>{title}</Text>
      <View style={{ alignItems: 'flex-start', gap: '1em' }}>{children}</View>
    </View>
  );
}

export function FormatSettings() {
  const sidebar = useSidebar();
  const [_firstDayOfWeekIdx, setFirstDayOfWeekIdxPref] =
    useLocalPref('firstDayOfWeekIdx'); // Sunday;
  const firstDayOfWeekIdx = _firstDayOfWeekIdx || '0';
  const dateFormat = useDateFormat() || 'MM/dd/yyyy';
  const [, setDateFormatPref] = useLocalPref('dateFormat');
  const [_numberFormat, setNumberFormatPref] = useLocalPref('numberFormat');
  const numberFormat = _numberFormat || 'comma-dot';
  const [hideFraction = false, setHideFractionPref] =
    useLocalPref('hideFraction');

  return (
    <Setting
      primaryAction={
        <View
          style={{
            flexDirection: 'column',
            gap: '1em',
            width: '100%',
            [`@media (min-width: ${
              sidebar.floating
                ? tokens.breakpoint_small
                : tokens.breakpoint_medium
            })`]: {
              flexDirection: 'row',
            },
          }}
        >
          <Column title="Numbers">
            <Button bounce={false} style={{ padding: 0 }}>
              <Select
                bare
                key={String(hideFraction)} // needed because label does not update
                value={numberFormat}
                onChange={format => setNumberFormatPref(format)}
                options={numberFormats.map(f => [
                  f.value,
                  hideFraction ? f.labelNoFraction : f.label,
                ])}
                style={{ padding: '2px 10px', fontSize: 15 }}
              />
            </Button>

            <Text style={{ display: 'flex' }}>
              <Checkbox
                id="settings-textDecimal"
                checked={!!hideFraction}
                onChange={e => setHideFractionPref(e.currentTarget.checked)}
              />
              <label htmlFor="settings-textDecimal">Hide decimal places</label>
            </Text>
          </Column>

          <Column title="Dates">
            <Button bounce={false} style={{ padding: 0 }}>
              <Select
                bare
                value={dateFormat}
                onChange={format => setDateFormatPref(format)}
                options={dateFormats.map(f => [f.value, f.label])}
                style={{ padding: '2px 10px', fontSize: 15 }}
              />
            </Button>
          </Column>

          <Column title="First day of the week">
            <Button bounce={false} style={{ padding: 0 }}>
              <Select
                bare
                value={firstDayOfWeekIdx}
                onChange={idx => setFirstDayOfWeekIdxPref(idx)}
                options={daysOfWeek.map(f => [f.value, f.label])}
                style={{ padding: '2px 10px', fontSize: 15 }}
              />
            </Button>
          </Column>
        </View>
      }
    >
      <Text>
        <strong>Formatting</strong> does not affect how budget data is stored,
        and can be changed at any time.
      </Text>
    </Setting>
  );
}