diff --git a/apps/dashboard/src/@/components/ui/tabs.tsx b/apps/dashboard/src/@/components/ui/tabs.tsx index 257694135fc..25c6ef890fa 100644 --- a/apps/dashboard/src/@/components/ui/tabs.tsx +++ b/apps/dashboard/src/@/components/ui/tabs.tsx @@ -165,6 +165,8 @@ function useUnderline() { block: "nearest", inline: "center", }); + } else if (lineRef.current) { + lineRef.current.style.width = "0px"; } } diff --git a/apps/dashboard/src/app/(dashboard)/layout.tsx b/apps/dashboard/src/app/(dashboard)/layout.tsx index cc3730be2f5..3b08e193fc2 100644 --- a/apps/dashboard/src/app/(dashboard)/layout.tsx +++ b/apps/dashboard/src/app/(dashboard)/layout.tsx @@ -1,6 +1,6 @@ import { AppFooter } from "@/components/blocks/app-footer"; -import { DashboardHeader } from "app/components/Header/DashboardHeader"; import { ErrorProvider } from "../../contexts/error-handler"; +import { DashboardHeader } from "../components/Header/DashboardHeader"; export default function DashboardLayout(props: { children: React.ReactNode }) { return ( diff --git a/apps/dashboard/src/app/components/Header/DashboardHeader.tsx b/apps/dashboard/src/app/components/Header/DashboardHeader.tsx index 4e8df82302f..fe2ab2be4ca 100644 --- a/apps/dashboard/src/app/components/Header/DashboardHeader.tsx +++ b/apps/dashboard/src/app/components/Header/DashboardHeader.tsx @@ -1,68 +1,101 @@ -import { ColorModeToggle } from "@/components/color-mode-toggle"; -import { Spinner } from "@/components/ui/Spinner/Spinner"; +import { NavLink } from "@/components/ui/NavLink"; +import { Button } from "@/components/ui/button"; import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet"; -import { ClientOnly } from "components/ClientOnly/ClientOnly"; +import { CmdKSearch } from "components/cmd-k-search"; +import { ColorModeToggle } from "components/color-mode/color-mode-toggle"; +import { Logo } from "components/logo"; +import { CreditsButton } from "components/settings/Account/Billing/CreditsButton"; +import { UpgradeButton } from "components/settings/Account/Billing/UpgradeButton"; +import { CircleHelpIcon } from "lucide-react"; import Link from "next/link"; -import { ThirdwebMiniLogo } from "../ThirdwebMiniLogo"; -import { NavLink } from "../nav-link.client"; -import { MobileBurgerMenu } from "./MobileBurgerMenu"; -import { headerLinks } from "./headerLinks"; +import { Suspense } from "react"; +import { DashboardHeaderTabs } from "./DashboardHeaderTabs"; -export function DashboardHeader() { +export const DashboardHeader: React.FC = () => { return ( - // the "h-24" avoids layout shift when connecting wallet (connected wallet button is taller than disconnected...) -
- {/* Left */} -
-
- +
+
+ {/* left */} +
- + +
-
- {headerLinks.left.map((link) => ( - - {link.name} - - ))} -
-
- {/* Right */} -
-
-
- {headerLinks.right.map((link) => ( - +
+ + + + +
+ + + + + + + +
+
+ + +
+ +
+
- - - - } - > - - - - + + + ); +}; + +function HeaderNavLink(props: { + label: string; + trackingLabel: string; + href: string; +}) { + return ( + + {props.label} + ); } diff --git a/apps/dashboard/src/app/components/Header/DashboardHeaderTabs.tsx b/apps/dashboard/src/app/components/Header/DashboardHeaderTabs.tsx new file mode 100644 index 00000000000..02b71728be9 --- /dev/null +++ b/apps/dashboard/src/app/components/Header/DashboardHeaderTabs.tsx @@ -0,0 +1,42 @@ +"use client"; + +import { TabLinks } from "@/components/ui/tabs"; +import { usePathname } from "next/navigation"; + +export function DashboardHeaderTabs() { + const pathname = usePathname() || ""; + return ( + + ); +} diff --git a/apps/dashboard/src/app/components/Header/MobileBurgerMenu.tsx b/apps/dashboard/src/app/components/Header/MobileBurgerMenu.tsx deleted file mode 100644 index 089e9bea691..00000000000 --- a/apps/dashboard/src/app/components/Header/MobileBurgerMenu.tsx +++ /dev/null @@ -1,66 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { useIsomorphicLayoutEffect } from "@/lib/useIsomorphicLayoutEffect"; -import { Menu, XIcon } from "lucide-react"; -import Link from "next/link"; -import { useState } from "react"; -import { headerLinks } from "./headerLinks"; - -export function MobileBurgerMenu() { - const [showBurgerMenu, setShowBurgerMenu] = useState(false); - - useIsomorphicLayoutEffect(() => { - if (showBurgerMenu) { - // eslint-disable-next-line react-compiler/react-compiler - document.body.style.overflow = "hidden"; - } else { - document.body.style.overflow = "auto"; - } - }, [showBurgerMenu]); - - useIsomorphicLayoutEffect(() => { - return () => { - document.body.style.overflow = "auto"; - }; - }); - - return ( - <> - - - {showBurgerMenu && ( - - )} - - ); -} diff --git a/apps/dashboard/src/app/components/Header/headerLinks.ts b/apps/dashboard/src/app/components/Header/headerLinks.ts deleted file mode 100644 index 1879f8d9b67..00000000000 --- a/apps/dashboard/src/app/components/Header/headerLinks.ts +++ /dev/null @@ -1,34 +0,0 @@ -export const headerLinks = { - left: [ - { - name: "Connect", - href: "/dashboard/connect/analytics", - }, - { - name: "Contracts", - href: "/dashboard/contracts", - }, - { - name: "Engine", - href: "/dashboard/engine", - }, - { - name: "Settings", - href: "/dashboard/settings/api-keys", - }, - ], - right: [ - { - name: "Chainlist", - href: "/chainlist", - }, - { - name: "Docs", - href: "https://portal.thirdweb.com", - }, - { - name: "Support", - href: "https://thirdweb.com/support", - }, - ], -}; diff --git a/apps/dashboard/src/app/components/nav-link.client.tsx b/apps/dashboard/src/app/components/nav-link.client.tsx deleted file mode 100644 index 387c8bfaa1c..00000000000 --- a/apps/dashboard/src/app/components/nav-link.client.tsx +++ /dev/null @@ -1,29 +0,0 @@ -"use client"; - -import { cn } from "@/lib/utils"; -import Link, { type LinkProps } from "next/link"; -import { usePathname } from "next/navigation"; - -type NavLinkProps = Omit< - React.AnchorHTMLAttributes, - keyof LinkProps -> & - Omit & { - href: string; - activeClassName: string; - }; - -export const NavLink: React.FC> = ({ - children, - className, - activeClassName, - ...props -}) => { - const pathname = usePathname(); - const isActive = !!pathname?.startsWith(props.href); - return ( - - {children} - - ); -}; diff --git a/apps/dashboard/src/components/cmd-k-search/index.tsx b/apps/dashboard/src/components/cmd-k-search/index.tsx index 39d853b8370..30a18d5bc7a 100644 --- a/apps/dashboard/src/components/cmd-k-search/index.tsx +++ b/apps/dashboard/src/components/cmd-k-search/index.tsx @@ -290,12 +290,12 @@ export const CmdKSearch: React.FC = () => { diff --git a/apps/dashboard/src/components/color-mode/color-mode-toggle.tsx b/apps/dashboard/src/components/color-mode/color-mode-toggle.tsx index 2f0de0b74a7..194285f02d7 100644 --- a/apps/dashboard/src/components/color-mode/color-mode-toggle.tsx +++ b/apps/dashboard/src/components/color-mode/color-mode-toggle.tsx @@ -1,3 +1,5 @@ +"use client"; + import { Button } from "@/components/ui/button"; import { SkeletonContainer } from "@/components/ui/skeleton"; import { useTheme } from "next-themes"; @@ -21,15 +23,15 @@ export const ColorModeToggle: React.FC = () => { render={(v) => { return ( ); diff --git a/apps/dashboard/src/components/layout/app-shell/index.tsx b/apps/dashboard/src/components/layout/app-shell/index.tsx index 0e069d2ab69..0330a196aac 100644 --- a/apps/dashboard/src/components/layout/app-shell/index.tsx +++ b/apps/dashboard/src/components/layout/app-shell/index.tsx @@ -1,24 +1,9 @@ import { AppFooter } from "@/components/blocks/app-footer"; -import { TabLinks } from "@/components/ui/tabs"; import { cn } from "@/lib/utils"; -import { CustomConnectWallet } from "@3rdweb-sdk/react/components/connect-wallet"; -import { Container, Flex, GridItem, Icon } from "@chakra-ui/react"; -import { CmdKSearch } from "components/cmd-k-search"; -import { ColorModeToggle } from "components/color-mode/color-mode-toggle"; -import { Logo } from "components/logo"; -import { CreditsButton } from "components/settings/Account/Billing/CreditsButton"; -import { UpgradeButton } from "components/settings/Account/Billing/UpgradeButton"; +import { Container } from "@chakra-ui/react"; import { BillingAlerts } from "components/settings/Account/Billing/alerts/Alert"; -import { useRouter } from "next/router"; -import { FiHelpCircle } from "react-icons/fi"; -import { - Button, - Link, - LinkButton, - TrackedIconButton, - TrackedLink, -} from "tw-components"; import type { ComponentWithChildren } from "types/component-with-children"; +import { DashboardHeader } from "../../../app/components/Header/DashboardHeader"; export interface AppShellProps { layout?: "custom-contract"; @@ -36,7 +21,7 @@ export const AppShell: ComponentWithChildren = ({ }) => { return (
- +
@@ -56,131 +41,3 @@ export const AppShell: ComponentWithChildren = ({
); }; - -const AppHeader: React.FC = () => { - const { pathname } = useRouter(); - - return ( - - - - - - - - - - - - - - - - - - - } - category="header" - label="support" - as={LinkButton} - href="/support" - /> - - -
- -
-
-
- - {/* Tabs */} - -
- ); -}; diff --git a/apps/dashboard/src/components/logo/index.tsx b/apps/dashboard/src/components/logo/index.tsx index 93a9db47022..9827a5ffa14 100644 --- a/apps/dashboard/src/components/logo/index.tsx +++ b/apps/dashboard/src/components/logo/index.tsx @@ -1,5 +1,4 @@ import { cn } from "@/lib/utils"; -import { VisuallyHidden } from "@chakra-ui/react"; export const IconLogo: React.FC<{ extraClass?: string; color?: string }> = ({ color, @@ -95,7 +94,7 @@ export const Logo: React.FC = ({ color = "var(--chakra-colors-wordmark)", }) => { return ( -

+

{hideIcon ?? } {(hideWordmark && !forceShowWordMark) ?? (
= ({
)} - thirdweb

); }; diff --git a/apps/dashboard/src/components/settings/Account/Billing/CreditsButton.tsx b/apps/dashboard/src/components/settings/Account/Billing/CreditsButton.tsx index 5649be3f77f..46312454cd5 100644 --- a/apps/dashboard/src/components/settings/Account/Billing/CreditsButton.tsx +++ b/apps/dashboard/src/components/settings/Account/Billing/CreditsButton.tsx @@ -1,21 +1,18 @@ +"use client"; + +import { Button } from "@/components/ui/button"; +import { + Dialog, + DialogContent, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog"; +import { cn } from "@/lib/utils"; import { useAccount, useAccountCredits } from "@3rdweb-sdk/react/hooks/useApi"; import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser"; -import { - Box, - Flex, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, - useDisclosure, -} from "@chakra-ui/react"; import { useTrack } from "hooks/analytics/useTrack"; -import { useRouter } from "next/router"; -import { useMemo, useState } from "react"; -import { Button, Card, Text } from "tw-components"; +import { useSearchParams } from "next/navigation"; +import { useState } from "react"; import { CreditsItem } from "./CreditsItem"; export const formatToDollars = (cents: number) => { @@ -27,16 +24,11 @@ export const formatToDollars = (cents: number) => { }; export const CreditsButton = () => { - const { isOpen, onOpen, onClose } = useDisclosure(); + const [isOpen, setIsOpen] = useState(false); const trackEvent = useTrack(); - - const router = useRouter(); - const { fromOpCredits: fromOpCreditsQuery } = router.query; - - const shouldShowTooltip = useMemo( - () => fromOpCreditsQuery !== undefined, - [fromOpCreditsQuery], - ); + const searchParams = useSearchParams(); + const fromOpCreditsQuery = searchParams?.get("fromOpCredits"); + const shouldShowTooltip = fromOpCreditsQuery !== null; const [shouldClose, setShouldClose] = useState(false); @@ -56,74 +48,65 @@ export const CreditsButton = () => { const restCredits = credits?.filter((crd) => !crd.name.startsWith("OP -")); return ( - <> - +
+ + +
+

+ You can view how many credits you have here at any time. +

+ +
- - - You can view how many credits you have here at any time. - + {/* Credits Modal */} + + + + + Credits + + +
+ { + setIsOpen(false); + }} + /> - - - - - - - - Credits Balance - - - { - onClose(); - }} - /> - {restCredits?.map((credit) => ( - - ))} - - - - - - + {restCredits?.map((credit) => ( + + ))} +
+
+
+
); }; diff --git a/apps/dashboard/src/components/settings/Account/Billing/CreditsItem.tsx b/apps/dashboard/src/components/settings/Account/Billing/CreditsItem.tsx index b9d111feec3..49438431c98 100644 --- a/apps/dashboard/src/components/settings/Account/Billing/CreditsItem.tsx +++ b/apps/dashboard/src/components/settings/Account/Billing/CreditsItem.tsx @@ -1,23 +1,23 @@ +import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert"; +import { Button } from "@/components/ui/button"; import { type BillingCredit, useAccount } from "@3rdweb-sdk/react/hooks/useApi"; -import { Alert, AlertDescription, AlertIcon, Flex } from "@chakra-ui/react"; -import { ChakraNextImage } from "components/Image"; import { ChainIcon } from "components/icons/ChainIcon"; import { formatDistance } from "date-fns"; import { useTrack } from "hooks/analytics/useTrack"; import { useLocalStorage } from "hooks/useLocalStorage"; -import { Card, LinkButton, Text } from "tw-components"; +import { CircleAlertIcon } from "lucide-react"; +import Image from "next/image"; +import Link from "next/link"; import { formatToDollars } from "./CreditsButton"; interface CreditsItemProps { credit?: BillingCredit; - onCreditsButton?: true; isOpCreditDefault?: boolean; onClickApply?: () => void; } export const CreditsItem: React.FC = ({ credit, - onCreditsButton, isOpCreditDefault, onClickApply, }) => { @@ -43,9 +43,9 @@ export const CreditsItem: React.FC = ({ } return ( - - -
+
+
+
{isOpCredit ? ( = ({ size={24} /> ) : isTwCredit ? ( - ) : isStartupCredit ? ( - ) : null} - {creditTitle} - {!hasAppliedForOpGrant && isOpCredit && ( - + +

{creditTitle}

+
+ +
+
+

+ Remaining Credits +

+

+ {formatToDollars(credit?.remainingValueUsdCents || 0)} +

+
+ + {!isTwCredit && ( +
+

+ Claimed Credits (All-Time) +

+

+ {formatToDollars(credit?.originalGrantUsdCents || 0)} +

+
+ )} + + {credit?.expiresAt && ( +
+

+ Expires +

+

+ {credit?.expiresAt + ? formatDistance(new Date(credit.expiresAt), Date.now(), { + addSuffix: true, + }) + : "N/A"} +

+
+ )} +
+ + {hasAppliedForOpGrant && !credit && isOpCredit && ( + + + Grant application pending approval + + You will receive an email once your application's status + changes. + + + )} + +
+ {!hasAppliedForOpGrant && isOpCredit && ( +
- - - Remaining Credits - - {formatToDollars(credit?.remainingValueUsdCents || 0)} - - - {!isTwCredit && ( - - Claimed Credits (All-Time) - - {formatToDollars(credit?.originalGrantUsdCents || 0)} - - - )} - {credit?.expiresAt && ( - - Expires - - {credit?.expiresAt - ? formatDistance(new Date(credit.expiresAt), Date.now(), { - addSuffix: true, - }) - : "N/A"} - - - )} - - {hasAppliedForOpGrant && !credit && isOpCredit && ( - - - - Grant application pending approval. You will receive an email once - your application's status changes. - - + + )} - - +
+
); }; diff --git a/apps/dashboard/src/components/settings/Account/Billing/UpgradeButton.tsx b/apps/dashboard/src/components/settings/Account/Billing/UpgradeButton.tsx index 9723e9a401f..5636b072071 100644 --- a/apps/dashboard/src/components/settings/Account/Billing/UpgradeButton.tsx +++ b/apps/dashboard/src/components/settings/Account/Billing/UpgradeButton.tsx @@ -1,34 +1,43 @@ +"use client"; + +import { NavLink } from "@/components/ui/NavLink"; +import { Button } from "@/components/ui/button"; import { AccountPlan, useAccount } from "@3rdweb-sdk/react/hooks/useApi"; import { useLoggedInUser } from "@3rdweb-sdk/react/hooks/useLoggedInUser"; -import { useRouter } from "next/router"; -import { TrackedLinkButton } from "tw-components"; +import { usePathname } from "next/navigation"; export const UpgradeButton = () => { const { isLoggedIn } = useLoggedInUser(); const meQuery = useAccount(); - const router = useRouter(); + const pathname = usePathname(); if ( !isLoggedIn || meQuery.isPending || !meQuery.data || - router.pathname.startsWith("/dashboard/settings/billing") + pathname?.startsWith("/dashboard/settings/billing") || + meQuery.data?.plan !== AccountPlan.Free ) { return null; } - const { plan } = meQuery.data; - - return plan === AccountPlan.Free ? ( - - Upgrade - - ) : null; + + Upgrade + + + ); };