Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 32 additions & 3 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -825,19 +825,48 @@ randomSatoshis = true
#### ** HTML **

```html
disabled="true"
hide-toasts="true"
```

#### ** JavaScript **

```javascript
disabled: true
hideToasts: true
```

#### ** React **

```react
disabled = true
hideToasts = true
```

<!-- tabs:end -->

## hide-send-button

> **The ‘hide-send-button’ parameter specifies whether or not the 'Send with XEC/BCH' button should be hidden.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing closing ** in the blockquote description.

Every other parameter description in this file closes the bold span before the period (e.g., > **The 'hide-toasts' parameter ... detected.**). Line 847 leaves the bold open.

📝 Proposed fix
-> **The 'hide-send-button' parameter specifies whether or not the 'Send with XEC/BCH' button should be hidden.
+> **The 'hide-send-button' parameter specifies whether the 'Send with XEC/BCH' button should be hidden.**

(The fix above also drops the wordy "or not", per the LanguageTool style hint.)

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
> **The hide-send-button parameter specifies whether or not the 'Send with XEC/BCH' button should be hidden.
> **The 'hide-send-button' parameter specifies whether the 'Send with XEC/BCH' button should be hidden.**
🧰 Tools
🪛 LanguageTool

[style] ~847-~847: ‘whether or not’ might be wordy. Consider a shorter alternative.
Context: ... ‘hide-send-button’ parameter specifies whether or not the 'Send with XEC/BCH' button should b...

(EN_WORDINESS_PREMIUM_WHETHER_OR_NOT)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/README.md` at line 847, Close the unclosed bold span in the blockquote
for the hide-send-button parameter: update the line starting with "> **The
‘hide-send-button’ parameter..." to end the bold span before the period (e.g.,
"> **The ‘hide-send-button’ parameter specifies whether the 'Send with XEC/BCH'
button should be hidden.**"), and optionally remove the redundant "or not" to
match the style used for other parameter descriptions like 'hide-toasts'.


?> This parameter is optional. Default value is false. Possible values are true or false.

**Example:**
<!-- tabs:start -->

#### ** HTML **

```html
hide-send-button="true"
```

#### ** JavaScript **

```javascript
hideSendButton: true
```

#### ** React **

```react
hideSendButton = true
```

<!-- tabs:end -->
Expand Down
33 changes: 30 additions & 3 deletions docs/zh-cn/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -792,23 +792,50 @@ randomSatoshis = true
#### ** HTML **

```html
disabled="true"
hide-toasts="true"
```

#### ** JavaScript **

```javascript
disabled: true
hideToasts: true
```

#### ** React **

```react
disabled = true
hideToasts = true
```

<!-- tabs:end -->

## hide-send-button

> **参数'hide-send-button'指定是否隐藏'使用 XEC/BCH 发送'按钮。**

?> 此参数是可选的。默认值为false。可能的值为true或false。

**示例:**
<!-- tabs:start -->

#### ** HTML **

```html
hide-send-button="true"
```

#### ** JavaScript **

```javascript
hideSendButton: true
```

#### ** React **

```react
hideSendButton = true
```

<!-- tabs:end -->

## disable-enforce-focus
Expand Down
35 changes: 32 additions & 3 deletions docs/zh-tw/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -792,19 +792,48 @@ randomSatoshis = true
#### ** HTML **

```html
disabled="true"
hide-toasts="true"
```

#### ** JavaScript **

```javascript
disabled: true
hideToasts: true
```

#### ** React **

```react
disabled = true
hideToasts = true
```

<!-- tabs:end -->

## hide-send-button

> **參數'hide-send-button'指定是否隱藏'使用 XEC/BCH 發送'按鈕。**

?> 此參數是可選的。默認值為false。可能的值為true或false。

**範例:**
<!-- tabs:start -->

#### ** HTML **

```html
hide-send-button="true"
```

#### ** JavaScript **

```javascript
hideSendButton: true
```

#### ** React **

```react
hideSendButton = true
```

<!-- tabs:end -->
Expand Down
7 changes: 7 additions & 0 deletions paybutton/dev/demo/paybutton-generator.html
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,11 @@
false-value="false">
<label for="disable-altpayment">Disable Altpayment</label>
</div>
<div class="form-input toggle">
<input type="checkbox" id="hide-send-button" v-model="paybuttonProps.hideSendButton" true-value="true"
false-value="false">
<label for="hide-send-button">Hide Send Button</label>
</div>
</div>
<div>
<div class="form-input toggle">
Expand Down Expand Up @@ -228,6 +233,7 @@
:on-success="mySuccessFuction"
:on-transaction="myTransactionFuction"
:disable-altpayment="paybuttonProps.disableAltpayment"
:hide-send-button="paybuttonProps.hideSendButton"
:transaction-text="paybuttonProps.transactionText"
:auto-close="paybuttonProps.autoClose"
:op-return="paybuttonProps.opReturn">
Expand Down Expand Up @@ -260,6 +266,7 @@
hideToasts: false,
disableEnforceFocus: false,
disableAltpayment: false,
hideSendButton: false,
contributionOffset: undefined,
opReturn:undefined,
transactiontext: '',
Expand Down
1 change: 1 addition & 0 deletions paybutton/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ const allowedProps = [
'currency',
'displayCurrency',
'hideToasts',
'hideSendButton',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Get context around line 85 in index.tsx
sed -n '75,95p' paybutton/src/index.tsx

Repository: PayButton/paybutton

Length of output: 333


🏁 Script executed:

# Get context around line 190 in index.tsx
sed -n '180,200p' paybutton/src/index.tsx

Repository: PayButton/paybutton

Length of output: 720


🏁 Script executed:

# Search for hideSendButton usage in Widget.tsx
rg 'hideSendButton' paybutton/src/ -B 2 -A 2

Repository: PayButton/paybutton

Length of output: 269


🏁 Script executed:

# Check the entire allowedProps and attributes handling section
sed -n '70,210p' paybutton/src/index.tsx

Repository: PayButton/paybutton

Length of output: 3695


🏁 Script executed:

# Find and examine Widget.tsx to see how hideSendButton is used
find paybutton/src -name 'Widget*' -type f

Repository: PayButton/paybutton

Length of output: 45


🏁 Script executed:

# Search for how hideSendButton is conditionally used in the codebase
rg 'hideSendButton' paybutton/src -B 3 -A 3

Repository: PayButton/paybutton

Length of output: 350


🏁 Script executed:

# Check if there are any boolean coercions for hideSendButton elsewhere
rg "hideSendButton.*===" paybutton/src

Repository: PayButton/paybutton

Length of output: 45


🏁 Script executed:

# Search for Widget component definition
rg 'Widget' paybutton/src --type tsx --type ts | head -20

Repository: PayButton/paybutton

Length of output: 90


🏁 Script executed:

# Look for all tsx/ts files
find paybutton/src -name '*.tsx' -o -name '*.ts'

Repository: PayButton/paybutton

Length of output: 86


🏁 Script executed:

# Search for where hideSendButton is actually used in component logic
rg 'hideSendButton' . -B 5 -A 5 --type tsx --type ts

Repository: PayButton/paybutton

Length of output: 90


🏁 Script executed:

# List all files in paybutton/src
ls -la paybutton/src/

Repository: PayButton/paybutton

Length of output: 232


🏁 Script executed:

# Search for hideSendButton without file type restrictions
rg 'hideSendButton' paybutton/ -B 5 -A 5

Repository: PayButton/paybutton

Length of output: 3482


🏁 Script executed:

# Check if Widget is imported or defined
rg 'Widget' paybutton/src -B 2 -A 2

Repository: PayButton/paybutton

Length of output: 1984


🏁 Script executed:

# Verify the exact lines around the hideToasts coercion to ensure nothing was missed
sed -n '185,195p' paybutton/src/index.tsx

Repository: PayButton/paybutton

Length of output: 404


hideSendButton HTML attribute is never coerced to boolean — hide-send-button="false" will incorrectly hide the button.

Every HTML attribute read through el.getAttribute() arrives as a string. hideToasts is explicitly coerced at line 190:

props.hideToasts = attributes.hideToasts === 'true';

hideSendButton is missing the equivalent conversion, so:

  • hide-send-button="true" → string "true" → truthy → button hidden ✓
  • hide-send-button="false" → string "false"truthy → button hidden ✗

Note: the new Widget tests pass hideSendButton as a JS boolean directly, so they bypass this code path entirely and won't catch this.

🐛 Proposed fix
  props.hideToasts = attributes.hideToasts === 'true';
+ props.hideSendButton = attributes.hideSendButton === 'true';

Also applies to: 190-190

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@paybutton/src/index.tsx` at line 85, The HTML attribute hide-send-button is
read as a string and never coerced to boolean, so set props.hideSendButton the
same way hideToasts is handled: convert attributes.hideSendButton === 'true'
before assigning to props.hideSendButton (same pattern used at
attributes.hideToasts and props.hideToasts), updating the attribute-to-prop
mapping in paybutton/src/index.tsx (look for attributes.hideSendButton and
props.hideSendButton) so "false" correctly yields false.

'hoverText',
'onSuccess',
'onTransaction',
Expand Down
3 changes: 3 additions & 0 deletions react/lib/components/PayButton/PayButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export interface PayButtonProps extends ButtonProps {
autoClose?: boolean | number | string;
disableAltpayment?:boolean
contributionOffset?:number
hideSendButton?: boolean;
size?: ButtonSize;
sizeScaleAlreadyApplied?: boolean;
donationAddress?: string;
Expand Down Expand Up @@ -89,6 +90,7 @@ export const PayButton = ({
autoClose = false,
disableAltpayment,
contributionOffset,
hideSendButton,
size = 'md',
sizeScaleAlreadyApplied = false,
donationRate = DEFAULT_DONATION_RATE,
Expand Down Expand Up @@ -435,6 +437,7 @@ export const PayButton = ({
hoverText={hoverText}
disableAltpayment={disableAltpayment}
contributionOffset={contributionOffset}
hideSendButton={hideSendButton}
autoClose={autoClose}
useAltpayment={useAltpayment}
setUseAltpayment={setUseAltpayment}
Expand Down
3 changes: 3 additions & 0 deletions react/lib/components/PaymentDialog/PaymentDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export interface PaymentDialogProps extends ButtonProps {
apiBaseUrl?: string;
disableAltpayment?: boolean;
contributionOffset?: number;
hideSendButton?: boolean;
useAltpayment: boolean
setUseAltpayment: Function;
txsSocket?: Socket;
Expand Down Expand Up @@ -99,6 +100,7 @@ export const PaymentDialog = ({
hoverText,
disableAltpayment,
contributionOffset,
hideSendButton,
autoClose = true,
useAltpayment,
setUseAltpayment,
Expand Down Expand Up @@ -231,6 +233,7 @@ export const PaymentDialog = ({
hoverText={hoverText}
disableAltpayment={disableAltpayment}
contributionOffset={contributionOffset}
hideSendButton={hideSendButton}
useAltpayment={useAltpayment}
setUseAltpayment={setUseAltpayment}
setTxsSocket={setTxsSocket}
Expand Down
4 changes: 3 additions & 1 deletion react/lib/components/Widget/Widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ export interface WidgetProps {
newTxText?: string;
transactionText?: string;
convertedCurrencyObj?: CurrencyObject;
hideSendButton?: boolean;
setConvertedCurrencyObj?: Function;
setPaymentId?: Function;
}
Expand Down Expand Up @@ -203,6 +204,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
donationRate = DEFAULT_DONATION_RATE,
setConvertedCurrencyObj = () => {},
setPaymentId,
hideSendButton,
} = props;
const [loading, setLoading] = useState(true);
const [draftAmount, setDraftAmount] = useState<string>("")
Expand Down Expand Up @@ -1347,7 +1349,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
</Box>
) : null}

{success ? null : (
{success || hideSendButton ? null : (
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check isPropsTrue usage in Widget.tsx and surrounding boolean prop checks
rg -n "isPropsTrue" react/lib/components/Widget/Widget.tsx

Repository: PayButton/paybutton

Length of output: 469


🏁 Script executed:

#!/bin/bash
# Get lines around 1352 to see the hideSendButton check
sed -n '1345,1395p' react/lib/components/Widget/Widget.tsx

Repository: PayButton/paybutton

Length of output: 1830


🏁 Script executed:

#!/bin/bash
# Get lines around 1276, 1360, 1368 to compare boolean prop usage
echo "=== Line 1276 (editable) ===" && sed -n '1270,1280p' react/lib/components/Widget/Widget.tsx
echo -e "\n=== Line 1360 (disabled) ===" && sed -n '1355,1365p' react/lib/components/Widget/Widget.tsx
echo -e "\n=== Line 1368 (disableAltpayment) ===" && sed -n '1363,1375p' react/lib/components/Widget/Widget.tsx

Repository: PayButton/paybutton

Length of output: 1430


🏁 Script executed:

#!/bin/bash
# Verify hideSendButton prop definition and destructuring
rg -n "hideSendButton" react/lib/components/Widget/Widget.tsx | head -20

Repository: PayButton/paybutton

Length of output: 173


🏁 Script executed:

#!/bin/bash
# Find the Vue demo file to check string attribute handling
find . -type f \( -name "*.vue" -o -name "*demo*.html" -o -name "*demo*.tsx" \) | head -20

Repository: PayButton/paybutton

Length of output: 45


hideSendButton must be wrapped with isPropsTrue()—it is the only boolean flag prop in this component that bypasses this check.

Every other boolean flag prop uses isPropsTrue() before truthiness evaluation: editable (line 1276), disabled (line 1360), disableAltpayment (line 1368). The bare hideSendButton at line 1352 breaks this pattern and risks malfunction if the prop arrives as a string (e.g., from the Vue demo's true-value="true" false-value="false" or from Web Component HTML attribute coercion). The string "false" is truthy in JavaScript, so toggling the checkbox off would leave the button permanently hidden.

Proposed fix
-            {success || hideSendButton ? null : (
+            {success || isPropsTrue(hideSendButton) ? null : (
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{success || hideSendButton ? null : (
{success || isPropsTrue(hideSendButton) ? null : (
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@react/lib/components/Widget/Widget.tsx` at line 1352, The conditional
rendering uses the bare prop hideSendButton (in the JSX expression currently
written as {success || hideSendButton ? null : (...)}) which breaks the
boolean-coercion pattern; change it to use isPropsTrue(hideSendButton) (i.e.,
{success || isPropsTrue(hideSendButton) ? null : (...)}), matching how other
flags like editable, disabled, and disableAltpayment are evaluated so
string-valued props like "false" don't erroneously hide the button.

<Box pt={2} flex={1} sx={classes.button_container}>
{
// Use createElement to avoid JSX element-type incompatibility from duplicate React types
Expand Down
3 changes: 3 additions & 0 deletions react/lib/components/Widget/WidgetContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export interface WidgetContainerProps
donationAddress?: string
donationRate?: number
convertedCurrencyObj?: CurrencyObject;
hideSendButton?: boolean;
}

const snackbarOptionsSuccess: OptionsObject = {
Expand Down Expand Up @@ -141,6 +142,7 @@ export const WidgetContainer: React.FunctionComponent<WidgetContainerProps> =
donationRate,
convertedCurrencyObj,
setConvertedCurrencyObj,
hideSendButton,
...widgetProps
} = props;
const [internalCurrencyObj, setInternalCurrencyObj] = useState<CurrencyObject>();
Expand Down Expand Up @@ -426,6 +428,7 @@ export const WidgetContainer: React.FunctionComponent<WidgetContainerProps> =
convertedCurrencyObj={convertedCurrencyObj}
setConvertedCurrencyObj={setConvertedCurrencyObj}
setPaymentId={setThisPaymentId}
hideSendButton={hideSendButton}
/>
</React.Fragment>
);
Expand Down
99 changes: 99 additions & 0 deletions react/lib/tests/components/PayButton.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -469,3 +469,102 @@ describe('PayButton – UI shows updated amount + QR after reopen', () => {
)
})

describe('PayButton – hideSendButton in dialog', () => {
test.each(CRYPTO_CASES)(
'send button is hidden in dialog when hideSendButton=true (%s)',
async ({ currency, address }) => {
const user = userEvent.setup()

render(
<PayButton
to={address}
amount={5}
currency={currency as any}
hideSendButton={true}
/>
)

// Open the dialog
await user.click(screen.getByRole('button', { name: /donate/i }))

await waitFor(() => {
const { createPayment } = require('../../util');
expect(createPayment).toHaveBeenCalledTimes(1)
})

// Wait for dialog to fully render
await waitFor(() => {
expect(screen.queryByText(/loading/i)).toBeNull()
})

// The send button should not be present in the dialog
const sendButton = screen.queryByRole('button', { name: /send with.*wallet/i })
expect(sendButton).toBeNull()
}
)

test.each(CRYPTO_CASES)(
'send button is visible in dialog when hideSendButton=false (%s)',
async ({ currency, address }) => {
const user = userEvent.setup()

render(
<PayButton
to={address}
amount={5}
currency={currency as any}
hideSendButton={false}
/>
)

// Open the dialog
await user.click(screen.getByRole('button', { name: /donate/i }))

await waitFor(() => {
const { createPayment } = require('../../util');
expect(createPayment).toHaveBeenCalledTimes(1)
})

// Wait for dialog to fully render
await waitFor(() => {
expect(screen.queryByText(/loading/i)).toBeNull()
})

// The send button should be present in the dialog
const sendButton = await screen.findByRole('button', { name: /send with.*wallet/i })
expect(sendButton).toBeTruthy()
}
)

test.each(CRYPTO_CASES)(
'send button is visible by default (hideSendButton undefined) (%s)',
async ({ currency, address }) => {
const user = userEvent.setup()

render(
<PayButton
to={address}
amount={5}
currency={currency as any}
/>
)

// Open the dialog
await user.click(screen.getByRole('button', { name: /donate/i }))

await waitFor(() => {
const { createPayment } = require('../../util');
expect(createPayment).toHaveBeenCalledTimes(1)
})

// Wait for dialog to fully render
await waitFor(() => {
expect(screen.queryByText(/loading/i)).toBeNull()
})

// The send button should be present in the dialog
const sendButton = await screen.findByRole('button', { name: /send with.*wallet/i })
expect(sendButton).toBeTruthy()
}
)
})
Loading