Skip to content

Commit

Permalink
Implement recent queries
Browse files Browse the repository at this point in the history
  • Loading branch information
DimitarTAtanasov committed Dec 27, 2024
1 parent 05644c2 commit bffe091
Show file tree
Hide file tree
Showing 18 changed files with 1,518 additions and 534 deletions.
5 changes: 5 additions & 0 deletions src/assets/svgs/icon/history.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
157 changes: 157 additions & 0 deletions src/components/drawers/recentQueries/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
import { busDispatch } from '@pivanov/event-bus';
import { formatDistanceToNowStrict } from 'date-fns';
import React, {
Fragment,
useCallback,
useEffect,
useState,
} from 'react';

import { Icon } from '@components/icon';
import { PDDrawer } from '@components/pdDrawer';
import { useStoreChain } from '@stores';
import { cn } from '@utils/helpers';
import { getRecentQueries } from '@utils/recentQueries';

import styles from './styles.module.css';

import type {
TCategory,
TRecentQuery,
} from '@custom-types/recentQueries';

interface QueryItemProps {
item: TRecentQuery;
}

interface RecentQueriesDrawerProps {
category: TCategory;
isOpen: boolean;
handleClose: () => void;
}

export const RecentQueriesDrawer = (props: RecentQueriesDrawerProps) => {
const {
category,
isOpen,
handleClose,
} = props;
const chain = useStoreChain.use.chain?.();

const [
items,
setItems,
] = useState<TRecentQuery[]>([]);

// recent queries logic
useEffect(() => {
if (!isOpen) return;
void (async () => {
getRecentQueries({
chainId: chain.id,
category,
})
.then((res) => setItems(res))
.catch(console.log);
})();
}, [
isOpen,
chain.id,
category,
]);

const handleRunRecentQuery = useCallback((e: React.MouseEvent<HTMLButtonElement>) => {
const queryId = e.currentTarget.getAttribute('data-query-id');
busDispatch({
type: '@@-recent-query',
data: items.find((item) => item.id === queryId),
});
handleClose();
}, [
handleClose,
items,
]);

const displayTimestamp = useCallback((time: number) => {
if (time) {
return formatDistanceToNowStrict(new Date(time), { addSuffix: true });
} else {
return 'undefined';
}
}, []);

return (
<Fragment>
<PDDrawer
isOpen={isOpen}
onClose={handleClose}
position="right"
>
<div className={cn(
'flex flex-col break-all p-4 text-black md:min-w-96',
)}
>
<div className={styles.drawerHeader}>
<p className={styles.drawerTitle}>Latest Activity</p>
<div
onClick={handleClose}
className={cn(
'cursor-pointer duration-300 ease-out',
'bg-dev-purple-700 p-2 dark:bg-dev-purple-50',
'hover:bg-dev-purple-900 hover:dark:bg-dev-purple-200',
)}
>
<Icon
className="text-dev-white-200 dark:text-dev-purple-700"
name="icon-close"
/>
</div>
</div>
{
!!items.length
? items.map((item) => (
<button
key={`recent-query-button-${item.id}`}
data-query-id={item.id}
onClick={handleRunRecentQuery}
className={cn(
'items-left',
styles.recentQuery,
)}
>
<QueryItem
item={item}
/>
<p className={styles.timestamp}>
{displayTimestamp(item.timestamp)}
</p>
</button>
))
: (
<p className="mt-20 text-center text-dev-purple-50">No recent queries</p>
)
}
</div>
</PDDrawer>
</Fragment>
);
};

const QueryItem = ({ item }: QueryItemProps) => {

return (
<div className="flex flex-col gap-1">
<p className={styles.queryItemName}>
{`${item.type ? `${item.type}/${item.pallet}` : item.pallet || item.name}`}
</p>

{item.storage || item.method
? (
<p className={styles.queryItemMethod}>
{item.storage || item.method}
</p>
)
: null}
</div>
);
};
38 changes: 38 additions & 0 deletions src/components/drawers/recentQueries/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
.historyButton {
@apply fixed right-14 top-20 size-10;
@apply flex items-center justify-center;
@apply text-white dark:text-black;
@apply bg-dev-purple-700 dark:bg-dev-purple-50;
}

.drawerHeader {
@apply relative flex flex-row items-center justify-between;
@apply py-4;
}

.drawerTitle {
@apply pl-4;
@apply text-lg font-semibold;
@apply text-dev-black-1000 dark:text-dev-purple-50;
}

.recentQuery {
@apply flex flex-col justify-between gap-1;
@apply py-4 pl-4 pr-28;
@apply transition-[background] duration-300;
@apply text-left text-dev-purple-300 dark:text-dev-black-800;
@apply hover:bg-dev-purple-200 dark:hover:bg-dev-purple-900;
@apply border-b border-b-dev-white-700 last:border-b-0 dark:border-b-dev-black-600;
}

.timestamp {
@apply text-sm font-normal text-dev-black-600 dark:text-dev-purple-300;
}

.queryItemName {
@apply text-sm font-semibold text-dev-black-1000 dark:text-dev-purple-50
}

.queryItemMethod {
@apply text-sm font-normal text-dev-pink-500;
}
71 changes: 51 additions & 20 deletions src/components/pageHeader/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import { useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import {
useCallback,
useMemo,
} from 'react';
import {
useLocation,
useNavigate,
} from 'react-router-dom';

import { Icon } from '@components/icon';
import { cn } from '@utils/helpers';
Expand All @@ -8,40 +14,65 @@ interface IPageHeader {
title: string;
location?: string;
blockNumber?: string;
children?: React.ReactNode;
className?: string;
}

export const PageHeader = (props: IPageHeader) => {
const { title, location = -1, blockNumber } = props;
const { title, location = -1, blockNumber, children, className } = props;
const navigate = useNavigate();

const currentLocation = useLocation();

const categoryPages = useMemo(() => [
'/chain-state',
'/extrinsics',
'/decoder',
'/decoder-dynamic',
'/rpc-calls',
'/runtime-calls',
'/constants',
], []);

const goBack = useCallback(() => {
if (location === -1) {
if (categoryPages.includes(currentLocation.pathname)) {
navigate('/');
} else if (location === -1) {
navigate(-1);
} else {
navigate(location);
}
}, [
location,
categoryPages,
currentLocation.pathname,
navigate,
location,
]);

return (
<div className="flex items-center">
<div
onClick={goBack}
className={cn(
'mr-8 cursor-pointer duration-300 ease-out',
'bg-dev-purple-700 p-2 dark:bg-dev-purple-50',
'hover:bg-dev-purple-900 hover:dark:bg-dev-purple-200',
)}
>
<Icon
className=" text-dev-white-200 dark:text-dev-purple-700"
name="icon-arrowLeft"
/>
<div className={cn('flex items-center justify-between', className)}>
<div className="flex items-center">
<div
onClick={goBack}
className={cn(
'mr-8 cursor-pointer duration-300 ease-out',
'bg-dev-purple-700 p-2 dark:bg-dev-purple-50',
'hover:bg-dev-purple-900 hover:dark:bg-dev-purple-200',
)}
>
<Icon
className="text-dev-white-200 dark:text-dev-purple-700"
name="icon-arrowLeft"
/>
</div>
<h4 className="mr-2 text-dev-black-300 font-h4-light dark:text-dev-purple-300">{title}</h4>
{blockNumber && <h4 className="font-h4-bold">{blockNumber}</h4>}
</div>
<h4 className="mr-2 font-h4-light">{title}</h4>
{blockNumber && <h4 className="font-h4-bold">{blockNumber}</h4>}
{children && (
<div className="flex items-center">
{children}
</div>
)}
</div>
);
};
87 changes: 87 additions & 0 deletions src/components/pdDrawer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { useEffect } from 'react';

import { ReactPortal } from '@components/reactPortal';
import { cn } from '@utils/helpers';

import styles from './styles.module.css';

import type React from 'react';

interface DrawerProps {
isOpen: boolean;
onClose: () => void;
children: React.ReactNode;
position: 'right' | 'left' | 'top' | 'bottom';
}

export const PDDrawer = ({
isOpen = false,
onClose,
children,
position = 'right',
}: DrawerProps) => {
console.log('@@', isOpen);

const positionClasses = {
right: 'right-0 top-0 h-full max-w-[90%]',
left: 'left-0 top-0 h-full max-w-[90%]',
top: 'top-0 w-full left-0 max-h-[90%]',
bottom: 'bottom-0 w-full left-0 max-h-[90%]',
};

const transformClasses = {
right: isOpen ? 'translate-x-0' : 'translate-x-full',
left: isOpen ? 'translate-x-0' : '-translate-x-full',
top: isOpen ? 'translate-y-0' : '-translate-y-full',
bottom: isOpen ? 'translate-y-0' : 'translate-y-full',
};

useEffect(() => {
const handleEscape = (e: KeyboardEvent) => {
if (e.key === 'Escape') {
onClose();
}
};

window.document.addEventListener('keydown', handleEscape);

return () => {
window.document.removeEventListener('keydown', handleEscape);
};

}, [onClose]);

return (
<ReactPortal id="pd-extras">
{/* Backdrop */}
{isOpen && (
<div
aria-hidden="true"
onClick={onClose}
className={cn(
'fixed inset-0 z-[999] bg-black bg-opacity-50 transition-opacity',
{
'opacity-100': isOpen,
'pointer-events-none opacity-0': !isOpen,
},
)}
/>
)}

{/* Drawer */}
<div
aria-modal="true"
role="dialog"
className={cn(`
fixed z-[999] overflow-y-auto
shadow-xl transition-transform duration-300 ease-in-out
${styles.drawer}
${positionClasses[position]}
${transformClasses[position]}
`)}
>
{children}
</div>
</ReactPortal>
);
};
4 changes: 4 additions & 0 deletions src/components/pdDrawer/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.drawer {
@apply border-l border-l-dev-white-700 bg-dev-purple-100;
@apply dark:border-l-dev-black-600 dark:bg-dev-black-900;
}
Loading

0 comments on commit bffe091

Please sign in to comment.