Skip to content
Closed
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"use client";

import { usePathname, useRouter } from "next/navigation";
import type { ReactNode } from "react";
import { useEffect } from "react";
import useNetwork from "@/hooks/useNetwork";
import type { Network } from "@/types";

interface NetworkSyncWrapperProps {
urlNetwork: Network;
children: ReactNode;
}

// URL <-> context reconciliation for explorer routes. A fresh load or deep link
// adopts the URL's network. After an explicit selection (header selector,
// console switcher, wallet sync) the selection wins: a stale URL — typically
// reached via the browser back button after switching networks in the console —
// is rewritten instead of clobbering the selection.
export function NetworkSyncWrapper({ urlNetwork, children }: NetworkSyncWrapperProps) {
const { network, adoptNetwork, hasUserSelection } = useNetwork();
const pathname = usePathname();
const router = useRouter();

useEffect(() => {
if (network === urlNetwork) return;
if (hasUserSelection) {
router.replace(pathname.replace(`/${urlNetwork}`, `/${network}`));
} else {
adoptNetwork(urlNetwork);
}
}, [urlNetwork, network, adoptNetwork, hasUserSelection, pathname, router]);

return <>{children}</>;
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { GlobalSearchBar, Stats, TopAccounts, TopOperators } from "@/components/Home";
import { ConsoleHero, GlobalSearchBar, Stats, TopAccounts, TopOperators } from "@/components/Home";

function Page() {
return (
<>
<ConsoleHero />
<GlobalSearchBar />
<Stats />
<TopAccounts />
Expand Down
13 changes: 13 additions & 0 deletions apps/explorer/src/app/(explorer)/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { ReactNode } from "react";
import { Navigation } from "@/components/shared";

type ExplorerLayoutProps = Readonly<{ children: ReactNode }>;

export default function ExplorerLayout({ children }: ExplorerLayoutProps) {
return (
<>
<Navigation backgroundVariant='light' />
{children}
</>
);
}
23 changes: 0 additions & 23 deletions apps/explorer/src/app/[network]/NetworkSyncWrapper.tsx

This file was deleted.

9 changes: 9 additions & 0 deletions apps/explorer/src/app/console/authorizations/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
"use client";
import { OperatorApprovalsSection } from "@/components/UserConsole";
import ConsoleAccountGate from "@/components/UserConsole/ConsoleAccountGate";

const AuthorizationsPage = () => (
<ConsoleAccountGate>{({ account }) => <OperatorApprovalsSection account={account} />}</ConsoleAccountGate>
);

export default AuthorizationsPage;
13 changes: 13 additions & 0 deletions apps/explorer/src/app/console/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"use client";

import type { ReactNode } from "react";
import ConsoleProviders from "@/components/UserConsole/ConsoleProviders";
import ConsoleShell from "@/components/UserConsole/ConsoleShell";

export default function ConsoleLayout({ children }: { children: ReactNode }) {
return (
<ConsoleProviders>
<ConsoleShell>{children}</ConsoleShell>
</ConsoleProviders>
);
}
68 changes: 25 additions & 43 deletions apps/explorer/src/app/console/notifications/page.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
"use client";
import { Button } from "@filecoin-foundation/ui-filecoin/Button";
import { EmptyStateCard } from "@filecoin-foundation/ui-filecoin/EmptyStateCard";
import { PageSection } from "@filecoin-foundation/ui-filecoin/PageSection";
import { WarningCircleIcon } from "@phosphor-icons/react";
import { useMutation } from "@tanstack/react-query";
import { ArrowLeft, ChevronRight, WifiOff } from "lucide-react";
import Link from "next/link";
import { ChevronRight, WifiOff } from "lucide-react";
import type React from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { BaseError, UserRejectedRequestError } from "viem";
import { createSiweMessage, generateSiweNonce } from "viem/siwe";
import { useConnection, useSignMessage } from "wagmi";
import ConsoleProviders from "@/components/UserConsole/ConsoleProviders";
import {
AlertsActiveCard,
AlertsOffCard,
Expand Down Expand Up @@ -440,47 +437,32 @@ const NotificationsMain = () => {
}

return (
<PageSection backgroundVariant='light'>
<div className='flex flex-col gap-15 -mt-25 sm:mt-0'>
<div>
<Link
href='/console'
className='inline-flex items-center gap-1.5 text-sm text-muted-foreground hover:text-foreground mb-6'
>
<ArrowLeft className='h-4 w-4' />
Back to console
</Link>
<div className='flex items-baseline justify-between'>
<h2 className='font-heading text-balance text-3xl/10 font-medium sm:text-5xl/15 sm:tracking-tight'>
Email alerts
</h2>
{showUpdateEmail && (
<button
type='button'
onClick={() => updateEmailRef.current?.()}
className='inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline'
>
Update email
<ChevronRight className='h-4 w-4' />
</button>
)}
</div>
<p className='mt-2 text-muted-foreground'>
Receive alerts when your account has less than 30 days of service runway remaining, so you can top up before
services are affected.
</p>
<div className='flex flex-col gap-15'>
<div>
<div className='flex items-baseline justify-between'>
<h2 className='font-heading text-balance text-3xl/10 font-medium sm:text-5xl/15 sm:tracking-tight'>
Email alerts
</h2>
{showUpdateEmail && (
<button
type='button'
onClick={() => updateEmailRef.current?.()}
className='inline-flex items-center gap-1 text-sm font-medium text-primary hover:underline'
>
Update email
<ChevronRight className='h-4 w-4' />
</button>
)}
</div>

<div>{renderContent()}</div>
<p className='mt-2 text-muted-foreground'>
Receive alerts when your account has less than 30 days of service runway remaining, so you can top up before
services are affected.
</p>
</div>
</PageSection>

<div>{renderContent()}</div>
</div>
);
};

const NotificationsPage = () => (
<ConsoleProviders>
<NotificationsMain />
</ConsoleProviders>
);

export default NotificationsPage;
export default NotificationsMain;
167 changes: 81 additions & 86 deletions apps/explorer/src/app/console/notifications/verify/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
"use client";
import { PageSection } from "@filecoin-foundation/ui-filecoin/PageSection";
import { Card } from "@filecoin-pay/ui/components/card";
import { useQueryClient } from "@tanstack/react-query";
import { AlertCircle, CheckCircle2, Clock, Link2Off, Loader2 } from "lucide-react";
Expand Down Expand Up @@ -158,102 +157,98 @@ const VerifyContent = () => {
}, [verifyState.type]);

return (
<PageSection backgroundVariant='light'>
<div aria-live='polite' aria-atomic='true'>
<Card className='mx-auto w-full max-w-lg p-8 text-center'>
{verifyState.type === "loading" && <VerifyLoadingContent showDelayedMessage={showDelayedMessage} />}
<div aria-live='polite' aria-atomic='true'>
<Card className='mx-auto w-full max-w-lg p-8 text-center'>
{verifyState.type === "loading" && <VerifyLoadingContent showDelayedMessage={showDelayedMessage} />}

{verifyState.type === "success" && (
<VerifyResultCard
icon={<CheckCircle2 className='h-8 w-8 text-green-500' />}
color='green'
title='Alerts are now on'
description="Your email has been verified. We'll notify you when this account has less than 30 days of service runway remaining."
actions={
<div className='flex w-full flex-col items-center gap-3'>
<Link
href='/console'
className='w-full rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700'
>
Back to Console
</Link>
<Link href='/console/notifications' className='text-sm text-primary hover:underline'>
Manage alerts
</Link>
</div>
}
/>
)}
{verifyState.type === "success" && (
<VerifyResultCard
icon={<CheckCircle2 className='h-8 w-8 text-green-500' />}
color='green'
title='Alerts are now on'
description="Your email has been verified. We'll notify you when this account has less than 30 days of service runway remaining."
actions={
<div className='flex w-full flex-col items-center gap-3'>
<Link
href='/console'
className='w-full rounded-md bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700'
>
Back to Console
</Link>
<Link href='/console/notifications' className='text-sm text-primary hover:underline'>
Manage alerts
</Link>
</div>
}
/>
)}

{verifyState.type === "not-found" && (
<VerifyResultCard
icon={<Clock className='h-8 w-8 text-amber-500' />}
color='amber'
title='This verification link is no longer available'
description='It may have expired or already been used. Return to alert settings to request a new verification email.'
actions={<AlertSettingsLink />}
/>
)}
{verifyState.type === "not-found" && (
<VerifyResultCard
icon={<Clock className='h-8 w-8 text-amber-500' />}
color='amber'
title='This verification link is no longer available'
description='It may have expired or already been used. Return to alert settings to request a new verification email.'
actions={<AlertSettingsLink />}
/>
)}

{verifyState.type === "rate-limited" && (
<VerifyResultCard
icon={<Clock className='h-8 w-8 text-amber-500' />}
color='amber'
title='Too many attempts'
description='Please wait a few minutes before trying again, then return to alert settings to request a new verification email.'
actions={<AlertSettingsLink />}
/>
)}
{verifyState.type === "rate-limited" && (
<VerifyResultCard
icon={<Clock className='h-8 w-8 text-amber-500' />}
color='amber'
title='Too many attempts'
description='Please wait a few minutes before trying again, then return to alert settings to request a new verification email.'
actions={<AlertSettingsLink />}
/>
)}

{verifyState.type === "error" && (
<VerifyResultCard
icon={<AlertCircle className='h-8 w-8 text-red-500' />}
color='red'
title="We couldn't verify your email"
description={
verifyState.kind === "network"
? "Check your internet connection and try again."
: "Something went wrong on our end. Try again in a moment, or return to alert settings to request a new verification email."
}
detail={verifyState.detail}
actions={
<div className='flex items-center gap-3'>
<button
type='button'
onClick={doVerify}
className='rounded-md bg-blue-600 px-6 py-2 text-sm font-medium text-white hover:bg-blue-700'
>
Try again
</button>
<AlertSettingsLink label='Alert settings' />
</div>
}
/>
)}
{verifyState.type === "error" && (
<VerifyResultCard
icon={<AlertCircle className='h-8 w-8 text-red-500' />}
color='red'
title="We couldn't verify your email"
description={
verifyState.kind === "network"
? "Check your internet connection and try again."
: "Something went wrong on our end. Try again in a moment, or return to alert settings to request a new verification email."
}
detail={verifyState.detail}
actions={
<div className='flex items-center gap-3'>
<button
type='button'
onClick={doVerify}
className='rounded-md bg-blue-600 px-6 py-2 text-sm font-medium text-white hover:bg-blue-700'
>
Try again
</button>
<AlertSettingsLink label='Alert settings' />
</div>
}
/>
)}

{verifyState.type === "missing-params" && (
<VerifyResultCard
icon={<Link2Off className='h-8 w-8 text-amber-500' />}
color='amber'
title='This verification link is incomplete'
description="We couldn't find the information needed to verify your email. Return to alert settings to request a new verification email."
actions={<AlertSettingsLink />}
/>
)}
</Card>
</div>
</PageSection>
{verifyState.type === "missing-params" && (
<VerifyResultCard
icon={<Link2Off className='h-8 w-8 text-amber-500' />}
color='amber'
title='This verification link is incomplete'
description="We couldn't find the information needed to verify your email. Return to alert settings to request a new verification email."
actions={<AlertSettingsLink />}
/>
)}
</Card>
</div>
);
};

const VerifyPage = () => (
<Suspense
fallback={
<PageSection backgroundVariant='light'>
<Card className='mx-auto w-full max-w-lg p-8 text-center'>
<VerifyLoadingContent />
</Card>
</PageSection>
<Card className='mx-auto w-full max-w-lg p-8 text-center'>
<VerifyLoadingContent />
</Card>
}
>
<VerifyContent />
Expand Down
Loading
Loading