diff --git a/src/app/space/layout.tsx b/src/app/space/layout.tsx index 9b20faa..2b45dcd 100644 --- a/src/app/space/layout.tsx +++ b/src/app/space/layout.tsx @@ -1,7 +1,6 @@ import { PropsWithChildren } from 'react' -import { H2 } from '@/components/Text' -import Link from 'next/link' import { Nav, NavLink } from '@/components/Nav' +import { UsageBar } from '@/components/UsageBar' export const runtime = 'edge' @@ -29,11 +28,16 @@ export function SpacesNav () { Pick a space to see what's in it, or create a new one.

*/} - +
+
+ +
+ +
) } \ No newline at end of file diff --git a/src/components/Nav.tsx b/src/components/Nav.tsx index 15ab485..e8b320a 100644 --- a/src/components/Nav.tsx +++ b/src/components/Nav.tsx @@ -7,7 +7,7 @@ import Link from "next/link" export function Nav ({ children, ...rest}: PropsWithChildren & { className?: string }) { return ( diff --git a/src/components/UsageBar.tsx b/src/components/UsageBar.tsx new file mode 100644 index 0000000..0a719f0 --- /dev/null +++ b/src/components/UsageBar.tsx @@ -0,0 +1,95 @@ +'use client' + +import { ReactNode, useEffect, useState } from 'react' +import { useKeyring, Plan } from '@w3ui/react-keyring' + +const B = 1024 +const MB = 1024 * B +const GB = 1024 * MB +const TB = 1024 * GB +const BarHeight = 10 + +const PlanLimit: Record<`did:${string}`, number> = { + 'did:web:starter.web3.storage': 5 * GB, + 'did:web:lite.web3.storage': 100 * GB, + 'did:web:business.web3.storage': 2 * TB +} + +const PlanNames: Record<`did:${string}`, string> = { + 'did:web:starter.web3.storage': 'Starter', + 'did:web:lite.web3.storage': 'Lite', + 'did:web:business.web3.storage': 'Business' +} + +export function UsageBar (): ReactNode { + const [{ account }, { getPlan }] = useKeyring() + const [plan, setPlan] = useState() + const [usage, setUsage] = useState>() + + useEffect(() => { + if (!account) return + (async () => { + if (account) { + try { + const result = await getPlan(account as `${string}@${string}`) + if (result.error) throw new Error('getting plan', { cause: result.error }) + setPlan(result.ok) + } catch (err) { + console.error(err) + } + } + })() + }, [account, getPlan]) + + useEffect(() => { + if (!account) return + // TODO: get usage by space + }, [account]) + + // if (!plan) setPlan({ product: 'did:web:starter.web3.storage' }) + // if (!usage) setUsage({ + // 'did:key:z6MkjCoKJcunQgzihb4tXBYDd9xunhpGNoC14HEypgAe5cNW': 500_000_000, + // 'did:key:z6MketbAFtbeqDeVHxSzSSDH2PfMTquQ3vzZCcPFweXBGe3R': 200_000_000, + // 'did:key:z6MkoEBnTj96thGj7H7c1DrdNHF4AiA9VPDRVqTmp4teYd6B': 78_000_000, + // }) + + const allocated = Object.values(usage ?? {}).reduce((total, n) => total + n, 0) + const limit = plan?.product ? PlanLimit[plan.product] : null + + return ( +
+ {plan?.product ? ( +
+ Plan: {PlanNames[plan.product] ?? plan.product} change +
+ ) : null} + {usage && limit ? ( + <> +
+ {Object.entries(usage).sort((a, b) => b[1] - a[1]).map(([space, total]) => { + return ( +
+ ) + })} +
+
+ {filesize(allocated)} + of {filesize(limit)} +
+ + ) : null} +
+ ) +} + +function filesize (bytes: number) { + if (bytes < B / 2) return `${bytes}B` // avoid 0.0KB + if (bytes < MB / 2) return `${(bytes / 1024).toFixed(1)}KB` // avoid 0.0MB + if (bytes < GB / 2) return `${(bytes / 1024 / 1024).toFixed(1)}MB` // avoid 0.0GB + return `${(bytes / 1024 / 1024 / 1024).toFixed(1)}GB` +}