Commit a9434592 by Arjun Jhukal

updated the new changes to firekirin reduced the size of the registration,…

updated the new changes to firekirin reduced the size of the registration, included the fortpay fields inline, changed the verified status for user
parent f95a2964
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
import Chatbot from '@/components/atom/ChatbotIcon'; import Chatbot from '@/components/atom/ChatbotIcon';
import DashboardLayout from '@/components/layouts/DashboardLayout'; import DashboardLayout from '@/components/layouts/DashboardLayout';
import Toast from '@/components/molecules/Toast';
import AgeVerificationModal from '@/components/organism/dialog'; import AgeVerificationModal from '@/components/organism/dialog';
import AgeGate from '@/components/organism/dialog/AgeGate';
import { useSearchParams } from 'next/navigation'; import { useSearchParams } from 'next/navigation';
import React, { Suspense, useEffect } from 'react'; import React, { Suspense, useEffect } from 'react';
...@@ -22,8 +22,12 @@ function LayoutContent({ children }: { children: React.ReactNode }) { ...@@ -22,8 +22,12 @@ function LayoutContent({ children }: { children: React.ReactNode }) {
<DashboardLayout> <DashboardLayout>
{children} {children}
<AgeVerificationModal /> <AgeVerificationModal />
<div className="fixed bottom-1 right-2 lg:bottom-2 lg:right-4 flex flex-col justify-end items-end z-[9999] gap-8">
<Chatbot /> <Chatbot />
<AgeGate /> <Toast />
</div>
{/* <AgeGate /> */}
</DashboardLayout> </DashboardLayout>
) )
......
import Toast from '@/components/molecules/Toast'
import UpdatePassword from '@/components/organism/UpdatePassword' import UpdatePassword from '@/components/organism/UpdatePassword'
import { ThemeContextProvider } from '@/context/ThemeContext' import { ThemeContextProvider } from '@/context/ThemeContext'
import { ClientProvider } from '@/hooks/ReduxProvider' import { ClientProvider } from '@/hooks/ReduxProvider'
...@@ -11,7 +10,7 @@ export default function ProviderWrapper({ children }: { children: React.ReactNod ...@@ -11,7 +10,7 @@ export default function ProviderWrapper({ children }: { children: React.ReactNod
<ClientProvider> <ClientProvider>
<ThemeCustomization> <ThemeCustomization>
{children} {children}
<Toast />
<UpdatePassword /> <UpdatePassword />
{/* <AgeChecker {/* <AgeChecker
apiKey="lwU8lOYysWXrIZaijSG3Hfcxmzc4DlS9" apiKey="lwU8lOYysWXrIZaijSG3Hfcxmzc4DlS9"
......
...@@ -12,7 +12,7 @@ export default function Chatbot() { ...@@ -12,7 +12,7 @@ export default function Chatbot() {
return ( return (
<Button <Button
className="fixed! bottom-2 right-2 lg:bottom-4 lg:right-4 max-w-fit px-8!" className=" max-w-fit px-8!"
variant="contained" variant="contained"
color="primary" color="primary"
fullWidth fullWidth
......
"use client"; "use client";
import React from "react"; import { Alert, IconButton, Snackbar } from "@mui/material";
import { Snackbar, Alert, IconButton } from "@mui/material";
import { CloseCircle } from "@wandersonalwes/iconsax-react"; import { CloseCircle } from "@wandersonalwes/iconsax-react";
import React from "react";
import { closeToast } from "@/slice/toastSlice";
import { useAppDispatch, useAppSelector } from "@/hooks/hook"; import { useAppDispatch, useAppSelector } from "@/hooks/hook";
import { closeToast } from "@/slice/toastSlice";
export default function Toast() { export default function Toast() {
const { variant, message, isActive, autoTimeout, duration } = useAppSelector( const { variant, message, isActive, autoTimeout, duration } = useAppSelector(
...@@ -28,10 +28,9 @@ export default function Toast() { ...@@ -28,10 +28,9 @@ export default function Toast() {
return ( return (
<Snackbar <Snackbar
open={isActive} open={isActive}
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
onClose={() => dispatch(closeToast())} onClose={() => dispatch(closeToast())}
autoHideDuration={autoTimeout ? duration || 3000 : null} autoHideDuration={autoTimeout ? duration || 3000 : null}
sx={{ zIndex: 9999 }} sx={{ position: "relative" }}
> >
<Alert <Alert
severity={currentVariant as "success" | "error" | "warning" | "info"} severity={currentVariant as "success" | "error" | "warning" | "info"}
......
"use client"; "use client";
import GlassWrapper from '@/components/molecules/GlassWrapper'; import GlassWrapper from '@/components/molecules/GlassWrapper';
import { useAppSelector } from '@/hooks/hook'; import { useAppSelector } from '@/hooks/hook';
import EditIcon from '@/icons/EditIcon' import EditIcon from '@/icons/EditIcon';
import { formatDateTime } from '@/utils/formatDateTime'; import { formatDateTime } from '@/utils/formatDateTime';
import Image from 'next/image' import Image from 'next/image';
import React from 'react' import AgeGate from '../dialog/AgeGate';
export default function UserProfileCard({ balance, loading }: { balance: any; loading?: boolean }) { export default function UserProfileCard({ balance, loading }: { balance: any; loading?: boolean }) {
const user = useAppSelector(state => state?.auth.user); const user = useAppSelector(state => state?.auth.user);
...@@ -56,11 +56,16 @@ export default function UserProfileCard({ balance, loading }: { balance: any; lo ...@@ -56,11 +56,16 @@ export default function UserProfileCard({ balance, loading }: { balance: any; lo
<div className="flex justify-center items-center gap-3"> <div className="flex justify-center items-center gap-3">
<Image src={"/assets/images/current-balance.svg"} alt='' width={48} height={48} /> <Image src={"/assets/images/current-balance.svg"} alt='' width={48} height={48} />
<div className="content mt-3 text-start"> <div className="content mt-3 text-start">
<strong className="text-[12px] leading-[120%] font-[700] text-white block ">SC:{balance?.data?.current_balance}</strong> <strong className="text-[12px] leading-[120%] font-[700] text-white block ">SC : {balance?.data?.current_balance.toFixed(2)}</strong>
<span className="text-white text-[9px]">Current Balance</span> <span className="text-white text-[9px]">Current Balance</span>
</div> </div>
</div> </div>
</div> </div>
{/* <Button variant="contained" color="primary" fullWidth className='col-span-1 md:col-span-2 mt-2' >
Verify Account Now
</Button> */}
<AgeGate />
{/* <div className="col-span-2 flex flex-col sm:flex-row gap-2"> {/* <div className="col-span-2 flex flex-col sm:flex-row gap-2">
<div className="w-full rounded-[14px] p-4 lg:py-6 flex justify-center sm:block text-left sm:text-center gap-3" style={{ background: "rgba(191, 26, 198, 0.10)" }}> <div className="w-full rounded-[14px] p-4 lg:py-6 flex justify-center sm:block text-left sm:text-center gap-3" style={{ background: "rgba(191, 26, 198, 0.10)" }}>
<Image src={"/assets/images/deposit.svg"} alt='' width={48} height={48} className='sm:mx-auto' /> <Image src={"/assets/images/deposit.svg"} alt='' width={48} height={48} className='sm:mx-auto' />
......
import Avatar from '@/components/atom/Avatar'; import Avatar from '@/components/atom/Avatar';
import { useAppDispatch, useAppSelector } from '@/hooks/hook'; import { useAppDispatch, useAppSelector } from '@/hooks/hook';
import { PATH } from '@/routes/PATH'; import { PATH } from '@/routes/PATH';
import { useGetAgeGateUuidQuery } from '@/services/authApi'; import { useGetAgeGateUuidMutation } from '@/services/authApi';
import { clearTokens } from '@/slice/authSlice'; import { clearTokens } from '@/slice/authSlice';
import { Box, ClickAwayListener, Fade, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Paper, Popper } from '@mui/material'; import { Box, ClickAwayListener, Fade, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Paper, Popper, Tooltip, Typography } from '@mui/material';
import { ArrowDown2, Coin, Logout, MoneySend, Profile, TickCircle, Wallet2 } from "@wandersonalwes/iconsax-react"; import { ArrowDown2, CloseCircle, Coin, Logout, MoneySend, Profile, TickCircle, Wallet2 } from "@wandersonalwes/iconsax-react";
import Link from 'next/link'; import Link from 'next/link';
import { usePathname, useRouter, useSearchParams } from 'next/navigation'; import { usePathname, useRouter, useSearchParams } from 'next/navigation';
import React, { useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
const avataur1 = '/assets/images/avatar-6.png'; const avataur1 = '/assets/images/avatar-6.png';
...@@ -106,7 +106,25 @@ export default function ProfileBlock() { ...@@ -106,7 +106,25 @@ export default function ProfileBlock() {
setGlassStyle((prev) => ({ ...prev, opacity: 0 })); setGlassStyle((prev) => ({ ...prev, opacity: 0 }));
}; };
const { data } = useGetAgeGateUuidQuery(); const [getAgeGateUuid] = useGetAgeGateUuidMutation();
const [isVerified, setIsVerified] = useState<boolean | null>(null);
useEffect(() => {
const fetchAgeStatus = async () => {
try {
const res = await getAgeGateUuid().unwrap();
setIsVerified(res?.data?.is_age_verified);
} catch (e) {
console.log(e)
// console.error("Failed to fetch age verification status", err);
setIsVerified(false);
}
};
fetchAgeStatus();
}, [getAgeGateUuid])
return ( return (
<Box > <Box >
...@@ -121,6 +139,7 @@ export default function ProfileBlock() { ...@@ -121,6 +139,7 @@ export default function ProfileBlock() {
padding: 0 padding: 0
}} }}
> >
<Tooltip title={isVerified ? "Verified" : "Not Verified"} placement="bottom">
<div className=' lg:flex items-center gap-1 relative'> <div className=' lg:flex items-center gap-1 relative'>
<Avatar alt="profile user" src={avataur1} /> <Avatar alt="profile user" src={avataur1} />
{user?.role && user.role.toLowerCase() !== "user" ? <> {user?.role && user.role.toLowerCase() !== "user" ? <>
...@@ -133,9 +152,16 @@ export default function ProfileBlock() { ...@@ -133,9 +152,16 @@ export default function ProfileBlock() {
<ArrowDown2 size={14} className='text-primary hidden lg:block' /> <ArrowDown2 size={14} className='text-primary hidden lg:block' />
</> : ""} </> : ""}
<div className="absolute bottom-0 right-0"> <div className="absolute bottom-0 right-0">
{data?.data?.is_age_verified ? <TickCircle variant='Bold' size={16} className="text-green-500" /> : <TickCircle variant='Bold' size={16} className="text-white" />} {isVerified ? (
<TickCircle variant="Bold" size={14} className="text-green-600" />
) : (
<span className="flex items-center justify-center w-[14px] h-[14px] rounded-full bg-yellow-400 text-[10px] font-bold text-white">
!
</span>
)}
</div> </div>
</div> </div>
</Tooltip>
</a> </a>
<Popper <Popper
id={id} id={id}
...@@ -150,7 +176,7 @@ export default function ProfileBlock() { ...@@ -150,7 +176,7 @@ export default function ProfileBlock() {
<Paper <Paper
elevation={3} elevation={3}
sx={{ sx={{
width: 215, width: 315,
borderRadius: 2, borderRadius: 2,
mt: 1, mt: 1,
}} }}
...@@ -203,6 +229,7 @@ export default function ProfileBlock() { ...@@ -203,6 +229,7 @@ export default function ProfileBlock() {
> >
<ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon> <ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon>
<ListItemText primary={item.label} className='group-hover:text-primary' /> <ListItemText primary={item.label} className='group-hover:text-primary' />
</Link> : <ListItemButton </Link> : <ListItemButton
href={item.href || ""} href={item.href || ""}
onClick={item.onClick} onClick={item.onClick}
...@@ -255,6 +282,25 @@ export default function ProfileBlock() { ...@@ -255,6 +282,25 @@ export default function ProfileBlock() {
> >
<ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon> <ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon>
<ListItemText primary={item.label} className='group-hover:text-primary' /> <ListItemText primary={item.label} className='group-hover:text-primary' />
{item.label === "Profile" && (
<div
className={`status flex flex-nowrap items-center gap-1 ml-auto p-1.5 rounded
${isVerified
? "bg-green-600/40 text-green-600"
: "bg-red-600/40 text-red-600"
}`}
>
{isVerified ? (
<TickCircle variant="Bold" size={12} />
) : (
<CloseCircle variant="Bold" size={12} />
)}
<Typography className="text-[10px]!">
{isVerified ? "Verified" : "Not Verified"}
</Typography>
</div>
)}
</Link> : </Link> :
<ListItemButton <ListItemButton
href={item.href || ""} href={item.href || ""}
...@@ -263,6 +309,7 @@ export default function ProfileBlock() { ...@@ -263,6 +309,7 @@ export default function ProfileBlock() {
> >
<ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon> <ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon>
<ListItemText primary={item.label} className='group-hover:text-primary' /> <ListItemText primary={item.label} className='group-hover:text-primary' />
</ListItemButton>} </ListItemButton>}
</ListItem> </ListItem>
))} ))}
......
"use client"; "use client";
import { useGetAgeGateUuidQuery, useVerifyAgeGateMutation } from "@/services/authApi"; import { useAppDispatch } from "@/hooks/hook";
import { useCallback, useEffect } from "react"; import { useGetAgeGateUuidMutation, useVerifyAgeGateMutation } from "@/services/authApi";
import { showToast, ToastVariant } from "@/slice/toastSlice";
import { Button } from "@mui/material";
import { useCallback } from "react";
export default function AgeGate() { export default function AgeGate() {
const { data, isSuccess } = useGetAgeGateUuidQuery();
const [getAgeGateUuid, { isLoading }] = useGetAgeGateUuidMutation();
const [verifyAgeGate] = useVerifyAgeGateMutation(); const [verifyAgeGate] = useVerifyAgeGateMutation();
const dispatch = useAppDispatch();
const handleSuccess = useCallback(async (uuid: string) => { const handleSuccess = useCallback(async (uuid: string) => {
try { try {
await verifyAgeGate({ age_verify_uuid: uuid }).unwrap(); await verifyAgeGate({ age_verify_uuid: uuid }).unwrap();
...@@ -15,12 +20,14 @@ export default function AgeGate() { ...@@ -15,12 +20,14 @@ export default function AgeGate() {
} }
}, [verifyAgeGate]); }, [verifyAgeGate]);
console.log("AgeGate data:", data?.data?.age_verify_uuid, "isSuccess:", isSuccess); const openAgeGate = async () => {
try {
const res = await getAgeGateUuid().unwrap();
const uuid = res?.data?.age_verify_uuid;
const verified = res?.data?.is_age_verified;
useEffect(() => { if (!uuid || verified) return;
if (!isSuccess || !data?.data?.age_verify_uuid) return;
if (data.data.is_age_verified) return;
const uuid = data.data.age_verify_uuid;
(window as any).AgeCheckerConfig = { (window as any).AgeCheckerConfig = {
key: process.env.NEXT_PUBLIC_AGE_CHECKER_KEY, key: process.env.NEXT_PUBLIC_AGE_CHECKER_KEY,
...@@ -41,6 +48,7 @@ export default function AgeGate() { ...@@ -41,6 +48,7 @@ export default function AgeGate() {
}; };
const existing = document.querySelector('script[src*="agechecker.net"]'); const existing = document.querySelector('script[src*="agechecker.net"]');
if (existing) { if (existing) {
(window as any).AgeCheckerAPI?.show(uuid); (window as any).AgeCheckerAPI?.show(uuid);
return; return;
...@@ -49,12 +57,31 @@ export default function AgeGate() { ...@@ -49,12 +57,31 @@ export default function AgeGate() {
const script = document.createElement("script"); const script = document.createElement("script");
script.src = "https://cdn.agechecker.net/static/popup/v1/popup.js"; script.src = "https://cdn.agechecker.net/static/popup/v1/popup.js";
script.crossOrigin = "anonymous"; script.crossOrigin = "anonymous";
script.onerror = () => { script.onerror = () => {
window.location.href = "https://agechecker.net/loaderror"; window.location.href = "https://agechecker.net/loaderror";Pp
}; };
document.head.insertBefore(script, document.head.firstChild); document.head.insertBefore(script, document.head.firstChild);
}, [isSuccess, data, handleSuccess]); } catch (err: any) {
dispatch(showToast({
message: err?.data?.message || "Failed to initiate age verification. Please try again.",
variant: ToastVariant.ERROR
}))
}
};
return null; return (
<Button
variant="contained"
color="primary"
fullWidth
className="col-span-1 md:col-span-2 mt-2"
onClick={openAgeGate}
disabled={isLoading}
>
{isLoading ? "Loading..." : "Verify Account Now"}
</Button>
);
} }
\ No newline at end of file
...@@ -6,16 +6,11 @@ import { useAppDispatch } from '@/hooks/hook'; ...@@ -6,16 +6,11 @@ import { useAppDispatch } from '@/hooks/hook';
import { PATH } from '@/routes/PATH'; import { PATH } from '@/routes/PATH';
import { useRegisterUserMutation } from '@/services/authApi'; import { useRegisterUserMutation } from '@/services/authApi';
import { showToast, ToastVariant } from '@/slice/toastSlice'; import { showToast, ToastVariant } from '@/slice/toastSlice';
import { Autocomplete, Box, Checkbox, FormControlLabel, InputLabel, OutlinedInput, TextField } from '@mui/material'; import { Box, Checkbox, FormControlLabel, InputLabel, OutlinedInput } from '@mui/material';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { DatePicker } from '@mui/x-date-pickers/DatePicker';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import { ArrowLeft } from '@wandersonalwes/iconsax-react'; import { ArrowLeft } from '@wandersonalwes/iconsax-react';
import dayjs, { Dayjs } from 'dayjs';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
import Link from 'next/link'; import Link from 'next/link';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import { useEffect, useState } from 'react';
import * as Yup from 'yup'; import * as Yup from 'yup';
import AuthMessageBlock from '../authMessageBlock'; import AuthMessageBlock from '../authMessageBlock';
...@@ -65,11 +60,11 @@ const validationSchema = Yup.object().shape({ ...@@ -65,11 +60,11 @@ const validationSchema = Yup.object().shape({
.email('Must be a valid email') .email('Must be a valid email')
.max(255) .max(255)
.required('Email is required'), .required('Email is required'),
// displayName: Yup.string() displayName: Yup.string()
// .required("Display Name is required") .required("Display Name is required")
// .max(14, "Display Name must be less than 14 characters") .max(14, "Display Name must be less than 14 characters")
// .min(6, "Display Name must be at least 6 characters long") .min(6, "Display Name must be at least 6 characters long")
// .matches(/^\S+$/, "Display Name cannot contain spaces"), .matches(/^\S+$/, "Display Name cannot contain spaces"),
phone: Yup.string() phone: Yup.string()
.required("Phone number is required"), .required("Phone number is required"),
password: Yup.string() password: Yup.string()
...@@ -83,22 +78,22 @@ const validationSchema = Yup.object().shape({ ...@@ -83,22 +78,22 @@ const validationSchema = Yup.object().shape({
confirmPassword: Yup.string() confirmPassword: Yup.string()
.oneOf([Yup.ref('password')], 'Passwords must match') .oneOf([Yup.ref('password')], 'Passwords must match')
.required('Confirm Password is required'), .required('Confirm Password is required'),
dob: Yup.date() // dob: Yup.date()
.required("Date of birth is required") // .required("Date of birth is required")
.max(new Date(), 'Date of birth cannot be in the future') // .max(new Date(), 'Date of birth cannot be in the future')
.test('age', 'You must be at least 21 years old', function (value) { // .test('age', 'You must be at least 21 years old', function (value) {
if (!value) return true; // if (!value) return true;
const cutoff = dayjs().subtract(21, 'years'); // const cutoff = dayjs().subtract(21, 'years');
return dayjs(value).isBefore(cutoff); // return dayjs(value).isBefore(cutoff);
}), // }),
first_name: Yup.string().required('First name is required'), first_name: Yup.string().required('First name is required'),
middle_name: Yup.string(), middle_name: Yup.string(),
last_name: Yup.string().required('Last name is required'), last_name: Yup.string().required('Last name is required'),
// photoid_number: Yup.string().required('Photo ID is required'), // photoid_number: Yup.string().required('Photo ID is required'),
city: Yup.string(), // city: Yup.string(),
pob: Yup.string().required('Place of birth is required'), // pob: Yup.string().required('Place of birth is required'),
agree: Yup.boolean().required().oneOf([true], 'You must agree to the terms and conditions'), agree: Yup.boolean().required().oneOf([true], 'You must agree to the terms and conditions'),
country_code: Yup.string().required("Country code is required"), // country_code: Yup.string().required("Country code is required"),
}) })
export default function RegisterPage() { export default function RegisterPage() {
...@@ -106,51 +101,51 @@ export default function RegisterPage() { ...@@ -106,51 +101,51 @@ export default function RegisterPage() {
const router = useRouter(); const router = useRouter();
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [countryCodes, setCountryCodes] = useState<any[]>([]); // const [countryCodes, setCountryCodes] = useState<any[]>([]);
useEffect(() => { // useEffect(() => {
const fetchCountries = async () => { // const fetchCountries = async () => {
try { // try {
const res = await fetch( // const res = await fetch(
"https://restcountries.com/v3.1/all?fields=name,idd" // "https://restcountries.com/v3.1/all?fields=name,idd"
); // );
if (!res.ok) { // if (!res.ok) {
throw new Error("Failed to fetch countries"); // throw new Error("Failed to fetch countries");
} // }
const data = await res.json(); // const data = await res.json();
const formatted = data // const formatted = data
.filter((country: any) => country?.idd?.root) // .filter((country: any) => country?.idd?.root)
.map((country: any) => { // .map((country: any) => {
const root = country.idd.root; // const root = country.idd.root;
const suffix = country.idd.suffixes?.[0] || ""; // const suffix = country.idd.suffixes?.[0] || "";
// 🔥 Special case: If root is "+1", do NOT append suffix // // 🔥 Special case: If root is "+1", do NOT append suffix
const dialCode = // const dialCode =
root === "+1" ? root : `${root}${suffix}`; // root === "+1" ? root : `${root}${suffix}`;
return { // return {
name: country.name.common, // name: country.name.common,
label: `${country.name.common} (${dialCode})`, // label: `${country.name.common} (${dialCode})`,
dialCode, // dialCode,
}; // };
}) // })
.sort((a: any, b: any) => // .sort((a: any, b: any) =>
a.name.localeCompare(b.name) // a.name.localeCompare(b.name)
); // );
setCountryCodes(formatted); // setCountryCodes(formatted);
} catch (error: any) { // } catch (error: any) {
console.error( // console.error(
error?.message || "Country fetch failed" // error?.message || "Country fetch failed"
); // );
} // }
}; // };
fetchCountries(); // fetchCountries();
}, []); // }, []);
const initialValues = { const initialValues = {
first_name: '', first_name: '',
middle_name: '', middle_name: '',
...@@ -161,24 +156,24 @@ export default function RegisterPage() { ...@@ -161,24 +156,24 @@ export default function RegisterPage() {
confirmPassword: "", confirmPassword: "",
phone: "", phone: "",
// photoid_number: '', // photoid_number: '',
dob: null as Dayjs | null, // dob: null as Dayjs | null,
city: '', // city: '',
pob: '', // pob: '',
agree: true, agree: true,
visitor_id: undefined, visitor_id: undefined,
country_code: '', // country_code: '',
} }
const { deviceId } = useSeon(); const { deviceId } = useSeon();
const { handleSubmit, handleBlur, handleChange, errors, dirty, values, touched, setFieldValue, setFieldTouched } = useFormik( const { handleSubmit, handleBlur, handleChange, errors, dirty, values, touched, setFieldValue } = useFormik(
{ {
initialValues, initialValues,
validationSchema, validationSchema,
onSubmit: async (values) => { onSubmit: async (values) => {
const formattedDob = values.dob ? dayjs(values.dob).format('YYYY-MM-DD') : ''; // const formattedDob = values.dob ? dayjs(values.dob).format('YYYY-MM-DD') : '';
const userFromPropeelVisitorId = localStorage.getItem("visitor_id"); const userFromPropeelVisitorId = localStorage.getItem("visitor_id");
const cleanedPhone = values.phone.replace(/^0+/, ''); // const cleanedPhone = values.phone.replace(/^0+/, '');
const fullPhoneNumber = `${values.country_code}${cleanedPhone}`; // const fullPhoneNumber = `${values.country_code}${cleanedPhone}`;
try { try {
const response = await registerUser({ const response = await registerUser({
...@@ -189,11 +184,11 @@ export default function RegisterPage() { ...@@ -189,11 +184,11 @@ export default function RegisterPage() {
first_name: values.first_name, first_name: values.first_name,
middle_name: values.middle_name, middle_name: values.middle_name,
last_name: values.last_name, last_name: values.last_name,
phone: fullPhoneNumber, phone: values.phone,
// photoid_number: values.photoid_number, // photoid_number: values.photoid_number,
dob: formattedDob, // dob: formattedDob,
city: values.city, // city: values.city,
pob: values.pob, // pob: values.pob,
agree: values.agree, agree: values.agree,
device_id: deviceId, device_id: deviceId,
visitor_id: userFromPropeelVisitorId || undefined, visitor_id: userFromPropeelVisitorId || undefined,
...@@ -291,7 +286,7 @@ export default function RegisterPage() { ...@@ -291,7 +286,7 @@ export default function RegisterPage() {
</div> </div>
{/* EMAIL */} {/* EMAIL */}
<div className="col-span-2 lg:col-span-6"> <div className="col-span-3 lg:col-span-3">
<div className="input_field"> <div className="input_field">
<InputLabel htmlFor="emailAddress">Email Address<span className="text-red-500">*</span></InputLabel> <InputLabel htmlFor="emailAddress">Email Address<span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
...@@ -311,7 +306,7 @@ export default function RegisterPage() { ...@@ -311,7 +306,7 @@ export default function RegisterPage() {
</div> </div>
{/* DISPLAY NAME */} {/* DISPLAY NAME */}
<div className="col-span-2 lg:col-span-3"> <div className="col-span-3 lg:col-span-3">
<div className="input_field"> <div className="input_field">
<InputLabel htmlFor="displayName">Display Name<span className="text-red-500">*</span></InputLabel> <InputLabel htmlFor="displayName">Display Name<span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
...@@ -330,7 +325,6 @@ export default function RegisterPage() { ...@@ -330,7 +325,6 @@ export default function RegisterPage() {
</div> </div>
</div> </div>
{/* Photo ID */} {/* Photo ID */}
{/* <div className="col-span-2 lg:col-span-3"> {/* <div className="col-span-2 lg:col-span-3">
<div className="input__field"> <div className="input__field">
...@@ -347,7 +341,7 @@ export default function RegisterPage() { ...@@ -347,7 +341,7 @@ export default function RegisterPage() {
</div> */} </div> */}
{/* Address */} {/* Address */}
<div className="col-span-2 lg:col-span-3"> {/* <div className="col-span-2 lg:col-span-3">
<div className="input__field"> <div className="input__field">
<InputLabel htmlFor="city">City</InputLabel> <InputLabel htmlFor="city">City</InputLabel>
<OutlinedInput <OutlinedInput
...@@ -362,10 +356,10 @@ export default function RegisterPage() { ...@@ -362,10 +356,10 @@ export default function RegisterPage() {
/> />
<span className="error">{touched.city && errors.city}</span> <span className="error">{touched.city && errors.city}</span>
</div> </div>
</div> </div> */}
{/* Country */} {/* Country */}
<div className="col-span-2 lg:col-span-3"> {/* <div className="col-span-2 lg:col-span-3">
<div className="input__field"> <div className="input__field">
<InputLabel htmlFor="pob" >Place of Birth<span className="text-red-500">*</span></InputLabel> <InputLabel htmlFor="pob" >Place of Birth<span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
...@@ -380,10 +374,10 @@ export default function RegisterPage() { ...@@ -380,10 +374,10 @@ export default function RegisterPage() {
/> />
<span className="error">{touched.pob && errors.pob}</span> <span className="error">{touched.pob && errors.pob}</span>
</div> </div>
</div> </div> */}
{/* Phone */} {/* Phone */}
<div className="col-span-2 lg:col-span-2"> {/* <div className="col-span-2 lg:col-span-2">
<InputLabel> <InputLabel>
Country Code <span className="text-red-500">*</span> Country Code <span className="text-red-500">*</span>
</InputLabel> </InputLabel>
...@@ -413,8 +407,8 @@ export default function RegisterPage() { ...@@ -413,8 +407,8 @@ export default function RegisterPage() {
/> />
)} )}
/> />
</div> </div> */}
<div className="col-span-2 lg:col-span-4"> <div className="col-span-3 lg:col-span-6">
<div className="input__field"> <div className="input__field">
<InputLabel htmlFor="phone">Phone <span className="text-red-500">*</span></InputLabel> <InputLabel htmlFor="phone">Phone <span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
...@@ -433,7 +427,7 @@ export default function RegisterPage() { ...@@ -433,7 +427,7 @@ export default function RegisterPage() {
</div> </div>
{/* DOB */} {/* DOB */}
<div className="col-span-2 lg:col-span-6"> {/* <div className="col-span-2 lg:col-span-6">
<div className="input__field"> <div className="input__field">
<InputLabel htmlFor="dob">Date of Birth <span className="text-red-500">*</span></InputLabel> <InputLabel htmlFor="dob">Date of Birth <span className="text-red-500">*</span></InputLabel>
<LocalizationProvider dateAdapter={AdapterDayjs}> <LocalizationProvider dateAdapter={AdapterDayjs}>
...@@ -493,9 +487,9 @@ export default function RegisterPage() { ...@@ -493,9 +487,9 @@ export default function RegisterPage() {
/> />
</LocalizationProvider> </LocalizationProvider>
</div> </div>
</div> </div> */}
<div className="col-span-2 lg:col-span-3"> <div className="col-span-3 lg:col-span-3">
<div className="input_field"> <div className="input_field">
<PasswordField <PasswordField
name="password" name="password"
...@@ -509,7 +503,7 @@ export default function RegisterPage() { ...@@ -509,7 +503,7 @@ export default function RegisterPage() {
</div> </div>
</div> </div>
<div className="col-span-2 lg:col-span-3"> <div className="col-span-3 lg:col-span-3">
<div className="input_field"> <div className="input_field">
<PasswordField <PasswordField
name="confirmPassword" name="confirmPassword"
...@@ -522,7 +516,7 @@ export default function RegisterPage() { ...@@ -522,7 +516,7 @@ export default function RegisterPage() {
/> />
</div> </div>
</div> </div>
<div className="col-span-4"> <div className="col-span-6">
<FormControlLabel <FormControlLabel
control={<Checkbox control={<Checkbox
checked={values.agree} checked={values.agree}
......
...@@ -135,7 +135,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel } ...@@ -135,7 +135,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel }
</div> </div>
<div className="input__field"> <div className="input__field">
<InputLabel htmlFor="address">Address</InputLabel> <InputLabel htmlFor="address">Address <span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
fullWidth fullWidth
id="address" id="address"
...@@ -151,7 +151,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel } ...@@ -151,7 +151,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel }
</div> </div>
<div className="input__field"> <div className="input__field">
<InputLabel htmlFor="city">City</InputLabel> <InputLabel htmlFor="city">City <span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
fullWidth fullWidth
id="city" id="city"
...@@ -167,7 +167,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel } ...@@ -167,7 +167,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel }
</div> </div>
<div className="input__field"> <div className="input__field">
<InputLabel htmlFor="phone">Phone</InputLabel> <InputLabel htmlFor="phone">Phone <span className="text-red-500">*</span></InputLabel>
<OutlinedInput <OutlinedInput
fullWidth fullWidth
id="phone" id="phone"
...@@ -181,6 +181,21 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel } ...@@ -181,6 +181,21 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel }
{formik.touched.phone && formik.errors.phone ? formik.errors.phone : ""} {formik.touched.phone && formik.errors.phone ? formik.errors.phone : ""}
</span> </span>
</div> </div>
<div className="input__field">
<InputLabel htmlFor="zip_code">Zip Code <span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="zip_code"
name="zip_code"
placeholder="Enter zip code"
value={formik.values.zip_code}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
/>
<span className="error">
{formik.touched.phone && formik.errors.phone ? formik.errors.phone : ""}
</span>
</div>
{/* DOB */} {/* DOB */}
<div className="input__field"> <div className="input__field">
......
...@@ -18,11 +18,12 @@ export const PlayerValidationSchema = (isEdit: boolean) => Yup.object().shape({ ...@@ -18,11 +18,12 @@ export const PlayerValidationSchema = (isEdit: boolean) => Yup.object().shape({
first_name: Yup.string().required("First name is required"), first_name: Yup.string().required("First name is required"),
last_name: Yup.string().required("Last name is required"), last_name: Yup.string().required("Last name is required"),
wallet_address: Yup.string().nullable(), wallet_address: Yup.string().nullable(),
address: Yup.string().nullable(), address: Yup.string().required("Address is required"),
city: Yup.string().nullable(), city: Yup.string().required("City is required"),
zip_code: Yup.string().required("Zip code is required"),
phone: Yup.string() phone: Yup.string()
.matches(/^\+?\d{7,15}$/, "Invalid phone number") .matches(/^\+?\d{7,15}$/, "Invalid phone number")
.nullable(), .required("Phone is required"),
password: isEdit password: isEdit
? Yup.string().nullable() // not required in edit mode ? Yup.string().nullable() // not required in edit mode
: Yup.string().min(6, "Password must be at least 6 characters").required("Password is required"), : Yup.string().min(6, "Password must be at least 6 characters").required("Password is required"),
...@@ -67,6 +68,7 @@ export default function AddPlayerPage({ id }: { id?: string }) { ...@@ -67,6 +68,7 @@ export default function AddPlayerPage({ id }: { id?: string }) {
password_confirmation: data?.data.password_confirmation, password_confirmation: data?.data.password_confirmation,
profile_image: null, profile_image: null,
dob: data?.data.dob || null as Dayjs | null, dob: data?.data.dob || null as Dayjs | null,
zip_code: data?.data.zip_code || "",
} : initialPlayerValues, } : initialPlayerValues,
validationSchema: PlayerValidationSchema(!!id), validationSchema: PlayerValidationSchema(!!id),
enableReinitialize: true, enableReinitialize: true,
......
...@@ -10,7 +10,6 @@ import dayjs, { Dayjs } from 'dayjs'; ...@@ -10,7 +10,6 @@ import dayjs, { Dayjs } from 'dayjs';
import { useFormik } from 'formik'; import { useFormik } from 'formik';
export default function EditUserProfile({ id, buttonLabel }: { id: string, buttonLabel?: string; }) { export default function EditUserProfile({ id, buttonLabel }: { id: string, buttonLabel?: string; }) {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const [updateUserProfile, { isLoading }] = useUpdateUserProfileMutation(); const [updateUserProfile, { isLoading }] = useUpdateUserProfileMutation();
const user = useAppSelector((state) => state?.auth.user); const user = useAppSelector((state) => state?.auth.user);
...@@ -31,6 +30,7 @@ export default function EditUserProfile({ id, buttonLabel }: { id: string, butto ...@@ -31,6 +30,7 @@ export default function EditUserProfile({ id, buttonLabel }: { id: string, butto
password_confirmation: '', password_confirmation: '',
profile_image: null, profile_image: null,
dob: user.dob || null as Dayjs | null, dob: user.dob || null as Dayjs | null,
zip_code: user.zip_code || "",
} : initialPlayerValues, } : initialPlayerValues,
validationSchema: PlayerValidationSchema(user?.id ? true : false), validationSchema: PlayerValidationSchema(user?.id ? true : false),
enableReinitialize: true, enableReinitialize: true,
......
// 'use client';
// import { useAppDispatch, useAppSelector } from '@/hooks/hook';
// import { useDepositMutation } from '@/services/transaction';
// import { showToast, ToastVariant } from '@/slice/toastSlice';
// import { DepositProps } from '@/types/transaction';
// import { Button, InputLabel, OutlinedInput } from '@mui/material';
// import { useRouter } from 'next/navigation';
// import Script from 'next/script';
// import { PaymentModeProps } from '.';
// declare global {
// interface Window {
// CollectJS: {
// configure: (config: {
// paymentType: string;
// callback: (response: any) => void;
// }) => void;
// };
// }
// }
// export default function PaymentForm({ id, amount, type }: DepositProps & { type: PaymentModeProps }) {
// const dispatch = useAppDispatch();
// const router = useRouter();
// const user = useAppSelector((state) => state.auth.user);
// const [payViaFortPay, { isLoading }] = useDepositMutation();
// const handleCollectJSLoad = () => {
// if (typeof window !== 'undefined' && window.CollectJS) {
// window.CollectJS.configure({
// paymentType: 'cc',
// callback: async (response) => {
// try {
// await payViaFortPay({
// id: id,
// amount: amount,
// type: type as PaymentModeProps,
// payment_token: response.token
// }).unwrap();
// router.push(`/buy-coins/${id}/success`)
// }
// catch (e: any) {
// dispatch(showToast({
// message: e?.data?.message || "Unable to deposit",
// variant: ToastVariant.ERROR
// }))
// }
// }
// });
// }
// };
// return (
// <>
// <Script
// src="https://secure.fppgateway.com/token/Collect.js"
// data-tokenization-key="NAhDuk-7V4u2u-tUAsT5-dCqbH5"
// strategy="afterInteractive"
// onReady={handleCollectJSLoad}
// />
// <form className="theForm">
// <div className="formInner flex flex-col gap-3 md:grid md:grid-cols-2">
// <div className="form-group">
// <InputLabel htmlFor="fname">First Name </InputLabel>
// <OutlinedInput type="text" className="form-control" placeholder="First Name" name="fname" defaultValue={user?.first_name} />
// </div>
// <div className="form-group">
// <InputLabel htmlFor="lname">Last Name </InputLabel>
// <OutlinedInput type="text" className="form-control" placeholder="Last Name" name="lname" defaultValue={user?.last_name} />
// </div>
// <div className="form-group">
// <InputLabel htmlFor="address1">Address </InputLabel>
// <OutlinedInput type="text" className="form-control" placeholder="Street Address" name="address1" defaultValue={user?.address} />
// </div>
// <div className="form-group">
// <InputLabel htmlFor="city">City </InputLabel>
// <OutlinedInput type="text" className="form-control" placeholder="City" name="city" defaultValue={user?.city} />
// </div>
// <div className="form-group">
// <InputLabel htmlFor="state">State </InputLabel>
// <OutlinedInput type="text" className="form-control" placeholder="State" name="state" defaultValue={user?.state} />
// </div>
// <div className="form-group">
// <InputLabel htmlFor="zip">Zip Code </InputLabel>
// <OutlinedInput type="text" className="form-control" placeholder="Zip code" name="zip" defaultValue={""} />
// </div>
// </div>
// {/* <OutlinedInput type="submit" id="payButton" value="Pay $5" className="btn btn-primary btn-block" /> */}
// <Button type="submit" id="payButton" variant='contained' color='primary' className='mt-4!'>{isLoading ? "Proceeding Payment" : "Proceed Payment"}</Button>
// </form>
// <div id="paymentTokenInfo"></div>
// </>
// );
// }
'use client'; 'use client';
import { useAppDispatch, useAppSelector } from '@/hooks/hook'; import { useAppDispatch, useAppSelector } from '@/hooks/hook';
import { useDepositMutation } from '@/services/transaction'; import { useDepositMutation } from '@/services/transaction';
import { showToast, ToastVariant } from '@/slice/toastSlice'; import { showToast, ToastVariant } from '@/slice/toastSlice';
import { DepositProps } from '@/types/transaction'; import { DepositProps } from '@/types/transaction';
import { Button, InputLabel, OutlinedInput } from '@mui/material'; import { Box, Button, FormHelperText, InputLabel, OutlinedInput, Typography } from '@mui/material';
import { useFormik } from 'formik';
import { useRouter } from 'next/navigation'; import { useRouter } from 'next/navigation';
import Script from 'next/script'; import Script from 'next/script';
import { useState } from 'react';
import * as Yup from 'yup';
import { PaymentModeProps } from '.'; import { PaymentModeProps } from '.';
declare global { declare global {
interface Window { interface Window {
CollectJS: { CollectJS: {
configure: (config: { configure: (config: object) => void;
paymentType: string; startPaymentRequest: () => void;
callback: (response: any) => void;
}) => void;
}; };
} }
} }
type CardFieldValidity = {
ccnumber: boolean;
ccexp: boolean;
cvv: boolean;
};
const billingSchema = Yup.object({
fname: Yup.string().required('First name is required'),
lname: Yup.string().required('Last name is required'),
address1: Yup.string().required('Address is required'),
city: Yup.string().required('City is required'),
state: Yup.string().required('State is required'),
zip: Yup.string()
.required('Zip code is required')
.matches(/^\d{5}(-\d{4})?$/, 'Enter a valid zip code'),
});
export default function PaymentForm({ id, amount, type }: DepositProps & { type: PaymentModeProps }) { export default function PaymentForm({ id, amount, type }: DepositProps & { type: PaymentModeProps }) {
const dispatch = useAppDispatch(); const dispatch = useAppDispatch();
const router = useRouter(); const router = useRouter();
const user = useAppSelector((state) => state.auth.user); const user = useAppSelector((state) => state.auth.user);
const [payViaFortPay, { isLoading }] = useDepositMutation(); const [payViaFortPay, { isLoading }] = useDepositMutation();
const handleCollectJSLoad = () => { const [cardValidity, setCardValidity] = useState<CardFieldValidity>({
ccnumber: false,
ccexp: false,
cvv: false,
});
const [cardTouched, setCardTouched] = useState(false);
const formik = useFormik({
initialValues: {
fname: user?.first_name || '',
lname: user?.last_name || '',
address1: user?.address || '',
city: user?.city || '',
state: user?.state || '',
zip: '',
},
validationSchema: billingSchema,
onSubmit: () => {
setCardTouched(true);
const allCardValid = cardValidity.ccnumber && cardValidity.ccexp && cardValidity.cvv;
if (!allCardValid) return;
if (typeof window !== 'undefined' && window.CollectJS) { if (typeof window !== 'undefined' && window.CollectJS) {
window.CollectJS.startPaymentRequest();
}
},
});
const handleCollectJSLoad = () => {
if (typeof window === 'undefined' || !window.CollectJS) return;
window.CollectJS.configure({ window.CollectJS.configure({
paymentType: 'cc', variant: 'inline',
callback: async (response) => { customCss: {
'border-radius': '27px',
border: '1px solid rgba(255,255,255,0.2)',
padding: '12px 16px',
'font-family': 'Inter, sans-serif',
'font-size': '14px',
width: '100%',
'box-sizing': 'border-box',
color: '#000000',
'-webkit-text-fill-color': '#000000',
opacity: '1',
},
placeholderCss: {
color: 'rgba(0,0,0,0.4)',
},
callback: async (response: any) => {
try { try {
await payViaFortPay({ await payViaFortPay({
id: id, id,
amount: amount, amount,
type: type as PaymentModeProps, type: type as PaymentModeProps,
payment_token: response.token payment_token: response.token,
}).unwrap(); }).unwrap();
router.push(`/buy-coins/${id}/success`) router.push(`/buy-coins/${id}/success`);
} } catch (e: any) {
catch (e: any) { dispatch(
dispatch(showToast({ showToast({
message: e?.data?.message || "Unable to deposit", message: e?.data?.message || 'Unable to deposit',
variant: ToastVariant.ERROR variant: ToastVariant.ERROR,
})) })
} );
} }
},
// CollectJS calls this whenever a field's validity changes
validationCallback: (field: string, status: boolean, _message: string) => {
setCardValidity((prev) => ({ ...prev, [field]: status }));
},
fields: {
ccnumber: { selector: '#ccnumber', placeholder: 'Card Number' },
ccexp: { selector: '#ccexp', placeholder: 'MM / YY' },
cvv: { selector: '#cvv', placeholder: 'CVV' },
},
}); });
}
}; };
return ( return (
<> <>
<Script <Script
src="https://secure.fppgateway.com/token/Collect.js" src="https://secure.fppgateway.com/token/Collect.js"
data-tokenization-key="NAhDuk-7V4u2u-tUAsT5-dCqbH5" data-tokenization-key="5mN8N7-jhr55W-N22pxX-uAW2s9"
strategy="afterInteractive" strategy="afterInteractive"
onReady={handleCollectJSLoad} onReady={handleCollectJSLoad}
/> />
<form className="theForm"> <form className="theForm" onSubmit={formik.handleSubmit} noValidate>
<div className="formInner flex flex-col gap-3 md:grid md:grid-cols-2"> <div className="formInner flex flex-col gap-3 md:grid md:grid-cols-2">
{/* ── Billing fields ── */}
<div className="form-group"> <div className="form-group">
<InputLabel htmlFor="fname">First Name </InputLabel> <InputLabel htmlFor="name">First Name<span className="text-red-500">*</span></InputLabel>
<OutlinedInput type="text" className="form-control" placeholder="First Name" name="fname" defaultValue={user?.first_name} />
<OutlinedInput
id="fname"
name="fname"
type="text"
placeholder="First Name"
value={formik.values.fname}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.fname && Boolean(formik.errors.fname)}
fullWidth
/>
{formik.touched.fname && formik.errors.fname && (
<FormHelperText error sx={{ ml: '14px' }}>{formik.errors.fname}</FormHelperText>
)}
</div> </div>
<div className="form-group"> <div className="form-group">
<InputLabel htmlFor="lname">Last Name </InputLabel> <InputLabel htmlFor="name">Last Name<span className="text-red-500">*</span></InputLabel>
<OutlinedInput type="text" className="form-control" placeholder="Last Name" name="lname" defaultValue={user?.last_name} />
<OutlinedInput
id="lname"
name="lname"
type="text"
placeholder="Last Name"
value={formik.values.lname}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.lname && Boolean(formik.errors.lname)}
fullWidth
/>
{formik.touched.lname && formik.errors.lname && (
<FormHelperText error sx={{ ml: '14px' }}>{formik.errors.lname}</FormHelperText>
)}
</div> </div>
<div className="form-group"> <div className="form-group">
<InputLabel htmlFor="address1">Address </InputLabel> <InputLabel htmlFor="address1">Address<span className="text-red-500">*</span></InputLabel>
<OutlinedInput type="text" className="form-control" placeholder="Street Address" name="address1" defaultValue={user?.address} /> <OutlinedInput
id="address1"
name="address1"
type="text"
placeholder="Street Address"
value={formik.values.address1}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.address1 && Boolean(formik.errors.address1)}
fullWidth
/>
{formik.touched.address1 && formik.errors.address1 && (
<FormHelperText error sx={{ ml: '14px' }}>{formik.errors.address1}</FormHelperText>
)}
</div> </div>
<div className="form-group"> <div className="form-group">
<InputLabel htmlFor="city">City </InputLabel> <InputLabel htmlFor="city">City<span className="text-red-500">*</span></InputLabel>
<OutlinedInput type="text" className="form-control" placeholder="City" name="city" defaultValue={user?.city} /> <OutlinedInput
id="city"
name="city"
type="text"
placeholder="City"
value={formik.values.city}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.city && Boolean(formik.errors.city)}
fullWidth
/>
{formik.touched.city && formik.errors.city && (
<FormHelperText error sx={{ ml: '14px' }}>{formik.errors.city}</FormHelperText>
)}
</div> </div>
<div className="form-group"> <div className="form-group">
<InputLabel htmlFor="state">State </InputLabel> <InputLabel htmlFor="state">State<span className="text-red-500">*</span></InputLabel>
<OutlinedInput type="text" className="form-control" placeholder="State" name="state" defaultValue={user?.state} /> <OutlinedInput
id="state"
name="state"
type="text"
placeholder="State"
value={formik.values.state}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.state && Boolean(formik.errors.state)}
fullWidth
/>
{formik.touched.state && formik.errors.state && (
<FormHelperText error sx={{ ml: '14px' }}>{formik.errors.state}</FormHelperText>
)}
</div> </div>
<div className="form-group"> <div className="form-group">
<InputLabel htmlFor="zip">Zip Code </InputLabel> <InputLabel htmlFor="zip">Zip Code<span className="text-red-500">*</span></InputLabel>
<OutlinedInput type="text" className="form-control" placeholder="Zip code" name="zip" defaultValue={""} /> <OutlinedInput
id="zip"
name="zip"
type="text"
placeholder="Zip code"
value={formik.values.zip}
onChange={formik.handleChange}
onBlur={formik.handleBlur}
error={formik.touched.zip && Boolean(formik.errors.zip)}
fullWidth
/>
{formik.touched.zip && formik.errors.zip && (
<FormHelperText error sx={{ ml: '14px' }}>{formik.errors.zip}</FormHelperText>
)}
</div> </div>
<Typography variant='h6' fontWeight={500}>FortPay Required Fields <span className="text-red-500">*</span></Typography>
{/* ── Inline CollectJS card fields ── */}
<Box className="md:col-span-2 flex flex-col gap-3 mt-1">
<div className="form-group">
<InputLabel htmlFor="ccnumber">Card Number<span className="text-red-500">*</span></InputLabel>
<Box id="ccnumber" />
{cardTouched && !cardValidity.ccnumber && (
<FormHelperText error sx={{ ml: '14px' }}>Card number is required</FormHelperText>
)}
</div>
<Box className="flex gap-3">
<div className="form-group flex-1">
<InputLabel htmlFor="ccexp">Expiration<span className="text-red-500">*</span></InputLabel>
<Box id="ccexp" />
{cardTouched && !cardValidity.ccexp && (
<FormHelperText error sx={{ ml: '14px' }}>Expiration is required</FormHelperText>
)}
</div>
<div className="form-group flex-1">
<InputLabel htmlFor="cvv">CVV<span className="text-red-500">*</span></InputLabel>
<Box id="cvv" />
{cardTouched && !cardValidity.cvv && (
<FormHelperText error sx={{ ml: '14px' }}>CVV is required</FormHelperText>
)}
</div>
</Box>
</Box>
</div> </div>
{/* <OutlinedInput type="submit" id="payButton" value="Pay $5" className="btn btn-primary btn-block" /> */} <Button
<Button type="submit" id="payButton" variant='contained' color='primary' className='mt-4!'>{isLoading ? "Proceeding Payment" : "Proceed Payment"}</Button> type="submit"
id="payButton"
variant="contained"
color="primary"
className="mt-4!"
disabled={isLoading}
>
{isLoading ? 'Processing Payment…' : 'Proceed Payment'}
</Button>
</form> </form>
<div id="paymentTokenInfo"></div> <div id="paymentTokenInfo" />
</> </>
); );
} }
\ No newline at end of file
...@@ -98,7 +98,9 @@ export default function CheckoutPage({ amount, slug, bonus }: { ...@@ -98,7 +98,9 @@ export default function CheckoutPage({ amount, slug, bonus }: {
</GlassWrapper> </GlassWrapper>
</div> </div>
</div> </div>
{currentPaymentMode === "fortpay" ? <PaymentForm id={slug} amount={amount} type={currentPaymentMode as PaymentModeProps} /> : ""} {currentPaymentMode === "fortpay" ? <>
<PaymentForm id={slug} amount={amount} type={currentPaymentMode as PaymentModeProps} />
</> : ""}
{currentPaymentMode === "crypto" ? <Button type='submit' variant='contained' color='primary' className='!mt-3' onClick={async () => { {currentPaymentMode === "crypto" ? <Button type='submit' variant='contained' color='primary' className='!mt-3' onClick={async () => {
try { try {
if (currentPaymentMode === "crypto") { if (currentPaymentMode === "crypto") {
......
...@@ -63,7 +63,7 @@ export const authApi = createApi({ ...@@ -63,7 +63,7 @@ export const authApi = createApi({
}, },
}) })
}), }),
getAgeGateUuid: builder.query<GlobalResponse & { data: { age_verify_uuid: string, is_age_verified: boolean } }, void>({ getAgeGateUuid: builder.mutation<GlobalResponse & { data: { age_verify_uuid: string, is_age_verified: boolean } }, void>({
query: () => ({ query: () => ({
url: `/api/user/age-verify`, url: `/api/user/age-verify`,
method: "GET", method: "GET",
...@@ -79,4 +79,4 @@ export const authApi = createApi({ ...@@ -79,4 +79,4 @@ export const authApi = createApi({
}) })
}) })
export const { useLoginMutation, useRegisterUserMutation, useSendVerificationLinkAgainMutation, useForgotPasswordMutation, useVerifyOTPMutation, useResetPasswordMutation, useVerifyEmailMutation, useGetAgeGateUuidQuery, useVerifyAgeGateMutation } = authApi; export const { useLoginMutation, useRegisterUserMutation, useSendVerificationLinkAgainMutation, useForgotPasswordMutation, useVerifyOTPMutation, useResetPasswordMutation, useVerifyEmailMutation, useGetAgeGateUuidMutation, useVerifyAgeGateMutation } = authApi;
\ No newline at end of file \ No newline at end of file
...@@ -37,11 +37,11 @@ export interface RegisterProps extends LoginProps { ...@@ -37,11 +37,11 @@ export interface RegisterProps extends LoginProps {
last_name: string; last_name: string;
phone: string; phone: string;
// photoid_number: string; // photoid_number: string;
dob: string; dob?: string;
city: string; city?: string;
pob: string; pob?: string;
agree: boolean; agree: boolean;
device_id?: string; device_id?: string;
visitor_id?: string; visitor_id?: string;
country_code: string; country_code?: string;
} }
\ No newline at end of file
...@@ -16,6 +16,8 @@ export interface CommonPlayerProps { ...@@ -16,6 +16,8 @@ export interface CommonPlayerProps {
role?: string; role?: string;
state?: string; state?: string;
dob?: string | Dayjs | null; dob?: string | Dayjs | null;
zip_code?: string;
} }
export interface PlayerProps extends CommonPlayerProps { export interface PlayerProps extends CommonPlayerProps {
id?: string; id?: string;
...@@ -40,6 +42,7 @@ export const initialPlayerValues: PlayerProps = { ...@@ -40,6 +42,7 @@ export const initialPlayerValues: PlayerProps = {
password_confirmation: "", password_confirmation: "",
profile_image: null, profile_image: null,
dob: null as Dayjs | null, dob: null as Dayjs | null,
zip_code: "",
}; };
type GameInformation = { type GameInformation = {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment