Skip to content
Merged
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
55 changes: 46 additions & 9 deletions apps/dashboard/redirects.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,51 @@ const legacyDashboardToTeamRedirects = [
},
];

const projectRoute = "/team/:team_slug/:project_slug";

const projectPageRedirects = [
{
source: `${projectRoute}/connect/pay/:path*`,
destination: `${projectRoute}/universal-bridge/:path*`,
permanent: false,
},
{
source: `${projectRoute}/connect/universal-bridge/:path*`,
destination: `${projectRoute}/universal-bridge/:path*`,
permanent: false,
},
{
source: `${projectRoute}/connect/account-abstraction/:path*`,
destination: `${projectRoute}/account-abstraction/:path*`,
permanent: false,
},
{
source: `${projectRoute}/connect/in-app-wallets/:path*`,
destination: `${projectRoute}/wallets/:path*`,
permanent: false,
},
{
source: `${projectRoute}/engine/cloud/vault/:path*`,
destination: `${projectRoute}/vault/:path*`,
permanent: false,
},
{
source: `${projectRoute}/engine/cloud/:path*`,
destination: `${projectRoute}/transactions/:path*`,
permanent: false,
},
{
source: `${projectRoute}/assets/:path*`,
destination: `${projectRoute}/tokens/:path*`,
permanent: false,
},
{
source: `${projectRoute}/nebula/:path*`,
destination: projectRoute,
permanent: false,
},
];

/** @type {import('next').NextConfig['redirects']} */
async function redirects() {
return [
Expand Down Expand Up @@ -326,14 +371,6 @@ async function redirects() {
destination: "/",
permanent: false,
},
// pay > universal-bridge redirect
{
source: "/team/:team_slug/:project_slug/connect/pay/:path*",
destination:
"/team/:team_slug/:project_slug/connect/universal-bridge/:path*",
permanent: false,
},

// all /learn/tutorials (and sub-routes) -> /learn/guides
{
source: "/learn/tutorials/:path*",
Expand Down Expand Up @@ -382,8 +419,8 @@ async function redirects() {
destination: "/transactions",
permanent: false,
},

...legacyDashboardToTeamRedirects,
...projectPageRedirects,
];
}

Expand Down
1 change: 1 addition & 0 deletions apps/dashboard/src/@/components/blocks/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export type SidebarBaseLink = {
label: React.ReactNode;
exactMatch?: boolean;
icon?: React.FC<{ className?: string }>;
isActive?: (pathname: string) => boolean;
};

export type SidebarLink =
Expand Down
1 change: 1 addition & 0 deletions apps/dashboard/src/@/components/blocks/SidebarLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ function RenderSidebarGroup(props: {
className="flex items-center gap-2 text-muted-foreground text-sm hover:bg-accent"
activeClassName="text-foreground bg-accent"
exactMatch={link.exactMatch}
isActive={link.isActive}
onClick={() => {
sidebar.setOpenMobile(false);
}}
Expand Down
13 changes: 8 additions & 5 deletions apps/dashboard/src/@/components/ui/NavLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,18 @@ export type NavButtonProps = {
href: string;
exactMatch?: boolean;
onClick?: () => void;
isActive?: (pathname: string) => boolean;
};

export function NavLink(props: React.PropsWithChildren<NavButtonProps>) {
const pathname = usePathname();
const isActive = pathname
? props.exactMatch
? pathname === props.href
: pathname.startsWith(props.href)
: false;
const isActive = props.isActive
? props.isActive(pathname)
: pathname
? props.exactMatch
? pathname === props.href
: pathname.startsWith(props.href)
: false;
return (
<Link
href={props.href}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function DeployedContractsPageHeader(props: {
const [importModalOpen, setImportModalOpen] = useState(false);

return (
<div className="border-b">
<div>
<ImportModal
client={props.client}
isOpen={importModalOpen}
Expand All @@ -28,24 +28,28 @@ export function DeployedContractsPageHeader(props: {
type="contract"
/>

<div className="container flex max-w-7xl flex-col gap-3 py-10 lg:flex-row lg:items-center lg:justify-between">
<div className="container flex max-w-7xl flex-col gap-3 pt-10 pb-5 lg:flex-row lg:items-center lg:justify-between">
<div>
<h1 className="font-semibold text-2xl tracking-tight lg:text-3xl">
Contracts
</h1>
<p className="text-muted-foreground">
Deploy and manage contracts for your project
</p>
</div>
<div className="flex gap-3 [&>*]:grow">
<Button
className="gap-2 bg-card"
className="gap-1.5 bg-card"
size="sm"
variant="outline"
onClick={() => {
setImportModalOpen(true);
}}
>
<DownloadIcon className="size-4" />
<DownloadIcon className="size-4 text-muted-foreground" />
Import contract
</Button>
<Button asChild className="gap-2">
<Button asChild className="gap-1.5" size="sm">
<Link href="/explore">
<PlusIcon className="size-4" />
Deploy contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Spinner } from "@/components/ui/Spinner/Spinner";
import { ContractTable } from "components/contract-components/tables/contract-table";
import { Suspense } from "react";
import type { ThirdwebClient } from "thirdweb";
import { DeployedContractsPageHeader } from "../DeployedContractsPageHeader";
import { DeployViaCLIOrImportCard } from "./DeployViaCLIOrImportCard";
import { getSortedDeployedContracts } from "./getSortedDeployedContracts";

Expand All @@ -16,24 +15,16 @@ export function DeployedContractsPage(props: {
projectSlug: string;
}) {
return (
<div className="flex grow flex-col">
<DeployedContractsPageHeader
<div className="container flex max-w-7xl grow flex-col">
<Suspense fallback={<Loading />}>
<DeployedContractsPageAsync {...props} />
</Suspense>
<div className="h-8" />
<DeployViaCLIOrImportCard
client={props.client}
teamId={props.teamId}
projectId={props.projectId}
client={props.client}
/>
<div className="h-6" />
<div className="container flex max-w-7xl grow flex-col">
<Suspense fallback={<Loading />}>
<DeployedContractsPageAsync {...props} />
</Suspense>
<div className="h-8" />
<DeployViaCLIOrImportCard
client={props.client}
teamId={props.teamId}
projectId={props.projectId}
/>
</div>
</div>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ import { SmartAccountIcon } from "../../../../../(dashboard)/(chain)/components/

export function ProjectSidebarLayout(props: {
layoutPath: string;
engineLinkType: "cloud" | "dedicated";
children: React.ReactNode;
}) {
const { layoutPath, children } = props;
const { layoutPath, engineLinkType, children } = props;

return (
<FullWidthSidebarLayout
Expand Down Expand Up @@ -62,9 +63,18 @@ export function ProjectSidebarLayout(props: {
icon: CoinsIcon,
},
{
href: `${layoutPath}/engine`,
href:
engineLinkType === "cloud"
? `${layoutPath}/transactions`
: `${layoutPath}/engine/dedicated`,
label: "Transactions",
icon: ArrowLeftRightIcon,
isActive: (pathname) => {
return (
pathname.startsWith(`${layoutPath}/transactions`) ||
pathname.startsWith(`${layoutPath}/engine/dedicated`)
);
},
},
{
href: `${layoutPath}/insight`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { getProject } from "@/api/projects";
import { getTeamBySlug } from "@/api/team";
import { TabPathLinks } from "@/components/ui/tabs";
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
import { DeployedContractsPageHeader } from "@app/account/contracts/DeployedContractsPageHeader";
import { getAuthToken } from "@app/api/lib/getAuthToken";
import { loginRedirect } from "@app/login/loginRedirect";
import { redirect } from "next/navigation";

export default async function Layout(props: {
children: React.ReactNode;
params: Promise<{ team_slug: string; project_slug: string }>;
}) {
const params = await props.params;

const [authToken, team, project] = await Promise.all([
getAuthToken(),
getTeamBySlug(params.team_slug),
getProject(params.team_slug, params.project_slug),
]);

if (!authToken) {
loginRedirect(`/team/${params.team_slug}/${params.project_slug}/contracts`);
}

if (!team) {
redirect("/team");
}

if (!project) {
redirect(`/team/${params.team_slug}`);
}

const client = getClientThirdwebClient({
jwt: authToken,
teamId: team.id,
});

const layoutPath = `/team/${params.team_slug}/${params.project_slug}/contracts`;

return (
<div className="flex grow flex-col">
<DeployedContractsPageHeader
teamId={team.id}
projectId={project.id}
client={client}
/>
<TabPathLinks
scrollableClassName="container max-w-7xl"
links={[
{
name: "Contracts",
path: layoutPath,
exactMatch: true,
},
{
name: "Webhooks",
path: `${layoutPath}/webhooks`,
},
]}
/>
<div className="h-6" />
{props.children}
</div>
);
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { getProject } from "@/api/projects";
import { getTeamBySlug } from "@/api/team";
import { getClientThirdwebClient } from "@/constants/thirdweb-client.client";
import { DeployedContractsPage } from "@app/account/contracts/_components/DeployedContractsPage";
import { getAuthToken } from "@app/api/lib/getAuthToken";
import { loginRedirect } from "@app/login/loginRedirect";
import { redirect } from "next/navigation";
import { DeployedContractsPage } from "../../../../../account/contracts/_components/DeployedContractsPage";
import { getAuthToken } from "../../../../../api/lib/getAuthToken";
import { loginRedirect } from "../../../../../login/loginRedirect";
import { FooterLinksSection } from "../components/footer/FooterLinksSection";

export default async function Page(props: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { getProject } from "@/api/projects";
import { getTeamBySlug } from "@/api/team";
import { getAuthToken } from "@app/api/lib/getAuthToken";
import { loginRedirect } from "@app/login/loginRedirect";
import { redirect } from "next/navigation";
import { ContractsWebhooksPageContent } from "../../webhooks/contract-webhooks/contract-webhooks-page";

export default async function Page(props: {
params: Promise<{ team_slug: string; project_slug: string }>;
}) {
const params = await props.params;

const [authToken, team, project] = await Promise.all([
getAuthToken(),
getTeamBySlug(params.team_slug),
getProject(params.team_slug, params.project_slug),
]);

if (!authToken) {
loginRedirect(
`/team/${params.team_slug}/${params.project_slug}/contracts/webhooks`,
);
}

if (!team) {
redirect("/team");
}

if (!project) {
redirect(`/team/${params.team_slug}`);
}

return (
<div className="container flex max-w-7xl grow flex-col">
<ContractsWebhooksPageContent project={project} authToken={authToken} />
</div>
);
}
Loading
Loading