ISSUE 2: add Add Card Method modal UI, as well as form validation, and integration with addNewCard functionality

This commit is contained in:
Ayobami
2025-06-30 20:25:54 +01:00
parent 20fc46dac5
commit 6612336460
+112 -11
View File
@@ -1,22 +1,35 @@
import { GlobalContext } from "@/globalContext";
import MkdSDK from "@/utils/MkdSDK";
import { Dialog, Transition } from "@headlessui/react";
import { CardCvcElement, CardExpiryElement, CardNumberElement, useElements, useStripe } from "@stripe/react-stripe-js";
import {
CardCvcElement,
CardExpiryElement,
CardNumberElement,
useElements,
useStripe,
} from "@stripe/react-stripe-js";
import React, { Fragment, useState } from "react";
import { useContext } from "react";
import { LoadingButton } from "../frontend";
export default function AddCardMethodModal({ modalOpen, closeModal, onSuccess }) {
export default function AddCardMethodModal({
modalOpen,
closeModal,
onSuccess,
}) {
const [loading, setLoading] = useState(false);
const stripe = useStripe();
const elements = useElements();
const { dispatch: globalDispatch, state: globalState } = useContext(GlobalContext);
const { dispatch: globalDispatch, state: globalState } =
useContext(GlobalContext);
const sdk = new MkdSDK();
const [ctrl] = useState(new AbortController());
const [error, setError] = useState("");
const addNewCard = async (e) => {
setLoading(true);
e.preventDefault();
setError("");
// create stripe token
try {
const cardNum = elements.getElement("cardNumber");
@@ -25,35 +38,123 @@ export default function AddCardMethodModal({ modalOpen, closeModal, onSuccess })
globalDispatch({
type: "SHOW_ERROR",
payload: {
message: r.error?.message ? r.error?.message : r?.trace?.raw?.message,
message: r.error?.message
? r.error?.message
: r?.trace?.raw?.message,
},
});
setError(
r.error?.message ? r.error?.message : r?.trace?.raw?.message
);
} else {
await sdk.createCustomerStripeCard({ sourceToken: r ? r.token.id : result.token.id }, ctrl.signal);
await sdk.createCustomerStripeCard(
{ sourceToken: r ? r.token.id : result.token.id },
ctrl.signal
);
closeModal();
onSuccess();
}
}
);
});
} catch (error) {
if (error.name == "AbortError") {
setLoading(false);
return;
}
console.log(error)
console.log(error);
globalDispatch({
type: "SHOW_ERROR",
payload: {
message: error?.message ? error?.message : "Declined",
},
});
setError(error?.message ? error?.message : "Declined");
}
setLoading(false);
};
return (
<div>
{/* Add Modal UI here to allow card to be created */}
</div>
<Transition appear show={modalOpen} as={Fragment}>
<Dialog as='div' className='relative z-50' onClose={closeModal}>
<Transition.Child
as={Fragment}
enter='ease-out duration-300'
enterFrom='opacity-0'
enterTo='opacity-100'
leave='ease-in duration-200'
leaveFrom='opacity-100'
leaveTo='opacity-0'
>
<div className='fixed inset-0 bg-black bg-opacity-25' />
</Transition.Child>
<div className='fixed inset-0 overflow-y-auto'>
<div className='flex min-h-full items-center justify-center p-4 text-center'>
<Transition.Child
as={Fragment}
enter='ease-out duration-300'
enterFrom='opacity-0 scale-95'
enterTo='opacity-100 scale-100'
leave='ease-in duration-200'
leaveFrom='opacity-100 scale-100'
leaveTo='opacity-0 scale-95'
>
<Dialog.Panel className='w-full max-w-md transform overflow-hidden rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all'>
<Dialog.Title
as='h3'
className='text-lg mb-4 font-medium leading-6 text-gray-900'
>
Add New Card
</Dialog.Title>
<form onSubmit={addNewCard} className='space-y-4'>
<div>
<label className='mb-1 block text-sm font-medium text-gray-700'>
Card Number
</label>
<div className='rounded border px-2 py-2'>
<CardNumberElement options={{ showIcon: true }} />
</div>
</div>
<div className='flex gap-2'>
<div className='w-1/2'>
<label className='mb-1 block text-sm font-medium text-gray-700'>
Expiry
</label>
<div className='rounded border px-2 py-2'>
<CardExpiryElement />
</div>
</div>
<div className='w-1/2'>
<label className='mb-1 block text-sm font-medium text-gray-700'>
CVC
</label>
<div className='rounded border px-2 py-2'>
<CardCvcElement />
</div>
</div>
</div>
{error && <div className='text-sm text-red-500'>{error}</div>}
<div className='mt-4 flex justify-end gap-2'>
<button
type='button'
className='rounded bg-gray-200 px-4 py-2 text-gray-700 hover:bg-gray-300'
onClick={closeModal}
disabled={loading}
>
Cancel
</button>
<LoadingButton
type='submit'
loading={loading}
className='rounded !bg-primary-dark px-4 py-2 text-white hover:!bg-primary'
>
Add Card
</LoadingButton>
</div>
</form>
</Dialog.Panel>
</Transition.Child>
</div>
</div>
</Dialog>
</Transition>
);
}