Skip to content

Commit

Permalink
feat: add logout page (#42)
Browse files Browse the repository at this point in the history
use the now-fixed react-keyring package to implement a logout page. we
can now add logout links to various places that send users to this page.
  • Loading branch information
travis committed Nov 28, 2023
1 parent 1b428c4 commit 654453d
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 72 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"@ucanto/core": "^9.0.0",
"@ucanto/interface": "^9.0.0",
"@ucanto/transport": "^9.0.0",
"@w3ui/react-keyring": "^6.2.0",
"@w3ui/react-keyring": "^6.2.1",
"@w3ui/react-uploader": "^5.2.0",
"@w3ui/react-uploads-list": "^4.2.0",
"@web3-storage/access": "^16.4.0",
Expand Down
12 changes: 6 additions & 6 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import SidebarLayout from '@/components/SidebarLayout'
import './globals.css'
import type { Metadata } from 'next'
import { W3APIProvider } from '@/components/W3API'

export const metadata: Metadata = {
title: 'w3up console',
Expand All @@ -15,9 +15,9 @@ export default function RootLayout ({
return (
<html lang="en">
<body className='bg-grad min-h-screen'>
<SidebarLayout>
<W3APIProvider uploadsListPageSize={20}>
{children}
</SidebarLayout>
</W3APIProvider>
</body>
</html>
)
Expand Down
19 changes: 19 additions & 0 deletions src/app/logout/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use client'
import { useKeyring } from "@w3ui/react-keyring"
import { useRouter } from "next/navigation"
import { useEffect } from "react"

export default function LogoutPage () {
const [, { unloadAgent }] = useKeyring()
const router = useRouter()
useEffect(function () {
if (unloadAgent) {
async function logOutAndRedirect () {
await unloadAgent()
router.push('/')
}
logOutAndRedirect()
}
}, [])
return <></>
}
12 changes: 11 additions & 1 deletion src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@ import { DidIcon } from '@/components/DidIcon'
import Link from 'next/link'
import { SpacesNav } from './space/layout'
import { H2 } from '@/components/Text'
import SidebarLayout from '@/components/SidebarLayout'
import { ReactNode } from 'react'

export default function SpacePage (): JSX.Element {
export default function HomePage () {
return (
<SidebarLayout>
<SpacePage />
</SidebarLayout>
)
}

function SpacePage (): ReactNode {
const [{ spaces }] = useKeyring()

if (spaces.length === 0) {
Expand Down
9 changes: 5 additions & 4 deletions src/app/space/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PropsWithChildren } from 'react'
import { PropsWithChildren, ReactNode } from 'react'
import { Nav, NavLink } from '@/components/Nav'
import { UsageBar } from '@/components/UsageBar'
import SidebarLayout from '@/components/SidebarLayout'

export const runtime = 'edge'

Expand All @@ -10,11 +11,11 @@ interface LayoutProps extends PropsWithChildren {
}
}

export default function Layout ({children}: LayoutProps): JSX.Element {
export default function Layout ({children}: LayoutProps): ReactNode {
return (
<>
<SidebarLayout>
{children}
</>
</SidebarLayout>
)
}

Expand Down
109 changes: 56 additions & 53 deletions src/components/SidebarLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import { Logo } from '../brand'
import { Fragment, useState } from 'react'
import { Dialog, Transition } from '@headlessui/react'
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
import { Authenticator, useKeyring, Space } from '@w3ui/react-keyring'
import { useKeyring, Space } from '@w3ui/react-keyring'
import { AuthenticationEnsurer } from '../components/Authenticator'
import { SpaceEnsurer } from '../components/SpaceEnsurer'
import { MaybePlanGate } from './PlanGate'
import { W3APIProvider } from '@/components/W3API'
import { SpaceFinder } from './SpaceFinder'
import { usePathname, useRouter } from 'next/navigation'
import { H2 } from './Text'
import Link from 'next/link'

const navLinks = [
{ name: 'Terms', href: 'https://web3.storage/docs/terms' },
Expand All @@ -23,6 +23,8 @@ interface SidebarComponentProps {
sidebar?: React.ReactNode
}

const footerLinkClasses = 'text-xs block text-center mt-2 px-1'

function Sidebar ({ sidebar = <div></div> }: SidebarComponentProps): JSX.Element {
const [{space, spaces}] = useKeyring()
const router = useRouter()
Expand All @@ -44,8 +46,11 @@ function Sidebar ({ sidebar = <div></div> }: SidebarComponentProps): JSX.Element
<div className='flex flex-col items-center'>
<div className='flex flex-row space-x-2'>
{navLinks.map((link, i) => (
<a key={i} className='text-xs block text-center mt-2 px-1' href={link.href}>{link.name}</a>
<a key={i} className={footerLinkClasses} href={link.href}>{link.name}</a>
))}
<a className={footerLinkClasses} href="/logout">
Log Out
</a>
</div>
</div>
</div>
Expand All @@ -61,61 +66,59 @@ export default function SidebarLayout ({ children }: LayoutComponentProps): JSX.
const [sidebarOpen, setSidebarOpen] = useState(false)

return (
<W3APIProvider uploadsListPageSize={20}>
<Authenticator className='h-full' as='div'>
<AuthenticationEnsurer>
<SpaceEnsurer>
<MaybePlanGate>
<div className='flex min-h-full w-full text-white'>
{/* dialog sidebar for narrow browsers */}
<Transition.Root show={sidebarOpen} >
<Dialog onClose={() => setSidebarOpen(false)} as='div' className='relative z-50'>
<div className='h-full'>
<AuthenticationEnsurer>
<SpaceEnsurer>
<MaybePlanGate>
<div className='flex min-h-full w-full text-white'>
{/* dialog sidebar for narrow browsers */}
<Transition.Root show={sidebarOpen} >
<Dialog onClose={() => setSidebarOpen(false)} as='div' className='relative z-50'>
<Transition.Child
as={Fragment}
enter="transition-opacity duration-200"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition-opacity duration-400"
leaveFrom="opacity-100"
leaveTo="opacity-0">
<div className="fixed inset-0 bg-black/70" aria-hidden="true" />
</Transition.Child>
<div className="fixed inset-0 flex justify-left">
<Transition.Child
as={Fragment}
enter="transition-opacity duration-200"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="transition-opacity duration-400"
leaveFrom="opacity-100"
leaveTo="opacity-0">
<div className="fixed inset-0 bg-black/70" aria-hidden="true" />
enter="transition duration-200"
enterFrom="-translate-x-full"
enterTo="translate-x-0"
leave="transition duration-400"
leaveFrom="translate-x-0"
leaveTo="-translate-x-full">
<Dialog.Panel>
<XMarkIcon className='text-white w-6 h-6 fixed top-2 -right-8' onClick={() => setSidebarOpen(false)} />
<Sidebar />
</Dialog.Panel>
</Transition.Child>
<div className="fixed inset-0 flex justify-left">
<Transition.Child
as={Fragment}
enter="transition duration-200"
enterFrom="-translate-x-full"
enterTo="translate-x-0"
leave="transition duration-400"
leaveFrom="translate-x-0"
leaveTo="-translate-x-full">
<Dialog.Panel>
<XMarkIcon className='text-white w-6 h-6 fixed top-2 -right-8' onClick={() => setSidebarOpen(false)} />
<Sidebar />
</Dialog.Panel>
</Transition.Child>
</div>
</Dialog>
</Transition.Root>
{/* static sidebar for wide browsers */}
<div className='hidden lg:block'>
<Sidebar />
</div>
<div className='w-full h-screen overflow-scroll text-white'>
{/* top nav bar for narrow browsers, mainly to have a place to put the hamburger */}
<div className='lg:hidden flex justify-between pt-4 px-4'>
<Bars3Icon className='w-6 h-6' onClick={() => setSidebarOpen(true)} />
<Logo className='w-full' />
</div>
<main className='grow text-black p-4'>
{children}
</main>
</Dialog>
</Transition.Root>
{/* static sidebar for wide browsers */}
<div className='hidden lg:block'>
<Sidebar />
</div>
<div className='w-full h-screen overflow-scroll text-white'>
{/* top nav bar for narrow browsers, mainly to have a place to put the hamburger */}
<div className='lg:hidden flex justify-between pt-4 px-4'>
<Bars3Icon className='w-6 h-6' onClick={() => setSidebarOpen(true)} />
<Logo className='w-full' />
</div>
<main className='grow text-black p-4'>
{children}
</main>
</div>
</MaybePlanGate>
</SpaceEnsurer>
</AuthenticationEnsurer>
</Authenticator>
</W3APIProvider>
</div>
</MaybePlanGate>
</SpaceEnsurer>
</AuthenticationEnsurer>
</div>
)
}
13 changes: 9 additions & 4 deletions src/components/W3API.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { useMemo } from 'react'
'use client'

import { ReactNode, useMemo } from 'react'
import {
useUploader,
UploaderContextValue,
Expand All @@ -10,6 +12,7 @@ import {
UploadsListProvider
} from '@w3ui/react-uploads-list'
import {
Authenticator,
useKeyring,
KeyringContextValue,
KeyringProvider
Expand All @@ -23,19 +26,21 @@ export interface W3APIContextValue {
}

export interface W3APIProviderProps {
children: JSX.Element | JSX.Element[]
children: ReactNode
uploadsListPageSize?: number
}

export function W3APIProvider ({
children,
uploadsListPageSize
}: W3APIProviderProps): JSX.Element {
}: W3APIProviderProps): ReactNode {
return (
<KeyringProvider servicePrincipal={servicePrincipal} connection={serviceConnection}>
<UploaderProvider servicePrincipal={servicePrincipal} connection={serviceConnection}>
<UploadsListProvider servicePrincipal={servicePrincipal} connection={serviceConnection} size={uploadsListPageSize}>
<>{children}</>
<Authenticator>
{children}
</Authenticator>
</UploadsListProvider>
</UploaderProvider>
</KeyringProvider>
Expand Down

0 comments on commit 654453d

Please sign in to comment.