Skip to content

Commit

Permalink
#76 Add title and description metadata to pages
Browse files Browse the repository at this point in the history
  • Loading branch information
nevendyulgerov authored Dec 14, 2023
1 parent 21d2b11 commit 25ffec0
Show file tree
Hide file tree
Showing 9 changed files with 362 additions and 352 deletions.
129 changes: 28 additions & 101 deletions apps/web/src/app/applications/[address]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,120 +1,47 @@
"use client";
import {
Anchor,
Breadcrumbs,
Group,
Pagination,
Select,
Stack,
Text,
Title,
} from "@mantine/core";
import { useScrollIntoView } from "@mantine/hooks";
import Link from "next/link";
import { pathOr } from "ramda";
import { FC, useEffect, useState } from "react";
import { Group, Stack, Title } from "@mantine/core";
import { FC } from "react";
import { Metadata } from "next";
import { TbInbox } from "react-icons/tb";
import Address from "../../../components/address";
import { InputOrderByInput, useInputsQuery } from "../../../graphql";
import {
limitBounds,
usePaginationParams,
} from "../../../hooks/usePaginationParams";
import InputsTable from "../../../components/inputsTable";
import Inputs from "../../../components/inputs";
import Breadcrumbs from "../../../components/breadcrumbs";

export type ApplicationPageProps = {
params: { address: string };
};
const ApplicationPage: FC<ApplicationPageProps> = ({ params }) => {
const [{ limit, page }, updateParams] = usePaginationParams();
const after = page === 1 ? undefined : ((page - 1) * limit).toString();
const [{ data, fetching }] = useInputsQuery({
variables: {
orderBy: InputOrderByInput.TimestampDesc,
applicationId: params.address.toLowerCase(),
limit,
after,
},
});
const totalInputs = data?.inputsConnection.totalCount ?? 1;
const totalPages = Math.ceil(totalInputs / limit);
const [activePage, setActivePage] = useState(
page > totalPages ? totalPages : page,
);
const inputs = data?.inputsConnection.edges.map((edge) => edge.node) ?? [];
const { scrollIntoView, targetRef } = useScrollIntoView<HTMLDivElement>({
duration: 700,
offset: 150,
cancelable: true,
});

if (!fetching && page > totalPages) {
updateParams(totalPages, limit);
}

useEffect(() => {
setActivePage((n) => {
return n !== page ? page : n;
});
}, [page]);
export async function generateMetadata({
params,
}: ApplicationPageProps): Promise<Metadata> {
return {
title: `Application ${params.address}`,
};
}

const ApplicationPage: FC<ApplicationPageProps> = ({ params }) => {
return (
<Stack>
<Breadcrumbs>
<Anchor href="/" component={Link}>
Home
</Anchor>
<Anchor href="/applications" component={Link}>
Applications
</Anchor>
<Breadcrumbs
breadcrumbs={[
{
href: "/",
label: "Home",
},
{
href: "/applications",
label: "Applications",
},
]}
>
<Address value={params.address as Address} icon />
</Breadcrumbs>
<Group ref={targetRef}>

<Group>
<TbInbox size={40} />
<Title order={2}>Inputs</Title>
</Group>
<Stack>
<Pagination
styles={{ root: { alignSelf: "flex-end" } }}
value={activePage}
total={totalPages}
onChange={(pageN) => {
updateParams(pageN, limit);
}}
/>

<InputsTable inputs={inputs} />

<Group justify="space-between" align="center">
<Group>
<Text>Show:</Text>
<Select
style={{ width: "5rem" }}
value={limit.toString()}
onChange={(val) => {
const entry = val ?? limit;
const l = pathOr(limit, [entry], limitBounds);
updateParams(page, l);
}}
data={[
limitBounds[10].toString(),
limitBounds[20].toString(),
limitBounds[30].toString(),
]}
/>
<Text>inputs</Text>
</Group>
<Pagination
styles={{ root: { alignSelf: "flex-end" } }}
value={activePage}
total={totalPages}
onChange={(pageN) => {
updateParams(pageN, limit);
scrollIntoView({ alignment: "center" });
}}
/>
</Group>
</Stack>{" "}
<Inputs applicationId={params.address} />
</Stack>
);
};
Expand Down
161 changes: 19 additions & 142 deletions apps/web/src/app/applications/page.tsx
Original file line number Diff line number Diff line change
@@ -1,154 +1,31 @@
"use client";
import {
Anchor,
Breadcrumbs,
Group,
Loader,
Pagination,
Select,
Stack,
Table,
Text,
Title,
} from "@mantine/core";
import { useScrollIntoView } from "@mantine/hooks";
import Link from "next/link";
import { pathOr } from "ramda";
import { FC, useEffect, useState } from "react";
import { Group, Stack, Title } from "@mantine/core";
import { Metadata } from "next";
import { TbApps } from "react-icons/tb";
import {
Application,
ApplicationOrderByInput,
useApplicationsConnectionQuery,
} from "../../graphql";
import {
limitBounds,
usePaginationParams,
} from "../../hooks/usePaginationParams";
import ApplicationRow from "../../components/applicationRow";
import Applications from "../../components/applications";
import Breadcrumbs from "../../components/breadcrumbs";

export type ApplicationsPageProps = {};

const ApplicationsPage: FC<ApplicationsPageProps> = (props) => {
const [{ limit, page }, updateParams] = usePaginationParams();
const after = page === 1 ? undefined : ((page - 1) * limit).toString();
const [query] = useApplicationsConnectionQuery({
variables: { orderBy: ApplicationOrderByInput.IdAsc, limit, after },
});
const totalInputs = query.data?.applicationsConnection.totalCount ?? 1;
const totalPages = Math.ceil(totalInputs / limit);
const [activePage, setActivePage] = useState(
page > totalPages ? totalPages : page,
);

const { scrollIntoView, targetRef } = useScrollIntoView<HTMLDivElement>({
duration: 700,
offset: 150,
cancelable: true,
});

useEffect(() => {
if (!query.fetching && page > totalPages) {
updateParams(totalPages, limit);
}
}, [limit, page, query.fetching, totalPages, updateParams]);

useEffect(() => {
setActivePage((n) => {
return n !== page ? page : n;
});
}, [page]);
export const metadata: Metadata = {
title: "Applications",
};

export default function ApplicationsPage() {
return (
<Stack>
<Breadcrumbs>
<Anchor href="/" component={Link}>
Home
</Anchor>
</Breadcrumbs>
<Breadcrumbs
breadcrumbs={[
{
href: "/",
label: "Home",
},
]}
/>

<Group>
<TbApps size={40} />
<Title order={2}>Applications</Title>
</Group>

<Stack>
<Pagination
styles={{ root: { alignSelf: "flex-end" } }}
value={activePage}
total={totalPages}
onChange={(pageN) => {
updateParams(pageN, limit);
}}
/>
<Table>
<Table.Thead>
<Table.Tr>
<Table.Th>Id</Table.Th>
<Table.Th>Owner</Table.Th>
<Table.Th>URL</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>
{query.fetching && (
<Table.Tr>
<Table.Td align="center" colSpan={3}>
<Loader />
</Table.Td>
</Table.Tr>
)}
{query.data?.applicationsConnection.totalCount ===
0 && (
<Table.Tr>
<Table.Td colSpan={3} align="center">
No applications
</Table.Td>
</Table.Tr>
)}
{query.data?.applicationsConnection.edges.map(
({ node }) => (
<ApplicationRow
key={node.id}
application={
node as Omit<Application, "inputs">
}
/>
),
)}
</Table.Tbody>
</Table>

<Group justify="space-between" align="center">
<Group>
<Text>Show:</Text>
<Select
style={{ width: "5rem" }}
value={limit.toString()}
onChange={(val) => {
const entry = val ?? limit;
const l = pathOr(limit, [entry], limitBounds);
updateParams(page, l);
}}
data={[
limitBounds[10].toString(),
limitBounds[20].toString(),
limitBounds[30].toString(),
]}
/>
<Text>Applications</Text>
</Group>
<Pagination
styles={{ root: { alignSelf: "flex-end" } }}
value={activePage}
total={totalPages}
onChange={(pageN) => {
updateParams(pageN, limit);
scrollIntoView({ alignment: "center" });
}}
/>
</Group>
</Stack>
<Applications />
</Stack>
);
};

export default ApplicationsPage;
}
20 changes: 16 additions & 4 deletions apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
import "@mantine/core/styles.css";
import "@mantine/notifications/styles.css";
import React, { FC } from "react";
import type { FC, ReactNode } from "react";
import { Metadata } from "next";
import { ColorSchemeScript } from "@mantine/core";
import { Providers } from "../providers/providers";
import Shell from "../components/shell";

export const metadata: Metadata = {
title: {
template: "%s | CartesiScan",
default: "Blockchain Explorer | CartesiScan",
},
description:
"CartesiScan is a tool for inspecting and analyzing Cartesi rollups applications. Blockchain explorer for Ethereum Networks.",
icons: {
icon: "/favicon.ico",
},
};

interface LayoutProps {
children: React.ReactNode;
children: ReactNode;
}

const Layout: FC<{ children: React.ReactNode }> = ({ children }) => {
const Layout: FC<LayoutProps> = ({ children }) => {
return (
<html lang="en">
<head>
<ColorSchemeScript />
<link rel="shortcut icon" href="/favicon.ico" />
</head>
<body>
<Providers>
Expand Down
Loading

2 comments on commit 25ffec0

@vercel
Copy link

@vercel vercel bot commented on 25ffec0 Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

rollups-explorer-workshop – ./apps/workshop

rollups-explorer-workshop-cartesi.vercel.app
rollups-explorer-workshop.vercel.app
rollups-explorer-workshop-git-main-cartesi.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 25ffec0 Dec 14, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.