chore(orderbook): use dialog for orderbook overlay

This commit is contained in:
theborakompanioni 2026-01-13 17:30:46 +01:00
parent 7918a64878
commit 77392c397d
No known key found for this signature in database
GPG key ID: E8070AF0053AAC0D
5 changed files with 46 additions and 37 deletions

View file

@ -1,13 +1,23 @@
import { useState, useMemo } from 'react'
import { DropdownMenu } from '@radix-ui/react-dropdown-menu'
import { useQuery } from '@tanstack/react-query'
import type { RowModel } from '@tanstack/react-table'
import type { i18n } from 'i18next'
import { ChevronDownIcon, RefreshCwIcon, PlusIcon, AlertCircleIcon, Loader2Icon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { useStore } from 'zustand'
import { DevBadge } from '@/components/dev/DevBadge'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { Button } from '@/components/ui/button'
import { ButtonGroup } from '@/components/ui/button-group'
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuGroup,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu'
import { Input } from '@/components/ui/input'
import { Label } from '@/components/ui/label'
import { Switch } from '@/components/ui/switch'
import { JM_DUST_THRESHOLD } from '@/constants/jm'
import * as OrderbookApi from '@/lib/api/orderbook'
@ -23,11 +33,6 @@ import {
} from '@/lib/utils'
import { jamSettingsStore } from '@/store/jamSettingsStore'
import { jmSessionStore } from '@/store/jmSessionStore'
import { DevBadge } from '../dev/DevBadge'
import { Alert, AlertDescription } from '../ui/alert'
import { ButtonGroup } from '../ui/button-group'
import { DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuTrigger } from '../ui/dropdown-menu'
import { Label } from '../ui/label'
import { OrderbookTable, type OrderTableEntry } from './OrderbookTable'
const offerToTableEntry = (
@ -89,9 +94,10 @@ const offerToTableEntry = (
interface OrderbookContentProps {
className?: string
enabled: boolean
}
export const OrderbookContent = ({ className }: OrderbookContentProps) => {
export const OrderbookContent = ({ enabled, className }: OrderbookContentProps) => {
const { t, i18n } = useTranslation()
const nickname = useStore(jmSessionStore, (state) => state.state?.nickname)
@ -142,6 +148,7 @@ export const OrderbookContent = ({ className }: OrderbookContentProps) => {
queryFn: withQueryDelay(OrderbookApi.fetchOrderbook, {
delayAfter: 210,
}),
enabled,
})
const isFetching = isFetchingOrderbookData || isFetchingOrderbookRefresh
@ -225,9 +232,15 @@ export const OrderbookContent = ({ className }: OrderbookContentProps) => {
<div className="flex items-center space-x-2">
{showDemoButton && (
<Button variant="outline" size="sm" onClick={__dev_generateDemoReportEntryButton} disabled={isFetching}>
<PlusIcon />
Generate Demo Entry
<Button
className="text-xs"
variant="outline"
size="sm"
onClick={__dev_generateDemoReportEntryButton}
disabled={isFetching}
>
<PlusIcon className="size-3" />
Add Demo Entry
<DevBadge />
</Button>
)}

View file

@ -1,7 +1,6 @@
import { XIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button'
import PageTitle from '../ui/jam/PageTitle'
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'
import PageTitle from '@/components/ui/jam/PageTitle'
import { OrderbookContent } from './OrderbookContent'
interface OrderbookOverlayProps {
@ -11,23 +10,19 @@ interface OrderbookOverlayProps {
export function OrderbookOverlay({ open, onOpenChange }: OrderbookOverlayProps) {
const { t } = useTranslation()
if (!open) {
return <></>
}
return (
<div className="light:bg-white animate-slide-up fixed inset-0 z-50 flex flex-col bg-zinc-900">
<div className="flex items-center justify-between border-b px-6 py-4">
<PageTitle title={t('orderbook.title')} />
<Button variant="ghost" size="lg" onClick={() => onOpenChange(false)} title={t('global.close')}>
<XIcon />
<span className="sr-only">{t('global.close')}</span>
</Button>
</div>
<Dialog open={open} onOpenChange={() => onOpenChange(false)}>
<DialogContent className="data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom flex h-screen max-w-screen! flex-col rounded-none border-none">
<DialogHeader>
<DialogTitle className="flex items-center gap-2">
<PageTitle title={t('orderbook.title')} />
</DialogTitle>
</DialogHeader>
<div className="flex-1 overflow-hidden">
<OrderbookContent className="flex h-full flex-col p-4" />
</div>
</div>
<div className="overflow-hidden">
<OrderbookContent enabled={open} className="flex h-full flex-col" />
</div>
</DialogContent>
</Dialog>
)
}

View file

@ -8,7 +8,7 @@ export const OrderbookPage = () => {
return (
<div className="mx-auto space-y-3 p-4">
<PageTitle title={t('orderbook.title')} />
<OrderbookContent />
<OrderbookContent enabled={true} />
</div>
)
}

View file

@ -57,14 +57,12 @@ export const SeedPhraseDialog = ({ walletFileName, open, onOpenChange }: SeedPhr
retry: false,
select: (data) => data.seedphrase,
})
const seedQueryData = useMemo(() => seedQuery.data, [seedQuery.data])
const seedQueryRefetch = useMemo(() => seedQuery.refetch, [seedQuery.refetch])
useEffect(() => {
if (open && isPasswordVerified && seedQueryData === undefined) {
seedQueryRefetch()
if (open && isPasswordVerified && seedQuery.data === undefined) {
seedQuery.refetch()
}
}, [open, isPasswordVerified, seedQueryData, seedQueryRefetch])
}, [open, isPasswordVerified, seedQuery])
useEffect(() => {
if (passwordVerifiedAt === undefined) {
@ -186,7 +184,7 @@ export const SeedPhraseDialog = ({ walletFileName, open, onOpenChange }: SeedPhr
<Button variant="outline" onClick={handleClose}>
{t('global.cancel')}
</Button>
<Button onClick={handlePasswordSubmit} disabled={!password || isSubmitting}>
<Button type="submit" onClick={handlePasswordSubmit} disabled={!password || isSubmitting}>
{isSubmitting ? (
<>
<Loader2Icon className="h-4 w-4 animate-spin motion-reduce:hidden" />

View file

@ -1,6 +1,7 @@
import * as React from 'react'
import * as DialogPrimitive from '@radix-ui/react-dialog'
import { XIcon } from 'lucide-react'
import { useTranslation } from 'react-i18next'
import { cn } from '@/lib/utils'
function Dialog({ ...props }: React.ComponentProps<typeof DialogPrimitive.Root>) {
@ -40,6 +41,7 @@ function DialogContent({
}: React.ComponentProps<typeof DialogPrimitive.Content> & {
showCloseButton?: boolean
}) {
const { t } = useTranslation()
return (
<DialogPortal data-slot="dialog-portal">
<DialogOverlay />
@ -54,11 +56,12 @@ function DialogContent({
{children}
{showCloseButton && (
<DialogPrimitive.Close
title={t('global.close')}
data-slot="dialog-close"
className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute top-4 right-4 cursor-pointer rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden disabled:pointer-events-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4"
>
<XIcon />
<span className="sr-only">Close</span>
<span className="sr-only">{t('global.close')}</span>
</DialogPrimitive.Close>
)}
</DialogPrimitive.Content>