chore: enable eslint recommendedTypeChecked

This commit is contained in:
theborakompanioni 2026-02-06 23:52:17 +01:00
parent 93f7cb10bb
commit 6f1a1f7ed1
No known key found for this signature in database
GPG key ID: E8070AF0053AAC0D
29 changed files with 125 additions and 184 deletions

View file

@ -1,7 +1,6 @@
// For more info, see https://github.com/storybookjs/eslint-plugin-storybook#configuration-flat-config-format
import js from '@eslint/js'
import compat from 'eslint-plugin-compat'
import eslintPluginPrettierRecommended from 'eslint-plugin-prettier/recommended'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import storybook from 'eslint-plugin-storybook'
@ -13,7 +12,7 @@ import tseslint from 'typescript-eslint'
export default defineConfig(
{ ignores: ['dist', './.storybook/**', './storybook-static/**'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended, eslintPluginPrettierRecommended],
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2023,
@ -38,11 +37,27 @@ export default defineConfig(
],
},
},
{
ignores: [
'./src/components/ui/*.tsx', // shadcn components
'./src/**/*.stories.tsx',
'./src/components/settings/CollaboratorFeesForm.tsx', // TODO: remove
],
files: ['./src/**/*.{ts,tsx}'],
languageOptions: {
parserOptions: {
projectService: true,
},
},
extends: [...tseslint.configs.recommendedTypeChecked],
rules: {
'@typescript-eslint/no-redundant-type-constituents': ['off'], // shows intent
},
},
{
extends: [eslintPluginUnicorn.configs.recommended],
ignores: [
'./src/components/ui/*.tsx', // shadcn components
'./src/components/earn/CreateFidelityBondDialog.tsx', // TODO: remove
'./src/components/settings/CollaboratorFeesForm.tsx', // TODO: remove
],
rules: {
@ -60,11 +75,7 @@ export default defineConfig(
'unicorn/catch-error-name': [
'error',
{
ignore: [
String.raw`^error\d*$`,
'_ignoredOnPurpose',
'e', // TODO: remove
],
ignore: ['_ignoredOnPurpose'],
},
],
'unicorn/numeric-separators-style': [

99
package-lock.json generated
View file

@ -72,9 +72,7 @@
"@vitest/coverage-v8": "4.0.9",
"conventional-changelog": "7.1.1",
"eslint": "9.39.2",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-compat": "6.1.0",
"eslint-plugin-prettier": "5.5.5",
"eslint-plugin-react-hooks": "7.0.1",
"eslint-plugin-react-refresh": "0.5.0",
"eslint-plugin-storybook": "10.2.5",
@ -1353,19 +1351,6 @@
"url": "https://paulmillr.com/funding/"
}
},
"node_modules/@pkgr/core": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.2.9.tgz",
"integrity": "sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==",
"dev": true,
"license": "MIT",
"engines": {
"node": "^12.20.0 || ^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/pkgr"
}
},
"node_modules/@playwright/test": {
"version": "1.58.1",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.1.tgz",
@ -6289,23 +6274,6 @@
}
}
},
"node_modules/eslint-config-prettier": {
"version": "10.1.8",
"resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz",
"integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"eslint-config-prettier": "bin/cli.js"
},
"funding": {
"url": "https://opencollective.com/eslint-config-prettier"
},
"peerDependencies": {
"eslint": ">=7.0.0"
}
},
"node_modules/eslint-plugin-compat": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-compat/-/eslint-plugin-compat-6.1.0.tgz",
@ -6355,37 +6323,6 @@
"node": ">=10"
}
},
"node_modules/eslint-plugin-prettier": {
"version": "5.5.5",
"resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz",
"integrity": "sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw==",
"dev": true,
"license": "MIT",
"dependencies": {
"prettier-linter-helpers": "^1.0.1",
"synckit": "^0.11.12"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint-plugin-prettier"
},
"peerDependencies": {
"@types/eslint": ">=8.0.0",
"eslint": ">=8.0.0",
"eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0",
"prettier": ">=3.0.0"
},
"peerDependenciesMeta": {
"@types/eslint": {
"optional": true
},
"eslint-config-prettier": {
"optional": true
}
}
},
"node_modules/eslint-plugin-react-hooks": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-7.0.1.tgz",
@ -6644,13 +6581,6 @@
"dev": true,
"license": "MIT"
},
"node_modules/fast-diff": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz",
"integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==",
"dev": true,
"license": "Apache-2.0"
},
"node_modules/fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
@ -8540,19 +8470,6 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prettier-linter-helpers": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz",
"integrity": "sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==",
"dev": true,
"license": "MIT",
"dependencies": {
"fast-diff": "^1.1.2"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/prettier-plugin-tailwindcss": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.7.2.tgz",
@ -9724,22 +9641,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/synckit": {
"version": "0.11.12",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.12.tgz",
"integrity": "sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@pkgr/core": "^0.2.9"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/synckit"
}
},
"node_modules/tailwind-merge": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.4.0.tgz",

View file

@ -115,9 +115,7 @@
"@vitest/coverage-v8": "4.0.9",
"conventional-changelog": "7.1.1",
"eslint": "9.39.2",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-compat": "6.1.0",
"eslint-plugin-prettier": "5.5.5",
"eslint-plugin-react-hooks": "7.0.1",
"eslint-plugin-react-refresh": "0.5.0",
"eslint-plugin-storybook": "10.2.5",

View file

@ -91,7 +91,12 @@ function LogViewer({ value, refresh }: LogViewerProps) {
<DownloadIcon className="group/download" />
{t('global.download')}
</Button>
<Button variant="outline" onClick={handleRefresh} disabled={isLoadingRefresh} title={t('global.refresh')}>
<Button
variant="outline"
onClick={() => void handleRefresh()}
disabled={isLoadingRefresh}
title={t('global.refresh')}
>
<RefreshCwIcon
className={cn({
'animate-spin': isLoadingRefresh,
@ -161,11 +166,13 @@ export const LogsContent = ({ enabled, className }: LogsContentProps) => {
setAlert(undefined)
setLogFileContent(data)
})
.catch((error) => {
.catch((error: unknown) => {
if (signal.aborted) return
const reason = (error instanceof Error ? error.message : undefined) || t('global.errors.reason_unknown')
const errorMessage = t('logs.error_loading_logs_failed', {
reason: error.message || t('global.errors.reason_unknown'),
/* TODO: add reason to i18n string */
reason,
})
if (isDevMode()) {
@ -183,7 +190,7 @@ export const LogsContent = ({ enabled, className }: LogsContentProps) => {
if (enabled && !isInitialized) {
const abortCtrl = new AbortController()
refresh(abortCtrl.signal).finally(() => {
void refresh(abortCtrl.signal).finally(() => {
if (abortCtrl.signal.aborted) return
setIsInitialized(true)
})

View file

@ -95,7 +95,12 @@ function LogContent({ value, refresh }: LogContentProps) {
<DownloadIcon className="group/download" />
{t('global.download')}
</Button>
<Button variant="outline" onClick={handleRefresh} disabled={isLoadingRefresh} title={t('global.refresh')}>
<Button
variant="outline"
onClick={() => void handleRefresh()}
disabled={isLoadingRefresh}
title={t('global.refresh')}
>
<RefreshCwIcon className={cn({ 'animate-spin': isLoadingRefresh })} />
{t('global.refresh')}
</Button>
@ -159,9 +164,10 @@ export const LogsPage = () => {
.catch((error) => {
if (signal.aborted) return
const reason = (error instanceof Error ? error.message : undefined) || t('global.errors.reason_unknown')
const errorMessage = t('logs.error_loading_logs_failed', {
/* TODO: add reason to i18n string */
reason: error.message || t('global.errors.reason_unknown'),
reason,
})
if (isDevMode()) {
@ -181,7 +187,7 @@ export const LogsPage = () => {
if (!isInitialized) {
const abortCtrl = new AbortController()
refresh(abortCtrl.signal).finally(() => {
void refresh(abortCtrl.signal).finally(() => {
if (abortCtrl.signal.aborted) return
setIsInitialized(true)
})

View file

@ -93,7 +93,7 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps)
{t('global.errors.error_loading_wallet_failed', {
reason: error.message || t('global.errors.reason_unknown'),
})}
<Button variant="outline" size="sm" onClick={() => refetchWalletData()}>
<Button variant="outline" size="sm" onClick={() => void refetchWalletData()}>
<RefreshCwIcon className={cn({ 'motion-safe:animate-spin': isFetching })} />
{t('global.retry')}
</Button>
@ -145,7 +145,7 @@ export default function MainWalletPage({ walletFileName }: MainWalletPageProps)
</div>
</div>
<div className="flex w-full max-w-xl justify-end">
<Button variant="ghost" size="xs" onClick={() => refetchWalletData()}>
<Button variant="ghost" size="xs" onClick={() => void refetchWalletData()}>
<RefreshCwIcon className={cn({ 'motion-safe:animate-spin': isFetching })} />
{t('global.refresh')}
</Button>

View file

@ -186,7 +186,7 @@ const SwitchWalletPage = ({ walletFileName }: SwitchWalletPageProps) => {
<Button
variant="default"
size="sm"
onClick={handleLockCurrentWallet}
onClick={() => void handleLockCurrentWallet()}
disabled={lockCurrentWallet.isFetching || currentWalletLocked}
className="flex-1"
>

View file

@ -81,19 +81,16 @@ const CreateWalletPage = () => {
}
const walletFileName = walletDisplayNameToFileName(walletName)
const { data: createData, error: createError } = await createwallet({
const { data: createData } = await createwallet({
client,
body: {
walletname: walletFileName,
password,
wallettype: 'sw-fb',
},
throwOnError: true,
})
if (createError) {
throw createError
}
let hashedPassword: string | undefined = undefined
try {
hashedPassword = await hashPassword(password, createData.walletname)

View file

@ -75,7 +75,7 @@ function DevConfigTabContent({ walletFileName }: DevConfigTabContentProps) {
<code className="light:text-red-700 text-red-800">feeConfig.maxFeesConfigMissing:</code>
<pre className="text-xs">{JSON.stringify(feeConfig.maxFeesConfigMissing, null, 2)}</pre>
</div>
<Button onClick={() => feeConfig.refetchAll()}>feeConfig.refetchAll()</Button>
<Button onClick={() => void feeConfig.refetchAll()}>feeConfig.refetchAll()</Button>
<FeeConfigTestComponent walletFileName={walletFileName} />
</div>

View file

@ -45,7 +45,7 @@ export function CreateFidelityBondDialog({ open, onOpenChange, walletFileName }:
<Button
variant="outline"
className="min-w-32"
onClick={handleUnfreezeUtxos}
onClick={() => void handleUnfreezeUtxos()}
disabled={unfreezeUtxo.isPending}
>
{unfreezeUtxo.isPending ? (
@ -78,7 +78,7 @@ export function CreateFidelityBondDialog({ open, onOpenChange, walletFileName }:
<Button variant="outline" className="min-w-24" onClick={() => handleOpenChange(false)} disabled={isLoading}>
{t('earn.fidelity_bond.select_date.text_secondary_button')}
</Button>
<Button className="min-w-32" onClick={handleNext} disabled={!canProceed() || isLoading}>
<Button className="min-w-32" onClick={() => void handleNext()} disabled={!canProceed() || isLoading}>
{isLoading && <Spinner className="mr-2 h-4 w-4" />}
{step === 'freeze_utxos'
? utxosToFreeze.length > 0

View file

@ -87,7 +87,7 @@ export function CreateFidelityBondDialogSteps({ wizard }: CreateFidelityBondDial
<Select
value={selectedMonth}
onValueChange={(month) => {
const year = selectedYear || String(parseInt(month, 10) >= minMonth ? minYear : minYear + 1)
const year = selectedYear || String(Number.parseInt(month, 10) >= minMonth ? minYear : minYear + 1)
const newLockdate = clampLockdate(`${year}-${month}`)
setSelectedLockdate(newLockdate)
}}

View file

@ -36,8 +36,8 @@ export function generateLockdateOptions(isDeveloperMode: boolean): { value: fb.L
export function getYearOptions(lockdateOptions: { value: fb.Lockdate }[]) {
if (lockdateOptions.length === 0) return []
const minYear = parseInt(lockdateOptions[0].value.slice(0, 4), 10)
const maxYear = parseInt(lockdateOptions[lockdateOptions.length - 1].value.slice(0, 4), 10)
const minYear = Number.parseInt(lockdateOptions[0].value.slice(0, 4), 10)
const maxYear = Number.parseInt(lockdateOptions.at(-1)!.value.slice(0, 4), 10)
return Array.from({ length: maxYear - minYear + 1 }, (_, i) => ({
value: String(minYear + i),
label: String(minYear + i),

View file

@ -42,8 +42,8 @@ export function useCreateFidelityBondWizard(
const yearOptions = useMemo(() => getYearOptions(lockdateOptions), [lockdateOptions])
const monthOptions = useMemo(() => getMonthOptions(), [])
const minLockdate = lockdateOptions[0]?.value ?? ''
const maxLockdate = lockdateOptions[lockdateOptions.length - 1]?.value ?? ''
const minLockdate = lockdateOptions.at(0)?.value ?? ''
const maxLockdate = lockdateOptions.at(-1)?.value ?? ''
const clampLockdate = (lockdate: string): fb.Lockdate | '' => {
if (!lockdate || lockdate < minLockdate) return minLockdate || ''
if (lockdate > maxLockdate) return maxLockdate || ''
@ -51,8 +51,8 @@ export function useCreateFidelityBondWizard(
}
const selectedYear = selectedLockdate ? selectedLockdate.slice(0, 4) : ''
const selectedMonth = selectedLockdate ? selectedLockdate.slice(5, 7) : ''
const minYear = minLockdate ? parseInt(minLockdate.slice(0, 4), 10) : 0
const minMonth = minLockdate ? parseInt(minLockdate.slice(5, 7), 10) : 1
const minYear = minLockdate ? Number.parseInt(minLockdate.slice(0, 4), 10) : 0
const minMonth = minLockdate ? Number.parseInt(minLockdate.slice(5, 7), 10) : 1
const existingFbLockdates = useMemo(() => {
return walletInfo.fidelityBondSummary.fbOutputs
@ -75,17 +75,17 @@ export function useCreateFidelityBondWizard(
const availableUtxos = useMemo(() => {
if (selectedJarIndex === undefined) return []
const jar = walletInfo.jars.find((j) => j.jarIndex === selectedJarIndex)
const jar = walletInfo.jars.find((it) => it.jarIndex === selectedJarIndex)
if (!jar) return []
return jar.utxos.filter((utxo) => !utxo.frozen && !fb.utxo.isFidelityBond(utxo))
}, [walletInfo.jars, selectedJarIndex])
const utxosToFreeze = useMemo(() => {
if (selectedJarIndex === undefined) return []
const jar = walletInfo.jars.find((j) => j.jarIndex === selectedJarIndex)
const jar = walletInfo.jars.find((it) => it.jarIndex === selectedJarIndex)
if (!jar) return []
return jar.utxos.filter(
(utxo) => !utxo.frozen && !fb.utxo.isFidelityBond(utxo) && !selectedUtxos.some((s) => s.utxo === utxo.utxo),
(utxo) => !utxo.frozen && !fb.utxo.isFidelityBond(utxo) && !selectedUtxos.some((it) => it.utxo === utxo.utxo),
)
}, [walletInfo.jars, selectedJarIndex, selectedUtxos])
@ -115,27 +115,24 @@ export function useCreateFidelityBondWizard(
const freezeUtxo = useMutation({
...freezeMutation({ client }),
onError: (err: ErrorMessage) => {
console.error('Freeze error:', err)
const reason = err.message || err.error_description || t('global.errors.reason_unknown')
onError: (error: ErrorMessage) => {
const reason = error.message || error.error_description || t('global.errors.reason_unknown')
setError(`${t('earn.fidelity_bond.error_freezing_utxos')} ${reason}`)
},
})
const unfreezeUtxo = useMutation({
...freezeMutation({ client }),
onError: (err: ErrorMessage) => {
console.error('Unfreeze error:', err)
const reason = err.message || err.error_description || t('global.errors.reason_unknown')
onError: (error: ErrorMessage) => {
const reason = error.message || error.error_description || t('global.errors.reason_unknown')
setError(`${t('earn.fidelity_bond.error_unfreezing_utxos')} ${reason}`)
},
})
const directSend = useMutation({
...directsendMutation({ client }),
onError: (err: ErrorMessage) => {
console.error('DirectSend error:', err)
const reason = err.message || err.error_description || t('global.errors.reason_unknown')
onError: (error: ErrorMessage) => {
const reason = error.message || error.error_description || t('global.errors.reason_unknown')
setError(`${t('earn.fidelity_bond.error_creating_fidelity_bond')} ${reason}`)
},
})
@ -243,7 +240,7 @@ export function useCreateFidelityBondWizard(
setTxResult(result)
setStep('success')
toast.success(t('earn.fidelity_bond.create_fidelity_bond.success_text'))
walletInfo.refetch()
await walletInfo.refetch()
} catch {
setStep('review')
}
@ -259,19 +256,19 @@ export function useCreateFidelityBondWizard(
}
setFrozenUtxos([])
toast.success(t('earn.fidelity_bond.unfreeze_utxos.done'))
walletInfo.refetch()
await walletInfo.refetch()
} catch {
// Error handled in onError
}
}
const toggleUtxoSelection = (utxo: Utxo) => {
setSelectedUtxos((prev) => {
const isSelected = prev.some((u) => u.utxo === utxo.utxo)
setSelectedUtxos((current) => {
const isSelected = current.some((u) => u.utxo === utxo.utxo)
if (isSelected) {
return prev.filter((u) => u.utxo !== utxo.utxo)
return current.filter((u) => u.utxo !== utxo.utxo)
}
return [...prev, utxo]
return [...current, utxo]
})
}

View file

@ -58,7 +58,7 @@ const baseSchema = yup
then: (schema) => schema.min(JAM.OFFER_FEE_ABS_MIN).required(),
otherwise: (schema) =>
schema
.transform((value) => (Number.isNaN(value) ? null : value))
.transform((value) => (Number.isSafeInteger(value) ? Number(value) : null))
.nullable()
.optional(),
}),
@ -68,7 +68,7 @@ const baseSchema = yup
schema.min(factorToPercentage(JAM.OFFER_FEE_REL_MIN)).max(factorToPercentage(JAM.OFFER_FEE_REL_MAX)).required(),
otherwise: (schema) =>
schema
.transform((value) => (Number.isNaN(value) ? null : value))
.transform((value) => (Number.isFinite(value) ? Number(value) : null))
.nullable()
.optional(),
}),

View file

@ -211,7 +211,7 @@ export const EarnPage = ({ walletFileName }: EarnPageProps) => {
value={jmSession.offer_list[0]}
nickname={jmSession.nickname}
>
<Button type="button" onClick={() => onStop()} className="w-full" size="lg">
<Button type="button" onClick={() => void onStop()} className="w-full" size="lg">
{isWaitingMakerStop ? (
<>
<Spinner className="motion-reduce:hidden" />

View file

@ -58,8 +58,8 @@ function UnknownError({ error }: { error: unknown }) {
return <ErrorView title={title} subtitle={subtitle} reason={t('global.errors.reason_unknown')} />
}
const reason = 'message' in error && error.message ? String(error.message) : undefined
const stacktrace = 'stack' in error && error.stack ? String(error.stack) : undefined
const reason = 'message' in error && typeof error.message === 'string' ? error.message : undefined
const stacktrace = 'stack' in error && typeof error.stack === 'string' ? error.stack : undefined
return (
<ErrorView
title={title}

View file

@ -210,7 +210,7 @@ export const OrderbookContent = ({ enabled, className }: OrderbookContentProps)
</AlertDescription>
</Alert>
<Button variant="ghost" onClick={() => refetchOrderbookData()} disabled={isFetching}>
<Button variant="ghost" onClick={() => void refetchOrderbookData()} disabled={isFetching}>
<RefreshCwIcon className={cn({ 'motion-safe:animate-spin': isFetching })} />
{t('global.retry')}
</Button>
@ -246,7 +246,13 @@ export const OrderbookContent = ({ enabled, className }: OrderbookContentProps)
)}
<ButtonGroup>
<Button variant="outline" className="rounded-r-none" size="sm" onClick={handleReload} disabled={isFetching}>
<Button
variant="outline"
className="rounded-r-none"
size="sm"
onClick={() => void handleReload()}
disabled={isFetching}
>
<RefreshCwIcon className={cn({ 'motion-safe:animate-spin': isFetching })} />
{t('orderbook.button_reload_title')}
</Button>
@ -259,7 +265,7 @@ export const OrderbookContent = ({ enabled, className }: OrderbookContentProps)
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="min-w-52">
<DropdownMenuGroup>
<DropdownMenuItem onClick={handleClearAndReload} disabled={isFetching}>
<DropdownMenuItem onClick={() => void handleClearAndReload()} disabled={isFetching}>
{t('orderbook.button_refresh_text')}
</DropdownMenuItem>
</DropdownMenuGroup>

View file

@ -70,6 +70,7 @@ type OrderTableColumnMeta =
| undefined
const fuzzyFilter: FilterFn<OrderTableEntry> = (row, columnId, value, addMeta) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- tanstack/table api
const itemRank = rankItem(row.getValue(columnId), value)
addMeta({ itemRank })
return itemRank.passed
@ -121,7 +122,7 @@ export const OrderbookTable = ({
numeric: true,
} as OrderTableColumnMeta,
}),
columnHelper.accessor('type', {
columnHelper.accessor<'type', OrderTableEntry['type']>('type', {
header: () => <div className="flex items-center">{t('orderbook.table.heading_type')}</div>,
sortingFn: (a, b) => a.original.type.displayValue.localeCompare(b.original.type.displayValue),
cell: (info) => (
@ -161,7 +162,7 @@ export const OrderbookTable = ({
numeric: true,
} as OrderTableColumnMeta,
}),
columnHelper.accessor('minimumSize', {
columnHelper.accessor<'minimumSize', OrderTableEntry['minimumSize']>('minimumSize', {
header: () => <div className="flex items-center">{t('orderbook.table.heading_minimum_size')}</div>,
sortingFn: (a, b) => Number(a.original.minimumSize) - Number(b.original.minimumSize),
cell: (info) => <Balance colored={false} valueString={info.getValue()} />,
@ -170,7 +171,7 @@ export const OrderbookTable = ({
numeric: true,
} as OrderTableColumnMeta,
}),
columnHelper.accessor('maximumSize', {
columnHelper.accessor<'maximumSize', OrderTableEntry['maximumSize']>('maximumSize', {
header: () => <div className="flex items-center">{t('orderbook.table.heading_maximum_size')}</div>,
sortingFn: (a, b) => Number(a.original.maximumSize) - Number(b.original.maximumSize),
cell: (info) => <Balance colored={false} valueString={info.getValue()} />,
@ -179,7 +180,7 @@ export const OrderbookTable = ({
numeric: true,
} as OrderTableColumnMeta,
}),
columnHelper.accessor('minerFeeContribution', {
columnHelper.accessor<'minerFeeContribution', OrderTableEntry['minerFeeContribution']>('minerFeeContribution', {
header: () => <div className="flex items-center">{t('orderbook.table.heading_miner_fee_contribution')}</div>,
sortingFn: (a, b) => Number(a.original.minerFeeContribution) - Number(b.original.minerFeeContribution),
cell: (info) => <Balance colored={false} valueString={info.getValue()} />,

View file

@ -44,7 +44,7 @@ const receiveFormSchema = (jars: Jar[]) => {
.integer()
.min(1)
.max(21_000_000 * 100_000_000)
.transform((value) => (Number.isNaN(value) ? undefined : value))
.transform((value) => (Number.isSafeInteger(value) ? Number(value) : null))
.nullable()
.optional(),
})
@ -83,8 +83,10 @@ export const ReceiveForm = ({ className, defaultValues, onSubmit, jars, disabled
const values = useWatch({ control })
const doOnChange = handleSubmit(onSubmit)
return (
<form onChange={handleSubmit(onSubmit)} className={cn('flex flex-col gap-4', className)} noValidate>
<form onChange={(event) => void doOnChange(event)} className={cn('flex flex-col gap-4', className)} noValidate>
<div className="space-y-2">
<Field className="space-y-4" data-invalid={errors.source !== undefined}>
<FieldLabel>{t('receive.label_source_jar')}</FieldLabel>

View file

@ -62,7 +62,7 @@ export const ReceivePage = ({ walletFileName }: ReceivePageProps) => {
const getAddressQueryOptions = getaddressOptions({
client,
path: {
walletname: encodeURIComponent(walletFileName!),
walletname: encodeURIComponent(walletFileName),
mixdepth: String(sourceJar?.jarIndex),
},
})
@ -147,7 +147,12 @@ export const ReceivePage = ({ walletFileName }: ReceivePageProps) => {
)}
<div className="mt-4 flex items-center gap-2">
<Button variant="outline" size="sm" onClick={getNewAddress} disabled={getAddressQuery.isFetching}>
<Button
variant="outline"
size="sm"
onClick={() => void getNewAddress()}
disabled={getAddressQuery.isFetching}
>
{getAddressQuery.isFetching ? (
<>
<RefreshCwIcon className="animate-spin motion-reduce:hidden" />

View file

@ -41,13 +41,16 @@ export default function JarSelectorDialog({
onOpenChange(false)
}
const confirm = () => {
const confirm = async () => {
if (selectedJar === undefined) return
setIsConfirming(true)
onConfirm(selectedJar.jarIndex)
.then(() => setSelectedJar(undefined))
.finally(() => setIsConfirming(false))
try {
await onConfirm(selectedJar.jarIndex)
setSelectedJar(undefined)
} finally {
setIsConfirming(false)
}
}
return (
@ -79,7 +82,7 @@ export default function JarSelectorDialog({
<Button className="flex-1" variant="outline" onClick={handleClose}>
{t('modal.confirm_button_reject')}
</Button>
<Button className="flex-1" onClick={confirm} disabled={!selectedJar || isConfirming}>
<Button className="flex-1" onClick={() => void confirm()} disabled={!selectedJar || isConfirming}>
{isConfirming ? (
<>
<Spinner className="motion-reduce:hidden" />

View file

@ -98,9 +98,13 @@ export default function PaymentConfirmDialog({
onOpenChange(false)
}
const confirm = () => {
const confirm = async () => {
setIsConfirming(true)
onConfirm(values).finally(() => setIsConfirming(false))
try {
await onConfirm(values)
} finally {
setIsConfirming(false)
}
}
return (
@ -213,7 +217,7 @@ export default function PaymentConfirmDialog({
<Button className="flex-1" variant="outline" onClick={handleClose}>
{t('modal.confirm_button_reject')}
</Button>
<Button className="flex-1" onClick={confirm} disabled={isConfirming}>
<Button className="flex-1" onClick={() => void confirm()} disabled={isConfirming}>
{isConfirming ? (
<>
<Spinner className="motion-reduce:hidden" />

View file

@ -241,7 +241,7 @@ export const AccountXpubsDialog = ({
useEffect(() => {
if (open && isPasswordVerified && seedQuery.data === undefined) {
seedQuery.refetch()
void seedQuery.refetch()
}
}, [open, isPasswordVerified, seedQuery])

View file

@ -30,9 +30,9 @@ const fillLevelToPercent = (fillLevel: JarFillLevel): number => {
}
interface JarIconProps {
color?: string
amount?: AmountSats
totalBalance?: number
color: string
amount: AmountSats
totalBalance: AmountSats
width?: number
height?: number
isSelected?: boolean

View file

@ -53,6 +53,7 @@ type BranchEntryTableColumnMeta =
| undefined
const fuzzyFilter: FilterFn<BranchEntryTableRow> = (row, columnId, value, addMeta) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- tanstack/table api
const itemRank = rankItem(row.getValue(columnId), value)
addMeta({ itemRank })
return itemRank.passed

View file

@ -53,6 +53,7 @@ type UtxoTableColumnMeta =
| undefined
const fuzzyFilter: FilterFn<UtxoTableEntry> = (row, columnId, value, addMeta) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument -- tanstack/table api
const itemRank = rankItem(row.getValue(columnId), value)
addMeta({ itemRank })
return itemRank.passed

View file

@ -117,6 +117,7 @@ describe('setIntervalDebounced', () => {
const callback = vi.fn().mockRejectedValueOnce(error).mockResolvedValueOnce(undefined)
const onTimerIdChanged = vi.fn()
const onError = vi.fn((_, loop) => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-call -- okay when using vi mocks
loop()
})

View file

@ -3,8 +3,8 @@
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "es2023",
"useDefineForClassFields": true,
"lib": ["es2023", "DOM", "DOM.Iterable"],
"module": "ESNext",
"lib": ["ES2023", "DOM", "DOM.Iterable"],
"module": "esnext",
"skipLibCheck": true,
"baseUrl": ".",
"paths": {

View file

@ -1,9 +1,9 @@
{
"compilerOptions": {
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
"target": "ES2022",
"target": "es2023",
"lib": ["ES2023"],
"module": "ESNext",
"module": "esnext",
"skipLibCheck": true,
/* Bundler mode */