Skip to content

Commit

Permalink
Merge pull request #30 from ya-erm/main-currency
Browse files Browse the repository at this point in the history
Currency rates and main currency
  • Loading branch information
ya-erm authored Mar 11, 2023
2 parents 4c214ab + 9a2cdbe commit 98c79e2
Show file tree
Hide file tree
Showing 19 changed files with 452 additions and 17 deletions.
13 changes: 13 additions & 0 deletions prisma/migrations/20230311162322_add_currency_rates/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- CreateTable
CREATE TABLE "CurrencyRate" (
"id" SERIAL NOT NULL,
"ownerId" INTEGER NOT NULL,
"cur1" TEXT NOT NULL,
"cur2" TEXT NOT NULL,
"rate" DOUBLE PRECISION NOT NULL,

CONSTRAINT "CurrencyRate_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "CurrencyRate" ADD CONSTRAINT "CurrencyRate_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "Group"("id") ON DELETE CASCADE ON UPDATE CASCADE;
12 changes: 12 additions & 0 deletions prisma/migrations/20230311173536_add_user_settings/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
-- CreateTable
CREATE TABLE "UserSettings" (
"userId" INTEGER NOT NULL,
"theme" TEXT,
"language" TEXT,
"currency" TEXT,

CONSTRAINT "UserSettings_pkey" PRIMARY KEY ("userId")
);

-- AddForeignKey
ALTER TABLE "UserSettings" ADD CONSTRAINT "UserSettings_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
37 changes: 30 additions & 7 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ model User {
name String?
password UserPassword?
settings UserSettings?
tokens AuthToken[]
groups UserToGroup[]
Expand All @@ -36,6 +37,16 @@ model UserPassword {
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model UserSettings {
userId Int @id
theme String?
language String?
currency String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
}

model AuthToken {
id Int @id @default(autoincrement())
value String @unique
Expand Down Expand Up @@ -90,13 +101,14 @@ model Group {
id Int @id @default(autoincrement())
name String
users UserToGroup[]
accounts Account[]
categories Category[]
transactions Transaction[]
tokens AuthToken[]
tags Tag[]
importRules ImportRule[]
users UserToGroup[]
accounts Account[]
categories Category[]
transactions Transaction[]
tokens AuthToken[]
tags Tag[]
importRules ImportRule[]
currencyRates CurrencyRate[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
Expand Down Expand Up @@ -176,3 +188,14 @@ model ImportRule {
category Category? @relation(fields: [categoryId], references: [id])
tags Tag[]
}

model CurrencyRate {
id Int @id @default(autoincrement())
ownerId Int
cur1 String
cur2 String
rate Float
owner Group @relation(fields: [ownerId], references: [id], onDelete: Cascade)
}
2 changes: 2 additions & 0 deletions src/lib/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ export const deps = {
transactions: 'transactions',
importRules: 'importRules',
tags: 'tags',
settings: 'settings',
currencyRates: 'currencyRates',
};
5 changes: 5 additions & 0 deletions src/lib/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ type RouteKey =
| 'transactions.import.rules.create'
| 'settings'
| 'settings.language'
| 'settings.currency_rates'
| 'uikit';

export const routes: { [key in RouteKey]: Route } = {
Expand Down Expand Up @@ -99,6 +100,10 @@ export const routes: { [key in RouteKey]: Route } = {
path: '/settings/language',
title: 'settings.select_language',
},
'settings.currency_rates': {
path: '/settings/currency-rates',
title: 'currency_rates.title',
},
uikit: {
path: '/uikit',
title: 'settings.uikit',
Expand Down
10 changes: 10 additions & 0 deletions src/lib/translate/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ export const enDict: Dictionary = {
// System
'system.category.transfer_in': 'Transfer from other account',
'system.category.transfer_out': 'Transfer to other account',
// Currency rates
'currency_rates.title': 'Currency rates',
'currency_rates.default_currency': 'Main currency',
'currency_rates.new_currency_rate': 'New currency rate',
'currency_rates.currency1': 'Currency 1',
'currency_rates.currency2': 'Currency 2',
'currency_rates.rate': 'Rate',
'currency_rates.delete_currency_rate': 'Delete currency rate',
'currency_rates.delete_currency_rate_success': 'Currency rate was deleted',
'currency_rates.delete_currency_rate_failure': 'Failed to delete currency rate',
// Settings
'settings.title': 'Settings',
'settings.language': 'Language',
Expand Down
2 changes: 1 addition & 1 deletion src/lib/translate/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,4 @@ export const languages: { [key in Locales]: { name: string; icon: string } } = {
export const activeLocale = storable<Locales>((initialLocale as Locales) ?? 'ru-RU', 'locale');
activeLocale.subscribe((value) => locale.set(value));

export const activeLocaleName = derived(activeLocale, (value) => languages[value].name);
export const activeLocaleName = derived(activeLocale, (value) => languages[value]?.name ?? languages['en-US'].name);
10 changes: 10 additions & 0 deletions src/lib/translate/messages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,16 @@ export type Messages =
// System
| 'system.category.transfer_out'
| 'system.category.transfer_in'
// Currency rates
| 'currency_rates.title'
| 'currency_rates.default_currency'
| 'currency_rates.new_currency_rate'
| 'currency_rates.currency1'
| 'currency_rates.currency2'
| 'currency_rates.rate'
| 'currency_rates.delete_currency_rate'
| 'currency_rates.delete_currency_rate_success'
| 'currency_rates.delete_currency_rate_failure'
// Settings
| 'settings.title'
| 'settings.common'
Expand Down
10 changes: 10 additions & 0 deletions src/lib/translate/ru.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,16 @@ export const ruDict: Dictionary = {
// System
'system.category.transfer_in': 'Перевод c другого счёта',
'system.category.transfer_out': 'Перевод на другой счёт',
// Currency rates
'currency_rates.title': 'Курсы валют',
'currency_rates.default_currency': 'Основная валюта',
'currency_rates.new_currency_rate': 'Новый курс валют',
'currency_rates.currency1': 'Валюта 1',
'currency_rates.currency2': 'Валюта 2',
'currency_rates.rate': 'Курс',
'currency_rates.delete_currency_rate': 'Удалить курс валют',
'currency_rates.delete_currency_rate_success': 'Курс валют удалён',
'currency_rates.delete_currency_rate_failure': 'Не удалось удалить курс валют',
// Settings
'settings.title': 'Настройки',
'settings.language': 'Язык',
Expand Down
2 changes: 2 additions & 0 deletions src/lib/ui/Modal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
export let opened: boolean;
export let header: string | null = null;
export let width: string | number | null = null;
const dispatch = createEventDispatcher();
const close = () => {
Expand Down Expand Up @@ -38,6 +39,7 @@
on:click|stopPropagation
in:fade={{ duration: 100 }}
out:fade={{ duration: 100 }}
style:width={typeof width === 'string' ? width : `${width}rem`}
aria-hidden
>
{#if $$slots.header}
Expand Down
14 changes: 13 additions & 1 deletion src/routes/accounts/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,17 @@ import type { Category } from '@prisma/client';
import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ locals, depends }) => {
const { groupId } = checkUserAndGroup(locals, { redirect: true });
const { userId, groupId } = checkUserAndGroup(locals, { redirect: true });

depends(deps.settings);
const settings = await db.userSettings.findUnique({
where: { userId },
});

depends(deps.currencyRates);
const currencyRates = await db.currencyRate.findMany({
where: { ownerId: groupId },
});

depends(deps.categories);
const categories = await db.category.findMany({
Expand All @@ -31,6 +41,8 @@ export const load: PageServerLoad = async ({ locals, depends }) => {
});

return {
settings,
currencyRates,
accounts: accounts.map((account) => ({
...account,
sum: transactions
Expand Down
15 changes: 13 additions & 2 deletions src/routes/accounts/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
useRightButton(AddAccountButton);
export let data: PageData;
$: settings = data.settings;
$: currencyRates = data.currencyRates;
$: accounts = data.accounts;
$: categories = data.categories;
$: tags = data.tags;
Expand Down Expand Up @@ -71,6 +73,15 @@
return res;
}, {} as { [key: string]: TransactionFullDto[] });
const findCurrencyRate = (currency: string) =>
settings?.currency !== currency
? currencyRates.find(
({ cur1, cur2 }) => [cur1, cur2].includes(settings?.currency) && [cur1, cur2].includes(currency),
) ?? null
: null;
$: currencyRate = findCurrencyRate(account?.currency ?? '');
onMount(() => {
if (cardId) {
scrollToCard(cardId);
Expand Down Expand Up @@ -116,7 +127,7 @@
<div class="accounts-list" bind:this={accountListElement} on:scroll={handleScroll}>
{#each accounts as account}
<div class="account-card" on:click={() => scrollToCard(account.id)} aria-hidden>
<AccountCard {account} />
<AccountCard {account} currencyRate={findCurrencyRate(account.currency)} />
<div id={`account-card-${account.id}`} class="account-card-anchor" />
</div>
{/each}
Expand All @@ -143,7 +154,7 @@
{#each Object.entries(groups) as [date, transactions] (date)}
<div>{date}</div>
{#each transactions as transaction (transaction.id)}
<TransactionListItem hideAccount={!!account} {transaction} />
<TransactionListItem hideAccount={!!account} {transaction} {currencyRate} />
{/each}
{/each}
</div>
Expand Down
21 changes: 19 additions & 2 deletions src/routes/accounts/AccountCard.svelte
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
<script lang="ts">
import { goto } from '$app/navigation';
import type { Account } from '@prisma/client';
import type { Account, CurrencyRate } from '@prisma/client';
import { routes } from '$lib/routes';
import Button from '$lib/ui/Button.svelte';
import Icon from '$lib/ui/Icon.svelte';
import { formatMoney } from '$lib/utils/formatMoney';
export let account: Account & { sum: number };
export let currencyRate: CurrencyRate | null = null;
const rate = currencyRate?.cur1 === account.currency ? currencyRate.rate : 1 / (currencyRate?.rate ?? 1);
const otherCurrency = currencyRate?.cur1 === account.currency ? currencyRate.cur2 : currencyRate?.cur1;
</script>

<div class="w-full h-full p-1 flex-col items-center justify-between">
Expand All @@ -20,7 +24,16 @@
<Icon name="mdi:pencil" padding={0.5} />
</Button>
</div>
<div class="money-value flex">{formatMoney(account.sum, account.currency)}</div>
<div class="flex-col items-center gap-0.25">
<div class="money-value">
{formatMoney(account.sum, account.currency)}
</div>
{#if currencyRate}
<div class="other-money-value">
{formatMoney(account.sum * rate, otherCurrency)}
</div>
{/if}
</div>
<div class="flex footer" />
</div>

Expand All @@ -32,6 +45,10 @@
.money-value {
font-size: 1.2rem;
}
.other-money-value {
font-size: 1rem;
color: var(--secondary-text-color);
}
.footer {
min-height: 2.5rem;
}
Expand Down
1 change: 1 addition & 0 deletions src/routes/settings/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { deps } from '$lib/deps';
import { db } from '$lib/server';
import { getGroups } from '$lib/server/api/groups';
import { checkUserAndGroup } from '$lib/utils';

import type { PageServerLoad } from './$types';

export const load: PageServerLoad = async ({ locals, depends }) => {
Expand Down
5 changes: 5 additions & 0 deletions src/routes/settings/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
<ListGroup title={$translate('settings.common')}>
<ListSelectItem title={$translate('settings.language')} value={$activeLocaleName} on:click={openLanguageModal} />
<ListSwitchItem title={$translate('settings.darkMode')} bind:checked={$darkMode} />
<ListSelectItem
title={$translate('currency_rates.title')}
value=""
on:click={() => goto(routes['settings.currency_rates'].path)}
/>
</ListGroup>

<ListGroup title={$translate('settings.profile')}>
Expand Down
Loading

1 comment on commit 98c79e2

@vercel
Copy link

@vercel vercel bot commented on 98c79e2 Mar 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.