Skip to content

Commit

Permalink
Merge pull request #36 from dsaltares/feat/33
Browse files Browse the repository at this point in the history
feat: 33 - allow display currency to be customised
  • Loading branch information
dsaltares authored Dec 9, 2024
2 parents defa7c1 + 12fc1c1 commit 120e5c5
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 9 deletions.
10 changes: 6 additions & 4 deletions src/components/BudgetOptionsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import createUTCDate from '@lib/createUTCDate';
import useFiltersFromUrl from '@lib/useFiltersFromUrl';
import { currencyOptionsById } from '@lib/autoCompleteOptions';
import { TimeGranularities, type TimeGranularity } from '@server/budget/types';
import client from '@lib/client';
import DefaultCurrency from '@lib/defaultCurrency';
import TimeGranularitySelect from './TimeGranularitySelect';
import CurrencyAutocomplete from './CurrencyAutocomplete';

const DefaultCurrency = 'EUR';

type Props = {
open: boolean;
onClose: () => void;
Expand All @@ -25,6 +25,8 @@ type Props = {
const id = 'budget-options-dialog';

export default function BudgetOptionsDialog({ open, onClose }: Props) {
const { data: settings } = client.getUserSettings.useQuery();
const defaultCurrency = settings?.currency ?? DefaultCurrency;
const theme = useTheme();
const fullScreen = useMediaQuery(theme.breakpoints.down('md'));
const { filtersByField, setFilters } = useFiltersFromUrl();
Expand All @@ -37,13 +39,13 @@ export default function BudgetOptionsDialog({ open, onClose }: Props) {
(filtersByField.granularity as TimeGranularity) || '',
);
const [currency, setCurrency] = useState(
currencyOptionsById[filtersByField.currency ?? DefaultCurrency],
currencyOptionsById[filtersByField.currency ?? defaultCurrency],
);

const handleApplyFilters = () => {
setFilters({
date: date?.toISOString(),
currency: currency.id !== DefaultCurrency ? currency.id : undefined,
currency: currency.id !== defaultCurrency ? currency.id : undefined,
granularity,
});
onClose();
Expand Down
4 changes: 3 additions & 1 deletion src/components/CurrencyAutocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,15 @@ type Props = {
onChange: (value: Option) => void;
error?: boolean;
onBlur?: FocusEventHandler<HTMLDivElement>;
label?: string;
};

export default function CurrencyAutocomplete({
value,
onChange,
error,
onBlur,
label = 'Currency',
}: Props) {
return (
<Autocomplete
Expand All @@ -38,7 +40,7 @@ export default function CurrencyAutocomplete({
renderInput={(params) => (
<TextField
{...params}
label="Currency"
label={label}
required
error={error}
InputProps={{
Expand Down
27 changes: 25 additions & 2 deletions src/components/SettingsForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { SubmitHandler } from 'react-hook-form';
import { useForm } from 'react-hook-form';
import { Controller, useForm } from 'react-hook-form';
import { useCallback } from 'react';
import TextField from '@mui/material/TextField';
import FolderIcon from '@mui/icons-material/Folder';
Expand All @@ -9,10 +9,14 @@ import IconButton from '@mui/material/IconButton';
import { enqueueSnackbar } from 'notistack';
import client from '@lib/client';
import type { UserSettings } from '@server/userSettings/types';
import { currencyOptionsById } from '@lib/autoCompleteOptions';
import Fab from './Fab';
import CurrencyAutocomplete from './CurrencyAutocomplete';

type Option = { label: string; id: string };
type UserSettingsFormValues = {
dataPath: string;
currency: Option;
};

type Props = {
Expand All @@ -39,15 +43,20 @@ export default function SettingsForm({ settings }: Props) {
handleSubmit,
formState: { errors },
setValue,
control,
} = useForm<UserSettingsFormValues>({
mode: 'onBlur',
defaultValues: {
dataPath: settings.dataPath,
currency: currencyOptionsById[settings.currency || 'EUR'],
},
});
const onSubmit: SubmitHandler<UserSettingsFormValues> = useCallback(
async (values) => {
updateUserSettings(values);
updateUserSettings({
...values,
currency: values.currency.id,
});
},
[updateUserSettings],
);
Expand Down Expand Up @@ -81,6 +90,20 @@ export default function SettingsForm({ settings }: Props) {
<FolderIcon fontSize="large" />
</IconButton>
</Stack>
<Controller
control={control}
name="currency"
rules={{ required: true }}
render={({ field: { value, onChange, onBlur } }) => (
<CurrencyAutocomplete
label="Preferred currency"
value={value}
onChange={onChange}
onBlur={onBlur}
error={!!errors.currency}
/>
)}
/>
</Stack>
<Fab type="submit">
<SaveIcon />
Expand Down
3 changes: 3 additions & 0 deletions src/lib/defaultCurrency.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const DefaultCurrency = 'EUR';

export default DefaultCurrency;
9 changes: 7 additions & 2 deletions src/server/accounts/getAccounts.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { convertAmount, getRates } from '@server/reports/utils';
import { type Procedure, procedure } from '@server/trpc';
import db from '@server/db';
import { getUserSettings } from '@server/userSettings/store';
import DefaultCurrency from '@lib/defaultCurrency';
import { GetAccountsInput, GetAccountsOutput } from './types';

const getAccounts: Procedure<
GetAccountsInput,
GetAccountsOutput
> = async () => {
const settings = getUserSettings();
const baseCurrency = settings.currency || DefaultCurrency;
const accounts = await db
.selectFrom('bankAccount')
.selectAll()
Expand All @@ -21,10 +25,11 @@ const getAccounts: Procedure<
total: {
value: accounts.reduce(
(acc, account) =>
acc + convertAmount(account.balance, account.currency, 'EUR', rates),
acc +
convertAmount(account.balance, account.currency, baseCurrency, rates),
0,
),
currency: 'EUR',
currency: baseCurrency,
},
};
};
Expand Down
1 change: 1 addition & 0 deletions src/server/userSettings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export const UserSettingsFile = z.object({

const UserSettingsV1 = z.object({
dataPath: z.string(),
currency: z.string().optional(),
});

export const UserSettings = UserSettingsV1;
Expand Down

0 comments on commit 120e5c5

Please sign in to comment.