From bda1c0721b7716934234c1741d3c10c88857b87d Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <nikola@txfusion.io> Date: Mon, 23 Dec 2024 14:25:55 +0100 Subject: [PATCH 1/6] feat: add toggle switch between time ago and utc time --- .../common/table/TableHeadColumn.vue | 2 +- .../common/table/fields/TimeField.vue | 7 ++++++- .../app/src/components/transactions/Table.vue | 21 ++++++++++++++++--- packages/app/src/locales/en.json | 1 + 4 files changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/app/src/components/common/table/TableHeadColumn.vue b/packages/app/src/components/common/table/TableHeadColumn.vue index 458fbd016a..eac1f77d84 100644 --- a/packages/app/src/components/common/table/TableHeadColumn.vue +++ b/packages/app/src/components/common/table/TableHeadColumn.vue @@ -8,6 +8,6 @@ <style> .table-head-col { - @apply whitespace-nowrap px-2 py-3 text-left text-xs font-medium uppercase tracking-wider text-gray-700 first:pl-6 last:pr-6; + @apply whitespace-nowrap px-2 py-3 text-left text-xs font-semibold uppercase tracking-wider text-gray-700 first:pl-6 last:pr-6; } </style> diff --git a/packages/app/src/components/common/table/fields/TimeField.vue b/packages/app/src/components/common/table/fields/TimeField.vue index 24216056e4..43a9fa6623 100644 --- a/packages/app/src/components/common/table/fields/TimeField.vue +++ b/packages/app/src/components/common/table/fields/TimeField.vue @@ -1,7 +1,7 @@ <template> <div class="info-field-time" :title="utcStringFromISOString(isoString)"> <span class="time-ago"> - {{ timeAgo }} + {{ isUtcDate ? localDateFromISOString(isoString) : timeAgo }} </span> <span v-if="showExactDate" class="full-date">{{ localDateFromISOString(isoString) }}</span> </div> @@ -28,6 +28,11 @@ const props = defineProps({ default: true, required: false, }, + isUtcDate: { + type: Boolean, + default: false, + required: false, + }, }); const messages = ref({ diff --git a/packages/app/src/components/transactions/Table.vue b/packages/app/src/components/transactions/Table.vue index aedbdf4ca9..e551ac9dff 100644 --- a/packages/app/src/components/transactions/Table.vue +++ b/packages/app/src/components/transactions/Table.vue @@ -8,8 +8,12 @@ <TableHeadColumn v-if="columns.includes('method')"> {{ t("transactions.table.method") }} </TableHeadColumn> - <TableHeadColumn v-if="columns.includes('age')"> - {{ t("transactions.table.age") }} + <TableHeadColumn + v-if="columns.includes('age')" + @click="toggleAgeTimestamp()" + class="hover:cursor-pointer text-blue-700" + > + {{ isTimeAgeView ? t("transactions.table.age") : t("transactions.table.dateTimeUTC") }} </TableHeadColumn> <TableHeadColumn v-if="columns.includes('from')" class="tablet-column-hidden"> {{ t("transactions.table.from") }} @@ -71,7 +75,12 @@ :data-heading="t('transactions.table.age')" > <CopyButton :value="utcStringFromISOString(item.receivedAt)"> - <TimeField :value="item.receivedAt" :show-exact-date="false" :data-testid="$testId.timestamp" /> + <TimeField + :value="item.receivedAt" + :show-exact-date="false" + :data-testid="$testId.timestamp" + :is-utc-date="!isTimeAgeView" + /> </CopyButton> </TableBodyColumn> <TableBodyColumn @@ -364,6 +373,12 @@ const isHighRowsSize = computed(() => props.columns.includes("fee")); function getDirection(item: TransactionListItem): Direction { return item.from === item.to ? "self" : item.to !== props.searchParams?.address ? "out" : "in"; } + +const isTimeAgeView = ref(true); + +const toggleAgeTimestamp = () => { + isTimeAgeView.value = !isTimeAgeView.value; +}; </script> <style lang="scss"> diff --git a/packages/app/src/locales/en.json b/packages/app/src/locales/en.json index 70faef1b62..289060c7fc 100644 --- a/packages/app/src/locales/en.json +++ b/packages/app/src/locales/en.json @@ -143,6 +143,7 @@ "transferMethodName": "Transfer", "timestamp": "Timestamp", "age": "Age", + "dateTimeUTC": "Date Time (UTC)", "tokenAddress": "Token address", "tokenName": "Token name", "tokenSymbol": "Token symbol", From a0615c73186b39ce53efe1deac33445062aaff33 Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <nikola@txfusion.io> Date: Mon, 27 Jan 2025 10:21:52 +0100 Subject: [PATCH 2/6] feat: refactor the props for timefield component --- packages/app/src/components/batches/Table.vue | 3 ++- packages/app/src/components/blocks/Table.vue | 4 +++- .../common/table/fields/TimeField.vue | 24 ++++++++----------- .../app/src/components/transactions/Table.vue | 5 ++-- .../transactions/infoTable/GeneralInfo.vue | 3 ++- .../app/src/components/transfers/Table.vue | 2 +- packages/app/src/types.ts | 6 +++++ 7 files changed, 26 insertions(+), 21 deletions(-) diff --git a/packages/app/src/components/batches/Table.vue b/packages/app/src/components/batches/Table.vue index 88d4d94a42..51ff3ead92 100644 --- a/packages/app/src/components/batches/Table.vue +++ b/packages/app/src/components/batches/Table.vue @@ -34,7 +34,7 @@ </TableBodyColumn> <TableBodyColumn v-if="columns.includes('age')" :data-heading="t('batches.table.age')"> <CopyButton :value="utcStringFromISOString(item.timestamp)"> - <TimeField :value="item.timestamp" :show-exact-date="false" /> + <TimeField :value="item.timestamp" /> </CopyButton> </TableBodyColumn> </template> @@ -65,6 +65,7 @@ import ZkSyncIcon from "@/components/icons/ZkSync.vue"; import type { BatchListItem } from "@/composables/useBatches"; import type { PropType } from "vue"; +import { TimeFormat } from "@/types"; import { utcStringFromISOString } from "@/utils/helpers"; const { t, te } = useI18n(); diff --git a/packages/app/src/components/blocks/Table.vue b/packages/app/src/components/blocks/Table.vue index 178c14c116..cdb2b248cb 100644 --- a/packages/app/src/components/blocks/Table.vue +++ b/packages/app/src/components/blocks/Table.vue @@ -49,7 +49,7 @@ </TableBodyColumn> <TableBodyColumn :data-heading="t('blocks.table.age')"> <CopyButton :value="item.timestamp"> - <TimeField :value="item.timestamp" :show-exact-date="false" /> + <TimeField :value="item.timestamp" /> </CopyButton> </TableBodyColumn> </template> @@ -79,6 +79,8 @@ import TimeField from "@/components/common/table/fields/TimeField.vue"; import type { BlockListItem } from "@/composables/useBlock"; import type { PropType } from "vue"; +import { TimeFormat } from "@/types"; + const { t } = useI18n(); defineProps({ diff --git a/packages/app/src/components/common/table/fields/TimeField.vue b/packages/app/src/components/common/table/fields/TimeField.vue index 43a9fa6623..6a14053db6 100644 --- a/packages/app/src/components/common/table/fields/TimeField.vue +++ b/packages/app/src/components/common/table/fields/TimeField.vue @@ -1,18 +1,20 @@ <template> <div class="info-field-time" :title="utcStringFromISOString(isoString)"> - <span class="time-ago"> - {{ isUtcDate ? localDateFromISOString(isoString) : timeAgo }} - </span> - <span v-if="showExactDate" class="full-date">{{ localDateFromISOString(isoString) }}</span> + <span class="time-ago" v-if="format === TimeFormat.FULL">{{ localDateFromISOString(isoString) }}</span> + <span class="time-ago" v-else>{{ timeAgo }}</span> + <span v-if="format === TimeFormat.TIME_AGO_AND_FULL" class="full-date">{{ + localDateFromISOString(isoString) + }}</span> </div> </template> <script lang="ts" setup> -import { computed, ref } from "vue"; +import { computed, type PropType, ref } from "vue"; import { useI18n } from "vue-i18n"; import { useTimeAgo } from "@vueuse/core"; +import { TimeFormat } from "@/types"; import { ISOStringFromUnixTimestamp, localDateFromISOString, utcStringFromISOString } from "@/utils/helpers"; const { t } = useI18n(); @@ -23,15 +25,9 @@ const props = defineProps({ default: "", required: true, }, - showExactDate: { - type: Boolean, - default: true, - required: false, - }, - isUtcDate: { - type: Boolean, - default: false, - required: false, + format: { + type: String as PropType<TimeFormat>, + default: TimeFormat.TIME_AGO, }, }); diff --git a/packages/app/src/components/transactions/Table.vue b/packages/app/src/components/transactions/Table.vue index e551ac9dff..06e917e336 100644 --- a/packages/app/src/components/transactions/Table.vue +++ b/packages/app/src/components/transactions/Table.vue @@ -77,9 +77,8 @@ <CopyButton :value="utcStringFromISOString(item.receivedAt)"> <TimeField :value="item.receivedAt" - :show-exact-date="false" :data-testid="$testId.timestamp" - :is-utc-date="!isTimeAgeView" + :format="isTimeAgeView ? TimeFormat.TIME_AGO : TimeFormat.FULL" /> </CopyButton> </TableBodyColumn> @@ -246,8 +245,8 @@ import useTransactions, { type TransactionListItem, type TransactionSearchParams import type { Direction } from "@/components/transactions/TransactionDirectionTableCell.vue"; import type { AbiFragment } from "@/composables/useAddress"; -import type { NetworkOrigin } from "@/types"; +import { type NetworkOrigin, TimeFormat } from "@/types"; import { isContractDeployerAddress, utcStringFromISOString } from "@/utils/helpers"; const { currentNetwork } = useContext(); diff --git a/packages/app/src/components/transactions/infoTable/GeneralInfo.vue b/packages/app/src/components/transactions/infoTable/GeneralInfo.vue index 7acc57fa46..fa6a84bd04 100644 --- a/packages/app/src/components/transactions/infoTable/GeneralInfo.vue +++ b/packages/app/src/components/transactions/infoTable/GeneralInfo.vue @@ -216,7 +216,7 @@ </InfoTooltip> </table-body-column> <table-body-column class="transaction-table-value"> - <TimeField :value="transaction?.receivedAt" /> + <TimeField :value="transaction?.receivedAt" :format="TimeFormat.TIME_AGO_AND_FULL" /> </table-body-column> </tr> </template> @@ -255,6 +255,7 @@ import TransferTableCell from "@/components/transactions/infoTable/TransferTable import type { TransactionItem } from "@/composables/useTransaction"; +import { TimeFormat } from "@/types"; import { isContractDeployerAddress } from "@/utils/helpers"; const { t } = useI18n(); diff --git a/packages/app/src/components/transfers/Table.vue b/packages/app/src/components/transfers/Table.vue index c80ac12370..0a7ca43a04 100644 --- a/packages/app/src/components/transfers/Table.vue +++ b/packages/app/src/components/transfers/Table.vue @@ -42,7 +42,7 @@ <TableBodyColumn :data-heading="t('transfers.table.age')"> <CopyButton :value="utcStringFromISOString(item.timestamp)"> - <TimeField :data-testid="$testId.timestamp" :value="item.timestamp" :show-exact-date="false" /> + <TimeField :data-testid="$testId.timestamp" :value="item.timestamp" /> </CopyButton> </TableBodyColumn> <TableBodyColumn :data-heading="t('transfers.table.type')" class="transfer-type"> diff --git a/packages/app/src/types.ts b/packages/app/src/types.ts index d0c87863c2..caf3a22281 100644 --- a/packages/app/src/types.ts +++ b/packages/app/src/types.ts @@ -59,3 +59,9 @@ export type ContractVerificationData = { }; export type ContractVerificationStatus = "successful" | "failed" | "in_progress" | "queued"; + +export enum TimeFormat { + TIME_AGO = "time_ago", + FULL = "full", + TIME_AGO_AND_FULL = "time_ago_and_full", +} From 9010f97789121ff21016d0d61b1457ea9d63c0bb Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <nikola@txfusion.io> Date: Mon, 27 Jan 2025 10:23:54 +0100 Subject: [PATCH 3/6] feat: remove unused lines --- packages/app/src/components/batches/Table.vue | 1 - packages/app/src/components/blocks/Table.vue | 2 -- 2 files changed, 3 deletions(-) diff --git a/packages/app/src/components/batches/Table.vue b/packages/app/src/components/batches/Table.vue index 51ff3ead92..8c1f523b15 100644 --- a/packages/app/src/components/batches/Table.vue +++ b/packages/app/src/components/batches/Table.vue @@ -65,7 +65,6 @@ import ZkSyncIcon from "@/components/icons/ZkSync.vue"; import type { BatchListItem } from "@/composables/useBatches"; import type { PropType } from "vue"; -import { TimeFormat } from "@/types"; import { utcStringFromISOString } from "@/utils/helpers"; const { t, te } = useI18n(); diff --git a/packages/app/src/components/blocks/Table.vue b/packages/app/src/components/blocks/Table.vue index cdb2b248cb..534f72e8e1 100644 --- a/packages/app/src/components/blocks/Table.vue +++ b/packages/app/src/components/blocks/Table.vue @@ -79,8 +79,6 @@ import TimeField from "@/components/common/table/fields/TimeField.vue"; import type { BlockListItem } from "@/composables/useBlock"; import type { PropType } from "vue"; -import { TimeFormat } from "@/types"; - const { t } = useI18n(); defineProps({ From f2883e2d4f8cbbfc3a647c420aef37c940ba85e1 Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <nikola@txfusion.io> Date: Mon, 27 Jan 2025 11:49:15 +0100 Subject: [PATCH 4/6] feat: fix props requirement --- packages/app/src/components/batches/Table.vue | 3 ++- packages/app/src/components/blocks/Table.vue | 4 +++- packages/app/src/components/common/table/fields/TimeField.vue | 3 ++- .../app/src/components/transactions/infoTable/GeneralInfo.vue | 3 +-- packages/app/src/components/transfers/Table.vue | 3 ++- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/app/src/components/batches/Table.vue b/packages/app/src/components/batches/Table.vue index 8c1f523b15..2fe784d2a8 100644 --- a/packages/app/src/components/batches/Table.vue +++ b/packages/app/src/components/batches/Table.vue @@ -34,7 +34,7 @@ </TableBodyColumn> <TableBodyColumn v-if="columns.includes('age')" :data-heading="t('batches.table.age')"> <CopyButton :value="utcStringFromISOString(item.timestamp)"> - <TimeField :value="item.timestamp" /> + <TimeField :value="item.timestamp" :format="TimeFormat.TIME_AGO" /> </CopyButton> </TableBodyColumn> </template> @@ -65,6 +65,7 @@ import ZkSyncIcon from "@/components/icons/ZkSync.vue"; import type { BatchListItem } from "@/composables/useBatches"; import type { PropType } from "vue"; +import { TimeFormat } from "@/types"; import { utcStringFromISOString } from "@/utils/helpers"; const { t, te } = useI18n(); diff --git a/packages/app/src/components/blocks/Table.vue b/packages/app/src/components/blocks/Table.vue index 534f72e8e1..1692e0a753 100644 --- a/packages/app/src/components/blocks/Table.vue +++ b/packages/app/src/components/blocks/Table.vue @@ -49,7 +49,7 @@ </TableBodyColumn> <TableBodyColumn :data-heading="t('blocks.table.age')"> <CopyButton :value="item.timestamp"> - <TimeField :value="item.timestamp" /> + <TimeField :value="item.timestamp" :format="TimeFormat.TIME_AGO" /> </CopyButton> </TableBodyColumn> </template> @@ -79,6 +79,8 @@ import TimeField from "@/components/common/table/fields/TimeField.vue"; import type { BlockListItem } from "@/composables/useBlock"; import type { PropType } from "vue"; +import { TimeFormat } from "@/types"; + const { t } = useI18n(); defineProps({ diff --git a/packages/app/src/components/common/table/fields/TimeField.vue b/packages/app/src/components/common/table/fields/TimeField.vue index 6a14053db6..d61817de16 100644 --- a/packages/app/src/components/common/table/fields/TimeField.vue +++ b/packages/app/src/components/common/table/fields/TimeField.vue @@ -27,7 +27,8 @@ const props = defineProps({ }, format: { type: String as PropType<TimeFormat>, - default: TimeFormat.TIME_AGO, + default: TimeFormat.TIME_AGO_AND_FULL, + required: false, }, }); diff --git a/packages/app/src/components/transactions/infoTable/GeneralInfo.vue b/packages/app/src/components/transactions/infoTable/GeneralInfo.vue index fa6a84bd04..7acc57fa46 100644 --- a/packages/app/src/components/transactions/infoTable/GeneralInfo.vue +++ b/packages/app/src/components/transactions/infoTable/GeneralInfo.vue @@ -216,7 +216,7 @@ </InfoTooltip> </table-body-column> <table-body-column class="transaction-table-value"> - <TimeField :value="transaction?.receivedAt" :format="TimeFormat.TIME_AGO_AND_FULL" /> + <TimeField :value="transaction?.receivedAt" /> </table-body-column> </tr> </template> @@ -255,7 +255,6 @@ import TransferTableCell from "@/components/transactions/infoTable/TransferTable import type { TransactionItem } from "@/composables/useTransaction"; -import { TimeFormat } from "@/types"; import { isContractDeployerAddress } from "@/utils/helpers"; const { t } = useI18n(); diff --git a/packages/app/src/components/transfers/Table.vue b/packages/app/src/components/transfers/Table.vue index 0a7ca43a04..f52883fae5 100644 --- a/packages/app/src/components/transfers/Table.vue +++ b/packages/app/src/components/transfers/Table.vue @@ -42,7 +42,7 @@ <TableBodyColumn :data-heading="t('transfers.table.age')"> <CopyButton :value="utcStringFromISOString(item.timestamp)"> - <TimeField :data-testid="$testId.timestamp" :value="item.timestamp" /> + <TimeField :data-testid="$testId.timestamp" :value="item.timestamp" :format="TimeFormat.TIME_AGO" /> </CopyButton> </TableBodyColumn> <TableBodyColumn :data-heading="t('transfers.table.type')" class="transfer-type"> @@ -156,6 +156,7 @@ import TransactionNetworkSquareBlock from "@/components/transactions/Transaction import useTransfers, { type Transfer } from "@/composables/useTransfers"; +import { TimeFormat } from "@/types"; import { utcStringFromISOString } from "@/utils/helpers"; const { t } = useI18n(); From 8f190e8daba84fdd78b5af31243dd4cd66ec6ad6 Mon Sep 17 00:00:00 2001 From: Nikola Pavlov <nikola@txfusion.io> Date: Mon, 27 Jan 2025 11:59:01 +0100 Subject: [PATCH 5/6] feat: fix TimeField test case --- .../tests/components/common/table/fields/TimeField.spec.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/app/tests/components/common/table/fields/TimeField.spec.ts b/packages/app/tests/components/common/table/fields/TimeField.spec.ts index 1ee586b36b..24dc6eae32 100644 --- a/packages/app/tests/components/common/table/fields/TimeField.spec.ts +++ b/packages/app/tests/components/common/table/fields/TimeField.spec.ts @@ -8,6 +8,8 @@ import TimeField from "@/components/common/table/fields/TimeField.vue"; import enUS from "@/locales/en.json"; +import { TimeFormat } from "@/types"; + describe("TimeField", () => { const i18n = createI18n({ locale: "en", @@ -47,7 +49,7 @@ describe("TimeField", () => { global, props: { value: "2022-12-02T09:26:06.605Z", - showExactDate: false, + format: TimeFormat.TIME_AGO, }, }); From 443557bfd0656b36f17a87aee918f1cee65f3e58 Mon Sep 17 00:00:00 2001 From: Vasyl Ivanchuk <vasyl.ivanchuk@gmail.com> Date: Tue, 28 Jan 2025 17:40:59 +0200 Subject: [PATCH 6/6] chore: time field test descriptions --- .../tests/components/common/table/fields/TimeField.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/app/tests/components/common/table/fields/TimeField.spec.ts b/packages/app/tests/components/common/table/fields/TimeField.spec.ts index 24dc6eae32..888446ff90 100644 --- a/packages/app/tests/components/common/table/fields/TimeField.spec.ts +++ b/packages/app/tests/components/common/table/fields/TimeField.spec.ts @@ -33,7 +33,7 @@ describe("TimeField", () => { expect(container.querySelector(".info-field-time")?.getAttribute("title")).toBe("2022-12-02 09:26:06 UTC"); unmount(); }); - it("renders full date when showExactDate is true by default", () => { + it("renders full date when time format is not specified", () => { const { container, unmount } = render(TimeField, { global, props: { @@ -44,7 +44,7 @@ describe("TimeField", () => { expect(container.querySelector(".full-date")?.textContent).toBe("2022-12-02 12:26"); unmount(); }); - it("doesn't render full date when showExactDate is false", () => { + it("doesn't render full date when time format is TIME_AGO", () => { const { container, unmount } = render(TimeField, { global, props: {