feat: new banking module (#54720)

* feat: initial SPA setup for banking

* wip: bring over new banking module

* feat: added Espresso design tokens

* feat: button styles

* fix: add all ink colors

* wip: espresso design system changes

* feat: button and badge espresso components

* fix: button styling for reconcile

* feat: Espresso progress bar

* feat: Espresso toggle switch

* feat: Espresso tabs design

* fix: vertical tab support

* fix: button sizing across modals

* feat: Espresso style table layout

* feat: Espresso tooltip

* feat: Espresso elevations and checkbox

* feat: Dialog with Espresso styles

* feat: Espresso textarea

* fix: input styles

* fix: colors on bank picker

* fix: breadcrumb styling

* fix: bank picker styling

* feat: create doctypes and fields for bank reconciliation

* feat: APIs for banking

* fix: use date format parser

* fix: font styling to match Espresso

* wip: settings modal

* feat: settings dialog component

* fix: icons and invalid requests

* feat: preferences tab

* fix: adjust icon stroke width to 1.5

* feat: rule configuration in settings

* fix: remove sheet component

* feat: alert and error banner component

* feat: dropdown in Espresso

* feat: popover and select in Espresso

* fix: cleanup more styles

* fix: match size of link fields

* feat: command styling

* fix: remove unused style tokens

* fix: styles for global date picker dropdown

* fix: styles for match and reconcile

* feat: table Espresso component

* feat: remove all other design tokens

* fix: remove unused tokens

* fix: form elements

* fix: remove unused styles and fix filters in bank transaction list

* feat: fetch bank rec doctypes for filtering

* fix: record payment modal

* feat: support for dark mode switching

* fix: move bank logos to public folder

* feat: add support for RTL

* feat: support for RTL

* chore: send layout direction in dev boot

* fix: make checkbox work in RTL

* feat: dark mode support

* fix: dark mode style

* feat: bank logos in dark mode

* feat: dark mode bank logos

* chore: use dark mode bank logos everywhere

* chore: move rule evaluation to controller

* chore: add tests for bank transaction rules

* fix: move deps to fix actions errors

* fix: move tw-animate-css to deps

* fix: remove shadcn

* fix: do not open modal if no transactions selected

* fix: add translation strings

* feat: add banner on existing bank reconciliation tool

* feat: bank statement import

* fix: translations and layout directions

* fix: validation for transaction matching rule

* fix: styles

* fix: show conflicting transactions in alert

* fix: show help text for new banking module forms

* feat: show total debits and credits

* fix: dark mode colors in automatic config

* feat: add keyboard shortcuts help

* feat: added keyboard shortcut for settings

* fix: decrease size of progress bar

* chore: bump packages

* feat: add tests for statement import

* fix: settings dialog

* fix: show banner on small screens

* fix: show banner when no bank account set
This commit is contained in:
Nikhil Kothari
2026-05-09 23:14:58 +05:30
committed by GitHub
parent 332026fe5e
commit 6de5367f12
262 changed files with 39467 additions and 14 deletions

View File

@@ -0,0 +1,64 @@
import { getErrorMessages } from '@/lib/frappe'
import { FrappeError } from 'frappe-react-sdk'
import { Alert, AlertDescription, AlertProps, AlertTitle } from '@/components/ui/alert'
import { AlertCircle } from 'lucide-react'
import MarkdownRenderer from '@/components/ui/markdown'
import _ from '@/lib/translate'
import { useMemo } from 'react'
type ErrorBannerProps = AlertProps & {
error?: FrappeError | null,
overrideHeading?: string,
}
interface ParsedErrorMessage {
message: string,
title?: string,
indicator?: string,
}
const parseHeading = (message?: ParsedErrorMessage) => {
if (message?.title === 'Message' || message?.title === 'Error') return "There was an error."
return message?.title
}
const wrapLooseListItemsWithUl = (html: string): string => {
// Regex matches consecutive <li>...</li> blocks not wrapped in <ul> or <ol>
// It wraps them in a <ul> if not already wrapped.
return html.replace(/(?:^|[^>])((<li[\s\S]*?<\/li>)+)(?![\s\S]*?<\/ul>)(?![\s\S]*?<\/ol>)/g, (match, p1) => {
// Check if the match already has <ul> or <ol> wrapping (simple check)
if (/^<ul>/.test(p1) || /^<ol>/.test(p1)) {
return match // Already wrapped, keep as is
}
return match.replace(p1, `<ul>${p1}</ul>`)
})
}
const ErrorBanner = ({ error, overrideHeading, ...props }: ErrorBannerProps) => {
//exc_type: "ValidationError" or "PermissionError" etc
// exc: With entire traceback - useful for reporting maybe
// httpStatus and httpStatusText - not needed
// _server_messages: Array of messages - useful for showing to user
// console.log(JSON.parse(error?._server_messages!))
const messages = useMemo(() => {
return getErrorMessages(error)
}, [error])
return (
<Alert theme={messages[0]?.indicator === 'yellow' ? 'amber' : "red"} {...props}>
<AlertCircle />
<AlertTitle>{overrideHeading ?? parseHeading(messages[0])}</AlertTitle>
<AlertDescription>
{messages.map((m, i) => {
const safeMessage = wrapLooseListItemsWithUl(m.message)
return <MarkdownRenderer content={safeMessage} key={i} />
})}
</AlertDescription>
</Alert>
)
}
export default ErrorBanner