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

feat: add advanced Transaction screen #77

Merged
merged 6 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { useRadixTheme } from '@fuels/ui';
import {
JsonView,
collapseAllNested,
darkStyles,
defaultStyles,
} from 'react-json-view-lite';
import { tv } from 'tailwind-variants';

export type JsonViewerProps = {
data: object | unknown[];
};

export function JsonViewer({ data, ...props }: JsonViewerProps) {
const classes = styles();
const ctx = useRadixTheme();
return (
<JsonView
LuizAsFight marked this conversation as resolved.
Show resolved Hide resolved
data={data}
shouldExpandNode={collapseAllNested}
style={{
...(ctx.appearance === 'dark' ? darkStyles : defaultStyles),
container: classes.json(),
}}
{...props}
/>
);
}

const styles = tv({
slots: {
json: 'bg-transparent text-sm py-2 px-1',
},
});
42 changes: 42 additions & 0 deletions packages/app/src/systems/Core/components/ViewMode/ViewMode.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Flex, Text } from '@fuels/ui';

export enum ViewModes {
Simple = 'Simple',
Advanced = 'Advanced',
}

export type ViewModeProps = {
mode: ViewModes;
onChange: (mode: ViewModes) => void;
};

export function ViewMode({ mode, onChange }: ViewModeProps) {
return (
<Flex
align="stretch"
justify="center"
className="bg-gray-3 p-1 rounded h-9"
>
<Flex
align="center"
justify="center"
className={`flex-1 rounded px-6 cursor-default ${
LuizAsFight marked this conversation as resolved.
Show resolved Hide resolved
mode === ViewModes.Simple ? 'bg-gray-1' : 'cursor-pointer'
}`}
onClick={() => onChange(ViewModes.Simple)}
>
<Text size="1">Simple</Text>
</Flex>
<Flex
align="center"
justify="center"
className={`flex-1 rounded px-3 cursor-default ${
mode === ViewModes.Advanced ? 'bg-gray-1' : 'cursor-pointer'
}`}
onClick={() => onChange(ViewModes.Advanced)}
>
<Text size="1">Advanced</Text>
</Flex>
</Flex>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use client';

import type { Maybe } from '@fuel-explorer/graphql';
import { Card, VStack } from '@fuels/ui';
import { JsonViewer } from '~/systems/Core/components/JsonViewer/JsonViewer';

import type { TransactionNode } from '../../types';

type TxScreenProps = {
transaction?: Maybe<TransactionNode>;
};

export function TxScreenAdvanced({ transaction: tx }: TxScreenProps) {
if (!tx) return null;

return (
<VStack gap="6" className="min-h-[75vh]">
<Card>
<Card.Body>
<JsonViewer data={tx} />
</Card.Body>
</Card>
</VStack>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
'use client';

import type {
GroupedInput,
GroupedOutput,
Maybe,
} from '@fuel-explorer/graphql';
import {
Badge,
Box,
EntityItem,
Flex,
Grid,
Heading,
Icon,
Text,
VStack,
} from '@fuels/ui';
import { IconArrowDown } from '@tabler/icons-react';
import { bn } from 'fuels';
import { EmptyCard } from '~/systems/Core/components/EmptyCard/EmptyCard';

import { TxInfo } from '../../component/TxInfo/TxInfo';
import { TxInput } from '../../component/TxInput/TxInput';
import { TxOutput } from '../../component/TxOutput/TxOutput';
import type { TransactionNode, TxStatus } from '../../types';
import { TX_INTENT_MAP, TxIcon } from '../TxIcon/TxIcon';
import { TxScripts } from '../TxScripts/TxScripts';

type TxScreenProps = {
transaction: TransactionNode;
};

export function TxScreenSimple({ transaction: tx }: TxScreenProps) {
const hasInputs = tx.groupedInputs?.length ?? 0 > 0;
const hasOutputs = tx.groupedOutputs?.length ?? 0 > 0;
const title = tx.title as string;

return (
<Grid columns="6" gap="9">
<Box className="col-span-2">
<VStack>
<TxInfo>
<EntityItem>
<EntityItem.Slot>
<TxIcon
status={tx.statusType as TxStatus}
type={title}
size="lg"
/>
</EntityItem.Slot>
<EntityItem.Info title={title}>
<Text as="span" className="text-muted">
<Badge
color={TX_INTENT_MAP[tx.statusType as string]}
variant="ghost"
>
{tx.statusType}
</Badge>
</Text>
</EntityItem.Info>
</EntityItem>
</TxInfo>
<TxInfo name={'Timestamp'} description={tx.time?.full}>
{tx.time?.fromNow}
</TxInfo>
{tx.blockHeight && <TxInfo name={'Block'}>#{tx.blockHeight}</TxInfo>}
<TxInfo
name={'Gas spent'}
description={`Gas limit: ${bn(tx.gasLimit).format()}`}
>
{bn(tx.gasUsed).format()}
</TxInfo>
</VStack>
</Box>
<Box className="col-span-4">
<VStack>
<VStack>
<Heading as="h2" size="5" className="leading-none">
Inputs
</Heading>
{hasInputs ? (
tx.groupedInputs?.map((input) => (
<TxInput
key={getInputId(input as GroupedInput)}
input={input as GroupedInput}
/>
))
) : (
<EmptyCard hideImage>
<EmptyCard.Title>No Inputs</EmptyCard.Title>
<EmptyCard.Description>
This transaction does not have any inputs.
</EmptyCard.Description>
</EmptyCard>
)}
</VStack>
<Flex justify="center">
<Icon icon={IconArrowDown} size={30} color="text-muted" />
</Flex>
<TxScripts tx={tx} />
<Flex justify="center">
<Icon icon={IconArrowDown} size={30} color="text-muted" />
</Flex>
<VStack>
<Heading as="h2" size="5" className="leading-none">
Outputs
</Heading>
{hasOutputs ? (
tx.groupedOutputs?.map((output) => (
<TxOutput
key={getOutputId(output as GroupedOutput)}
output={output as GroupedOutput}
/>
))
) : (
<EmptyCard hideImage>
<EmptyCard.Title>No Outputs</EmptyCard.Title>
<EmptyCard.Description>
This transaction does not have any outputs.
</EmptyCard.Description>
</EmptyCard>
)}
</VStack>
</VStack>
</Box>
</Grid>
);
}

function getInputId(input?: Maybe<GroupedInput>) {
if (!input) return 0;
if (input.type === 'InputCoin') return input.assetId;
if (input.type === 'InputContract') return input.contractId;
return input.sender;
}

function getOutputId(output?: Maybe<GroupedOutput>) {
if (!output) return 0;
if (output.type === 'ContractOutput') return output.inputIndex;
if (output.type === 'ContractCreated') return output.contract?.id ?? 0;
if (output.type === 'MessageOutput') return output.recipient;
return output.assetId;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
IconButton,
Text,
VStack,
useRadixTheme,
} from '@fuels/ui';
import {
IconChevronUp,
Expand All @@ -26,15 +25,10 @@ import {
import { bn } from 'fuels';
import Image from 'next/image';
import { useState } from 'react';
import {
JsonView,
defaultStyles,
darkStyles,
collapseAllNested,
} from 'react-json-view-lite';
import { tv } from 'tailwind-variants';
import { useAsset } from '~/systems/Asset/hooks/useAsset';
import { EmptyCard } from '~/systems/Core/components/EmptyCard/EmptyCard';
import { JsonViewer } from '~/systems/Core/components/JsonViewer/JsonViewer';

import type { TransactionNode } from '../../types';

Expand All @@ -56,7 +50,6 @@ function TxScriptRow({ item }: TxScriptRowProps) {
const [opened, setOpened] = useState(false);
const asset = useAsset(item.assetId);
const classes = styles();
const ctx = useRadixTheme();
const amount = bn(item.amount);
const isDanger =
item.receiptType === 'PANIC' ||
Expand Down Expand Up @@ -113,14 +106,7 @@ function TxScriptRow({ item }: TxScriptRowProps) {
</Card.Header>
{opened && (
<Card.Body className={classes.utxos()}>
<JsonView
data={parseJson(item)}
shouldExpandNode={collapseAllNested}
style={{
...(ctx.appearance === 'dark' ? darkStyles : defaultStyles),
container: classes.json(),
}}
/>
<JsonViewer data={parseJson(item)} />
</Card.Body>
)}
</Card>
Expand Down Expand Up @@ -215,7 +201,6 @@ const styles = tv({
slots: {
icon: 'transition-transform group-data-[state=closed]:hover:rotate-180 group-data-[state=open]:rotate-180',
utxos: 'bg-gray-3 mx-3 mb-3 p-0 rounded',
json: 'bg-transparent text-sm py-2 px-1',
lines: [
'relative flex-1 border-t border-b border-border',
'before:h-[1px] before:absolute before:top-1/2 before:left-0 before:w-full before:bg-border',
Expand Down
Loading
Loading