Skip to content

Commit 0e4a44d

Browse files
committed
feat: add deal details page
1 parent fbfc524 commit 0e4a44d

21 files changed

+1389
-110
lines changed

package-lock.json

Lines changed: 972 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/DataTable.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,8 @@ export function DataTable<TData extends { destination: string }, TValue>({
5757
{table.getRowModel().rows.map((row) => (
5858
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
5959
{row.getVisibleCells().map((cell) => (
60-
<TableCell key={cell.id} className="p-0">
60+
<TableCell key={cell.id}>
6161
<Link
62-
className="block px-5 py-6"
6362
to={cell.row.original.destination}
6463
>
6564
{flexRender(cell.column.columnDef.cell, cell.getContext())}

src/components/SmartLinkGroup.tsx

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
import { Link } from '@tanstack/react-router';
2+
import { ExternalLink } from 'lucide-react';
3+
import CopyButton from '@/components/CopyButton';
4+
import { Button } from '@/components/ui/button';
5+
import { truncateAddress } from '@/utils/truncateAddress';
6+
import {
7+
Tooltip,
8+
TooltipContent,
9+
TooltipProvider,
10+
TooltipTrigger,
11+
} from './ui/tooltip';
12+
13+
const blockExplorerUrl = 'https://blockscout.iex.ec'; // adapte selon ton environnement
14+
15+
type LinkType =
16+
| 'deal'
17+
| 'dataset'
18+
| 'workerpool'
19+
| 'app'
20+
| 'address'
21+
| 'transaction';
22+
23+
interface SmartLinkGroupProps {
24+
type: LinkType;
25+
addressOrId: string;
26+
label?: string;
27+
}
28+
29+
export default function SmartLinkGroup({
30+
type,
31+
addressOrId,
32+
label,
33+
}: SmartLinkGroupProps) {
34+
const basePath = {
35+
deal: 'deals',
36+
dataset: 'datasets',
37+
workerpool: 'workerpool',
38+
app: 'apps',
39+
address: 'address',
40+
transaction: 'transaction',
41+
};
42+
43+
const blockExplorerPath = {
44+
deal: `tx/${addressOrId}`,
45+
dataset: `address/${addressOrId}`,
46+
workerpool: `address/${addressOrId}`,
47+
app: `address/${addressOrId}`,
48+
address: `address/${addressOrId}`,
49+
transaction: `tx/${addressOrId}`,
50+
};
51+
52+
return (
53+
<div className="content flex items-center gap-1">
54+
<Button
55+
variant="link"
56+
className="h-auto p-0 text-sm text-orange-200"
57+
asChild
58+
>
59+
<Link to={`/${basePath[type]}/${addressOrId}`}>
60+
<span className="hidden md:inline">{label ?? addressOrId}</span>
61+
<span className="inline md:hidden">
62+
{(label ? truncateAddress(label) : '') ?? addressOrId}
63+
</span>
64+
</Link>
65+
</Button>
66+
67+
<TooltipProvider delayDuration={0}>
68+
<Tooltip>
69+
<TooltipTrigger asChild>
70+
<Button
71+
variant="link"
72+
className="h-auto p-0! text-sm text-white"
73+
asChild
74+
>
75+
<a
76+
href={`${blockExplorerUrl}/${blockExplorerPath[type]}`}
77+
target="_blank"
78+
rel="noopener noreferrer"
79+
>
80+
<ExternalLink />
81+
</a>
82+
</Button>
83+
</TooltipTrigger>
84+
<TooltipContent side="top" className="max-w-sm">
85+
Open in Block Explorer
86+
</TooltipContent>
87+
</Tooltip>
88+
</TooltipProvider>
89+
90+
<CopyButton textToCopy={addressOrId} />
91+
</div>
92+
);
93+
}

src/components/ui/breadcrumb.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ function BreadcrumbList({ className, ...props }: React.ComponentProps<'ol'>) {
1212
<ol
1313
data-slot="breadcrumb-list"
1414
className={cn(
15-
'text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words sm:gap-2.5',
15+
'text-muted-foreground flex flex-wrap items-center gap-1.5 text-sm break-words font-bold sm:gap-2',
1616
className
1717
)}
1818
{...props}
@@ -48,14 +48,13 @@ function BreadcrumbLink({
4848
);
4949
}
5050

51-
function BreadcrumbPage({ className, ...props }: React.ComponentProps<'span'>) {
51+
function BreadcrumbPage({ ...props }: React.ComponentProps<'span'>) {
5252
return (
5353
<span
5454
data-slot="breadcrumb-page"
5555
role="link"
5656
aria-disabled="true"
5757
aria-current="page"
58-
className={cn('text-foreground font-normal', className)}
5958
{...props}
6059
/>
6160
);

src/components/ui/button.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ const buttonVariants = cva(
1818
ghost:
1919
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
2020
link: 'text-primary underline-offset-4 hover:underline',
21+
'gradient-outline': 'from-grey-400 hover:before:bg-muted relative z-0 overflow-hidden bg-gradient-to-b to-transparent before:absolute before:inset-px before:-z-10 before:rounded-[29px] before:bg-[#15151B] before:duration-300',
22+
'gradient-outline-active': 'from-primary text-primary hover:before:bg-muted relative z-0 overflow-hidden bg-gradient-to-b to-primary before:absolute before:inset-px before:-z-10 before:rounded-[29px] before:bg-[#322B1E] before:duration-300',
2123
},
2224
size: {
2325
default: 'h-9 px-4 py-2 has-[>svg]:px-3 rounded-full',

src/components/ui/table.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ function TableHead({ className, ...props }: React.ComponentProps<'th'>) {
7070
<th
7171
data-slot="table-head"
7272
className={cn(
73-
'text-muted-foreground h-14 px-5 text-left align-middle font-medium whitespace-nowrap uppercase first:pl-10 last:pr-10 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
73+
'text-muted-foreground h-14 px-2 text-left align-middle font-medium whitespace-nowrap uppercase first:pl-4 last:pr-4 sm:px-3 sm:first:pl-6 sm:last:pr-6 md:px-5 md:first:pl-10 md:last:pr-10 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
7474
className
7575
)}
7676
{...props}
@@ -83,7 +83,7 @@ function TableCell({ className, ...props }: React.ComponentProps<'td'>) {
8383
<td
8484
data-slot="table-cell"
8585
className={cn(
86-
'px-5 py-6 align-middle whitespace-nowrap first:*:pl-10 last:*:pr-10 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
86+
'px-2 py-6 align-middle whitespace-nowrap first:pl-4 last:pr-4 sm:px-3 sm:first:pl-6 sm:last:pr-6 md:px-5 md:first:pl-10 md:last:pr-10 [&:has([role=checkbox])]:pr-0 [&>[role=checkbox]]:translate-y-[2px]',
8787
className
8888
)}
8989
{...props}

src/graphql/gql.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ type Documents = {
2020
"\n query Datasets($length: Int = 20, $skip: Int = 0) {\n datasets(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n address: id\n owner {\n address: id\n }\n timestamp\n name\n multiaddr\n checksum\n transfers(orderBy: timestamp, orderDirection: desc) {\n transaction {\n txHash: id\n timestamp\n blockNumber\n }\n }\n }\n }\n": typeof types.DatasetsDocument,
2121
"\n query NextDatasets($length: Int = 20, $skip: Int = 0) {\n datasets(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n address: id\n }\n }\n": typeof types.NextDatasetsDocument,
2222
"\n query Deal($dealAddress: ID!) {\n deal(id: $dealAddress) {\n dealid: id\n timestamp\n startTime\n app {\n address: id\n name\n }\n dataset {\n address: id\n name\n }\n workerpool {\n address: id\n description\n }\n beneficiary {\n address: id\n }\n callback {\n address: id\n }\n appPrice\n datasetPrice\n workerpoolPrice\n params\n tag\n trust\n category {\n catid: id\n name\n workClockTimeRef\n description\n }\n botSize\n botFirst\n completedTasksCount\n claimedTasksCount\n requester {\n address: id\n }\n dealEvents: events(orderBy: timestamp, orderDirection: asc) {\n timestamp\n id\n type: __typename\n transaction {\n txHash: id\n }\n }\n }\n }\n": typeof types.DealDocument,
23+
"\n query DealTasks($dealAddress: ID!) {\n deal(id: $dealAddress) {\n tasks(orderBy: index, orderDirection: asc) {\n taskid: id\n index\n status\n finalDeadline\n }\n }\n }\n": typeof types.DealTasksDocument,
2324
"\n query Deals($length: Int = 20, $skip: Int = 0) {\n deals(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n dealid: id\n timestamp\n requester {\n address: id\n }\n beneficiary {\n address: id\n }\n callback {\n address: id\n }\n app {\n address: id\n }\n dataset {\n address: id\n }\n workerpool {\n address: id\n }\n category {\n catid: id\n workClockTimeRef\n }\n startTime\n appPrice\n datasetPrice\n workerpoolPrice\n botSize\n trust\n completedTasksCount\n claimedTasksCount\n }\n }\n": typeof types.DealsDocument,
2425
"\n query NextDeals($length: Int = 20, $skip: Int = 0) {\n deals(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n dealid: id\n }\n }\n": typeof types.NextDealsDocument,
2526
"\n query NextTasks($length: Int = 20, $skip: Int = 0) {\n tasks(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n taskid: id\n }\n }\n": typeof types.NextTasksDocument,
@@ -33,6 +34,7 @@ const documents: Documents = {
3334
"\n query Datasets($length: Int = 20, $skip: Int = 0) {\n datasets(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n address: id\n owner {\n address: id\n }\n timestamp\n name\n multiaddr\n checksum\n transfers(orderBy: timestamp, orderDirection: desc) {\n transaction {\n txHash: id\n timestamp\n blockNumber\n }\n }\n }\n }\n": types.DatasetsDocument,
3435
"\n query NextDatasets($length: Int = 20, $skip: Int = 0) {\n datasets(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n address: id\n }\n }\n": types.NextDatasetsDocument,
3536
"\n query Deal($dealAddress: ID!) {\n deal(id: $dealAddress) {\n dealid: id\n timestamp\n startTime\n app {\n address: id\n name\n }\n dataset {\n address: id\n name\n }\n workerpool {\n address: id\n description\n }\n beneficiary {\n address: id\n }\n callback {\n address: id\n }\n appPrice\n datasetPrice\n workerpoolPrice\n params\n tag\n trust\n category {\n catid: id\n name\n workClockTimeRef\n description\n }\n botSize\n botFirst\n completedTasksCount\n claimedTasksCount\n requester {\n address: id\n }\n dealEvents: events(orderBy: timestamp, orderDirection: asc) {\n timestamp\n id\n type: __typename\n transaction {\n txHash: id\n }\n }\n }\n }\n": types.DealDocument,
37+
"\n query DealTasks($dealAddress: ID!) {\n deal(id: $dealAddress) {\n tasks(orderBy: index, orderDirection: asc) {\n taskid: id\n index\n status\n finalDeadline\n }\n }\n }\n": types.DealTasksDocument,
3638
"\n query Deals($length: Int = 20, $skip: Int = 0) {\n deals(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n dealid: id\n timestamp\n requester {\n address: id\n }\n beneficiary {\n address: id\n }\n callback {\n address: id\n }\n app {\n address: id\n }\n dataset {\n address: id\n }\n workerpool {\n address: id\n }\n category {\n catid: id\n workClockTimeRef\n }\n startTime\n appPrice\n datasetPrice\n workerpoolPrice\n botSize\n trust\n completedTasksCount\n claimedTasksCount\n }\n }\n": types.DealsDocument,
3739
"\n query NextDeals($length: Int = 20, $skip: Int = 0) {\n deals(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n dealid: id\n }\n }\n": types.NextDealsDocument,
3840
"\n query NextTasks($length: Int = 20, $skip: Int = 0) {\n tasks(\n first: $length\n skip: $skip\n orderBy: timestamp\n orderDirection: desc\n ) {\n taskid: id\n }\n }\n": types.NextTasksDocument,
@@ -61,6 +63,10 @@ export function graphql(source: "\n query NextDatasets($length: Int = 20, $skip
6163
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
6264
*/
6365
export function graphql(source: "\n query Deal($dealAddress: ID!) {\n deal(id: $dealAddress) {\n dealid: id\n timestamp\n startTime\n app {\n address: id\n name\n }\n dataset {\n address: id\n name\n }\n workerpool {\n address: id\n description\n }\n beneficiary {\n address: id\n }\n callback {\n address: id\n }\n appPrice\n datasetPrice\n workerpoolPrice\n params\n tag\n trust\n category {\n catid: id\n name\n workClockTimeRef\n description\n }\n botSize\n botFirst\n completedTasksCount\n claimedTasksCount\n requester {\n address: id\n }\n dealEvents: events(orderBy: timestamp, orderDirection: asc) {\n timestamp\n id\n type: __typename\n transaction {\n txHash: id\n }\n }\n }\n }\n"): typeof import('./graphql').DealDocument;
66+
/**
67+
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
68+
*/
69+
export function graphql(source: "\n query DealTasks($dealAddress: ID!) {\n deal(id: $dealAddress) {\n tasks(orderBy: index, orderDirection: asc) {\n taskid: id\n index\n status\n finalDeadline\n }\n }\n }\n"): typeof import('./graphql').DealTasksDocument;
6470
/**
6571
* The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients.
6672
*/

src/graphql/graphql.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8395,6 +8395,13 @@ export type DealQueryVariables = Exact<{
83958395

83968396
export type DealQuery = { __typename?: 'Query', deal?: { __typename?: 'Deal', timestamp: any, startTime: any, appPrice: any, datasetPrice: any, workerpoolPrice: any, params: string, tag: any, trust: any, botSize: any, botFirst: any, completedTasksCount: any, claimedTasksCount: any, dealid: string, app: { __typename?: 'App', name: string, address: string }, dataset?: { __typename?: 'Dataset', name: string, address: string } | null, workerpool: { __typename?: 'Workerpool', description: string, address: string }, beneficiary: { __typename?: 'Account', address: string }, callback: { __typename?: 'Account', address: string }, category: { __typename?: 'Category', name: string, workClockTimeRef: any, description: string, catid: string }, requester: { __typename?: 'Account', address: string }, dealEvents: Array<{ __typename?: 'OrdersMatched', timestamp: any, id: string, type: 'OrdersMatched', transaction: { __typename?: 'Transaction', txHash: string } }> } | null };
83978397

8398+
export type DealTasksQueryVariables = Exact<{
8399+
dealAddress: Scalars['ID']['input'];
8400+
}>;
8401+
8402+
8403+
export type DealTasksQuery = { __typename?: 'Query', deal?: { __typename?: 'Deal', tasks: Array<{ __typename?: 'Task', index: any, status: TaskStatus, finalDeadline: any, taskid: string }> } | null };
8404+
83988405
export type DealsQueryVariables = Exact<{
83998406
length?: InputMaybe<Scalars['Int']['input']>;
84008407
skip?: InputMaybe<Scalars['Int']['input']>;
@@ -8574,6 +8581,18 @@ export const DealDocument = new TypedDocumentString(`
85748581
}
85758582
}
85768583
`) as unknown as TypedDocumentString<DealQuery, DealQueryVariables>;
8584+
export const DealTasksDocument = new TypedDocumentString(`
8585+
query DealTasks($dealAddress: ID!) {
8586+
deal(id: $dealAddress) {
8587+
tasks(orderBy: index, orderDirection: asc) {
8588+
taskid: id
8589+
index
8590+
status
8591+
finalDeadline
8592+
}
8593+
}
8594+
}
8595+
`) as unknown as TypedDocumentString<DealTasksQuery, DealTasksQueryVariables>;
85778596
export const DealsDocument = new TypedDocumentString(`
85788597
query Deals($length: Int = 20, $skip: Int = 0) {
85798598
deals(first: $length, skip: $skip, orderBy: timestamp, orderDirection: desc) {

src/hooks/useSyncAccountWithUserStore.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { useEffect } from 'react';
22
import { useAccount } from 'wagmi';
3+
import { cleanIExecSDKs, initIExecSDKs } from '@/externals/iexecSdkClient';
34
import useUserStore from '@/stores/useUser.store';
45

56
export function useSyncAccountWithUserStore() {
@@ -24,4 +25,11 @@ export function useSyncAccountWithUserStore() {
2425
setAddress,
2526
setChainId,
2627
]);
28+
29+
// Update dataProtector client
30+
if (status === 'connected') {
31+
initIExecSDKs({ connector });
32+
return;
33+
}
34+
cleanIExecSDKs();
2735
}

src/modules/deals/deal/DealDetailsTable.tsx renamed to src/modules/DetailsTable.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
1-
// components/DealDetailsTable.tsx
21
import { Table, TableBody, TableCell, TableRow } from '@/components/ui/table';
32

43
type DealDetailsTableProps = {
54
details: Record<string, React.ReactNode | React.ReactNode[]>;
65
};
76

8-
export function DealDetailsTable({ details }: DealDetailsTableProps) {
7+
export function DetailsTable({ details }: DealDetailsTableProps) {
98
return (
109
<Table>
1110
<TableBody>
1211
{Object.entries(details).map(([key, value], i) => (
1312
<TableRow key={i}>
14-
<TableCell>{key} :</TableCell>
15-
<TableCell>
13+
<TableCell className="min-w-32 text-pretty! whitespace-normal">
14+
{key} :
15+
</TableCell>
16+
<TableCell className="relative overflow-x-auto">
1617
{Array.isArray(value)
1718
? value.map((v, j) => <div key={j}>{v}</div>)
1819
: value}

0 commit comments

Comments
 (0)