Skip to content

Commit cd84a43

Browse files
talissoncostaclaude
andcommitted
refactor(design-system): fold SuccessMessage into Banner, deduplicate ErrorMessage
messages/ErrorMessage was a near-copy of the one beside it, differing only in import style, interface vs type, ?? vs ||, and a displayName. That drift is how enabledButton ended up alive in one copy and dead in the other. The file stays so existing imports keep working, but it now re-exports the real one rather than carrying a second implementation. SuccessMessage renders a Banner and keeps its bold title. Its url, buttonText, isClosable, close and infoMessageClass props had no callers at all, and its one successStyles caller was setting a margin the Banner does not have. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 0281d34 commit cd84a43

3 files changed

Lines changed: 15 additions & 141 deletions

File tree

frontend/web/components/TestWebhook.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,7 @@ const TestWebhook: FC<TestWebhookType> = ({ scope, secret, webhookUrl }) => {
2424
{backendError && <ErrorMessage error={backendError} />}
2525
{isBackendSuccess && (
2626
<div style={{ maxWidth: 'fit-content' }}>
27-
<SuccessMessage
28-
successStyles={{
29-
marginBottom: '0',
30-
width: 'fit-content !important',
31-
}}
32-
>
27+
<SuccessMessage>
3328
{'Your API returned with a successful 200 response.'}
3429
</SuccessMessage>
3530
</div>
Lines changed: 2 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,79 +1,2 @@
1-
import React from 'react'
2-
import Icon from 'components/icons/Icon'
3-
import Button from 'components/base/forms/Button'
4-
import Format from 'common/utils/format'
5-
import Constants from 'common/constants'
6-
7-
interface ErrorMessageProps {
8-
error?: any
9-
errorMessageClass?: string
10-
errorStyles?: React.CSSProperties
11-
enabledButton?: boolean
12-
}
13-
14-
const ErrorMessage: React.FC<ErrorMessageProps> = ({
15-
enabledButton,
16-
error,
17-
errorMessageClass,
18-
errorStyles,
19-
}) => {
20-
const errorMessageClassName = `alert alert-danger ${
21-
errorMessageClass || 'flex-1 align-items-center'
22-
}`
23-
24-
const resolvedError =
25-
error?.data?.metadata?.find((item: any) =>
26-
Object.prototype.hasOwnProperty.call(item, 'non_field_errors'),
27-
)?.non_field_errors?.[0] ??
28-
error?.data ??
29-
error?.message ??
30-
error
31-
32-
if (!error) return null
33-
34-
return (
35-
<div
36-
className={errorMessageClassName}
37-
style={{
38-
display: errorMessageClass ? 'initial' : '',
39-
...errorStyles,
40-
}}
41-
>
42-
<span className='icon-alert'>
43-
<Icon name='close-circle' />
44-
</span>
45-
{resolvedError instanceof Error ? (
46-
resolvedError.message
47-
) : typeof resolvedError === 'object' ? (
48-
<div
49-
dangerouslySetInnerHTML={{
50-
__html: Object.keys(resolvedError)
51-
.map(
52-
(v) =>
53-
`${Format.camelCase(Format.enumeration.get(v))}: ${
54-
resolvedError[v]
55-
}`,
56-
)
57-
.join('<br/>'),
58-
}}
59-
/>
60-
) : (
61-
resolvedError
62-
)}
63-
{enabledButton && (
64-
<Button
65-
className='btn ml-3'
66-
onClick={() => {
67-
document.location.replace(Constants.getUpgradeUrl())
68-
}}
69-
>
70-
Upgrade plan
71-
</Button>
72-
)}
73-
</div>
74-
)
75-
}
76-
77-
ErrorMessage.displayName = 'ErrorMessage'
78-
79-
export default ErrorMessage
1+
// Kept so existing imports keep working. One implementation, next door.
2+
export { default } from 'components/ErrorMessage'
Lines changed: 12 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,21 @@
1-
import React from 'react'
2-
import Icon from 'components/icons/Icon'
3-
import { close as closeIcon } from 'ionicons/icons'
4-
import { IonIcon } from '@ionic/react'
5-
import Button from 'components/base/forms/Button'
1+
import { FC, ReactNode } from 'react'
2+
import Banner from 'components/Banner'
63

7-
interface SuccessMessageProps {
8-
url?: string
9-
buttonText?: string
4+
type SuccessMessageProps = {
5+
children?: ReactNode
106
title?: string
11-
children?: React.ReactNode
12-
infoMessageClass?: string
13-
successStyles?: React.CSSProperties
14-
isClosable?: boolean
15-
close?: () => void
167
}
178

18-
const SuccessMessage: React.FC<SuccessMessageProps> = ({
19-
buttonText,
9+
const SuccessMessage: FC<SuccessMessageProps> = ({
2010
children,
21-
close,
22-
infoMessageClass,
23-
isClosable,
24-
successStyles,
2511
title = 'SUCCESS',
26-
url,
27-
}) => {
28-
const handleOpenNewWindow = () => {
29-
if (url) window.open(url, '_blank')
30-
}
31-
32-
const infoMessageClassName = `alert alert-success ${
33-
infoMessageClass || 'flex-1'
34-
}`
35-
36-
const titleDescClass = infoMessageClass ? `${infoMessageClass} body mr-2` : ''
37-
38-
return (
39-
<div className={infoMessageClassName} style={{ ...successStyles }}>
40-
<span className={`icon-alert ${infoMessageClass} info-icon`}>
41-
<Icon fill='#27AB95' name='checkmark-circle' />
42-
</span>
43-
<div className={titleDescClass}>
44-
<div className='fw-semibold'>{title}</div>
45-
{children}
46-
</div>
47-
{url && (
48-
<Button className='btn my-2' onClick={handleOpenNewWindow}>
49-
{buttonText}
50-
</Button>
51-
)}
52-
{isClosable && (
53-
<a onClick={close} className='mt-n2 mr-n2 pl-2'>
54-
<span className={`icon ${infoMessageClass} close-btn`}>
55-
<IonIcon icon={closeIcon} />
56-
</span>
57-
</a>
58-
)}
12+
}) => (
13+
<Banner variant='success'>
14+
<div>
15+
<div className='fw-semibold'>{title}</div>
16+
{children}
5917
</div>
60-
)
61-
}
62-
63-
SuccessMessage.displayName = 'SuccessMessage'
18+
</Banner>
19+
)
6420

6521
export default SuccessMessage

0 commit comments

Comments
 (0)