mirror of
https://github.com/joinmarket-webui/jam.git
synced 2026-08-19 13:18:30 +02:00
chore: add debugFeatures, routes and dev pages
This commit is contained in:
parent
4ac04d4f0a
commit
8ca65a112b
12 changed files with 313 additions and 74 deletions
|
|
@ -4,7 +4,7 @@
|
|||
"version": "0.1.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"dev": "VITE_JAM_DEV_MODE=true vite",
|
||||
"dev:secondary": "JAM_BACKEND=jam-standalone JAM_API_PORT=29080 npm run dev",
|
||||
"build": "tsc -b && vite build",
|
||||
"lint": "eslint .",
|
||||
|
|
|
|||
126
src/App.tsx
126
src/App.tsx
|
|
@ -1,35 +1,42 @@
|
|||
import { useEffect, useMemo } from 'react'
|
||||
import { lazy, Suspense, useEffect, useMemo } from 'react'
|
||||
import type { PropsWithChildren } from 'react'
|
||||
import { QueryClientProvider, useQuery } from '@tanstack/react-query'
|
||||
import { Loader2 } from 'lucide-react'
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Navigate, Route, BrowserRouter as Router, Routes } from 'react-router-dom'
|
||||
import { toast } from 'sonner'
|
||||
import { useStore } from 'zustand'
|
||||
import CreateWallet from '@/components/CreateWallet'
|
||||
import JamLanding from '@/components/JamLanding'
|
||||
import LoginPage from '@/components/Login'
|
||||
import { Logs } from '@/components/Logs'
|
||||
import { Orderbook } from '@/components/Orderbook'
|
||||
import SwitchWallet from '@/components/SwitchWallet'
|
||||
import { EarnPage } from '@/components/earn/EarnPage'
|
||||
import { Layout } from '@/components/layout/Layout'
|
||||
import { Receive } from '@/components/receive/Receive'
|
||||
import { SendPage } from '@/components/send/SendPage'
|
||||
import { RescanChain } from '@/components/settings/RescanChain'
|
||||
import { Settings } from '@/components/settings/Settings'
|
||||
import { SweepPage } from '@/components/sweep/SweepPage'
|
||||
import { Toaster } from '@/components/ui/sonner'
|
||||
import { JAM_API_AUTH_TOKEN_RENEW_INTERVAL, JAM_JM_SESSION_REFRESH_INTERVAL } from '@/constants/jam'
|
||||
import { routes } from '@/constants/routes'
|
||||
import { useApiClient } from '@/hooks/useApiClient'
|
||||
import { token } from '@/lib/jm-api/generated/client'
|
||||
import { sessionOptions } from '@/lib/jm-api/generated/client/@tanstack/react-query.gen'
|
||||
import { queryClient } from '@/lib/queryClient'
|
||||
import { setIntervalDebounced } from '@/lib/utils'
|
||||
import { authStore } from '@/store/authStore'
|
||||
import { Logs } from './components/Logs'
|
||||
import { Orderbook } from './components/Orderbook'
|
||||
import { EarnPage } from './components/earn/EarnPage'
|
||||
import { Receive } from './components/receive/Receive'
|
||||
import { SendPage } from './components/send/SendPage'
|
||||
import { RescanChain } from './components/settings/RescanChain'
|
||||
import { Settings } from './components/settings/Settings'
|
||||
import { SweepPage } from './components/sweep/SweepPage'
|
||||
import { JAM_API_AUTH_TOKEN_RENEW_INTERVAL, JAM_JM_SESSION_REFRESH_INTERVAL } from './constants/jam'
|
||||
import { sessionOptions } from './lib/jm-api/generated/client/@tanstack/react-query.gen'
|
||||
import { jmSessionStore } from './store/jmSessionStore'
|
||||
import { jmSessionStore } from '@/store/jmSessionStore'
|
||||
import { isDebugFeatureEnabled, isDevMode } from './constants/debugFeatures'
|
||||
|
||||
const DevSetupPage = lazy(() => import('@/components/dev/DevSetupPage'))
|
||||
const DevPage = lazy(() => import('@/components/dev/DevPage'))
|
||||
|
||||
const ProtectedRoute = ({ authenticated, children }: PropsWithChildren<{ authenticated: boolean }>) => {
|
||||
return authenticated ? <>{children}</> : <Navigate to="/login" replace />
|
||||
return authenticated ? <>{children}</> : <Navigate to={routes.login} replace />
|
||||
}
|
||||
|
||||
function App() {
|
||||
|
|
@ -47,10 +54,16 @@ function App() {
|
|||
<RefreshJmSession />
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path="/login" element={authenticated ? <Navigate to="/" replace /> : <LoginPage />} />
|
||||
<Route path="/create-wallet" element={authenticated ? <Navigate to="/" replace /> : <CreateWallet />} />
|
||||
<Route
|
||||
path="/switch-wallet"
|
||||
path={routes.login}
|
||||
element={authenticated ? <Navigate to={routes.home} replace /> : <LoginPage />}
|
||||
/>
|
||||
<Route
|
||||
path={routes.createWallet}
|
||||
element={authenticated ? <Navigate to={routes.home} replace /> : <CreateWallet />}
|
||||
/>
|
||||
<Route
|
||||
path={routes.switchWallet}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<SwitchWallet walletFileName={walletFileName!} />
|
||||
|
|
@ -58,7 +71,7 @@ function App() {
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/"
|
||||
path={routes.home}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
|
|
@ -68,7 +81,7 @@ function App() {
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/receive"
|
||||
path={routes.receive}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
|
|
@ -78,7 +91,7 @@ function App() {
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/send"
|
||||
path={routes.send}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
|
|
@ -88,17 +101,7 @@ function App() {
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings/rescan"
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
<RescanChain walletFileName={walletFileName!} />
|
||||
</Layout>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/earn"
|
||||
path={routes.earn}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
|
|
@ -108,7 +111,7 @@ function App() {
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/sweep"
|
||||
path={routes.sweep}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
|
|
@ -118,7 +121,7 @@ function App() {
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings"
|
||||
path={routes.settings}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
|
|
@ -128,7 +131,7 @@ function App() {
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/orderbook"
|
||||
path={routes.orderbook}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
|
|
@ -138,7 +141,7 @@ function App() {
|
|||
}
|
||||
/>
|
||||
<Route
|
||||
path="/logs"
|
||||
path={routes.logs}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
|
|
@ -147,7 +150,40 @@ function App() {
|
|||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
<Route path="*" element={<Navigate to="/login" replace />} />
|
||||
<Route
|
||||
path={routes.rescan}
|
||||
element={
|
||||
<ProtectedRoute authenticated={authenticated}>
|
||||
<Layout>
|
||||
<RescanChain walletFileName={walletFileName!} />
|
||||
</Layout>
|
||||
</ProtectedRoute>
|
||||
}
|
||||
/>
|
||||
{isDebugFeatureEnabled('devPage') && (
|
||||
<Route
|
||||
path={routes.__dev}
|
||||
element={
|
||||
<Layout>
|
||||
<DevPage />
|
||||
</Layout>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{isDebugFeatureEnabled('devSetupPage') && (
|
||||
<Route
|
||||
id="dev-setup"
|
||||
path={routes.__devSetup}
|
||||
element={
|
||||
<Layout>
|
||||
<Suspense fallback={<Loading />}>
|
||||
<DevSetupPage />
|
||||
</Suspense>
|
||||
</Layout>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
<Route path="*" element={<Navigate to={routes.login} replace />} />
|
||||
</Routes>
|
||||
<Toaster closeButton />
|
||||
</Router>
|
||||
|
|
@ -156,12 +192,22 @@ function App() {
|
|||
)
|
||||
}
|
||||
|
||||
const Loading = () => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className="m-2 flex items-center justify-center">
|
||||
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
||||
{t('global.loading')}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
function RefreshApiToken() {
|
||||
const client = useApiClient()
|
||||
|
||||
// TODO: stop this interval if no wallet is active
|
||||
useEffect(() => {
|
||||
if (import.meta.env.DEV) {
|
||||
if (isDevMode()) {
|
||||
toast.info(`[DEV] setup refresh interval`)
|
||||
}
|
||||
|
||||
|
|
@ -182,7 +228,7 @@ function RefreshApiToken() {
|
|||
if (!response.data) {
|
||||
authStore.getState().clear()
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
if (isDevMode()) {
|
||||
const message = response.error?.message || response.error?.error_description || 'Unknown error.'
|
||||
toast.error(`[DEV] Error while renewing auth token: ${message}`)
|
||||
}
|
||||
|
|
@ -194,7 +240,7 @@ function RefreshApiToken() {
|
|||
},
|
||||
})
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
if (isDevMode()) {
|
||||
toast.info(`[DEV] Successfully renewed auth token.`, {
|
||||
id: 'token-renew-success',
|
||||
})
|
||||
|
|
@ -227,7 +273,7 @@ function RefreshJmSession() {
|
|||
if (sessionQuery.data) {
|
||||
jmSessionStore.getState().update(sessionQuery.data)
|
||||
|
||||
if (import.meta.env.DEV) {
|
||||
if (isDevMode()) {
|
||||
toast.info(`[DEV] Successfully refreshed session data.`, {
|
||||
id: 'jm-session-refresh-success',
|
||||
})
|
||||
|
|
@ -238,7 +284,7 @@ function RefreshJmSession() {
|
|||
useEffect(() => {
|
||||
if (authState === undefined) {
|
||||
sessionQuery.refetch().catch(() => {
|
||||
if (import.meta.env.DEV) {
|
||||
if (isDevMode()) {
|
||||
toast.error(`[DEV] Error while refreshing session data.`)
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -3,11 +3,13 @@ import { BlocksIcon, BookOpen, Check, File, X } from 'lucide-react'
|
|||
import { useTranslation, Trans } from 'react-i18next'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { useStore } from 'zustand'
|
||||
import { OrderbookDialog } from '@/components/OrderbookDialog'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { isDebugFeatureEnabled } from '@/constants/debugFeatures'
|
||||
import { routes } from '@/constants/routes'
|
||||
import { toSemVer } from '@/lib/utils'
|
||||
import { jmSessionStore } from '@/store/jmSessionStore'
|
||||
import packageInfo from '../../package.json'
|
||||
import { OrderbookDialog } from './OrderbookDialog'
|
||||
|
||||
const APP_DISPLAY_VERSION = (() => {
|
||||
const version = toSemVer(packageInfo.version)
|
||||
|
|
@ -39,7 +41,16 @@ export function Footer() {
|
|||
</Button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-1 justify-end">
|
||||
<div className="flex flex-1 justify-end gap-2">
|
||||
<div className="flex items-center">
|
||||
{isDebugFeatureEnabled('devSetupPage') && (
|
||||
<div className="">
|
||||
<Link className="light:text-yellow-800 text-sm text-yellow-200 underline" to={routes.__devSetup}>
|
||||
Dev Setup
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex flex-col gap-1">
|
||||
<a
|
||||
href="https://github.com/joinmarket-webui/jam/tags"
|
||||
|
|
|
|||
|
|
@ -1,24 +1,14 @@
|
|||
import { useState } from 'react'
|
||||
import { Info, Loader2, RefreshCw } from 'lucide-react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStore } from 'zustand'
|
||||
import { Jar } from '@/components/layout/Jar'
|
||||
import { useJamDisplayContext } from '@/components/layout/display-mode-context'
|
||||
import { FeeLimitDialog } from '@/components/settings/FeeLimitDialog'
|
||||
import { FeeConfigErrorAlert } from '@/components/ui/FeeConfigErrorAlert'
|
||||
import { FeeConfigTestComponent } from '@/components/ui/FeeConfigTestComponent'
|
||||
import { Alert, AlertDescription } from '@/components/ui/alert'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { Card } from '@/components/ui/card'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
|
||||
import { useFeeConfigValidation } from '@/hooks/useFeeConfigValidation'
|
||||
import { authStore } from '@/store/authStore'
|
||||
|
||||
export default function JamLanding() {
|
||||
const { t } = useTranslation()
|
||||
const [showFeeConfigDialog, setShowFeeConfigDialog] = useState(false)
|
||||
const authState = useStore(authStore, (state) => state.state)
|
||||
const { maxFeesConfigMissing } = useFeeConfigValidation()
|
||||
|
||||
const {
|
||||
currency,
|
||||
|
|
@ -62,11 +52,6 @@ export default function JamLanding() {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/* Fee Config Error Alert */}
|
||||
{maxFeesConfigMissing && (
|
||||
<FeeConfigErrorAlert onOpenFeeConfig={() => setShowFeeConfigDialog(true)} className="mb-4 max-w-2xl" />
|
||||
)}
|
||||
|
||||
{error && (
|
||||
<Alert variant="destructive" className="mb-4 max-w-2xl">
|
||||
<AlertDescription>
|
||||
|
|
@ -131,18 +116,6 @@ export default function JamLanding() {
|
|||
{t('global.refresh')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{import.meta.env.DEV && (
|
||||
<div className="mt-8">
|
||||
<FeeConfigTestComponent />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<FeeLimitDialog
|
||||
open={showFeeConfigDialog}
|
||||
onOpenChange={setShowFeeConfigDialog}
|
||||
walletFileName={authState?.walletFileName || ''}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
27
src/components/dev/DevPage.tsx
Normal file
27
src/components/dev/DevPage.tsx
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
import { useState } from 'react'
|
||||
import { useStore } from 'zustand'
|
||||
import { FeeLimitDialog } from '@/components/settings/FeeLimitDialog'
|
||||
import { FeeConfigTestComponent } from '@/components/ui/FeeConfigTestComponent'
|
||||
import { authStore } from '@/store/authStore'
|
||||
|
||||
export default function DevPage() {
|
||||
const authState = useStore(authStore, (state) => state.state)
|
||||
const [showFeeConfigDialog, setShowFeeConfigDialog] = useState(false)
|
||||
|
||||
return (
|
||||
<div className="mx-auto max-w-2xl space-y-3 p-4">
|
||||
<h1 className="my-2 text-2xl font-semibold tracking-tight">Development</h1>
|
||||
<p className="text-muted-foreground mb-4 text-sm">Development specific information</p>
|
||||
|
||||
<div className="mt-8">
|
||||
<FeeConfigTestComponent />
|
||||
|
||||
<FeeLimitDialog
|
||||
open={showFeeConfigDialog}
|
||||
onOpenChange={setShowFeeConfigDialog}
|
||||
walletFileName={authState?.walletFileName || ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
114
src/components/dev/DevSetupPage.tsx
Normal file
114
src/components/dev/DevSetupPage.tsx
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
import { BlocksIcon, TerminalIcon } from 'lucide-react'
|
||||
import { Badge } from '../ui/badge'
|
||||
|
||||
const DEFAULT_BASIC_AUTH = {
|
||||
user: 'joinmarket',
|
||||
password: 'joinmarket',
|
||||
}
|
||||
|
||||
const LINK_JM_REGTEST_JOINMARKET2 = 'http://localhost:29080'
|
||||
const LINK_JM_REGTEST_JOINMARKET2_AUTH = DEFAULT_BASIC_AUTH
|
||||
const LINK_JM_REGTEST_JOINMARKET3 = 'http://localhost:30080'
|
||||
const LINK_JM_REGTEST_EXPLORER = 'http://localhost:3002'
|
||||
const LINK_JM_REGTEST_EXPLORER_AUTH = DEFAULT_BASIC_AUTH
|
||||
const LINK_JM_REGTEST_RPC_TERMINAL = `${LINK_JM_REGTEST_EXPLORER}/rpc-terminal`
|
||||
|
||||
export default function DevSetupPage() {
|
||||
return (
|
||||
<div className="mx-auto max-w-2xl space-y-3 p-4">
|
||||
<h1 className="my-2 text-2xl font-semibold tracking-tight">Development setup</h1>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="mb-4">
|
||||
<h5 className="text-xl font-bold">Test Wallet</h5>
|
||||
<div className="my-2 ms-3">
|
||||
Name: <span className="font-mono">Satoshi</span>
|
||||
<br />
|
||||
Password: <span className="font-mono">test</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="mb-4">
|
||||
<h5 className="text-xl font-bold">Links</h5>
|
||||
<div className="my-2">
|
||||
{/*<Link className="link-dark" to={routes.__errorExample}>
|
||||
Error Example Page
|
||||
</Link>*/}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="mb-4">
|
||||
<h5 className="text-xl font-bold">Jam Instances</h5>
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
{/*<Sprite symbol="logo" width="24" height="24" className="me-2" />*/}
|
||||
<a href={LINK_JM_REGTEST_JOINMARKET2} target="_blank" rel="noopener noreferrer" className="underline">
|
||||
jm_regtest_joinmarket2 ({LINK_JM_REGTEST_JOINMARKET2})
|
||||
</a>
|
||||
<Badge>secondary</Badge>
|
||||
</div>
|
||||
|
||||
<div className="my-2 ms-5">
|
||||
Basic Authentication
|
||||
<br />
|
||||
<small>
|
||||
User: <span className="font-mono">{LINK_JM_REGTEST_JOINMARKET2_AUTH.user}</span>
|
||||
<br />
|
||||
Password: <span className="font-mono">{LINK_JM_REGTEST_JOINMARKET2_AUTH.password}</span>
|
||||
</small>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
{/*<Sprite symbol="logo" width="24" height="24" className="me-2" />*/}
|
||||
<a href={LINK_JM_REGTEST_JOINMARKET3} target="_blank" rel="noopener noreferrer" className="underline">
|
||||
jm_regtest_joinmarket3 ({LINK_JM_REGTEST_JOINMARKET3})
|
||||
</a>
|
||||
<Badge>tertiary</Badge>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-3">
|
||||
<div className="mb-4">
|
||||
<h5 className="text-xl font-bold">Block Explorer</h5>
|
||||
<div>
|
||||
{' '}
|
||||
<div className="flex items-center gap-2">
|
||||
<BlocksIcon className="h-4 w-4" />
|
||||
|
||||
<a href={LINK_JM_REGTEST_EXPLORER} target="_blank" rel="noopener noreferrer" className="underline">
|
||||
jm_regtest_explorer ({LINK_JM_REGTEST_EXPLORER})
|
||||
</a>
|
||||
</div>
|
||||
<div className="my-2 ms-5">
|
||||
Basic Authentication
|
||||
<br />
|
||||
<small>
|
||||
User: <span className="font-mono">{LINK_JM_REGTEST_EXPLORER_AUTH.user}</span>
|
||||
<br />
|
||||
Password: <span className="font-mono">{LINK_JM_REGTEST_EXPLORER_AUTH.password}</span>
|
||||
</small>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="flex items-center gap-2">
|
||||
<TerminalIcon className="h-4 w-4" />
|
||||
|
||||
<a href={LINK_JM_REGTEST_RPC_TERMINAL} target="_blank" rel="noopener noreferrer" className="underline">
|
||||
Regtest RPC Terminal ({LINK_JM_REGTEST_RPC_TERMINAL})
|
||||
</a>
|
||||
</div>
|
||||
<div className="my-2 ms-5">
|
||||
Mine a block, e.g.:
|
||||
<pre>generatetoaddress 1 bcrt1qrnz0thqslhxu86th069r9j6y7ldkgs2tzgf5wx</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -22,6 +22,8 @@ import { DevBadge } from '../ui/DevBadge'
|
|||
import { CollaboratorFeesForm, type CollaboratorFeesFormRef } from './CollaboratorFeesForm'
|
||||
import { MiningFeesForm, type MiningFeesFormRef } from './MiningFeesForm'
|
||||
|
||||
//TODO: needs testing!
|
||||
|
||||
interface FeeLimitDialogProps {
|
||||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
|
|
|
|||
40
src/constants/debugFeatures.ts
Normal file
40
src/constants/debugFeatures.ts
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
interface DebugFeatures {
|
||||
insecureScheduleTesting: boolean
|
||||
allowCreatingExpiredFidelityBond: boolean
|
||||
skipWalletBackupConfirmation: boolean
|
||||
errorExamplePage: boolean
|
||||
devPage: boolean
|
||||
devSetupPage: boolean
|
||||
importDummyMnemonicPhrase: boolean
|
||||
allowFeeValuesReset: boolean
|
||||
enableDemoEarnReport: boolean
|
||||
enableDemoOrderbook: boolean
|
||||
}
|
||||
|
||||
const devMode = import.meta.env.DEV && import.meta.env.VITE_JAM_DEV_MODE === 'true'
|
||||
|
||||
const debugFeatures: DebugFeatures = {
|
||||
allowCreatingExpiredFidelityBond: devMode,
|
||||
insecureScheduleTesting: devMode,
|
||||
skipWalletBackupConfirmation: devMode,
|
||||
errorExamplePage: devMode,
|
||||
devPage: devMode,
|
||||
devSetupPage: devMode,
|
||||
importDummyMnemonicPhrase: devMode,
|
||||
allowFeeValuesReset: devMode,
|
||||
enableDemoEarnReport: devMode,
|
||||
enableDemoOrderbook: devMode,
|
||||
}
|
||||
|
||||
type DebugFeature = keyof DebugFeatures
|
||||
|
||||
export const isDevMode = (): boolean => devMode
|
||||
|
||||
export const isDebugFeatureEnabled = (name: DebugFeature): boolean => {
|
||||
return debugFeatures[name] || false
|
||||
}
|
||||
|
||||
// only to be used in tests
|
||||
export const __testSetDebugFeatureEnabled = (name: DebugFeature, enabled: boolean): boolean => {
|
||||
return (debugFeatures[name] = enabled)
|
||||
}
|
||||
23
src/constants/routes.ts
Normal file
23
src/constants/routes.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
export const routes = {
|
||||
home: '/',
|
||||
login: '/login',
|
||||
createWallet: '/create-wallet',
|
||||
switchWallet: '/switch-wallet',
|
||||
receive: '/receive',
|
||||
send: '/send',
|
||||
rescan: '/rescan',
|
||||
earn: '/earn',
|
||||
sweep: '/sweep',
|
||||
settings: '/settings',
|
||||
orderbook: '/orderbook',
|
||||
logs: '/logs',
|
||||
/* walletList: '/',
|
||||
wallet: '/wallet',
|
||||
importWallet: '/import-wallet',
|
||||
*/
|
||||
__dev: '/dev',
|
||||
//__devErrorExample: '/dev/error-example',
|
||||
__devSetup: '/dev/setup',
|
||||
}
|
||||
|
||||
export type Route = keyof typeof routes
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { useQuery } from '@tanstack/react-query'
|
||||
import { useStore } from 'zustand'
|
||||
import { isDevMode } from '@/constants/debugFeatures'
|
||||
import { fetchFeatures } from '@/lib/api/logs'
|
||||
import { authStore } from '@/store/authStore'
|
||||
|
||||
|
|
@ -45,7 +46,8 @@ export const useFeatures = () => {
|
|||
|
||||
const isLogsEnabled = () => {
|
||||
if (error) {
|
||||
return import.meta.env.DEV
|
||||
// show regardless of error in development mode
|
||||
return isDevMode()
|
||||
}
|
||||
|
||||
if (features) {
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@ import { useApiClient } from '@/hooks/useApiClient'
|
|||
import { configgetMutation } from '@/lib/jm-api/generated/client/@tanstack/react-query.gen'
|
||||
import { authStore } from '@/store/authStore'
|
||||
|
||||
//TODO: needs testing!
|
||||
|
||||
export interface FeeConfigValues {
|
||||
max_cj_fee_abs?: string
|
||||
max_cj_fee_rel?: string
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { isDevMode } from '@/constants/debugFeatures'
|
||||
import { createClient } from '@/lib/jm-api'
|
||||
import type { ClientOptions, UnlockWalletResponse } from '@/lib/jm-api/generated/client'
|
||||
import { authStore } from '@/store/authStore'
|
||||
|
|
@ -39,9 +40,7 @@ export const createApiClient = (): Client => {
|
|||
const jamAuthMiddleware = createJamAuthenticationMiddleware()
|
||||
client.interceptors.request.use(jamAuthMiddleware)
|
||||
|
||||
const isDevelopment = import.meta.env.DEV
|
||||
|
||||
if (isDevelopment) {
|
||||
if (isDevMode()) {
|
||||
client.interceptors.request.use(loggingRequestInterceptor)
|
||||
client.interceptors.response.use(loggingResponseInterceptor)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue