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
9 changes: 9 additions & 0 deletions components/Paybutton/LoadingSpinner.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import style from './paybutton.module.css'

export default (): JSX.Element => {
return (
<div className={style.loading_spinner_ctn}>
<div className={style.loading_spinner} />
</div>
)
}
26 changes: 22 additions & 4 deletions components/Paybutton/PaybuttonForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ import { WalletWithAddressesWithPaybuttons } from 'services/walletService'
import Image from 'next/image'
import style from './paybutton.module.css'
import Plus from 'assets/plus.png'
import LoadingSpinner from './LoadingSpinner'

interface IProps {
onSubmit: Function
onSubmit: (data: PaybuttonPOSTParameters) => Promise<void>
paybuttons: []
wallets: WalletWithAddressesWithPaybuttons[]
error: String
Expand All @@ -16,6 +17,7 @@ interface IProps {
export default function PaybuttonForm ({ onSubmit, paybuttons, wallets, error }: IProps): ReactElement {
const { register, handleSubmit, reset } = useForm<PaybuttonPOSTParameters>()
const [modal, setModal] = useState(false)
const [loading, setLoading] = useState(false)

useEffect(() => {
setModal(false)
Expand All @@ -28,6 +30,16 @@ export default function PaybuttonForm ({ onSubmit, paybuttons, wallets, error }:
label: wallet.name
}
})

const handleFormSubmit = async (data: PaybuttonPOSTParameters): Promise<void> => {
setLoading(true)
try {
await onSubmit(data)
} finally {
setLoading(false)
}
}

return (
<>
<div className={style.create_button_ctn}>
Expand All @@ -42,7 +54,13 @@ export default function PaybuttonForm ({ onSubmit, paybuttons, wallets, error }:
<div className={style.form_ctn_inner}>
<h4>Create Button</h4>
<div className={style.form_ctn}>
<form onSubmit={(e) => { void handleSubmit(onSubmit)(e) }} method='post'>
<form
onSubmit={(e) => {
e.preventDefault()
void handleSubmit(handleFormSubmit)()
}}
method="post"
>
<label htmlFor='name'>Name*</label>
<input {...register('name')} type='text' id='name' name='name' placeholder="The unique name of your button" required />
<label htmlFor='wallet'>Wallet*</label>
Expand All @@ -69,8 +87,8 @@ export default function PaybuttonForm ({ onSubmit, paybuttons, wallets, error }:
<textarea {...register('description')} id='description' name='description' placeholder="More information about your button (optional)"/>
<div className={style.btn_row}>
{error !== '' && <div className={style.error_message}>{error}</div>}
<button type='submit' className='button_main'>Submit</button>
<button onClick={() => { setModal(false); reset() }} className='button_outline'>Cancel</button>
<button type='submit' className='button_main loading_btn' disabled={loading}>Submit{loading && <LoadingSpinner />}</button>
<button onClick={() => { setModal(false); reset() }} className='button_outline' disabled={loading}>Cancel</button>
</div>
</form>
</div>
Expand Down
26 changes: 26 additions & 0 deletions components/Paybutton/paybutton.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,32 @@ body[data-theme='dark'] .form_ctn_outer {
font-weight: 600;
}

.loading_spinner_ctn {
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
border-radius: 10px;
z-index: 5;
}

.loading_spinner {
display: inline-block;
width: 24px;
height: 24px;
border: 3px solid rgba(255,255,255,.3);
border-radius: 50%;
border-top-color: var(--primary-text-color);
animation: spin 1s ease-in-out infinite;
}

@keyframes spin {
to { transform: rotate(360deg); }
}

@media (max-width: 960px) {
.arrow {
Expand Down
20 changes: 13 additions & 7 deletions pages/button/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { UserProfile } from '@prisma/client'
import { fetchUserProfileFromId } from 'services/userService'
import { removeUnserializableFields } from 'utils'
import moment from 'moment-timezone'
import LoadingSpinner from 'components/Paybutton/LoadingSpinner'

export const getServerSideProps: GetServerSideProps = async (context) => {
supertokensNode.init(SuperTokensConfig.backendConfig())
Expand Down Expand Up @@ -59,6 +60,7 @@ export default function Button (props: PaybuttonProps): React.ReactElement {
const userProfile = props.userProfile
const timezone = userProfile?.preferredTimezone === '' ? moment.tz.guess() : userProfile.preferredTimezone
const router = useRouter()
const [loading, setLoading] = useState(false)

const updateIsSyncing = (addressStringList: string[]): void => {
const newIsSyncing = { ...isSyncing }
Expand Down Expand Up @@ -118,6 +120,7 @@ export default function Button (props: PaybuttonProps): React.ReactElement {

const downloadCSV = async (paybutton: { id: string, name: string }, currency: string): Promise<void> => {
try {
setLoading(true)
const preferredCurrencyId = userProfile?.preferredCurrencyId ?? ''
let url = `/api/paybutton/download/transactions/${paybutton.id}?currency=${preferredCurrencyId}`
const isCurrencyEmptyOrUndefined = (value: string): boolean => (value === '' || value === undefined)
Expand Down Expand Up @@ -148,6 +151,7 @@ export default function Button (props: PaybuttonProps): React.ReactElement {
} catch (error) {
console.error('An error occurred while downloading the CSV:', error)
} finally {
setLoading(false)
setSelectedCurrency('')
}
}
Expand All @@ -173,30 +177,32 @@ export default function Button (props: PaybuttonProps): React.ReactElement {
id='export-btn'
value={selectedCurrency}
onChange={handleExport}
disabled={loading}
className="button_outline button_small"
style={{ marginBottom: '0', cursor: 'pointer' }}
>
<option value='' disabled> Export as CSV</option>
<option value='' disabled>{loading ? 'Downloading...' : 'Export as CSV'}</option>
<option key="all" value="all">
All Currencies
{loading ? 'Downloading...' : 'All Currencies'}
</option>
{Object.entries(NETWORK_TICKERS_FROM_ID)
.filter(([id]) => paybuttonNetworks.includes(Number(id)))
.map(([id, ticker]) => (
<option key={id} value={ticker}>
{ticker.toUpperCase()}
{loading ? 'Downloading...' : ticker.toUpperCase()}
</option>
))}
</select>
)
: (
<div
<button
onClick={handleExport}
className="button_outline button_small"
disabled={loading}
className="button_outline button_small loading_btn"
style={{ marginBottom: '0', cursor: 'pointer' }}
>
Export as CSV
</div>
Export as CSV{loading && <LoadingSpinner />}
</button>
)}
</div>
</div>
Expand Down
17 changes: 17 additions & 0 deletions styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,23 @@ body[data-theme='dark'] .button_main {
color: #231f20 !important;
}

.button_outline:disabled {
background-color: var(--secondary-bg-color) !important;
color: var(--primary-text-color) !important;
border: none !important;
opacity: 0.6;
cursor: not-allowed !important;
}

.loading_btn {
position: relative;
}

.loading_btn:disabled,
.loading_btn:disabled:hover {
color: transparent !important;
}

body[data-theme='dark'] .button_outline:hover {
border-color: #000;
}
Expand Down
Loading