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 @@
import Chatbot from '@/components/atom/ChatbotIcon';
import DashboardLayout from '@/components/layouts/DashboardLayout';
import Toast from '@/components/molecules/Toast';
import AgeVerificationModal from '@/components/organism/dialog';
import AgeGate from '@/components/organism/dialog/AgeGate';
import { useSearchParams } from 'next/navigation';
import React, { Suspense, useEffect } from 'react';
......@@ -22,8 +22,12 @@ function LayoutContent({ children }: { children: React.ReactNode }) {
<DashboardLayout>
{children}
<AgeVerificationModal />
<Chatbot />
<AgeGate />
<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 />
<Toast />
</div>
{/* <AgeGate /> */}
</DashboardLayout>
)
......
import Toast from '@/components/molecules/Toast'
import UpdatePassword from '@/components/organism/UpdatePassword'
import { ThemeContextProvider } from '@/context/ThemeContext'
import { ClientProvider } from '@/hooks/ReduxProvider'
......@@ -11,7 +10,7 @@ export default function ProviderWrapper({ children }: { children: React.ReactNod
<ClientProvider>
<ThemeCustomization>
{children}
<Toast />
<UpdatePassword />
{/* <AgeChecker
apiKey="lwU8lOYysWXrIZaijSG3Hfcxmzc4DlS9"
......
......@@ -12,7 +12,7 @@ export default function Chatbot() {
return (
<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"
color="primary"
fullWidth
......
"use client";
import React from "react";
import { Snackbar, Alert, IconButton } from "@mui/material";
import { Alert, IconButton, Snackbar } from "@mui/material";
import { CloseCircle } from "@wandersonalwes/iconsax-react";
import React from "react";
import { closeToast } from "@/slice/toastSlice";
import { useAppDispatch, useAppSelector } from "@/hooks/hook";
import { closeToast } from "@/slice/toastSlice";
export default function Toast() {
const { variant, message, isActive, autoTimeout, duration } = useAppSelector(
......@@ -28,10 +28,9 @@ export default function Toast() {
return (
<Snackbar
open={isActive}
anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
onClose={() => dispatch(closeToast())}
autoHideDuration={autoTimeout ? duration || 3000 : null}
sx={{ zIndex: 9999 }}
sx={{ position: "relative" }}
>
<Alert
severity={currentVariant as "success" | "error" | "warning" | "info"}
......
"use client";
import GlassWrapper from '@/components/molecules/GlassWrapper';
import { useAppSelector } from '@/hooks/hook';
import EditIcon from '@/icons/EditIcon'
import EditIcon from '@/icons/EditIcon';
import { formatDateTime } from '@/utils/formatDateTime';
import Image from 'next/image'
import React from 'react'
import Image from 'next/image';
import AgeGate from '../dialog/AgeGate';
export default function UserProfileCard({ balance, loading }: { balance: any; loading?: boolean }) {
const user = useAppSelector(state => state?.auth.user);
......@@ -56,11 +56,16 @@ export default function UserProfileCard({ balance, loading }: { balance: any; lo
<div className="flex justify-center items-center gap-3">
<Image src={"/assets/images/current-balance.svg"} alt='' width={48} height={48} />
<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>
</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="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' />
......
import Avatar from '@/components/atom/Avatar';
import { useAppDispatch, useAppSelector } from '@/hooks/hook';
import { PATH } from '@/routes/PATH';
import { useGetAgeGateUuidQuery } from '@/services/authApi';
import { useGetAgeGateUuidMutation } from '@/services/authApi';
import { clearTokens } from '@/slice/authSlice';
import { Box, ClickAwayListener, Fade, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Paper, Popper } from '@mui/material';
import { ArrowDown2, Coin, Logout, MoneySend, Profile, TickCircle, Wallet2 } from "@wandersonalwes/iconsax-react";
import { Box, ClickAwayListener, Fade, List, ListItem, ListItemButton, ListItemIcon, ListItemText, Paper, Popper, Tooltip, Typography } from '@mui/material';
import { ArrowDown2, CloseCircle, Coin, Logout, MoneySend, Profile, TickCircle, Wallet2 } from "@wandersonalwes/iconsax-react";
import Link from 'next/link';
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';
......@@ -106,7 +106,25 @@ export default function ProfileBlock() {
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 (
<Box >
......@@ -121,21 +139,29 @@ export default function ProfileBlock() {
padding: 0
}}
>
<div className=' lg:flex items-center gap-1 relative'>
<Avatar alt="profile user" src={avataur1} />
{user?.role && user.role.toLowerCase() !== "user" ? <>
<div className=' hidden lg:block'>
<strong className='text-[14px] leading-[120%] font-bold text-text-title block mb-1 text-nowrap'>{user?.name}</strong>
<p className='text-[12px] text-left leading-[120%] font-[500] text-para-light text-nowrap'>
{user?.role || "User"}
</p>
<Tooltip title={isVerified ? "Verified" : "Not Verified"} placement="bottom">
<div className=' lg:flex items-center gap-1 relative'>
<Avatar alt="profile user" src={avataur1} />
{user?.role && user.role.toLowerCase() !== "user" ? <>
<div className=' hidden lg:block'>
<strong className='text-[14px] leading-[120%] font-bold text-text-title block mb-1 text-nowrap'>{user?.name}</strong>
<p className='text-[12px] text-left leading-[120%] font-[500] text-para-light text-nowrap'>
{user?.role || "User"}
</p>
</div>
<ArrowDown2 size={14} className='text-primary hidden lg:block' />
</> : ""}
<div className="absolute bottom-0 right-0">
{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>
<ArrowDown2 size={14} className='text-primary hidden lg:block' />
</> : ""}
<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" />}
</div>
</div>
</Tooltip>
</a>
<Popper
id={id}
......@@ -150,7 +176,7 @@ export default function ProfileBlock() {
<Paper
elevation={3}
sx={{
width: 215,
width: 315,
borderRadius: 2,
mt: 1,
}}
......@@ -203,6 +229,7 @@ export default function ProfileBlock() {
>
<ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon>
<ListItemText primary={item.label} className='group-hover:text-primary' />
</Link> : <ListItemButton
href={item.href || ""}
onClick={item.onClick}
......@@ -255,6 +282,25 @@ export default function ProfileBlock() {
>
<ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon>
<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> :
<ListItemButton
href={item.href || ""}
......@@ -263,6 +309,7 @@ export default function ProfileBlock() {
>
<ListItemIcon className="min-w-[30px] mr-1 group-hover:text-primary">{item.icon}</ListItemIcon>
<ListItemText primary={item.label} className='group-hover:text-primary' />
</ListItemButton>}
</ListItem>
))}
......
"use client";
import { useGetAgeGateUuidQuery, useVerifyAgeGateMutation } from "@/services/authApi";
import { useCallback, useEffect } from "react";
import { useAppDispatch } from "@/hooks/hook";
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() {
const { data, isSuccess } = useGetAgeGateUuidQuery();
const [getAgeGateUuid, { isLoading }] = useGetAgeGateUuidMutation();
const [verifyAgeGate] = useVerifyAgeGateMutation();
const dispatch = useAppDispatch();
const handleSuccess = useCallback(async (uuid: string) => {
try {
await verifyAgeGate({ age_verify_uuid: uuid }).unwrap();
......@@ -15,46 +20,68 @@ export default function AgeGate() {
}
}, [verifyAgeGate]);
console.log("AgeGate data:", data?.data?.age_verify_uuid, "isSuccess:", isSuccess);
useEffect(() => {
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 = {
key: process.env.NEXT_PUBLIC_AGE_CHECKER_KEY,
mode: "manual",
autoload: true,
show_close: true,
onready: () => {
(window as any).AgeCheckerAPI.show(uuid);
},
onstatuschanged: (verification: { uuid: string; status: string }) => {
if (verification.status === "accepted") {
handleSuccess(verification.uuid);
const openAgeGate = async () => {
try {
const res = await getAgeGateUuid().unwrap();
const uuid = res?.data?.age_verify_uuid;
const verified = res?.data?.is_age_verified;
if (!uuid || verified) return;
(window as any).AgeCheckerConfig = {
key: process.env.NEXT_PUBLIC_AGE_CHECKER_KEY,
mode: "manual",
autoload: true,
show_close: true,
onready: () => {
(window as any).AgeCheckerAPI.show(uuid);
},
onstatuschanged: (verification: { uuid: string; status: string }) => {
if (verification.status === "accepted") {
handleSuccess(verification.uuid);
}
},
onpagehide: () => {
(window as any).AgeCheckerAPI.close();
}
},
onpagehide: () => {
(window as any).AgeCheckerAPI.close();
};
const existing = document.querySelector('script[src*="agechecker.net"]');
if (existing) {
(window as any).AgeCheckerAPI?.show(uuid);
return;
}
};
const existing = document.querySelector('script[src*="agechecker.net"]');
if (existing) {
(window as any).AgeCheckerAPI?.show(uuid);
return;
}
const script = document.createElement("script");
script.src = "https://cdn.agechecker.net/static/popup/v1/popup.js";
script.crossOrigin = "anonymous";
const script = document.createElement("script");
script.src = "https://cdn.agechecker.net/static/popup/v1/popup.js";
script.crossOrigin = "anonymous";
script.onerror = () => {
window.location.href = "https://agechecker.net/loaderror";
};
document.head.insertBefore(script, document.head.firstChild);
script.onerror = () => {
window.location.href = "https://agechecker.net/loaderror";Pp
};
}, [isSuccess, data, handleSuccess]);
document.head.insertBefore(script, document.head.firstChild);
} 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
......@@ -135,7 +135,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel }
</div>
<div className="input__field">
<InputLabel htmlFor="address">Address</InputLabel>
<InputLabel htmlFor="address">Address <span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="address"
......@@ -151,7 +151,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel }
</div>
<div className="input__field">
<InputLabel htmlFor="city">City</InputLabel>
<InputLabel htmlFor="city">City <span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="city"
......@@ -167,7 +167,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel }
</div>
<div className="input__field">
<InputLabel htmlFor="phone">Phone</InputLabel>
<InputLabel htmlFor="phone">Phone <span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
id="phone"
......@@ -181,6 +181,21 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel }
{formik.touched.phone && formik.errors.phone ? formik.errors.phone : ""}
</span>
</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 */}
<div className="input__field">
......
......@@ -18,11 +18,12 @@ export const PlayerValidationSchema = (isEdit: boolean) => Yup.object().shape({
first_name: Yup.string().required("First name is required"),
last_name: Yup.string().required("Last name is required"),
wallet_address: Yup.string().nullable(),
address: Yup.string().nullable(),
city: Yup.string().nullable(),
address: Yup.string().required("Address is required"),
city: Yup.string().required("City is required"),
zip_code: Yup.string().required("Zip code is required"),
phone: Yup.string()
.matches(/^\+?\d{7,15}$/, "Invalid phone number")
.nullable(),
.required("Phone is required"),
password: isEdit
? Yup.string().nullable() // not required in edit mode
: 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 }) {
password_confirmation: data?.data.password_confirmation,
profile_image: null,
dob: data?.data.dob || null as Dayjs | null,
zip_code: data?.data.zip_code || "",
} : initialPlayerValues,
validationSchema: PlayerValidationSchema(!!id),
enableReinitialize: true,
......
......@@ -10,7 +10,6 @@ import dayjs, { Dayjs } from 'dayjs';
import { useFormik } from 'formik';
export default function EditUserProfile({ id, buttonLabel }: { id: string, buttonLabel?: string; }) {
const dispatch = useAppDispatch();
const [updateUserProfile, { isLoading }] = useUpdateUserProfileMutation();
const user = useAppSelector((state) => state?.auth.user);
......@@ -31,6 +30,7 @@ export default function EditUserProfile({ id, buttonLabel }: { id: string, butto
password_confirmation: '',
profile_image: null,
dob: user.dob || null as Dayjs | null,
zip_code: user.zip_code || "",
} : initialPlayerValues,
validationSchema: PlayerValidationSchema(user?.id ? true : false),
enableReinitialize: true,
......
......@@ -98,7 +98,9 @@ export default function CheckoutPage({ amount, slug, bonus }: {
</GlassWrapper>
</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 () => {
try {
if (currentPaymentMode === "crypto") {
......
......@@ -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: () => ({
url: `/api/user/age-verify`,
method: "GET",
......@@ -79,4 +79,4 @@ export const authApi = createApi({
})
})
export const { useLoginMutation, useRegisterUserMutation, useSendVerificationLinkAgainMutation, useForgotPasswordMutation, useVerifyOTPMutation, useResetPasswordMutation, useVerifyEmailMutation, useGetAgeGateUuidQuery, useVerifyAgeGateMutation } = authApi;
\ No newline at end of file
export const { useLoginMutation, useRegisterUserMutation, useSendVerificationLinkAgainMutation, useForgotPasswordMutation, useVerifyOTPMutation, useResetPasswordMutation, useVerifyEmailMutation, useGetAgeGateUuidMutation, useVerifyAgeGateMutation } = authApi;
\ No newline at end of file
......@@ -37,11 +37,11 @@ export interface RegisterProps extends LoginProps {
last_name: string;
phone: string;
// photoid_number: string;
dob: string;
city: string;
pob: string;
dob?: string;
city?: string;
pob?: string;
agree: boolean;
device_id?: string;
visitor_id?: string;
country_code: string;
country_code?: string;
}
\ No newline at end of file
......@@ -16,6 +16,8 @@ export interface CommonPlayerProps {
role?: string;
state?: string;
dob?: string | Dayjs | null;
zip_code?: string;
}
export interface PlayerProps extends CommonPlayerProps {
id?: string;
......@@ -40,6 +42,7 @@ export const initialPlayerValues: PlayerProps = {
password_confirmation: "",
profile_image: null,
dob: null as Dayjs | null,
zip_code: "",
};
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