From 7126f6cc0cf5e139de0aeb6f38408964e1821c8d Mon Sep 17 00:00:00 2001
From: Yaroslav Ermilov <25526713+ya-erm@users.noreply.github.com>
Date: Sat, 18 Nov 2023 04:20:10 +0300
Subject: [PATCH 1/7] Calc expressions in comments
---
src/lib/calc/calculator.ts | 223 ++++++++++++++++++
src/lib/calc/types.ts | 159 +++++++++++++
src/lib/utils/calc.ts | 18 ++
.../transactions/TransactionListItem.svelte | 3 +-
.../transactions/form/TransactionForm.svelte | 22 +-
5 files changed, 423 insertions(+), 2 deletions(-)
create mode 100644 src/lib/calc/calculator.ts
create mode 100644 src/lib/calc/types.ts
create mode 100644 src/lib/utils/calc.ts
diff --git a/src/lib/calc/calculator.ts b/src/lib/calc/calculator.ts
new file mode 100644
index 0000000..e8bf9ae
--- /dev/null
+++ b/src/lib/calc/calculator.ts
@@ -0,0 +1,223 @@
+// Original source:
+// https://github.com/ya-erm/calculator-react/blob/dev/src/model/Calculator.ts
+
+import { CalculationToken } from './types';
+
+class CalculatorError extends Error {
+ message: string;
+ position?: number;
+ constructor(message: string, position?: number) {
+ super();
+ this.message = message;
+ this.position = position;
+ }
+}
+
+const parse: (expression: string) => CalculationToken[] = (expression) => {
+ const tokens: CalculationToken[] = [];
+ let previous: CalculationToken | null = null;
+ let numberChars: string[] = [];
+ let bracketsCount = 0;
+ let unary = false;
+
+ const checkToken = (token: CalculationToken, position: number) => {
+ if (!previous) {
+ if (!token.canBeFirst()) {
+ throw new CalculatorError(`Token ${token} can't be first`, position);
+ }
+ } else if (!token.canBeAfter(previous)) {
+ throw new CalculatorError(`Token ${token} can't be after ${previous.type}`, position);
+ }
+ if (position === expression.length - 1 && !token.canBeLast()) {
+ throw new CalculatorError(`Token ${token} can't be last`, position);
+ }
+ };
+
+ const processNumber = (position: number) => {
+ let numberText = numberChars.join('');
+ if (previous?.type === 'minus' && unary) {
+ numberText = `-${numberText}`;
+ tokens.pop();
+ previous = null;
+ unary = false;
+ }
+ const numberToken = CalculationToken.parse(numberText);
+ if (!numberToken) {
+ throw new CalculatorError(`Failed to initialize number token from "${numberText}"`, position);
+ }
+ checkToken(numberToken, position);
+ tokens.push(numberToken);
+ previous = numberToken;
+ numberChars = [];
+ };
+
+ for (let i = 0; i < expression.length; i++) {
+ const symbol = expression[i];
+ if (symbol === ' ') {
+ continue;
+ }
+ if (symbol.match(/\d/) || symbol === '.') {
+ numberChars.push(symbol);
+ continue;
+ }
+ if (numberChars.length > 0) {
+ processNumber(i);
+ }
+ const token = CalculationToken.parse(symbol);
+ if (!token) {
+ throw new CalculatorError(`Unsupported symbol "${symbol}"`, i);
+ }
+ switch (token.type) {
+ case 'minus':
+ switch (previous?.type) {
+ case 'leftBracket':
+ case 'pow':
+ case null:
+ case undefined:
+ unary = true;
+ break;
+ default:
+ unary = false;
+ break;
+ }
+ break;
+ case 'leftBracket':
+ bracketsCount += 1;
+ break;
+ case 'rightBracket':
+ bracketsCount -= 1;
+ break;
+ default:
+ break;
+ }
+ if (bracketsCount < 0) {
+ throw new CalculatorError('Closed brackets more than opened', i);
+ }
+ checkToken(token, i);
+ tokens.push(token);
+ previous = token;
+ }
+ if (numberChars.length > 0) {
+ processNumber(expression.length - 1);
+ }
+ if (bracketsCount > 0) {
+ throw new CalculatorError('Opened brackets more than closed', expression.length - 1);
+ }
+
+ return tokens;
+};
+
+const performOperation = (operationToken: CalculationToken, left: number, right: number) => {
+ switch (operationToken.type) {
+ case 'plus':
+ return left + right;
+ case 'minus':
+ return left - right;
+ case 'multiply':
+ return left * right;
+ case 'divide':
+ return left / right;
+ case 'mod':
+ return left % right;
+ case 'pow':
+ return Math.pow(left, right);
+ case 'leftBracket':
+ case 'rightBracket':
+ case 'number':
+ throw Error(`${operationToken.type} is not operationToken`);
+ }
+};
+
+export const calculate = (expression: string, previous: number | null) => {
+ let leftStack: CalculationToken[] = [];
+ const rightStack = parse(expression);
+ let accumulator: number | null = null;
+
+ if (previous) {
+ rightStack[0] = new CalculationToken('number', previous.toString());
+ }
+
+ const scroll = () => {
+ const accumulatedValue = accumulator;
+ if (accumulatedValue !== null) {
+ const newToken = new CalculationToken('number', accumulatedValue.toString());
+ leftStack = [newToken, ...leftStack];
+ accumulator = null;
+ }
+ do {
+ const token = rightStack.shift();
+ if (!token) {
+ return;
+ }
+ switch (token.type) {
+ case 'number': {
+ accumulator = parseFloat(token.value!);
+ return;
+ }
+ default: {
+ leftStack = [token, ...leftStack];
+ break;
+ }
+ }
+ } while (rightStack.length > 0);
+ };
+
+ scroll();
+
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ let leftToken = leftStack[0];
+ const rightToken = rightStack[0];
+ let delta = (leftToken?.leftPriority() ?? 0) - (rightToken?.rightPriority() ?? 0);
+ if (leftToken && delta > 0) {
+ const operation = leftStack.shift();
+ const leftOperand = leftStack.shift();
+ if (!operation || !leftOperand) {
+ return;
+ }
+ switch (leftOperand.type) {
+ case 'number': {
+ const value = parseFloat(leftOperand.value!);
+ const result = performOperation(operation, value, accumulator ?? 0);
+ accumulator = result;
+ leftToken = leftStack[0];
+ delta = (leftToken?.leftPriority() ?? 0) - (rightToken?.rightPriority() ?? 0);
+ break;
+ }
+ default: {
+ throw new Error(`Left operand ${leftOperand.type} is not number`);
+ }
+ }
+ }
+ if (rightToken && rightToken?.type !== 'number' && delta < 0) {
+ scroll();
+ }
+ if (leftToken?.type === 'leftBracket' && rightToken?.type === 'rightBracket') {
+ leftStack.shift();
+ rightStack.shift();
+ }
+ if (leftStack.length === 0 && rightStack.length === 0) {
+ break;
+ }
+ }
+
+ return accumulator;
+};
+
+export function roundTo(n: number, digits?: number) {
+ let negative = false;
+ if (digits === undefined) {
+ digits = 0;
+ }
+ if (n < 0) {
+ negative = true;
+ n = -1 * n;
+ }
+ const m = Math.pow(10, digits);
+ let r = parseFloat((n * m).toFixed(11));
+ r = Number((Math.round(r) / m).toFixed(digits));
+ if (negative) {
+ r = -1 * r;
+ }
+ return r;
+}
diff --git a/src/lib/calc/types.ts b/src/lib/calc/types.ts
new file mode 100644
index 0000000..7974a51
--- /dev/null
+++ b/src/lib/calc/types.ts
@@ -0,0 +1,159 @@
+// Original source:
+// https://github.com/ya-erm/calculator-react/blob/dev/src/model/CalculationToken.ts
+
+type ICalculationTokenType =
+ | 'plus'
+ | 'minus'
+ | 'multiply'
+ | 'divide'
+ | 'mod'
+ | 'pow'
+ | 'leftBracket'
+ | 'rightBracket'
+ | 'number';
+
+export class CalculationToken {
+ type: ICalculationTokenType;
+ value?: string;
+
+ constructor(type: ICalculationTokenType, value?: string) {
+ this.type = type;
+ this.value = value;
+ }
+
+ static parse(text: string) {
+ switch (text) {
+ case '+':
+ return new this('plus', text);
+ case '-':
+ return new this('minus', text);
+ case '*':
+ return new this('multiply', text);
+ case '/':
+ return new this('divide', text);
+ case '%':
+ return new this('mod', text);
+ case '^':
+ return new this('pow', text);
+ case '(':
+ return new this('leftBracket', text);
+ case ')':
+ return new this('rightBracket', text);
+
+ default:
+ if (isNaN(parseFloat(text))) {
+ throw new Error(`Can't parse "${text}" as number token`);
+ }
+ return new this('number', text);
+ }
+ }
+
+ canBeAfter = (previous?: CalculationToken) => {
+ if (previous == null) {
+ return this.canBeFirst();
+ }
+ switch (this.type) {
+ case 'leftBracket':
+ case 'number':
+ switch (previous.type) {
+ case 'rightBracket':
+ case 'number':
+ return false;
+ default:
+ return true;
+ }
+ case 'multiply':
+ case 'divide':
+ case 'mod':
+ case 'pow':
+ case 'rightBracket':
+ switch (previous.type) {
+ case 'rightBracket':
+ case 'number':
+ return true;
+ default:
+ return false;
+ }
+ case 'plus':
+ case 'minus':
+ switch (previous.type) {
+ case 'leftBracket':
+ case 'rightBracket':
+ case 'number':
+ return true;
+ default:
+ return false;
+ }
+ }
+ };
+
+ canBeFirst = () => {
+ switch (this.type) {
+ case 'plus':
+ case 'minus':
+ case 'leftBracket':
+ case 'number':
+ return true;
+ case 'multiply':
+ case 'divide':
+ case 'mod':
+ case 'pow':
+ case 'rightBracket':
+ return false;
+ }
+ };
+
+ canBeLast = () => {
+ switch (this.type) {
+ case 'rightBracket':
+ case 'number':
+ return true;
+ default:
+ return false;
+ }
+ };
+
+ canBeUnary = () => {
+ switch (this.type) {
+ case 'minus':
+ case 'plus':
+ return true;
+ default:
+ return false;
+ }
+ };
+
+ isNumber = () => this.type === 'number';
+
+ leftPriority = () => {
+ switch (this.type) {
+ case 'plus':
+ case 'minus':
+ return 2;
+ case 'multiply':
+ case 'divide':
+ case 'mod':
+ return 4;
+ case 'pow':
+ return 5;
+ default:
+ return 0;
+ }
+ };
+
+ rightPriority = () => {
+ switch (this.type) {
+ case 'plus':
+ case 'minus':
+ return 1;
+ case 'multiply':
+ case 'divide':
+ case 'mod':
+ return 3;
+ case 'pow':
+ return 6;
+ default:
+ return 0;
+ }
+ };
+}
diff --git a/src/lib/utils/calc.ts b/src/lib/utils/calc.ts
new file mode 100644
index 0000000..6285925
--- /dev/null
+++ b/src/lib/utils/calc.ts
@@ -0,0 +1,18 @@
+import { calculate } from '$lib/calc/calculator';
+
+import { Logger } from './logger';
+
+const logger = new Logger('Calc');
+
+export function replaceCalcExpressions(text: string) {
+ return text.replaceAll(/\$\{[^}]+\}/g, (substring) => {
+ const expression = substring.slice(2, -1);
+ try {
+ const result = calculate(expression.replaceAll(',', '.'), null);
+ return result?.toFixed(2) ?? substring;
+ } catch (e) {
+ logger.warn('Failed to calculate expression', { text, expression }, e);
+ return substring;
+ }
+ });
+}
diff --git a/src/routes/transactions/TransactionListItem.svelte b/src/routes/transactions/TransactionListItem.svelte
index bfbb52e..4c64a66 100644
--- a/src/routes/transactions/TransactionListItem.svelte
+++ b/src/routes/transactions/TransactionListItem.svelte
@@ -2,6 +2,7 @@
import type { CurrencyRate, TransactionViewModel } from '$lib/data/interfaces';
import { translate, type Messages } from '$lib/translate';
import Icon from '$lib/ui/Icon.svelte';
+ import { replaceCalcExpressions } from '$lib/utils/calc';
import { formatMoney } from '$lib/utils/formatMoney';
export let transaction: TransactionViewModel;
@@ -63,7 +64,7 @@
{#if transaction.comment}
{/if}
{#if transaction.tags?.length}
diff --git a/src/routes/transactions/form/TransactionForm.svelte b/src/routes/transactions/form/TransactionForm.svelte
index 14cfb03..78479fd 100644
--- a/src/routes/transactions/form/TransactionForm.svelte
+++ b/src/routes/transactions/form/TransactionForm.svelte
@@ -11,6 +11,7 @@
import InputLabel from '$lib/ui/InputLabel.svelte';
import { showErrorToast } from '$lib/ui/toasts';
import { formatMoney, getSearchParam } from '$lib/utils';
+ import { replaceCalcExpressions } from '$lib/utils/calc';
import {
checkNumberFormParameter,
checkStringFormParameter,
@@ -65,6 +66,8 @@
let selectedTags = transaction?.tags.map((t) => `${t.id}`) ?? [];
+ let comment = transaction?.comment ?? '';
+
const handleSubmit = async (e: Event) => {
const formData = new FormData(e.target as HTMLFormElement);
if (!formData.get('accountId')) {
@@ -193,7 +196,18 @@
{/if}
-
+ (comment = value)}
+ optional
+ />
+ {#if comment && replaceCalcExpressions(comment) !== comment}
+
+ {/if}
From a327d1899e39c70d5484840e316a34eab8adaaa2 Mon Sep 17 00:00:00 2001
From: Yaroslav Ermilov <25526713+ya-erm@users.noreply.github.com>
Date: Sat, 18 Nov 2023 04:20:30 +0300
Subject: [PATCH 2/7] Show error toast when filed to fetch updates
---
src/lib/data/journal.ts | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/src/lib/data/journal.ts b/src/lib/data/journal.ts
index 5c7d352..154e039 100644
--- a/src/lib/data/journal.ts
+++ b/src/lib/data/journal.ts
@@ -5,6 +5,7 @@ import type {
} from '$lib/server/api/v2/journal';
import type { GetJournalRequest } from '$lib/server/api/v2/journal/getJournal';
import { store } from '$lib/store';
+import { showErrorToast } from '$lib/ui/toasts';
import { unexpectedCase } from '$lib/utils';
import { Logger } from '$lib/utils/logger';
import { useFetch } from '$lib/utils/useFetch';
@@ -147,6 +148,11 @@ export class JournalService implements Initialisable {
await this.fetchUpdates();
} catch (e) {
logger.error('Failed to fetch updates', e);
+ if (e instanceof Error) {
+ showErrorToast(`Failed to fetch updates: ${e.message}`);
+ } else {
+ showErrorToast('Failed to fetch updates');
+ }
} finally {
this._state.set('idle');
}
From e448e0f17e9048227b28ff9985c64727c7fba64c Mon Sep 17 00:00:00 2001
From: Yaroslav Ermilov <25526713+ya-erm@users.noreply.github.com>
Date: Sat, 18 Nov 2023 04:22:22 +0300
Subject: [PATCH 3/7] Version 2.6.0
---
package-lock.json | 4 ++--
package.json | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/package-lock.json b/package-lock.json
index 7bdc494..fdd6314 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "client",
- "version": "2.5.2",
+ "version": "2.6.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "client",
- "version": "2.5.2",
+ "version": "2.6.0",
"dependencies": {
"@prisma/client": "^4.14.1",
"@vercel/analytics": "^1.0.1",
diff --git a/package.json b/package.json
index 40f5bbd..80483c3 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "client",
- "version": "2.5.2",
+ "version": "2.6.0",
"private": true,
"scripts": {
"dev": "vite dev",
From 89eef045817d45bf154419f4281ec90b841416ca Mon Sep 17 00:00:00 2001
From: Yaroslav Ermilov <25526713+ya-erm@users.noreply.github.com>
Date: Sat, 18 Nov 2023 05:28:46 +0300
Subject: [PATCH 4/7] Add another currency option for transaction
---
src/lib/data/interfaces.ts | 2 +
src/lib/translate/en.ts | 2 +
src/lib/translate/messages.ts | 2 +
src/lib/translate/ru.ts | 5 +-
src/lib/utils/calc.ts | 6 ++
src/lib/utils/index.ts | 1 +
src/lib/utils/spreadIf.ts | 21 +++++++
.../transactions/TransactionListItem.svelte | 5 ++
.../transactions/form/TransactionForm.svelte | 61 ++++++++++++++++---
9 files changed, 96 insertions(+), 9 deletions(-)
create mode 100644 src/lib/utils/spreadIf.ts
diff --git a/src/lib/data/interfaces.ts b/src/lib/data/interfaces.ts
index a370d8d..e92a1bb 100644
--- a/src/lib/data/interfaces.ts
+++ b/src/lib/data/interfaces.ts
@@ -100,6 +100,8 @@ export type Transaction = {
comment?: string | null;
description?: string | null;
linkedTransactionId?: string | null;
+ anotherCurrency?: string | null;
+ anotherCurrencyAmount?: number | null;
tagIds?: string[];
deleted?: boolean;
};
diff --git a/src/lib/translate/en.ts b/src/lib/translate/en.ts
index 8c138a6..daa9b6a 100644
--- a/src/lib/translate/en.ts
+++ b/src/lib/translate/en.ts
@@ -179,6 +179,8 @@ export const enDict: Dictionary = {
'transactions.delete_transaction_success': 'Operation was deleted',
'transactions.delete_transaction_failure': 'Failed to delete operation',
'transactions.feature_operations': 'Feature operations',
+ 'transactions.another_currency': 'Another currency',
+ 'transactions.same_currency': 'Same currency',
// Transactions import
'transactions.import': 'Import',
'transactions.import.title': 'Import operations',
diff --git a/src/lib/translate/messages.ts b/src/lib/translate/messages.ts
index fedd983..b836604 100644
--- a/src/lib/translate/messages.ts
+++ b/src/lib/translate/messages.ts
@@ -173,6 +173,8 @@ export type Messages =
| 'transactions.delete_transaction_success'
| 'transactions.delete_transaction_failure'
| 'transactions.feature_operations'
+ | 'transactions.another_currency'
+ | 'transactions.same_currency'
// Transactions import
| 'transactions.import'
| 'transactions.import.title'
diff --git a/src/lib/translate/ru.ts b/src/lib/translate/ru.ts
index 2b32ac0..8ca1c15 100644
--- a/src/lib/translate/ru.ts
+++ b/src/lib/translate/ru.ts
@@ -178,6 +178,10 @@ export const ruDict: Dictionary = {
'transactions.delete_transaction': 'Удалить операцию',
'transactions.delete_transaction_success': 'Операция удалена',
'transactions.delete_transaction_failure': 'Не удалось удалить операцию',
+ 'transactions.feature_operations': 'Будущие операции',
+ 'transactions.another_currency': 'Другая валюта',
+ 'transactions.same_currency': 'Та же валюта',
+ // Transactions import
'transactions.import': 'Импорт',
'transactions.import.title': 'Импорт операций',
'transactions.import.invalid_expression': 'Введите поисковый запрос, чтобы выбрать операции одной категории',
@@ -209,7 +213,6 @@ export const ruDict: Dictionary = {
'transactions.import.rules.delete': 'Удалить правило',
'transactions.import.rules.delete_success': 'Правило удалено',
'transactions.import.rules.delete_failure': 'Не удалось удалить правило',
- 'transactions.feature_operations': 'Будущие операции',
// System
'system.category.transfer_in': 'Перевод c другого счёта',
'system.category.transfer_out': 'Перевод на другой счёт',
diff --git a/src/lib/utils/calc.ts b/src/lib/utils/calc.ts
index 6285925..28ef3b8 100644
--- a/src/lib/utils/calc.ts
+++ b/src/lib/utils/calc.ts
@@ -4,6 +4,12 @@ import { Logger } from './logger';
const logger = new Logger('Calc');
+/**
+ * Replaces calculation expressions in the given text with their evaluated results.
+ *
+ * @param text The text containing calculation expressions in the format "${expression}".
+ * @returns The text with replaced calculation expressions.
+ */
export function replaceCalcExpressions(text: string) {
return text.replaceAll(/\$\{[^}]+\}/g, (substring) => {
const expression = substring.slice(2, -1);
diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts
index 1faabcd..dd71b16 100644
--- a/src/lib/utils/index.ts
+++ b/src/lib/utils/index.ts
@@ -21,6 +21,7 @@ export { join } from './join';
export { keyTransactions } from './keyTransactions';
export { longPress } from './longPress';
export { serialize } from './serialize';
+export { spreadIf } from './spreadIf';
export { unexpectedCase } from './unexpectedCase';
export { useFetch } from './useFetch';
export { useSmartLoading } from './useSmartLoading';
diff --git a/src/lib/utils/spreadIf.ts b/src/lib/utils/spreadIf.ts
new file mode 100644
index 0000000..39e8d85
--- /dev/null
+++ b/src/lib/utils/spreadIf.ts
@@ -0,0 +1,21 @@
+/**
+ * Returns the `values` object if `condition` is true, otherwise returns an empty object.
+ *
+ * @template T The type of the `values` object.
+ * @param {boolean} condition - The condition to check.
+ * @param {T} values The object to return if `condition` is true.
+ * @returns The `values` object if `condition` is true, otherwise an empty object.
+ *
+ * @example
+ * const someObj = {
+ * someProps: 'someProps',
+ * // will add value and description to the object if value is not null
+ * ...spreadIf(value !== null, {
+ * value,
+ * description: 'something',
+ * }),
+ * }
+ */
+export function spreadIf>(condition: boolean, values: T) {
+ return condition ? values : {};
+}
diff --git a/src/routes/transactions/TransactionListItem.svelte b/src/routes/transactions/TransactionListItem.svelte
index 4c64a66..5f993ae 100644
--- a/src/routes/transactions/TransactionListItem.svelte
+++ b/src/routes/transactions/TransactionListItem.svelte
@@ -74,6 +74,11 @@
{/if}
+ {#if !!transaction.anotherCurrencyAmount}
+
+ {formatMoney(transaction.anotherCurrencyAmount, { currency: transaction.anotherCurrency ?? undefined })}
+
+ {/if}
{incoming ? '+' : outgoing ? '-' : ''}{formatMoney(transaction.amount)}
{transaction.account.currency}
diff --git a/src/routes/transactions/form/TransactionForm.svelte b/src/routes/transactions/form/TransactionForm.svelte
index 78479fd..7f92416 100644
--- a/src/routes/transactions/form/TransactionForm.svelte
+++ b/src/routes/transactions/form/TransactionForm.svelte
@@ -7,10 +7,12 @@
import { SYSTEM_CATEGORY_TRANSFER_IN, SYSTEM_CATEGORY_TRANSFER_OUT } from '$lib/data/categories';
import type { AccountViewModel, Category, Tag, Transaction, TransactionViewModel } from '$lib/data/interfaces';
import { translate } from '$lib/translate';
+ import Button from '$lib/ui/Button.svelte';
import Input from '$lib/ui/Input.svelte';
import InputLabel from '$lib/ui/InputLabel.svelte';
+ import Modal from '$lib/ui/Modal.svelte';
import { showErrorToast } from '$lib/ui/toasts';
- import { formatMoney, getSearchParam } from '$lib/utils';
+ import { formatMoney, getSearchParam, spreadIf } from '$lib/utils';
import { replaceCalcExpressions } from '$lib/utils/calc';
import {
checkNumberFormParameter,
@@ -58,7 +60,7 @@
$: destinationAccountCurrency = accounts.find(({ id }) => id === destinationAccountId)?.currency;
let _value1 = (isTransfer ? sourceTransaction?.amount : transaction?.amount)?.toString() ?? '';
- let _value2 = destinationTransaction?.amount?.toString() ?? '';
+ let _value2 = destinationTransaction?.amount?.toString() ?? transaction?.anotherCurrencyAmount?.toString() ?? '';
$: _rate = Number(_value1) / Number(_value2);
let selectingAccount = false;
@@ -68,6 +70,9 @@
let comment = transaction?.comment ?? '';
+ let anotherCurrencyModalOpened = false;
+ let anotherCurrency: string | null = transaction?.anotherCurrency ?? null;
+
const handleSubmit = async (e: Event) => {
const formData = new FormData(e.target as HTMLFormElement);
if (!formData.get('accountId')) {
@@ -102,6 +107,10 @@
amount: checkNumberFormParameter(formData, 'amount'),
comment: checkStringOptionalFormParameter(formData, 'comment'),
tagIds: selectedTags,
+ ...spreadIf(!!anotherCurrency, {
+ anotherCurrency,
+ anotherCurrencyAmount: checkNumberFormParameter(formData, 'destinationAmount'),
+ }),
});
if (type === 'TRANSFER') {
@@ -166,7 +175,20 @@
-
+
+
+ {#if type !== 'TRANSFER'}
+ {#if !anotherCurrency}
+
+ {:else}
+
+ {/if}
+ {/if}
+
- {#if type === 'TRANSFER'}
+ {#if type === 'TRANSFER' || !!anotherCurrency}
{/if}
- {#if type === 'TRANSFER' && Number(_value1) && Number(_value2)}
+ {#if (type === 'TRANSFER' || !!anotherCurrency) && Number(_value1) && Number(_value2)}
{`1 ${accountCurrency} = ${formatMoney(1 / _rate, {
maxPrecision: 4,
- currency: destinationAccountCurrency,
+ currency: destinationAccountCurrency || (anotherCurrency ?? undefined),
})}`}
- {`(1 ${destinationAccountCurrency} = ${formatMoney(_rate, { maxPrecision: 4, currency: accountCurrency })})`}
+ {`(1 ${destinationAccountCurrency || anotherCurrency} = ${formatMoney(_rate, {
+ maxPrecision: 4,
+ currency: accountCurrency,
+ })})`}
{/if}
@@ -224,6 +249,26 @@
+
+
+
+