Skip to content
Open
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
96 changes: 69 additions & 27 deletions react/lib/components/Widget/AltpaymentWidget.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Fragment, useEffect, useRef, useState } from 'react'
import React, { Fragment, useEffect, useMemo, useRef, useState } from 'react'
import { TextField, Select, MenuItem, InputLabel, FormControl, Box, CircularProgress } from '@mui/material'
import { styled } from '@mui/material/styles'
import { QRCodeSVG } from 'qrcode.react'
Expand Down Expand Up @@ -377,38 +377,30 @@ export const AltpaymentWidget: React.FunctionComponent<AltpaymentProps> = props
}
}

const SideshiftCtn = styled('div')({
const SideshiftCtn = useMemo(() => styled('div')({
alignItems: 'center',
justifyContent: 'flex-start',
display: 'flex',
flexDirection: 'column',
boxSizing: 'border-box',
position: 'absolute',
zIndex: 9,
top: 0,
left: 0,
right: 0,
bottom: 0,
position: 'relative',
background: '#f5f5f7',
overflowY: 'auto',
overflowX: 'hidden',
width: '100%',
padding: '16px',
'@media (min-width: 760px)': {
padding: '24px',
},
})
}), [])

const LoadingCenter = styled('div')({
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
justifyContent: 'center',
gap: '16px',
textAlign: 'center',
width: 'max-content',
width: '100%',
minHeight: '300px',
maxWidth: '100%',
})

Expand All @@ -419,11 +411,18 @@ export const AltpaymentWidget: React.FunctionComponent<AltpaymentProps> = props
})

const BackLink = styled('div')({
fontSize: '14px', marginTop: '20px', cursor: 'pointer',
fontSize: '14px', cursor: 'pointer',
border: '1px solid #000', opacity: '0.7', padding: '2px 20px',
borderRadius: '3px', '&:hover': { opacity: '1' },
})
Comment on lines +414 to 417

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate file =="
fd -a 'AltpaymentWidget.tsx$' . || true

echo "== file stats =="
wc -l react/lib/components/Widget/AltpaymentWidget.tsx

echo "== BackLink usages and definitions around referenced ranges =="
sed -n '390,430p' react/lib/components/Widget/AltpaymentWidget.tsx
printf '\n--- range 740-760 ---\n'
sed -n '740,760p' react/lib/components/Widget/AltpaymentWidget.tsx
printf '\n--- range 845-865 ---\n'
sed -n '845,865p' react/lib/components/Widget/AltpaymentWidget.tsx
printf '\n--- range 905-925 ---\n'
sed -n '905,925p' react/lib/components/Widget/AltpaymentWidget.tsx
printf '\n--- range 994-1014 ---\n'
sed -n '994,1014p' react/lib/components/Widget/AltpaymentWidget.tsx

echo "== search BackLink definitions/usages =="
rg -n "BackLink|backToWidget|showManualAmountBackButton|AmountBackButton" react/lib/components/Widget/AltpaymentWidget.tsx

Repository: PayButton/paybutton

Length of output: 5044


Make BackLink keyboard-accessible.

BackLink is rendered as a clickable <div> without focusability or a keyboard handler, so keyboard and assistive-technology users cannot operate these navigation controls. Use a real <button type="button"> or MUI button primitive while preserving the same styling and handling.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@react/lib/components/Widget/AltpaymentWidget.tsx` around lines 414 - 417,
Update the BackLink clickable element to use a native button with type="button"
or an equivalent MUI button primitive, preserving its existing styling and click
handling while making it keyboard-focusable and operable.


const BackRow = styled('div')({
width: '100%',
display: 'flex',
justifyContent: 'center',
marginTop: '30px',
})

const ShiftReady = styled('div')({
width: '100%', display: 'flex', flexDirection: 'column',
minWidth: 0,
Expand Down Expand Up @@ -479,8 +478,16 @@ export const AltpaymentWidget: React.FunctionComponent<AltpaymentProps> = props
})

const AmountError = styled('p')({
position: 'absolute', bottom: '10px', textAlign: 'center',
background: '#00000014', padding: '10px', borderRadius: '5px'
margin: '12px auto 0',
textAlign: 'center',
background: '#00000014',
padding: '10px',
borderRadius: '5px',
minHeight: '28px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
transition: 'opacity 120ms ease',
})

const ErrorMsg = styled('p')({
Expand Down Expand Up @@ -699,6 +706,13 @@ export const AltpaymentWidget: React.FunctionComponent<AltpaymentProps> = props

const isAutoStart = Boolean(preselectedCoin)
const isAutoStartLoading = isAutoStart && !altpaymentShift && !altpaymentError
const showManualAmountBackButton = altpaymentEditable
const amountValidationMessage =
pairAmount && !isAboveMinimumAltpaymentAmount
? 'Amount is below minimum.'
: pairAmount && !isBelowMaximumAltpaymentAmount
? 'Amount is above maximum.'
: ''
Comment on lines +709 to +715

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not treat uninitialized validation flags as failures.

Both flags initially equal null; while pairAmount is truthy, !null evaluates to true, so a valid amount can briefly render “Amount is below minimum” before the validation effect runs. Compare explicitly with === false or initialize the flags to a neutral valid state.

Proposed fix
 const amountValidationMessage =
-  pairAmount && !isAboveMinimumAltpaymentAmount
+  pairAmount && isAboveMinimumAltpaymentAmount === false
     ? 'Amount is below minimum.'
-    : pairAmount && !isBelowMaximumAltpaymentAmount
+    : pairAmount && isBelowMaximumAltpaymentAmount === false
📝 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
const showManualAmountBackButton = altpaymentEditable
const amountValidationMessage =
pairAmount && !isAboveMinimumAltpaymentAmount
? 'Amount is below minimum.'
: pairAmount && !isBelowMaximumAltpaymentAmount
? 'Amount is above maximum.'
: ''
const showManualAmountBackButton = altpaymentEditable
const amountValidationMessage =
pairAmount && isAboveMinimumAltpaymentAmount === false
? 'Amount is below minimum.'
: pairAmount && isBelowMaximumAltpaymentAmount === false
? 'Amount is above maximum.'
: ''
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@react/lib/components/Widget/AltpaymentWidget.tsx` around lines 709 - 715,
Update the amountValidationMessage logic in AltpaymentWidget so null validation
flags do not produce error messages; only display the below- or above-maximum
messages when isAboveMinimumAltpaymentAmount or isBelowMaximumAltpaymentAmount
is explicitly false, while preserving the existing pairAmount requirement.


const renderLoading = (message: string) => (
<LoadingCenter>
Expand All @@ -717,12 +731,28 @@ export const AltpaymentWidget: React.FunctionComponent<AltpaymentProps> = props
</LoadingCenter>
)

const backToWidget = () => {
setUseAltpayment(false)
}
Comment on lines +734 to +736

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reset parent-owned altpayment state before hiding the widget.

Widget.tsx retains coinPair, loadingPair, loadingShift, and shift/error state after setUseAltpayment(false). If Back is pressed during a pending request, the socket is disconnected but loading flags and stale rates remain; reopening can show stale data or hide the rate-selection button indefinitely.

Clear the trade and loading state before leaving the widget.

Proposed fix
 const backToWidget = () => {
+  resetTrade()
+  setLoadingPair(false)
+  setLoadingShift(false)
   setUseAltpayment(false)
 }

Also applies to: 1004-1006

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@react/lib/components/Widget/AltpaymentWidget.tsx` around lines 734 - 736,
Update backToWidget to reset the parent-owned altpayment trade, loading, shift,
and error state before calling setUseAltpayment(false). Reuse the existing
state-reset mechanism or setters exposed by Widget.tsx, and apply the same reset
behavior to the other Back handler around the alternate location.


const backToRateSelection = () => {
autoQuoteRequestedRef.current = false
setAltpaymentError(undefined)
setAltpaymentShift(undefined)
setLoadingShift(false)
setCoinPair(undefined)
}

return (
<SideshiftCtn>
{altpaymentError ? (
<Fragment>
<ErrorMsg>Error: {altpaymentError.errorMessage}</ErrorMsg>
<BackLink onClick={resetTrade}>Back</BackLink>
{showManualAmountBackButton ? (
<BackRow>
<BackLink onClick={resetTrade}>Back</BackLink>
</BackRow>
) : null}
Comment on lines 748 to +755

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Keep an exit or retry action available for every altpayment error.

When altpaymentEditable is false, showManualAmountBackButton is false, so the error branch renders only the error text. Auto-start and fixed-amount users can become trapped in altpayment mode with no way to recover.

Render a Back/Retry action for non-editable flows as well, using backToWidget or an equivalent reset path.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@react/lib/components/Widget/AltpaymentWidget.tsx` around lines 748 - 755,
Update the altpaymentError branch in AltpaymentWidget so non-editable flows also
render an exit or retry action when showManualAmountBackButton is false. Use
backToWidget or the existing resetTrade path as appropriate, while preserving
the current manual-amount Back behavior.

</Fragment>
) : isAutoStartLoading ? (
renderLoading('Loading SideShift...')
Expand Down Expand Up @@ -822,6 +852,11 @@ export const AltpaymentWidget: React.FunctionComponent<AltpaymentProps> = props
</CopyCtn>
</ShiftReadyMain>
</ShiftReadyBody>
{showManualAmountBackButton ? (
<BackRow>
<BackLink onClick={resetTrade}>Back</BackLink>
</BackRow>
) : null}
</ShiftReady>
)
) : loadingShift ? (
Expand Down Expand Up @@ -870,12 +905,17 @@ export const AltpaymentWidget: React.FunctionComponent<AltpaymentProps> = props
animation={animation}
/>
</div>
{pairAmount && !isAboveMinimumAltpaymentAmount && (
<AmountError>Amount is below minimum.</AmountError>
)}
{pairAmount && !isBelowMaximumAltpaymentAmount && (
<AmountError>Amount is above maximum.</AmountError>
)}
<AmountError
aria-live="polite"
style={amountValidationMessage ? { opacity: 1, visibility: 'visible' } : { opacity: 0, visibility: 'hidden' }}
>
{amountValidationMessage || '\u00A0'}
</AmountError>
{showManualAmountBackButton ? (
<BackRow>
<BackLink onClick={backToRateSelection}>Back</BackLink>
</BackRow>
) : null}
</Fragment>
) : (
<Fragment>
Expand Down Expand Up @@ -961,7 +1001,9 @@ export const AltpaymentWidget: React.FunctionComponent<AltpaymentProps> = props
animation={animation}
/>
)}
<BackLink onClick={() => {setUseAltpayment(false)}}>Back</BackLink>
<BackRow>
<BackLink onClick={backToWidget}>Back</BackLink>
</BackRow>
</Fragment>
)
// END: Altpayment region
Expand Down
4 changes: 2 additions & 2 deletions react/lib/components/Widget/Widget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
...(thisUseAltpayment ? {
minWidth: 320,
width: thisAltpaymentShift ? 'min(94vw, 600px)' : 'min(92vw, 420px)',
minHeight: thisAltpaymentShift ? 640 : 520,
minHeight: 420,
} : {}),
}}
pt={0}
Expand Down Expand Up @@ -1183,7 +1183,7 @@ export const Widget: React.FunctionComponent<WidgetProps> = props => {
px={thisUseAltpayment ? 0 : 3}
pt={thisUseAltpayment ? 0 : 2}
position="relative"
sx={thisUseAltpayment ? { minHeight: 480, flex: 1, alignSelf: 'stretch', width: '100%' } : undefined}
sx={thisUseAltpayment ? { flex: 1, alignSelf: 'stretch', width: '100%' } : undefined}
>
{thisUseAltpayment ? (
<AltpaymentWidget
Expand Down
Loading