diff --git a/src/components/common/PaymentConfirmationModal/PaymentConfirmationModal.tsx b/src/components/common/PaymentConfirmationModal/PaymentConfirmationModal.tsx new file mode 100644 index 00000000..3dfbc07d --- /dev/null +++ b/src/components/common/PaymentConfirmationModal/PaymentConfirmationModal.tsx @@ -0,0 +1,59 @@ +import React, { PropsWithChildren } from 'react'; +import { Stack } from '@mui/system'; +import { BaseModal } from '../BaseModal'; // Assuming you have a BaseModal component +import IconButton from '../IconButton2'; // Assuming you have an IconButton2 component +import { useCreateModal } from '../useCreateModal'; // Assuming you have a custom hook useCreateModal + +export type PaymentConfirmationModalProps = PropsWithChildren<{ + onClose: () => void; + onConfirmPayment: () => void; + onCancel?: () => void; +}>; + +export const PaymentConfirmationModal = ({ + onClose, + children, + onCancel, + onConfirmPayment +}: PaymentConfirmationModalProps) => { + const closeHandler = () => { + onClose(); + onCancel?.(); + }; + + const confirmPaymentHandler = () => { + onConfirmPayment(); + onClose(); + }; + + return ( + + + {children} + + + + + + + ); +}; + +export const usePaymentConfirmationModal = () => { + const openModal = useCreateModal(); + + const openPaymentConfirmation = (props: Omit) => { + openModal({ + Component: PaymentConfirmationModal, + props + }); + }; + + return { openPaymentConfirmation }; +}; diff --git a/src/components/common/PaymentConfirmationModal/__tests__/PaymentConfirmationModal.spec.tsx b/src/components/common/PaymentConfirmationModal/__tests__/PaymentConfirmationModal.spec.tsx new file mode 100644 index 00000000..0b15ae57 --- /dev/null +++ b/src/components/common/PaymentConfirmationModal/__tests__/PaymentConfirmationModal.spec.tsx @@ -0,0 +1,46 @@ +import '@testing-library/jest-dom'; +import { fireEvent, render, waitFor } from '@testing-library/react'; +import React from 'react'; +import { PaymentConfirmationModal } from '../PaymentConfirmationModal'; + +describe('PaymentConfirmationModal', () => { + it('renders correctly', () => { + const onCloseMock = jest.fn(); + const onConfirmPaymentMock = jest.fn(); + const { getByText } = render( + + Are you sure you want to pay this bounty? + + ); + + expect(getByText('Are you sure you want to pay this bounty?')).toBeInTheDocument(); + }); + + it('calls onClose when Cancel button is clicked', async () => { + const onCloseMock = jest.fn(); + const onConfirmPaymentMock = jest.fn(); + const { getByText } = render( + + Are you sure you want to pay this bounty? + + ); + + fireEvent.click(getByText('Cancel')); + await waitFor(() => expect(onCloseMock).toHaveBeenCalledTimes(1)); + expect(onConfirmPaymentMock).not.toHaveBeenCalled(); + }); + + it('calls onConfirmPayment and onClose when Confirm button is clicked', async () => { + const onCloseMock = jest.fn(); + const onConfirmPaymentMock = jest.fn(); + const { getByText } = render( + + Are you sure you want to pay this bounty? + + ); + + fireEvent.click(getByText('Confirm')); + await waitFor(() => expect(onCloseMock).toHaveBeenCalledTimes(1)); + expect(onConfirmPaymentMock).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/components/common/PaymentConfirmationModal/index.ts b/src/components/common/PaymentConfirmationModal/index.ts new file mode 100644 index 00000000..1ad32cab --- /dev/null +++ b/src/components/common/PaymentConfirmationModal/index.ts @@ -0,0 +1 @@ +export * from './PaymentConfirmationModal'; diff --git a/src/components/common/index.tsx b/src/components/common/index.tsx index 29fe297c..7f046d03 100644 --- a/src/components/common/index.tsx +++ b/src/components/common/index.tsx @@ -22,6 +22,7 @@ export * from './BaseModal'; export * from './DeleteConfirmationModal'; export * from './AfterDeleteNotification'; export * from './ButtonContainer'; +export * from './PaymentConfirmationModal'; export { SearchableSelect, diff --git a/src/components/form/inputs/TextAreaInput.tsx b/src/components/form/inputs/TextAreaInput.tsx index 0a9239fe..d1867240 100644 --- a/src/components/form/inputs/TextAreaInput.tsx +++ b/src/components/form/inputs/TextAreaInput.tsx @@ -92,9 +92,7 @@ export default function TextAreaInput({ const color = colors['light']; if (error) labeltext = `${labeltext} (${error})`; const [active, setActive] = useState(false); - const normalizeAndTrimText = (text: string) => { - return text.split('\n').join('\n'); - }; + const normalizeAndTrimText = (text: string) => text.split('\n').join('\n'); const handleTextChange = (e: any) => { const newText = normalizeAndTrimText(e.target.value.trimStart()); diff --git a/src/people/widgetViews/summaries/wantedSummaries/CodingBounty.tsx b/src/people/widgetViews/summaries/wantedSummaries/CodingBounty.tsx index 00bf2854..53557195 100644 --- a/src/people/widgetViews/summaries/wantedSummaries/CodingBounty.tsx +++ b/src/people/widgetViews/summaries/wantedSummaries/CodingBounty.tsx @@ -5,7 +5,8 @@ import { observer } from 'mobx-react-lite'; import moment from 'moment'; import { isInvoiceExpired, userCanManageBounty } from 'helpers'; import { SOCKET_MSG, createSocketInstance } from 'config/socket'; -import { Button, Divider, Modal } from '../../../../components/common'; +import { Box } from '@mui/system'; +import { Button, Divider, Modal, usePaymentConfirmationModal } from '../../../../components/common'; import { colors } from '../../../../config/colors'; import { renderMarkdown } from '../../../utils/RenderMarkdown'; import { satToUsd } from '../../../../helpers'; @@ -380,6 +381,22 @@ function MobileView(props: CodingBountiesProps) { const hasAccess = isOwner || userBountyRole; const payBountyDisable = !isOwner && !userBountyRole; + const { openPaymentConfirmation } = usePaymentConfirmationModal(); + + const confirmPaymentHandler = () => { + openPaymentConfirmation({ + onConfirmPayment: makePayment, + children: ( + + Are you sure you want to
+ + Pay this Bounty? + +
+ ) + }); + }; + useEffect(() => { setPaidStatus(paid); }, [paid]); @@ -445,7 +462,7 @@ function MobileView(props: CodingBountiesProps) { }} hovercolor={color.button_secondary.hover} shadowcolor={color.button_secondary.shadow} - onClick={makePayment} + onClick={confirmPaymentHandler} /> ) } @@ -740,7 +757,7 @@ function MobileView(props: CodingBountiesProps) { iconSize={14} width={220} height={48} - onClick={makePayment} + onClick={confirmPaymentHandler} style={{ marginTop: '30px', marginBottom: '-20px', textAlign: 'left' }} text="Pay Bounty" ButtonTextStyle={{ padding: 0 }}