From f764653689beddcbda86817375ee446d4aade383 Mon Sep 17 00:00:00 2001 From: evavirseda Date: Tue, 21 Nov 2023 16:04:41 +0100 Subject: [PATCH 1/8] feat: add expiration date to deeplinks --- .../deep-link/enums/send-operation-parameter.enum.ts | 1 + .../handleDeepLinkSendConfirmationOperation.ts | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/packages/shared/lib/auxiliary/deep-link/enums/send-operation-parameter.enum.ts b/packages/shared/lib/auxiliary/deep-link/enums/send-operation-parameter.enum.ts index 915e569e414..6becf23ced4 100644 --- a/packages/shared/lib/auxiliary/deep-link/enums/send-operation-parameter.enum.ts +++ b/packages/shared/lib/auxiliary/deep-link/enums/send-operation-parameter.enum.ts @@ -12,4 +12,5 @@ export enum SendOperationParameter { Surplus = 'surplus', DisableToggleGift = 'disableToggleGift', DisableChangeExpiration = 'disableChangeExpiration', + ExpirationDate = 'expirationDate', } diff --git a/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts b/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts index c31412f621c..48a7b01f775 100644 --- a/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts +++ b/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts @@ -90,10 +90,19 @@ function parseSendConfirmationOperation(searchParams: URLSearchParams): NewTrans throw new TagLengthError() } + const getExpirationDate = (expirationDate: string): Date | undefined => { + if (!expirationDate) { + return undefined + } + const expirationDateTime = new Date(expirationDate) + return expirationDateTime + } + const unit = searchParams.get(SendOperationParameter.Unit) ?? getUnitFromTokenMetadata(asset.metadata) const giftStorageDeposit = isStringTrue(searchParams.get(SendOperationParameter.GiftStorageDeposit)) const disableToggleGift = isStringTrue(searchParams.get(SendOperationParameter.DisableToggleGift)) const disableChangeExpiration = isStringTrue(searchParams.get(SendOperationParameter.DisableChangeExpiration)) + const expirationDate = getExpirationDate(searchParams.get(SendOperationParameter.ExpirationDate)) return { type: NewTransactionType.TokenTransfer, @@ -107,5 +116,6 @@ function parseSendConfirmationOperation(searchParams: URLSearchParams): NewTrans ...(surplus && { surplus }), ...(disableToggleGift && { disableToggleGift }), ...(disableChangeExpiration && { disableChangeExpiration }), + ...(expirationDate && { expirationDate }), } } From 2fa30ab848df294f747d5eeea06cc408a458432b Mon Sep 17 00:00:00 2001 From: evavirseda Date: Tue, 21 Nov 2023 16:58:47 +0100 Subject: [PATCH 2/8] fix: cleanup --- .../lib/auxiliary/deep-link/errors/index.ts | 4 +++- .../errors/invalid-expiration-date.error.ts | 14 ++++++++++++++ .../errors/past-expiration-date.error.ts | 14 ++++++++++++++ .../handleDeepLinkSendConfirmationOperation.ts | 16 ++++------------ .../utils/getRawExpirationDateFromSearchParam.ts | 15 +++++++++++++++ .../lib/auxiliary/deep-link/utils/index.ts | 1 + packages/shared/locales/en.json | 2 ++ 7 files changed, 53 insertions(+), 13 deletions(-) create mode 100644 packages/shared/lib/auxiliary/deep-link/errors/invalid-expiration-date.error.ts create mode 100644 packages/shared/lib/auxiliary/deep-link/errors/past-expiration-date.error.ts create mode 100644 packages/shared/lib/auxiliary/deep-link/utils/getRawExpirationDateFromSearchParam.ts diff --git a/packages/shared/lib/auxiliary/deep-link/errors/index.ts b/packages/shared/lib/auxiliary/deep-link/errors/index.ts index 066181b1df4..30b8105bdb9 100644 --- a/packages/shared/lib/auxiliary/deep-link/errors/index.ts +++ b/packages/shared/lib/auxiliary/deep-link/errors/index.ts @@ -1,9 +1,11 @@ export * from './amount-not-an-integer.error' export * from './invalid-address.error' export * from './invalid-asset-id.error' +export * from './invalid-expiration-date.error' export * from './metadata-length.error' export * from './no-address-specified.error' -export * from './tag-length.error' +export * from './past-expiration-date.error' export * from './surplus-not-a-number.error' export * from './surplus-not-supported.error' +export * from './tag-length.error' export * from './unknown-asset.error' diff --git a/packages/shared/lib/auxiliary/deep-link/errors/invalid-expiration-date.error.ts b/packages/shared/lib/auxiliary/deep-link/errors/invalid-expiration-date.error.ts new file mode 100644 index 00000000000..feec537ce9b --- /dev/null +++ b/packages/shared/lib/auxiliary/deep-link/errors/invalid-expiration-date.error.ts @@ -0,0 +1,14 @@ +import { BaseError } from '@core/error' +import { localize } from '@core/i18n' + +export class InvalidExpirationDateError extends BaseError { + constructor() { + const message = localize('error.send.invalidExpirationDate') + super({ + message, + showNotification: false, + saveToErrorLog: false, + logToConsole: true, + }) + } +} diff --git a/packages/shared/lib/auxiliary/deep-link/errors/past-expiration-date.error.ts b/packages/shared/lib/auxiliary/deep-link/errors/past-expiration-date.error.ts new file mode 100644 index 00000000000..99f56336b41 --- /dev/null +++ b/packages/shared/lib/auxiliary/deep-link/errors/past-expiration-date.error.ts @@ -0,0 +1,14 @@ +import { BaseError } from '@core/error' +import { localize } from '@core/i18n' + +export class PastExpirationDateError extends BaseError { + constructor() { + const message = localize('error.send.pastExpirationDate') + super({ + message, + showNotification: false, + saveToErrorLog: false, + logToConsole: true, + }) + } +} diff --git a/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts b/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts index 48a7b01f775..6aaca1df0d7 100644 --- a/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts +++ b/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts @@ -1,4 +1,6 @@ import { PopupId, openPopup } from '@auxiliary/popup' +import { getActiveNetworkId } from '@core/network/utils/getNetworkId' +import { getNetworkHrp } from '@core/profile/actions' import { getByteLengthOfString, isStringTrue, isValidBech32AddressAndPrefix, validateAssetId } from '@core/utils' import { NewTransactionDetails, @@ -21,9 +23,7 @@ import { TagLengthError, UnknownAssetError, } from '../../../errors' -import { getRawAmountFromSearchParam } from '../../../utils' -import { getNetworkHrp } from '@core/profile/actions' -import { getActiveNetworkId } from '@core/network/utils/getNetworkId' +import { getExpirationDateFromSearchParam, getRawAmountFromSearchParam } from '../../../utils' export function handleDeepLinkSendConfirmationOperation(searchParams: URLSearchParams): void { const transactionDetails = parseSendConfirmationOperation(searchParams) @@ -90,19 +90,11 @@ function parseSendConfirmationOperation(searchParams: URLSearchParams): NewTrans throw new TagLengthError() } - const getExpirationDate = (expirationDate: string): Date | undefined => { - if (!expirationDate) { - return undefined - } - const expirationDateTime = new Date(expirationDate) - return expirationDateTime - } - const unit = searchParams.get(SendOperationParameter.Unit) ?? getUnitFromTokenMetadata(asset.metadata) const giftStorageDeposit = isStringTrue(searchParams.get(SendOperationParameter.GiftStorageDeposit)) const disableToggleGift = isStringTrue(searchParams.get(SendOperationParameter.DisableToggleGift)) const disableChangeExpiration = isStringTrue(searchParams.get(SendOperationParameter.DisableChangeExpiration)) - const expirationDate = getExpirationDate(searchParams.get(SendOperationParameter.ExpirationDate)) + const expirationDate = getExpirationDateFromSearchParam(searchParams.get(SendOperationParameter.ExpirationDate)) return { type: NewTransactionType.TokenTransfer, diff --git a/packages/shared/lib/auxiliary/deep-link/utils/getRawExpirationDateFromSearchParam.ts b/packages/shared/lib/auxiliary/deep-link/utils/getRawExpirationDateFromSearchParam.ts new file mode 100644 index 00000000000..5491ed2df49 --- /dev/null +++ b/packages/shared/lib/auxiliary/deep-link/utils/getRawExpirationDateFromSearchParam.ts @@ -0,0 +1,15 @@ +import { InvalidExpirationDateError, PastExpirationDateError } from '../errors' + +export function getExpirationDateFromSearchParam(expirationDate: string): Date | undefined { + if (!expirationDate) { + return undefined + } + const expirationDateTime = new Date(expirationDate) + if (isNaN(expirationDateTime.getTime())) { + throw new InvalidExpirationDateError() + } else if (expirationDateTime.getTime() < Date.now()) { + throw new PastExpirationDateError() + } else { + return expirationDateTime + } +} diff --git a/packages/shared/lib/auxiliary/deep-link/utils/index.ts b/packages/shared/lib/auxiliary/deep-link/utils/index.ts index 1174377121b..2a2cf2fbf86 100644 --- a/packages/shared/lib/auxiliary/deep-link/utils/index.ts +++ b/packages/shared/lib/auxiliary/deep-link/utils/index.ts @@ -1 +1,2 @@ export * from './getRawAmountFromSearchParam' +export * from './getRawExpirationDateFromSearchParam' diff --git a/packages/shared/locales/en.json b/packages/shared/locales/en.json index 03ac0d48f1f..5f4abe1801e 100644 --- a/packages/shared/locales/en.json +++ b/packages/shared/locales/en.json @@ -1942,6 +1942,8 @@ "wrongAddressPrefix": "Addresses start with the prefix {prefix}.", "wrongAddressFormat": "The address is not correctly formatted.", "invalidAddress": "The address is not valid.", + "invalidExpirationDate": "The expiration date is not valid.", + "pastExpirationDate": "The expiration date is in the past.", "invalidAssetId": "The asset id is not valid.", "unknownAsset": "The asset is not known to this account.", "insufficientFunds": "This wallet has insufficient funds.", From 1106e44635d7b507b7b15f94ca7e1f0781caf796 Mon Sep 17 00:00:00 2001 From: evavirseda Date: Tue, 21 Nov 2023 16:59:42 +0100 Subject: [PATCH 3/8] fix: cleanup --- ...teFromSearchParam.ts => getExpirationDateFromSearchParam.ts} | 0 packages/shared/lib/auxiliary/deep-link/utils/index.ts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename packages/shared/lib/auxiliary/deep-link/utils/{getRawExpirationDateFromSearchParam.ts => getExpirationDateFromSearchParam.ts} (100%) diff --git a/packages/shared/lib/auxiliary/deep-link/utils/getRawExpirationDateFromSearchParam.ts b/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts similarity index 100% rename from packages/shared/lib/auxiliary/deep-link/utils/getRawExpirationDateFromSearchParam.ts rename to packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts diff --git a/packages/shared/lib/auxiliary/deep-link/utils/index.ts b/packages/shared/lib/auxiliary/deep-link/utils/index.ts index 2a2cf2fbf86..37761bf0334 100644 --- a/packages/shared/lib/auxiliary/deep-link/utils/index.ts +++ b/packages/shared/lib/auxiliary/deep-link/utils/index.ts @@ -1,2 +1,2 @@ +export * from './getExpirationDateFromSearchParam' export * from './getRawAmountFromSearchParam' -export * from './getRawExpirationDateFromSearchParam' From 13210632d755a8df9b7e199cf094fc19128b692c Mon Sep 17 00:00:00 2001 From: evavirseda Date: Wed, 22 Nov 2023 11:23:51 +0100 Subject: [PATCH 4/8] fix: improve timestamp, use unix and allow 1h, 1d... --- .../enums/send-operation-parameter.enum.ts | 2 +- ...handleDeepLinkSendConfirmationOperation.ts | 2 +- .../utils/getExpirationDateFromSearchParam.ts | 52 ++++++++++++++++--- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/packages/shared/lib/auxiliary/deep-link/enums/send-operation-parameter.enum.ts b/packages/shared/lib/auxiliary/deep-link/enums/send-operation-parameter.enum.ts index 6becf23ced4..cfc20f777b6 100644 --- a/packages/shared/lib/auxiliary/deep-link/enums/send-operation-parameter.enum.ts +++ b/packages/shared/lib/auxiliary/deep-link/enums/send-operation-parameter.enum.ts @@ -12,5 +12,5 @@ export enum SendOperationParameter { Surplus = 'surplus', DisableToggleGift = 'disableToggleGift', DisableChangeExpiration = 'disableChangeExpiration', - ExpirationDate = 'expirationDate', + Expiration = 'expiration', } diff --git a/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts b/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts index 6aaca1df0d7..3911c1d5c92 100644 --- a/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts +++ b/packages/shared/lib/auxiliary/deep-link/handlers/wallet/operations/handleDeepLinkSendConfirmationOperation.ts @@ -94,7 +94,7 @@ function parseSendConfirmationOperation(searchParams: URLSearchParams): NewTrans const giftStorageDeposit = isStringTrue(searchParams.get(SendOperationParameter.GiftStorageDeposit)) const disableToggleGift = isStringTrue(searchParams.get(SendOperationParameter.DisableToggleGift)) const disableChangeExpiration = isStringTrue(searchParams.get(SendOperationParameter.DisableChangeExpiration)) - const expirationDate = getExpirationDateFromSearchParam(searchParams.get(SendOperationParameter.ExpirationDate)) + const expirationDate = getExpirationDateFromSearchParam(searchParams.get(SendOperationParameter.Expiration)) return { type: NewTransactionType.TokenTransfer, diff --git a/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts b/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts index 5491ed2df49..9eac58b084f 100644 --- a/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts +++ b/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts @@ -1,15 +1,55 @@ import { InvalidExpirationDateError, PastExpirationDateError } from '../errors' +enum TimeUnit { + Weeks = 'w', + Days = 'd', + Hours = 'h', + Minutes = 'm', +} + +const timeUnitValues: Record = { + [TimeUnit.Weeks]: 604800000, + [TimeUnit.Days]: 86400000, + [TimeUnit.Hours]: 3600000, + [TimeUnit.Minutes]: 60000, +} + export function getExpirationDateFromSearchParam(expirationDate: string): Date | undefined { if (!expirationDate) { return undefined } - const expirationDateTime = new Date(expirationDate) - if (isNaN(expirationDateTime.getTime())) { + + // Check if it's a Unix timestamp (numeric value) + if (!isNaN(Number(expirationDate))) { + const expirationTimestamp = parseInt(expirationDate) + const expirationDateTime = new Date(expirationTimestamp * 1000) // Convert seconds to milliseconds + if (isNaN(expirationDateTime.getTime())) { + throw new InvalidExpirationDateError() + } else if (expirationDateTime.getTime() < Date.now()) { + throw new PastExpirationDateError() + } else { + return expirationDateTime + } + } + + // Validate expiration date format for relative time + const expirationRegex = /^(\d+)([hdwm])$/ + const regexMatch = expirationRegex.exec(expirationDate) + + if (!regexMatch) { throw new InvalidExpirationDateError() - } else if (expirationDateTime.getTime() < Date.now()) { - throw new PastExpirationDateError() - } else { - return expirationDateTime } + + const value = parseInt(regexMatch[1]) + const unit = regexMatch[2] as TimeUnit + + const selectedTimeUnitValue = timeUnitValues[unit] + + if (selectedTimeUnitValue === undefined) { + throw new InvalidExpirationDateError() + } + + const expirationDateTime = new Date(Date.now() + value * selectedTimeUnitValue) + + return expirationDateTime } From 1196eb58e1dfbefa69e898fb0b574977be7ce63d Mon Sep 17 00:00:00 2001 From: evavirseda Date: Wed, 22 Nov 2023 11:37:51 +0100 Subject: [PATCH 5/8] feat: update handbook --- docs/specifications/deep-links.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/docs/specifications/deep-links.md b/docs/specifications/deep-links.md index 96a7fe4d4a0..bb5c8f75966 100644 --- a/docs/specifications/deep-links.md +++ b/docs/specifications/deep-links.md @@ -103,7 +103,7 @@ This operation brings the user to the send confirmation popup: The deep link structure is as follows: ``` -firefly://wallet/sendConfirmation?address=
&amount=[&unit=][&assetId=][&metadata=][&tag=][&giftStorageDeposit=][&disableToggleGift=][&disableChangeExpiration=][&surplus=] +firefly://wallet/sendConfirmation?address=
&amount=[&unit=][&assetId=][&metadata=][&tag=][&giftStorageDeposit=][&disableToggleGift=][&disableChangeExpiration=][&surplus=][&expiration=] ``` The following parameters are **required**: @@ -123,15 +123,16 @@ The following parameters are **optional**: - `disableToggleGift` - prevents the user from being able to toggle the option to gift the storage deposit - `disableChangeExpiration` - prevents the user from being able to change the expiration time of the transaction - `surplus` - send additional amounts of the base token when transferring native tokens +- `expiration` - the expiration time of the transaction, e.g. `1w`, `2d`, `5h` or `10m`. Also accepts a UNIX timestamp in milliseconds. Example: -[!button Click me!](firefly://wallet/sendForm?address=iota1qrhacyfwlcnzkvzteumekfkrrwks98mpdm37cj4xx3drvmjvnep6xqgyzyx&amount=10&unit=Gi&giftStorageDeposit=true&surplus=1&metadata=Take%20my%20money) +[!button Click me!](firefly://wallet/sendConfirmation?address=iota1qrhacyfwlcnzkvzteumekfkrrwks98mpdm37cj4xx3drvmjvnep6xqgyzyx&amount=10&unit=Gi&giftStorageDeposit=true&surplus=1&metadata=Take%20my%20money&expiration=1h) Source: ``` -firefly://wallet/sendConfirmation?address=iota1qrhacyfwlcnzkvzteumekfkrrwks98mpdm37cj4xx3drvmjvnep6xqgyzyx&amount=10&unit=Gi&giftStorageDeposit=true&disableToggleGift=true&surplus=1&metadata=Take%20my%20money +firefly://wallet/sendConfirmation?address=iota1qrhacyfwlcnzkvzteumekfkrrwks98mpdm37cj4xx3drvmjvnep6xqgyzyx&amount=10&unit=Gi&giftStorageDeposit=true&disableToggleGift=true&surplus=1&metadata=Take%20my%20money&expiration=1h ``` ### Collectibles From d901aa106847bb436b73200dbf690a724fff8196 Mon Sep 17 00:00:00 2001 From: evavirseda Date: Thu, 30 Nov 2023 12:09:50 +0100 Subject: [PATCH 6/8] fix: update sendConfirmation flow and split constnats,enums.. in different files --- .../popups/send/SendConfirmationPopup.svelte | 6 +++++ .../expiration-date-regex.constant.ts | 3 +++ .../auxiliary/deep-link/constants/index.ts | 2 ++ .../constants/time-unit-ms.constant.ts | 14 +++++++++++ .../lib/auxiliary/deep-link/enums/index.ts | 3 ++- .../deep-link/enums/time-unit.enum.ts | 6 +++++ .../errors/invalid-expiration-date.error.ts | 2 +- .../errors/past-expiration-date.error.ts | 2 +- .../utils/getExpirationDateFromSearchParam.ts | 24 +++++-------------- .../core/utils/constants/time.constants.ts | 3 +++ 10 files changed, 44 insertions(+), 21 deletions(-) create mode 100644 packages/shared/lib/auxiliary/deep-link/constants/expiration-date-regex.constant.ts create mode 100644 packages/shared/lib/auxiliary/deep-link/constants/time-unit-ms.constant.ts create mode 100644 packages/shared/lib/auxiliary/deep-link/enums/time-unit.enum.ts diff --git a/packages/desktop/components/popups/send/SendConfirmationPopup.svelte b/packages/desktop/components/popups/send/SendConfirmationPopup.svelte index 6d1e94b05d0..4dc003e0d60 100644 --- a/packages/desktop/components/popups/send/SendConfirmationPopup.svelte +++ b/packages/desktop/components/popups/send/SendConfirmationPopup.svelte @@ -68,6 +68,12 @@ $: isLayer2Transaction = !!layer2Parameters $: isTransferring = $selectedAccount.isTransferring $: hideGiftToggle = isBaseTokenTransfer || isLayer2Transaction || (disableToggleGift && !giftStorageDeposit) + $: initialExpirationDate = getInitialExpirationDate( + expirationDate, + storageDeposit, + giftStorageDeposit, + isLayer2Transaction + ) $: if (!isSendAndClosePopup) expirationDate, giftStorageDeposit, void rebuildTransactionOutput() diff --git a/packages/shared/lib/auxiliary/deep-link/constants/expiration-date-regex.constant.ts b/packages/shared/lib/auxiliary/deep-link/constants/expiration-date-regex.constant.ts new file mode 100644 index 00000000000..e5f947a0ee8 --- /dev/null +++ b/packages/shared/lib/auxiliary/deep-link/constants/expiration-date-regex.constant.ts @@ -0,0 +1,3 @@ +import { TimeUnit } from '../enums' + +export const EXPIRATION_DATE_REGEX = new RegExp(`^(\\d+)(${Object.values(TimeUnit).join('|')})$`) diff --git a/packages/shared/lib/auxiliary/deep-link/constants/index.ts b/packages/shared/lib/auxiliary/deep-link/constants/index.ts index fb65a20e027..b76e09a4e36 100644 --- a/packages/shared/lib/auxiliary/deep-link/constants/index.ts +++ b/packages/shared/lib/auxiliary/deep-link/constants/index.ts @@ -1 +1,3 @@ +export * from './expiration-date-regex.constant' +export * from './time-unit-ms.constant' export * from './url-cleanup-regex.constant' diff --git a/packages/shared/lib/auxiliary/deep-link/constants/time-unit-ms.constant.ts b/packages/shared/lib/auxiliary/deep-link/constants/time-unit-ms.constant.ts new file mode 100644 index 00000000000..97561be9ae7 --- /dev/null +++ b/packages/shared/lib/auxiliary/deep-link/constants/time-unit-ms.constant.ts @@ -0,0 +1,14 @@ +import { + MILLISECONDS_PER_DAY, + MILLISECONDS_PER_HOUR, + MILLISECONDS_PER_MINUTE, + MILLISECONDS_PER_WEEK, +} from 'shared/lib/core/utils' +import { TimeUnit } from '../enums' + +export const TIME_UNIT_MS_MAP: Record = { + [TimeUnit.Weeks]: MILLISECONDS_PER_WEEK, + [TimeUnit.Days]: MILLISECONDS_PER_DAY, + [TimeUnit.Hours]: MILLISECONDS_PER_HOUR, + [TimeUnit.Minutes]: MILLISECONDS_PER_MINUTE, +} diff --git a/packages/shared/lib/auxiliary/deep-link/enums/index.ts b/packages/shared/lib/auxiliary/deep-link/enums/index.ts index c91ee775505..944421bbf18 100644 --- a/packages/shared/lib/auxiliary/deep-link/enums/index.ts +++ b/packages/shared/lib/auxiliary/deep-link/enums/index.ts @@ -1,5 +1,6 @@ +export * from './add-proposal-parameter.enum' export * from './deep-link-context.enum' export * from './governance-operation.enum' -export * from './add-proposal-parameter.enum' export * from './send-operation-parameter.enum' +export * from './time-unit.enum' export * from './wallet-operation.enum' diff --git a/packages/shared/lib/auxiliary/deep-link/enums/time-unit.enum.ts b/packages/shared/lib/auxiliary/deep-link/enums/time-unit.enum.ts new file mode 100644 index 00000000000..62fe4f044ec --- /dev/null +++ b/packages/shared/lib/auxiliary/deep-link/enums/time-unit.enum.ts @@ -0,0 +1,6 @@ +export enum TimeUnit { + Weeks = 'w', + Days = 'd', + Hours = 'h', + Minutes = 'm', +} diff --git a/packages/shared/lib/auxiliary/deep-link/errors/invalid-expiration-date.error.ts b/packages/shared/lib/auxiliary/deep-link/errors/invalid-expiration-date.error.ts index feec537ce9b..36f1516dbbb 100644 --- a/packages/shared/lib/auxiliary/deep-link/errors/invalid-expiration-date.error.ts +++ b/packages/shared/lib/auxiliary/deep-link/errors/invalid-expiration-date.error.ts @@ -6,7 +6,7 @@ export class InvalidExpirationDateError extends BaseError { const message = localize('error.send.invalidExpirationDate') super({ message, - showNotification: false, + showNotification: true, saveToErrorLog: false, logToConsole: true, }) diff --git a/packages/shared/lib/auxiliary/deep-link/errors/past-expiration-date.error.ts b/packages/shared/lib/auxiliary/deep-link/errors/past-expiration-date.error.ts index 99f56336b41..70f10edfe4a 100644 --- a/packages/shared/lib/auxiliary/deep-link/errors/past-expiration-date.error.ts +++ b/packages/shared/lib/auxiliary/deep-link/errors/past-expiration-date.error.ts @@ -6,7 +6,7 @@ export class PastExpirationDateError extends BaseError { const message = localize('error.send.pastExpirationDate') super({ message, - showNotification: false, + showNotification: true, saveToErrorLog: false, logToConsole: true, }) diff --git a/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts b/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts index 9eac58b084f..88320a2338c 100644 --- a/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts +++ b/packages/shared/lib/auxiliary/deep-link/utils/getExpirationDateFromSearchParam.ts @@ -1,19 +1,8 @@ +import { convertUnixTimestampToDate } from 'shared/lib/core/utils' +import { EXPIRATION_DATE_REGEX, TIME_UNIT_MS_MAP } from '../constants' +import { TimeUnit } from '../enums' import { InvalidExpirationDateError, PastExpirationDateError } from '../errors' -enum TimeUnit { - Weeks = 'w', - Days = 'd', - Hours = 'h', - Minutes = 'm', -} - -const timeUnitValues: Record = { - [TimeUnit.Weeks]: 604800000, - [TimeUnit.Days]: 86400000, - [TimeUnit.Hours]: 3600000, - [TimeUnit.Minutes]: 60000, -} - export function getExpirationDateFromSearchParam(expirationDate: string): Date | undefined { if (!expirationDate) { return undefined @@ -22,7 +11,7 @@ export function getExpirationDateFromSearchParam(expirationDate: string): Date | // Check if it's a Unix timestamp (numeric value) if (!isNaN(Number(expirationDate))) { const expirationTimestamp = parseInt(expirationDate) - const expirationDateTime = new Date(expirationTimestamp * 1000) // Convert seconds to milliseconds + const expirationDateTime = convertUnixTimestampToDate(expirationTimestamp) // Convert seconds to milliseconds if (isNaN(expirationDateTime.getTime())) { throw new InvalidExpirationDateError() } else if (expirationDateTime.getTime() < Date.now()) { @@ -33,8 +22,7 @@ export function getExpirationDateFromSearchParam(expirationDate: string): Date | } // Validate expiration date format for relative time - const expirationRegex = /^(\d+)([hdwm])$/ - const regexMatch = expirationRegex.exec(expirationDate) + const regexMatch = EXPIRATION_DATE_REGEX.exec(expirationDate) if (!regexMatch) { throw new InvalidExpirationDateError() @@ -43,7 +31,7 @@ export function getExpirationDateFromSearchParam(expirationDate: string): Date | const value = parseInt(regexMatch[1]) const unit = regexMatch[2] as TimeUnit - const selectedTimeUnitValue = timeUnitValues[unit] + const selectedTimeUnitValue = TIME_UNIT_MS_MAP[unit] if (selectedTimeUnitValue === undefined) { throw new InvalidExpirationDateError() diff --git a/packages/shared/lib/core/utils/constants/time.constants.ts b/packages/shared/lib/core/utils/constants/time.constants.ts index d792a17f7d3..f1c2c74c93b 100644 --- a/packages/shared/lib/core/utils/constants/time.constants.ts +++ b/packages/shared/lib/core/utils/constants/time.constants.ts @@ -9,3 +9,6 @@ export const DAYS_PER_YEAR = 365 // DERIVED export const SECONDS_PER_DAY = HOURS_PER_DAY * MINUTES_PER_HOUR * SECONDS_PER_MINUTE export const MILLISECONDS_PER_DAY = SECONDS_PER_DAY * MILLISECONDS_PER_SECOND +export const MILLISECONDS_PER_WEEK = SECONDS_PER_DAY * DAYS_PER_WEEK * MILLISECONDS_PER_SECOND +export const MILLISECONDS_PER_HOUR = SECONDS_PER_MINUTE * MINUTES_PER_HOUR * MILLISECONDS_PER_SECOND +export const MILLISECONDS_PER_MINUTE = SECONDS_PER_MINUTE * MILLISECONDS_PER_SECOND From 2178692fbae8eb824d257de39430c496baf0b335 Mon Sep 17 00:00:00 2001 From: evavirseda Date: Thu, 30 Nov 2023 15:22:00 +0100 Subject: [PATCH 7/8] feat: remove debris --- .../popups/send/SendConfirmationPopup.svelte | 20 ------------------- 1 file changed, 20 deletions(-) diff --git a/packages/desktop/components/popups/send/SendConfirmationPopup.svelte b/packages/desktop/components/popups/send/SendConfirmationPopup.svelte index 4dc003e0d60..6e0b56404d3 100644 --- a/packages/desktop/components/popups/send/SendConfirmationPopup.svelte +++ b/packages/desktop/components/popups/send/SendConfirmationPopup.svelte @@ -90,14 +90,6 @@ await updateStorageDeposit() if (isSendAndClosePopup) { - // Needed after 'return from stronghold' to SHOW to correct expiration date before output is sent - initialExpirationDate = getInitialExpirationDate( - expirationDate, - storageDeposit, - giftStorageDeposit, - isLayer2Transaction - ) - try { await _onMount() } catch (err) { @@ -118,18 +110,6 @@ const outputParams = await getOutputParameters(transactionDetails) preparedOutput = await prepareOutput($selectedAccount.index, outputParams, getDefaultTransactionOptions()) await updateStorageDeposit() - - // This potentially triggers a second 'prepareOutput', - // as it updates expiration date through the ExpirationTimePicker bind - // Could be avoided with a rework of ExpirationTimePicker - if (transactionDetails.expirationDate === undefined) { - initialExpirationDate = getInitialExpirationDate( - expirationDate, - storageDeposit, - giftStorageDeposit, - isLayer2Transaction - ) - } } catch (err) { handleError(err) } From efc637f6b275400d08e7341263fa5439ca7966fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bego=C3=B1a=20Alvarez?= Date: Thu, 25 Jan 2024 16:52:57 +0100 Subject: [PATCH 8/8] fix: initial expiration component calculation --- .../popups/send/SendConfirmationPopup.svelte | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/desktop/components/popups/send/SendConfirmationPopup.svelte b/packages/desktop/components/popups/send/SendConfirmationPopup.svelte index bae255d74e5..8b6a5f39382 100644 --- a/packages/desktop/components/popups/send/SendConfirmationPopup.svelte +++ b/packages/desktop/components/popups/send/SendConfirmationPopup.svelte @@ -70,12 +70,6 @@ $: isLayer2Transaction = !!layer2Parameters $: isTransferring = $selectedAccount.isTransferring $: hideGiftToggle = isBaseTokenTransfer || isLayer2Transaction || (disableToggleGift && !giftStorageDeposit) - $: initialExpirationDate = getInitialExpirationDate( - expirationDate, - storageDeposit, - giftStorageDeposit, - isLayer2Transaction - ) $: if (!isSendAndClosePopup) expirationDate, giftStorageDeposit, void rebuildTransactionOutput() @@ -91,7 +85,15 @@ onMount(async () => { await updateStorageDeposit() - if (isSendAndClosePopup) { + if (isSendAndClosePopup || expirationDate) { + // Needed after 'return from stronghold' to SHOW to correct expiration date before output is sent + initialExpirationDate = getInitialExpirationDate( + expirationDate, + storageDeposit, + giftStorageDeposit, + isLayer2Transaction + ) + try { await _onMount() } catch (err) { @@ -114,6 +116,18 @@ const outputParams = await getOutputParameters(transactionDetails) preparedOutput = await prepareOutput($selectedAccount.index, outputParams, getDefaultTransactionOptions()) await updateStorageDeposit() + + // This potentially triggers a second 'prepareOutput', + // as it updates expiration date through the ExpirationTimePicker bind + // Could be avoided with a rework of ExpirationTimePicker + if (transactionDetails.expirationDate === undefined) { + initialExpirationDate = getInitialExpirationDate( + expirationDate, + storageDeposit, + giftStorageDeposit, + isLayer2Transaction + ) + } } catch (err) { handleError(err) } finally {