diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f02522d4..15f8434a2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Features +- [#131](https://github.com/alleslabs/celatone-frontend/pull/131) Add CW2-related information to contract details page - [#120](https://github.com/alleslabs/celatone-frontend/pull/120) Add simulate migrate fee and the final migration step - [#108](https://github.com/alleslabs/celatone-frontend/pull/108) Add migrate options on migrate page and upload new code for migration - [#130](https://github.com/alleslabs/celatone-frontend/pull/130) Add support for Terra public projects @@ -102,6 +103,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Improvements +- [#139](https://github.com/alleslabs/celatone-frontend/pull/139) Fix Date to Dayjs +- [#135](https://github.com/alleslabs/celatone-frontend/pull/135) Invalidate queries after update/clear admin tx - [#123](https://github.com/alleslabs/celatone-frontend/pull/123) Refactor tables to use custom components - [#128](https://github.com/alleslabs/celatone-frontend/pull/128) Rewrite add to other list state and add default list to save to - [#114](https://github.com/alleslabs/celatone-frontend/pull/114) Handle wallet connection cases in instantiate button @@ -115,6 +118,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Bug fixes - [#142](https://github.com/alleslabs/celatone-frontend/pull/142) Fix migration table row duplicate and add key to port id render +- [#138](https://github.com/alleslabs/celatone-frontend/pull/138) Remove execute table in contract details page (due to data issue) +- [#136](https://github.com/alleslabs/celatone-frontend/pull/136) Fix decode message from query param in execute page - [#132](https://github.com/alleslabs/celatone-frontend/pull/132) Fix permission field in upload simulation - [#121](https://github.com/alleslabs/celatone-frontend/pull/121) Fix code snippet for query axios - [#129](https://github.com/alleslabs/celatone-frontend/pull/129) Fix wallet disconnection on network query change diff --git a/src/lib/app-fns/tx/clearAdmin.tsx b/src/lib/app-fns/tx/clearAdmin.tsx index 52e0a156a..8eb485014 100644 --- a/src/lib/app-fns/tx/clearAdmin.tsx +++ b/src/lib/app-fns/tx/clearAdmin.tsx @@ -23,7 +23,7 @@ interface ClearAdminTxParams { fee: StdFee; memo?: string; client: SigningCosmWasmClient; - onTxSucceed?: (txHash: string) => void; + onTxSucceed?: () => void; } export const clearAdminTx = ({ @@ -40,7 +40,7 @@ export const clearAdminTx = ({ postFn: () => client.clearAdmin(address, contractAddress, fee, memo), }), ({ value: txInfo }) => { - onTxSucceed?.(txInfo.transactionHash); + onTxSucceed?.(); return { value: null, phase: TxStreamPhase.SUCCEED, diff --git a/src/lib/app-fns/tx/execute.tsx b/src/lib/app-fns/tx/execute.tsx index 0b2182406..1f842cd70 100644 --- a/src/lib/app-fns/tx/execute.tsx +++ b/src/lib/app-fns/tx/execute.tsx @@ -5,6 +5,7 @@ import type { } from "@cosmjs/cosmwasm-stargate"; import type { Coin, StdFee } from "@cosmjs/stargate"; import { pipe } from "@rx-stream/pipe"; +import dayjs from "dayjs"; import { MdCheckCircle } from "react-icons/md"; import type { Observable } from "rxjs"; @@ -52,7 +53,7 @@ export const executeContractTx = ({ sender: address, contractAddress, msg: encode(JSON.stringify(msg)), // base64 - timestamp: new Date(), + timestamp: dayjs(), }); return { value: null, diff --git a/src/lib/app-provider/tx/clearAdmin.ts b/src/lib/app-provider/tx/clearAdmin.ts index 601538350..a9828f79b 100644 --- a/src/lib/app-provider/tx/clearAdmin.ts +++ b/src/lib/app-provider/tx/clearAdmin.ts @@ -1,4 +1,5 @@ import { useWallet } from "@cosmos-kit/react"; +import { useQueryClient } from "@tanstack/react-query"; import { useCallback } from "react"; import { useFabricateFee } from "../hooks"; @@ -7,11 +8,12 @@ import { CLEAR_ADMIN_GAS } from "lib/data"; import type { ContractAddr } from "lib/types"; export interface ClearAdminStreamParams { - onTxSucceed?: (txHash: string) => void; + onTxSucceed?: () => void; } export const useClearAdminTx = (contractAddress: ContractAddr) => { const { address, getCosmWasmClient } = useWallet(); + const queryClient = useQueryClient(); const fabricateFee = useFabricateFee(); const clearAdminFee = fabricateFee(CLEAR_ADMIN_GAS); @@ -26,9 +28,19 @@ export const useClearAdminTx = (contractAddress: ContractAddr) => { contractAddress, fee: clearAdminFee, client, - onTxSucceed, + onTxSucceed: () => { + onTxSucceed?.(); + Promise.all([ + queryClient.invalidateQueries({ + queryKey: ["admin_by_contracts"], + }), + queryClient.invalidateQueries({ + queryKey: ["query", "instantiate_info"], + }), + ]); + }, }); }, - [address, clearAdminFee, contractAddress, getCosmWasmClient] + [address, clearAdminFee, queryClient, contractAddress, getCosmWasmClient] ); }; diff --git a/src/lib/components/ContractSelectSection.tsx b/src/lib/components/ContractSelectSection.tsx index 990e6b075..7a8d895da 100644 --- a/src/lib/components/ContractSelectSection.tsx +++ b/src/lib/components/ContractSelectSection.tsx @@ -123,7 +123,7 @@ export const ContractSelectSection = observer( }); const { refetch } = useQuery( - ["query", "instantiateInfo", endpoint, contractAddress], + ["query", "instantiate_info", endpoint, contractAddress], async () => queryInstantiateInfo(endpoint, indexerGraphClient, contractAddress), { diff --git a/src/lib/components/modal/contract/ClearAdminContract.tsx b/src/lib/components/modal/contract/ClearAdminContract.tsx index 1644d903d..feb7b080d 100644 --- a/src/lib/components/modal/contract/ClearAdminContract.tsx +++ b/src/lib/components/modal/contract/ClearAdminContract.tsx @@ -20,7 +20,7 @@ export const ClearAdminContract = ({ const clearAdminTx = useClearAdminTx(contractAddress); const proceed = useCallback(async () => { - const stream = await clearAdminTx({ onTxSucceed: () => {} }); + const stream = await clearAdminTx({}); if (stream) broadcast(stream); }, [broadcast, clearAdminTx]); diff --git a/src/lib/components/modal/contract/SaveNewContract.tsx b/src/lib/components/modal/contract/SaveNewContract.tsx index aabff1be3..240c6812a 100644 --- a/src/lib/components/modal/contract/SaveNewContract.tsx +++ b/src/lib/components/modal/contract/SaveNewContract.tsx @@ -95,7 +95,7 @@ export function SaveNewContract({ list, buttonProps }: SaveNewContractProps) { // TODO: Abstract query const { refetch } = useQuery( - ["query", "instantiateInfo", endpoint, contractAddressState], + ["query", "instantiate_info", endpoint, contractAddressState], async () => queryInstantiateInfo( endpoint, diff --git a/src/lib/components/modal/select-contract/SelectContractAdmin.tsx b/src/lib/components/modal/select-contract/SelectContractAdmin.tsx index 0368bb8f7..248156645 100644 --- a/src/lib/components/modal/select-contract/SelectContractAdmin.tsx +++ b/src/lib/components/modal/select-contract/SelectContractAdmin.tsx @@ -11,6 +11,7 @@ import { Heading, } from "@chakra-ui/react"; import { useWallet } from "@cosmos-kit/react"; +import dayjs from "dayjs"; import { MdList, MdSwapHoriz } from "react-icons/md"; import { ADMIN_SPECIAL_SLUG } from "lib/data"; @@ -42,7 +43,7 @@ export const SelectContractAdmin = ({ ...contract, ...getContractLocalInfo(contract.contractAddress), })), - lastUpdated: new Date(), + lastUpdated: dayjs(), isInfoEditable: false, isContractRemovable: false, }; diff --git a/src/lib/model/contract.ts b/src/lib/model/contract.ts index 773eaf1a2..72c87502b 100644 --- a/src/lib/model/contract.ts +++ b/src/lib/model/contract.ts @@ -1,17 +1,18 @@ import { useWallet } from "@cosmos-kit/react"; import { useQuery } from "@tanstack/react-query"; +import dayjs from "dayjs"; import { useCelatoneApp } from "lib/app-provider"; import { INSTANTIATED_LIST_NAME } from "lib/data"; import { useCodeStore, useContractStore, useLCDEndpoint } from "lib/hooks"; import { useAssetInfos } from "lib/services/assetService"; -import type { InstantiateInfo } from "lib/services/contract"; +import type { ContractCw2Info, InstantiateInfo } from "lib/services/contract"; import { + queryContractCw2Info, queryContractBalances, queryInstantiateInfo, } from "lib/services/contract"; import { - useExecuteTxsCountByContractAddress, useInstantiatedCountByUserQuery, useInstantiateDetailByContractQuery, useInstantiatedListByUserQuery, @@ -39,6 +40,7 @@ export interface ContractData { chainId: string; codeInfo: Option; contractLocalInfo: Option; + contractCw2Info: Option; instantiateInfo: Option; publicProject: { publicInfo: Option; @@ -66,7 +68,7 @@ export const useInstantiatedByMe = (enable: boolean): ContractListInfo => { })), name: INSTANTIATED_LIST_NAME, slug: formatSlugName(INSTANTIATED_LIST_NAME), - lastUpdated: new Date(), + lastUpdated: dayjs(), isInfoEditable: false, isContractRemovable: false, }; @@ -83,11 +85,11 @@ export const useInstantiatedMockInfoByMe = (): ContractListInfo => { contractAddress: "" as ContractAddr, instantiator: "", label: "", - created: new Date(0), + created: dayjs(0), })), name: INSTANTIATED_LIST_NAME, slug: formatSlugName(INSTANTIATED_LIST_NAME), - lastUpdated: new Date(), + lastUpdated: dayjs(), isInfoEditable: false, isContractRemovable: false, }; @@ -107,11 +109,18 @@ export const useContractData = ( const { data: publicInfoBySlug } = usePublicProjectBySlug(publicInfo?.slug); const { data: instantiateInfo } = useQuery( - ["query", "instantiateInfo", endpoint, contractAddress], + ["query", "instantiate_info", endpoint, contractAddress], async () => queryInstantiateInfo(endpoint, indexerGraphClient, contractAddress), { enabled: !!currentChainRecord } ); + + const { data: contractCw2Info } = useQuery( + ["query", "contract_cw2_info", endpoint, contractAddress], + async () => queryContractCw2Info(endpoint, contractAddress), + { enabled: !!currentChainRecord } + ); + const { data: contractBalances } = useQuery( ["query", "contractBalances", contractAddress], async () => @@ -154,6 +163,7 @@ export const useContractData = ( chainId: currentChainRecord.chain.chain_id, codeInfo, contractLocalInfo, + contractCw2Info, instantiateInfo, publicProject: { publicInfo, @@ -167,26 +177,31 @@ export const useContractData = ( }; }; +/** + * @remark + * Remove execute table for now + * + */ export const useContractDetailsTableCounts = ( contractAddress: ContractAddr ) => { - const { data: executeCount = 0, refetch: refetchExecute } = - useExecuteTxsCountByContractAddress(contractAddress); + // const { data: executeCount = 0, refetch: refetchExecute } = + // useExecuteTxsCountByContractAddress(contractAddress); const { data: migrationCount = 0, refetch: refetchMigration } = useMigrationHistoriesCountByContractAddress(contractAddress); const { data: transactionsCount = 0, refetch: refetchTransactions } = useTxsCountByContractAddress(contractAddress); - const { data: relatedProposalsCount = 0, refetch: refetchRelatedProposals } = useRelatedProposalsCountByContractAddress(contractAddress); + return { tableCounts: { - executeCount, + // executeCount, migrationCount, transactionsCount, relatedProposalsCount, }, - refetchExecute, + // refetchExecute, refetchMigration, refetchTransactions, refetchRelatedProposals, diff --git a/src/lib/pages/admin/index.tsx b/src/lib/pages/admin/index.tsx index d50f17ba6..904eb583b 100644 --- a/src/lib/pages/admin/index.tsx +++ b/src/lib/pages/admin/index.tsx @@ -109,7 +109,7 @@ const UpdateAdmin = () => { * @remarks Contract admin validation */ useQuery( - ["query", "instantiateInfo", endpoint, contractAddressParam], + ["query", "instantiate_info", endpoint, contractAddressParam], async () => queryInstantiateInfo(endpoint, indexerGraphClient, contractAddressParam), { diff --git a/src/lib/pages/contract-details/components/InstantiateInfo.tsx b/src/lib/pages/contract-details/components/InstantiateInfo.tsx index bfbe3349f..ba0e171e5 100644 --- a/src/lib/pages/contract-details/components/InstantiateInfo.tsx +++ b/src/lib/pages/contract-details/components/InstantiateInfo.tsx @@ -48,6 +48,7 @@ const RenderPortId = ({ portId }: { portId: string }) => { export const InstantiateInfo = ({ contractData: { + contractCw2Info, instantiateInfo, chainId, codeInfo, @@ -84,6 +85,18 @@ export const InstantiateInfo = ({ /> + + {contractCw2Info ? ( + + {contractCw2Info.contract} ({contractCw2Info.version}) + + ) : ( + + No Info + + )} + + Transactions - Executes + {/* Executes */} Migration Related Proposals @@ -110,14 +108,15 @@ const ContractDetailsBody = observer( refetchCount={refetchTransactions} /> - + {/* Remove execute table for now */} + {/* - + */} { router.query.contract ) as ContractAddr; - let decodeMsg = decode(getFirstQueryParam(router.query.msg)); + let decodeMsg = libDecode(getFirstQueryParam(router.query.msg)); if (decodeMsg && jsonValidate(decodeMsg) !== null) { onContractSelect(contractAddressParam); decodeMsg = ""; diff --git a/src/lib/pages/home/components/RecentlyViewContracts.tsx b/src/lib/pages/home/components/RecentlyViewContracts.tsx index 6eede513c..2d3dc5c82 100644 --- a/src/lib/pages/home/components/RecentlyViewContracts.tsx +++ b/src/lib/pages/home/components/RecentlyViewContracts.tsx @@ -1,4 +1,5 @@ import { Heading, Box, Flex, Text } from "@chakra-ui/react"; +import dayjs from "dayjs"; import { ContractListTable } from "lib/pages/contract-list/components/ContractListTable"; import type { ContractAddr } from "lib/types"; @@ -14,7 +15,7 @@ const contracts = [ description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque sed facilisis facilisis risus. Ut volutpat accumsan massa eget consequat, id egestas nulla.", label: "label1", - created: new Date(), + created: dayjs(), }, { contractAddress: @@ -24,7 +25,7 @@ const contracts = [ instantiator: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq", description: "Lorem ipsum dolor id egestas nulla.", label: "label2", - created: new Date(), + created: dayjs(), }, { contractAddress: @@ -34,7 +35,7 @@ const contracts = [ instantiator: "terra18kw0z0nmpk9drz4qxq8y7xvh05tr7spyzja3rq", description: "", label: "label3", - created: new Date(), + created: dayjs(), }, { contractAddress: @@ -45,7 +46,7 @@ const contracts = [ description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. id egestas nulla.", label: "label4", - created: new Date(), + created: dayjs(), }, ]; export const RecentlyViewContracts = () => { diff --git a/src/lib/pages/migrate/index.tsx b/src/lib/pages/migrate/index.tsx index d7a62f35b..04a109808 100644 --- a/src/lib/pages/migrate/index.tsx +++ b/src/lib/pages/migrate/index.tsx @@ -62,7 +62,7 @@ const Migrate = () => { ); useQuery( - ["query", "instantiateInfo", endpoint, contractAddress], + ["query", "instantiate_info", endpoint, contractAddress], async () => queryInstantiateInfo(endpoint, indexerGraphClient, contractAddress), { diff --git a/src/lib/pages/query/components/QueryArea.tsx b/src/lib/pages/query/components/QueryArea.tsx index 473939796..846c899e3 100644 --- a/src/lib/pages/query/components/QueryArea.tsx +++ b/src/lib/pages/query/components/QueryArea.tsx @@ -3,6 +3,7 @@ import { Box, Flex, Spacer, Button, ButtonGroup, Text } from "@chakra-ui/react"; import { useWallet } from "@cosmos-kit/react"; import { useQuery } from "@tanstack/react-query"; import type { AxiosError } from "axios"; +import dayjs from "dayjs"; import dynamic from "next/dynamic"; import { useEffect, useState } from "react"; @@ -58,7 +59,7 @@ export const QueryArea = ({ sender: address, contractAddress, msg: encode(msg), - timestamp: new Date(), + timestamp: dayjs(), }); }, onError(err: AxiosError) { diff --git a/src/lib/services/contract.ts b/src/lib/services/contract.ts index bddb77143..4554d193c 100644 --- a/src/lib/services/contract.ts +++ b/src/lib/services/contract.ts @@ -1,4 +1,5 @@ import axios from "axios"; +import type { Dayjs } from "dayjs"; import type { GraphQLClient } from "graphql-request"; import { CELATONE_API_ENDPOINT, getChainApiPath } from "env"; @@ -10,7 +11,16 @@ import type { Option, PublicInfo, } from "lib/types"; -import { encode, parseDateDefault } from "lib/utils"; +import { encode, libDecode, parseDateDefault } from "lib/utils"; + +export interface ContractCw2InfoRaw { + data: string; +} + +export interface ContractCw2Info { + contract: string; + version: string; +} interface ContractResponse { address: ContractAddr; @@ -42,7 +52,7 @@ export interface InstantiateInfo { admin?: HumanAddr | ContractAddr; label: string; createdHeight: number; - createdTime: Option; + createdTime: Option; ibcPortId: string; raw: ContractResponse; } @@ -69,6 +79,16 @@ export const queryContract = async ( return data; }; +export const queryContractCw2Info = async ( + endpoint: string, + contractAddress: ContractAddr +) => { + const { data } = await axios.get( + `${endpoint}/cosmwasm/wasm/v1/contract/${contractAddress}/raw/Y29udHJhY3RfaW5mbw%3D%3D` + ); + return JSON.parse(libDecode(data.data)) as ContractCw2Info; +}; + export const queryInstantiateInfo = async ( endpoint: string, indexerGraphClient: GraphQLClient, diff --git a/src/lib/stores/contract.ts b/src/lib/stores/contract.ts index f200eaa98..353f4116c 100644 --- a/src/lib/stores/contract.ts +++ b/src/lib/stores/contract.ts @@ -1,3 +1,5 @@ +import type { Dayjs } from "dayjs"; +import dayjs from "dayjs"; import { makeAutoObservable } from "mobx"; import { isHydrated, makePersistable } from "mobx-persist-store"; @@ -19,7 +21,7 @@ interface ContractList { name: string; slug: string; contracts: ContractAddr[]; - lastUpdated: Date; + lastUpdated: Dayjs; isInfoEditable: boolean; isContractRemovable: boolean; } @@ -32,8 +34,7 @@ export const cmpContractListInfo = ( a: ContractListInfo, b: ContractListInfo ) => { - if (a.lastUpdated !== b.lastUpdated) - return b.lastUpdated.getTime() - a.lastUpdated.getTime(); + if (a.lastUpdated !== b.lastUpdated) return b.lastUpdated.diff(a.lastUpdated); return a.slug.localeCompare(b.slug); }; @@ -43,7 +44,7 @@ export interface Activity { sender: string | undefined; contractAddress: ContractAddr; msg: string; // base64 - timestamp: Date; + timestamp: Dayjs; } export class ContractStore { @@ -54,7 +55,7 @@ export class ContractStore { name: SAVED_LIST_NAME, slug: formatSlugName(SAVED_LIST_NAME), contracts: [], - lastUpdated: new Date(), + lastUpdated: dayjs(), isInfoEditable: false, isContractRemovable: true, }, @@ -160,7 +161,7 @@ export class ContractStore { name: name.trim(), slug: formatSlugName(name), contracts: [], - lastUpdated: new Date(), + lastUpdated: dayjs(), isInfoEditable: true, isContractRemovable: true, }, @@ -192,7 +193,7 @@ export class ContractStore { list.name = newName; list.slug = formatSlugName(newName); - list.lastUpdated = new Date(); + list.lastUpdated = dayjs(); } } @@ -332,7 +333,7 @@ export class ContractStore { if (!list) return; list.contracts = Array.from(new Set(list.contracts).add(contractAddress)); - list.lastUpdated = new Date(); + list.lastUpdated = dayjs(); } private removeContractFromList( @@ -346,7 +347,7 @@ export class ContractStore { if (!list) return; list.contracts = list.contracts.filter((addr) => addr !== contractAddress); - list.lastUpdated = new Date(); + list.lastUpdated = dayjs(); } addActivity(userKey: string, activity: Activity) { diff --git a/src/lib/types/code.ts b/src/lib/types/code.ts index a0c2b742e..55a6f7b7d 100644 --- a/src/lib/types/code.ts +++ b/src/lib/types/code.ts @@ -1,3 +1,5 @@ +import type { Dayjs } from "dayjs"; + import type { CodeLocalInfo } from "lib/stores/code"; import type { HumanAddr, ContractAddr, Option } from "lib/types"; @@ -22,7 +24,7 @@ export interface CodeInfo extends CodeLocalInfo { interface CodeProposal { proposalId: number; height: Option; - created: Date; + created: Dayjs; } export interface CodeData { @@ -31,7 +33,7 @@ export interface CodeData { uploader: ContractAddr | HumanAddr; hash: Option; height: Option; - created: Date; + created: Dayjs; proposal: Option; instantiatePermission: InstantiatePermission; permissionAddresses: PermissionAddresses; diff --git a/src/lib/types/contract.ts b/src/lib/types/contract.ts index ed13500ca..ea7d185d2 100644 --- a/src/lib/types/contract.ts +++ b/src/lib/types/contract.ts @@ -1,11 +1,13 @@ +import type { Dayjs } from "dayjs"; + import type { ContractLocalInfo } from "lib/stores/contract"; import type { ContractAddr, HumanAddr, Option } from "lib/types"; export interface ContractInfo extends ContractLocalInfo { admin: Option; - instantiated: Date; + instantiated: Dayjs; latestUpdator: Option; - latestUpdated: Date; + latestUpdated: Dayjs; } export interface ContractInstances { @@ -32,7 +34,7 @@ export interface ContractMigrationHistory { codeDescription?: string; sender: HumanAddr | ContractAddr; height: number; - timestamp: Date; + timestamp: Dayjs; remark: MigrationRemark; } @@ -58,8 +60,8 @@ export interface ContractRelatedProposals { proposalId: number; title: string; status: ProposalStatus; - votingEndTime: Date; - depositEndTime: Date; + votingEndTime: Dayjs; + depositEndTime: Dayjs; resolvedHeight: number | null | undefined; type: ProposalType; proposer: HumanAddr | ContractAddr | undefined; diff --git a/src/lib/types/tx/transaction.ts b/src/lib/types/tx/transaction.ts index ee856fcfa..96df275da 100644 --- a/src/lib/types/tx/transaction.ts +++ b/src/lib/types/tx/transaction.ts @@ -1,3 +1,5 @@ +import type { Dayjs } from "dayjs"; + import type { ContractAddr, HumanAddr } from "lib/types"; import type { @@ -25,7 +27,7 @@ export enum MsgFurtherAction { export interface PastTransaction { hash: string; messages: Message[]; - created: Date; + created: Dayjs; success: boolean; actionMsgType: ActionMsgType; furtherAction: MsgFurtherAction; @@ -62,7 +64,7 @@ export interface ExecuteTransaction { messages: Message[]; sender: ContractAddr | HumanAddr; height: number; - created: Date; + created: Dayjs; success: boolean; } diff --git a/src/lib/utils/date.ts b/src/lib/utils/date.ts index abf4303dc..3ef7eb69b 100644 --- a/src/lib/utils/date.ts +++ b/src/lib/utils/date.ts @@ -1,23 +1,17 @@ +import type { Dayjs } from "dayjs"; import dayjs from "dayjs"; import type { Option } from "lib/types"; -export const formatUTC = (timestamp: string | Date) => { - const localDate = - typeof timestamp === "string" ? timestamp.concat("Z") : timestamp; - return dayjs(localDate).utc().format("MMM DD, YYYY, h:mm:ss A [(UTC)]"); -}; +export const parseDate = (date: string) => dayjs(date).utc(true); -export const dateFromNow = (timestamp: string | Date) => { - const localDate = - typeof timestamp === "string" ? timestamp.concat("Z") : timestamp; - return dayjs(localDate).fromNow(); -}; +export const parseDateOpt = (dateOpt: Option): Option => + dateOpt ? parseDate(dateOpt) : undefined; -export const parseDate = (date: string) => new Date(`${date}Z`); +export const parseDateDefault = (dateOpt: Option): Dayjs => + dateOpt ? parseDate(dateOpt) : dayjs(0); -export const parseDateOpt = (dateOpt: Option): Option => - dateOpt ? parseDate(dateOpt) : undefined; +export const formatUTC = (date: Dayjs) => + date.format("MMM DD, YYYY, h:mm:ss A [(UTC)]"); -export const parseDateDefault = (dateOpt: Option): Date => - dateOpt ? parseDate(dateOpt) : new Date(0); +export const dateFromNow = (date: Dayjs) => date.fromNow();