Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve Timeline Widget UX #34 #53

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion src/features/store.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { create } from 'zustand';
import { persist } from 'zustand/middleware';

import { FinalTransferStatuses, TransferContext, TransferStatus } from './transfer/types';
import {
FinalTransferStatuses,
TransferContext,
TransferStatus,
TransferStatusParams,
} from './transfer/types';

// Increment this when persist state has breaking changes
const PERSIST_STATE_VERSION = 1;
Expand All @@ -28,6 +33,7 @@ export interface AppState {
setIsSenderNftOwner: (isOwner: boolean | null) => void;
transferLoading: boolean;
setTransferLoading: (isLoading: boolean) => void;
updateTransferStatusParams: (i: number, params: TransferStatusParams) => void;
}

export const useStore = create<AppState>()(
Expand All @@ -52,6 +58,16 @@ export const useStore = create<AppState>()(
};
});
},
updateTransferStatusParams: (i, params) => {
set((state) => {
if (i >= state.transfers.length) return state;
const txs = [...state.transfers];
txs[i].statusParams ||= params;
return {
transfers: txs,
};
});
},
failUnconfirmedTransfers: () => {
set((state) => ({
transfers: state.transfers.map((t) =>
Expand Down
42 changes: 37 additions & 5 deletions src/features/transfer/TransfersDetailsModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { getChainReference } from '../caip/chains';
import { AssetNamespace, parseCaip19Id } from '../caip/tokens';
import { getChainDisplayName, hasPermissionlessChain } from '../chains/utils';
import { getMultiProvider } from '../multiProvider';
import { useStore } from '../store';
import { getToken } from '../tokens/metadata';
import { useAccountForChain } from '../wallet/hooks';

Expand All @@ -26,10 +27,12 @@ export function TransfersDetailsModal({
isOpen,
onClose,
transfer,
transferIndex,
}: {
isOpen: boolean;
onClose: () => void;
transfer: TransferContext;
transferIndex: number;
}) {
const [fromUrl, setFromUrl] = useState<string>('');
const [toUrl, setToUrl] = useState<string>('');
Expand Down Expand Up @@ -138,7 +141,12 @@ export function TransfersDetailsModal({
{isPermissionlessRoute ? (
<TransferStatusIcon transferStatus={status} />
) : (
<Timeline transferStatus={status} originTxHash={originTxHash} />
<Timeline
transferStatus={status}
transferIndex={transferIndex}
originTxHash={originTxHash}
transfer={transfer}
/>
)}
{status !== TransferStatus.ConfirmedTransfer && status !== TransferStatus.Delivered ? (
<div
Expand Down Expand Up @@ -270,23 +278,47 @@ export function TransfersDetailsModal({
function Timeline({
transferStatus,
originTxHash,
transferIndex,
transfer,
}: {
transferStatus: TransferStatus;
originTxHash?: string;
transferIndex: number;
transfer: TransferContext;
}) {
const isFailed = transferStatus === TransferStatus.Failed;
const { stage, timings, message } = useMessageTimeline({
originTxHash: isFailed ? undefined : originTxHash,
});
const messageStatus = isFailed ? MessageStatus.Failing : message?.status || MessageStatus.Pending;

const messageStatus = isFailed
? MessageStatus.Failing
: transfer.statusParams?.message?.status || message?.status || MessageStatus.Pending;

// TODO move this so it runs even if timeline isn't open
const { updateTransferStatus, updateTransferStatusParams } = useStore((s) => ({
updateTransferStatus: s.updateTransferStatus,
updateTransferStatusParams: s.updateTransferStatusParams,
}));

useEffect(() => {
if (messageStatus === MessageStatus.Delivered) {
updateTransferStatus(transferIndex, TransferStatus.Delivered);
if (!transfer.statusParams) {
updateTransferStatusParams(transferIndex, { stage, timings, message });
}
}
}, [transferIndex, messageStatus, updateTransferStatus]);

return (
<div className="mt-6 mb-2 w-full flex flex-col justify-center items-center timeline-container">
<MessageTimeline
status={messageStatus}
stage={stage}
timings={timings}
timestampSent={message?.origin?.timestamp}
stage={transfer.statusParams?.stage || stage}
timings={transfer.statusParams?.timings || timings}
timestampSent={
transfer.statusParams?.message?.origin?.timestamp || message?.origin?.timestamp
}
hideDescriptions={true}
/>
</div>
Expand Down
9 changes: 9 additions & 0 deletions src/features/transfer/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { ApiMessage, MessageStage, StageTimings } from '@hyperlane-xyz/widgets';

import type { Route } from '../tokens/routes/types';

export interface TransferFormValues {
Expand Down Expand Up @@ -30,10 +32,17 @@ export const FinalTransferStatuses = [

export interface TransferContext {
status: TransferStatus;
statusParams?: TransferStatusParams;
route: Route;
params: TransferFormValues;
originTxHash?: string;
msgId?: string;
timestamp: number;
activeAccountAddress: Address;
}

export interface TransferStatusParams {
stage: MessageStage;
timings: StageTimings;
message: ApiMessage | null;
}
13 changes: 10 additions & 3 deletions src/features/wallet/SideBarMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export function SideBarMenu({
const [isMenuOpen, setIsMenuOpen] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
const [selectedTransfer, setSelectedTransfer] = useState<TransferContext | null>(null);
const [selectedTransferIndex, setSelectedTransferIndex] = useState<number | null>(null);

const disconnects = useDisconnectFns();
const { readyAccounts } = useAccounts();
const didMountRef = useRef(false);
Expand All @@ -70,6 +72,7 @@ export function SideBarMenu({
didMountRef.current = true;
} else if (transferLoading) {
setSelectedTransfer(transfers[transfers.length - 1]);
setSelectedTransferIndex(transfers.length - 1);
setIsModalOpen(true);
}
}, [transfers, transferLoading]);
Expand Down Expand Up @@ -147,11 +150,15 @@ export function SideBarMenu({
<div className="flex grow flex-col px-3.5">
<div className="grow flex flex-col w-full">
{sortedTransfers?.length > 0 &&
sortedTransfers.map((t) => (
sortedTransfers.map((t, i) => (
<button
key={t.timestamp}
onClick={() => {
const transferIndex = transfers.findIndex(
(transfer) => transfer.timestamp === t.timestamp,
);
setSelectedTransfer(t);
setSelectedTransferIndex(transferIndex);
setIsModalOpen(true);
}}
className="flex justify-between items-center rounded-md border border-gray-300 px-2.5 py-2 mb-3 hover:bg-gray-100 active:bg-gray-200 transition-all duration-500"
Expand Down Expand Up @@ -215,14 +222,14 @@ export function SideBarMenu({
</div>
</div>
</div>
{selectedTransfer && (
{selectedTransferIndex !== null && selectedTransfer && (
<TransfersDetailsModal
isOpen={isModalOpen}
onClose={() => {
setIsModalOpen(false);
setSelectedTransfer(null);
}}
transfer={selectedTransfer}
transferIndex={selectedTransferIndex}
/>
)}
</>
Expand Down