Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Prevent closing modal & disable input during form submission #124

Open
wants to merge 2 commits into
base: development
Choose a base branch
from
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
1 change: 1 addition & 0 deletions src/components/CreateProfileModal/CreateProfileModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export default function CreateProfileModal({ setIsOpen, isOpen }: NewRepoModalPr
})

function closeModal() {
if (isSubmitting) return
setIsOpen(false)
}

Expand Down
19 changes: 13 additions & 6 deletions src/components/DragonDeploy/ArNSUpdateModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import SVG from 'react-inlinesvg'

import CloseCrossIcon from '@/assets/icons/close-cross.svg'
import { Button } from '@/components/common/buttons'
import useCursorNotAllowed from '@/helpers/hooks/useCursorNotAllowded'
import { withAsync } from '@/helpers/withAsync'
import { getANT, getDomainStatus, updateArNSDomain } from '@/lib/dragondeploy/arns'
import { useGlobalStore } from '@/stores/globalStore'
Expand All @@ -19,7 +20,7 @@ export default function ArNSDomainModal() {
const [isLoading, setIsLoading] = useState(false)
const [domainTxId, setDomainTxId] = useState('')
const [intervalValue, setIntervalValue] = useState<number>()

const { cursorNotAllowed, closeModalCursor } = useCursorNotAllowed(isLoading)
const [connectedAddress, selectedRepo, updateDomain] = useGlobalStore((state) => [
state.authState.address,
state.repoCoreState.selectedRepo.repo,
Expand All @@ -41,6 +42,7 @@ export default function ArNSDomainModal() {
}, [deployment, domainTxId, domain])

function closeModal() {
if (isLoading) return
setIsOpen(false)
}

Expand Down Expand Up @@ -145,7 +147,7 @@ export default function ArNSDomainModal() {
ArNS Domain
</Button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Dialog as="div" className={clsx('relative z-10', cursorNotAllowed)} onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
Expand Down Expand Up @@ -174,7 +176,7 @@ export default function ArNSDomainModal() {
<Dialog.Title as="h3" className="text-xl font-medium text-gray-900">
ArNS Domain
</Dialog.Title>
<SVG onClick={closeModal} src={CloseCrossIcon} className="w-6 h-6 cursor-pointer" />
<SVG onClick={closeModal} src={CloseCrossIcon} className={clsx('w-6 h-6', closeModalCursor)} />
</div>
<Dialog.Description className="mt-4">
<div className="flex justify-center items-center w-full">
Expand All @@ -198,12 +200,16 @@ export default function ArNSDomainModal() {
</div>
{!updateNeeded && !isUpdated && isOnline && <span>Update in progress...</span>}
{updateNeeded && <span>Update to latest deployment?</span>}
{!isOnline && <span className='text-sm text-gray-600'>Note: It might take ~30 minutes for the domain to go live.</span>}
{!isOnline && (
<span className="text-sm text-gray-600">
Note: It might take ~30 minutes for the domain to go live.
</span>
)}
</div>
<div className="flex flex-col gap-3 justify-center mt-6">
<div className="flex gap-2">
<Button
className="w-full flex justify-center"
className={clsx('w-full flex justify-center', cursorNotAllowed)}
variant="primary-solid"
isLoading={isLoading}
disabled={isLoading || !updateNeeded}
Expand All @@ -213,9 +219,10 @@ export default function ArNSDomainModal() {
Update
</Button>
<Button
className="w-full flex justify-center"
className={clsx('w-full flex justify-center', cursorNotAllowed)}
variant="secondary"
onClick={() => closeModal()}
disabled={isLoading}
>
Cancel
</Button>
Expand Down
10 changes: 7 additions & 3 deletions src/components/DragonDeploy/DragonDeploy.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Dialog, Transition } from '@headlessui/react'
import clsx from 'clsx'
import { useEffect, useState } from 'react'
import { Fragment } from 'react'
import toast from 'react-hot-toast'
Expand All @@ -7,6 +8,7 @@ import SVG from 'react-inlinesvg'
import CloseCrossIcon from '@/assets/icons/close-cross.svg'
import { Button } from '@/components/common/buttons'
import CostEstimatesToolTip from '@/components/CostEstimatesToolTip'
import useCursorNotAllowed from '@/helpers/hooks/useCursorNotAllowded'
import {
type Commit,
type File,
Expand All @@ -28,6 +30,7 @@ export default function DragonDeploy() {
const [currentDeployment, setCurrentDeployment] = useState<Deployment>()
const [uploadPercent, setUploadPercent] = useState(0)
const [branchToRestore, setBranchToRestore] = useState('')
const { cursorNotAllowed, closeModalCursor } = useCursorNotAllowed(isDeploying)
const [currentBranch, selectedRepo, branchState, branchActions, addDeployment] = useGlobalStore((state) => [
state.branchState.currentBranch,
state.repoCoreState.selectedRepo.repo,
Expand All @@ -53,6 +56,7 @@ export default function DragonDeploy() {
}, [isOpen])

function closeModal() {
if (isDeploying) return
setIsOpen(false)
}

Expand Down Expand Up @@ -115,7 +119,7 @@ export default function DragonDeploy() {
Dragon Deploy
</Button>
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Dialog as="div" className={clsx('relative z-10', cursorNotAllowed)} onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
Expand Down Expand Up @@ -144,7 +148,7 @@ export default function DragonDeploy() {
<Dialog.Title as="h3" className="text-xl font-medium text-gray-900">
Dragon Deploy
</Dialog.Title>
<SVG onClick={closeModal} src={CloseCrossIcon} className="w-6 h-6 cursor-pointer" />
<SVG onClick={closeModal} src={CloseCrossIcon} className={clsx('w-6 h-6', closeModalCursor)} />
</div>
<Dialog.Description className="mt-4">
<div className="flex flex-col text-md gap-2">
Expand Down Expand Up @@ -188,7 +192,7 @@ export default function DragonDeploy() {
<Button
isLoading={isDeploying}
disabled={isDeploying || isProcessing || !!currentDeployment}
className="w-full justify-center font-medium"
className={clsx('w-full justify-center font-medium', cursorNotAllowed)}
onClick={deploy}
loadingText="Deploying"
variant="primary-solid"
Expand Down
7 changes: 7 additions & 0 deletions src/helpers/hooks/useCursorNotAllowded.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import clsx from 'clsx'

export default function useCursorNotAllowed(isSubmitting: boolean) {
const cursorNotAllowed = clsx({ 'cursor-not-allowed': isSubmitting })
const closeModalCursor = isSubmitting ? 'cursor-not-allowed' : 'cursor-pointer'
return { cursorNotAllowed, closeModalCursor }
}
30 changes: 23 additions & 7 deletions src/pages/home/components/NewRepoModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import CloseCrossIcon from '@/assets/icons/close-cross.svg'
import { Button } from '@/components/common/buttons'
import CostEstimatesToolTip from '@/components/CostEstimatesToolTip'
import { trackGoogleAnalyticsEvent } from '@/helpers/google-analytics'
import useCursorNotAllowed from '@/helpers/hooks/useCursorNotAllowded'
import { withAsync } from '@/helpers/withAsync'
import { createNewRepo, postNewRepo } from '@/lib/git'
import { fsWithName } from '@/lib/git/helpers/fsWithName'
Expand Down Expand Up @@ -41,6 +42,7 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
const [isSubmitting, setIsSubmitting] = React.useState(false)
const [visibility, setVisibility] = React.useState('public')
const navigate = useNavigate()
const { cursorNotAllowed, closeModalCursor } = useCursorNotAllowed(isSubmitting)
const [authState] = useGlobalStore((state) => [state.authState])
const {
register,
Expand All @@ -51,6 +53,7 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
})

function closeModal() {
if (isSubmitting) return
setIsOpen(false)
}

Expand Down Expand Up @@ -96,16 +99,19 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
}
} catch (error) {
trackGoogleAnalyticsEvent('Repository', 'Failed to create a new repo', 'Create new repo')
toast.error(`Failed to create new repository.`)
}
setIsSubmitting(false)
}

function handleRepositoryVisibilityChange(event: ChangeEvent<HTMLInputElement>) {
if (isSubmitting) return
setVisibility(event.target.value)
}

return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Dialog as="div" className={clsx('relative z-10', cursorNotAllowed)} onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
Expand Down Expand Up @@ -134,7 +140,7 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
<Dialog.Title as="h3" className="text-xl font-medium text-gray-900">
Create a new Repository
</Dialog.Title>
<SVG onClick={closeModal} src={CloseCrossIcon} className="w-6 h-6 cursor-pointer" />
<SVG onClick={closeModal} src={CloseCrossIcon} className={clsx('w-6 h-6', closeModalCursor)} />
</div>
<div className="mt-6 flex flex-col gap-2.5">
<div>
Expand All @@ -146,9 +152,11 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
{...register('title')}
className={clsx(
'bg-white border-[1px] text-gray-900 text-base rounded-lg hover:shadow-[0px_2px_4px_0px_rgba(0,0,0,0.10)] focus:border-primary-500 focus:border-[1.5px] block w-full px-3 py-[10px] outline-none',
errors.title ? 'border-red-500' : 'border-gray-300'
errors.title ? 'border-red-500' : 'border-gray-300',
cursorNotAllowed
)}
placeholder="my-cool-repo"
disabled={isSubmitting}
/>
{errors.title && <p className="text-red-500 text-sm italic mt-2">{errors.title?.message}</p>}
</div>
Expand All @@ -161,9 +169,11 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
{...register('description')}
className={clsx(
'bg-white border-[1px] text-gray-900 text-base rounded-lg hover:shadow-[0px_2px_4px_0px_rgba(0,0,0,0.10)] focus:border-primary-500 focus:border-[1.5px] block w-full px-3 py-[10px] outline-none',
errors.description ? 'border-red-500' : 'border-gray-300'
errors.description ? 'border-red-500' : 'border-gray-300',
cursorNotAllowed
)}
placeholder="A really cool repo fully decentralized"
disabled={isSubmitting}
/>
{errors.description && (
<p className="text-red-500 text-sm italic mt-2">{errors.description?.message}</p>
Expand All @@ -179,7 +189,10 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
onChange={handleRepositoryVisibilityChange}
value="public"
defaultChecked
className="mr-2 rounded-full h-4 w-4 checked:accent-primary-700 accent-primary-600 bg-white focus:ring-primary-600 outline-none"
className={clsx(
'mr-2 rounded-full h-4 w-4 checked:accent-primary-700 accent-primary-600 bg-white focus:ring-primary-600 outline-none',
cursorNotAllowed
)}
/>
Public
</label>
Expand All @@ -190,7 +203,10 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
disabled={authState.method === 'othent'}
onChange={handleRepositoryVisibilityChange}
value="private"
className="mr-2 rounded-full h-4 w-4 checked:accent-primary-700 accent-primary-600 bg-white focus:ring-primary-600 outline-none"
className={clsx(
'mr-2 rounded-full h-4 w-4 checked:accent-primary-700 accent-primary-600 bg-white focus:ring-primary-600 outline-none',
cursorNotAllowed
)}
/>
Private
</label>
Expand All @@ -205,7 +221,7 @@ export default function NewRepoModal({ setIsOpen, isOpen }: NewRepoModalProps) {
<Button
isLoading={isSubmitting}
disabled={Object.keys(errors).length > 0 || isSubmitting}
className="w-full justify-center font-medium"
className={clsx('w-full justify-center font-medium', cursorNotAllowed)}
onClick={handleSubmit(handleCreateBtnClick)}
variant="primary-solid"
>
Expand Down
22 changes: 15 additions & 7 deletions src/pages/issue/read/tabs/bounty/NewBountyModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import * as yup from 'yup'
import ArweaveLogo from '@/assets/arweave.svg'
import CloseCrossIcon from '@/assets/icons/close-cross.svg'
import { Button } from '@/components/common/buttons'
import useCursorNotAllowed from '@/helpers/hooks/useCursorNotAllowded'
import { withAsync } from '@/helpers/withAsync'
import { useGlobalStore } from '@/stores/globalStore'

type NewBountyModalProps = {
Expand All @@ -36,6 +38,7 @@ export default function NewBountyModal({ isOpen, setIsOpen }: NewBountyModalProp
const { issueId } = useParams()
const [addBounty] = useGlobalStore((state) => [state.issuesActions.addBounty])
const [isSubmitting, setIsSubmitting] = React.useState(false)
const { cursorNotAllowed, closeModalCursor } = useCursorNotAllowed(isSubmitting)
const {
register,
handleSubmit,
Expand All @@ -49,20 +52,21 @@ export default function NewBountyModal({ isOpen, setIsOpen }: NewBountyModalProp

const unixTimestampOfExpiry = Math.floor(data.expiry.getTime() / 1000)

await addBounty(+issueId!, data.amount, unixTimestampOfExpiry)
const { error } = await withAsync(() => addBounty(+issueId!, data.amount, unixTimestampOfExpiry))

setIsSubmitting(false)

closeModal()
if (!error) closeModal()
}

function closeModal() {
if (isSubmitting) return
setIsOpen(false)
}

return (
<Transition appear show={isOpen} as={Fragment}>
<Dialog as="div" className="relative z-10" onClose={closeModal}>
<Dialog as="div" className={clsx('relative z-10', cursorNotAllowed)} onClose={closeModal}>
<Transition.Child
as={Fragment}
enter="ease-out duration-300"
Expand Down Expand Up @@ -91,7 +95,7 @@ export default function NewBountyModal({ isOpen, setIsOpen }: NewBountyModalProp
<Dialog.Title as="h3" className="text-xl font-medium text-gray-900">
Add bounty
</Dialog.Title>
<SVG onClick={closeModal} src={CloseCrossIcon} className="w-6 h-6 cursor-pointer" />
<SVG onClick={closeModal} src={CloseCrossIcon} className={clsx('w-6 h-6', closeModalCursor)} />
</div>
<div className="mt-6 flex flex-col gap-2.5">
<div className="flex flex-col gap-1">
Expand All @@ -115,12 +119,14 @@ export default function NewBountyModal({ isOpen, setIsOpen }: NewBountyModalProp
{...register('amount')}
className={clsx(
'bg-white border-[1px] text-gray-900 text-base rounded-lg hover:shadow-[0px_2px_4px_0px_rgba(0,0,0,0.10)] focus:border-primary-500 focus:border-[1.5px] block w-full px-3 py-[10px] outline-none',
errors.amount ? 'border-red-500' : 'border-gray-300'
errors.amount ? 'border-red-500' : 'border-gray-300',
cursorNotAllowed
)}
step="0.5"
type="number"
placeholder="2"
min={'0'}
disabled={isSubmitting}
/>
<div className="h-full absolute right-4 top-0 flex items-center">
<span className="font-medium text-gray-600">AR</span>
Expand All @@ -137,11 +143,13 @@ export default function NewBountyModal({ isOpen, setIsOpen }: NewBountyModalProp
{...register('expiry')}
className={clsx(
'bg-white border-[1px] text-gray-900 text-base rounded-lg hover:shadow-[0px_2px_4px_0px_rgba(0,0,0,0.10)] focus:border-primary-500 focus:border-[1.5px] block w-full px-3 py-[10px] outline-none',
errors.expiry ? 'border-red-500' : 'border-gray-300'
errors.expiry ? 'border-red-500' : 'border-gray-300',
cursorNotAllowed
)}
type="date"
min={new Date().toISOString().split('T')[0]}
placeholder="2"
disabled={isSubmitting}
/>
</div>
{errors.expiry && <p className="text-red-500 text-sm italic mt-2">{errors.expiry.message}</p>}
Expand All @@ -151,7 +159,7 @@ export default function NewBountyModal({ isOpen, setIsOpen }: NewBountyModalProp
<div className="mt-6">
<Button
disabled={Object.keys(errors).length > 0 || isSubmitting}
className="w-full justify-center font-medium"
className={clsx('w-full justify-center font-medium', cursorNotAllowed)}
onClick={handleSubmit(handleAddButtonClick)}
variant="primary-solid"
isLoading={isSubmitting}
Expand Down
Loading