Commit 6092c896 by Arjun Jhukal

updated the verif process for the pre registerd user

parent 3aadc4c2
......@@ -28,14 +28,12 @@ export default function PaymentSuccess() {
if (result.success && result.data) {
// Update Redux store
dispatch(setTokens({
access_token: result.data.access_token,
user: result.data.user,
refreshToken: result.data.refresh_token
}));
// Dispatch custom event for other components
window.dispatchEvent(new CustomEvent('auth:hydrated', {
detail: {
source: result.source,
......
import DashboardLayout from '@/components/layouts/DashboardLayout'
import ComingSoonGate from '@/components/organism/ComingSoonGate'
import Private from '@/routes/Private'
import React from 'react'
"use client";
import DashboardLayout from '@/components/layouts/DashboardLayout';
import ComingSoonGate from '@/components/organism/ComingSoonGate';
import Private from '@/routes/Private';
import React from 'react';
export default function PrivateUserLayout({ children }: { children: React.ReactNode }) {
return (
<ComingSoonGate>
<Private>
......
"use client";
import { useAppDispatch, useAppSelector } from '@/hooks/hook';
import { useVerifyProfileMutation } from '@/services/authApi';
import { showToast, ToastVariant } from '@/slice/toastSlice';
import { Box } from '@mui/material';
import { styled } from '@mui/material/styles';
import { usePathname } from 'next/navigation';
import React from 'react';
import React, { useState } from 'react';
import ImportantBlock from '../molecules/ImportantBlock';
import PaymentModal from '../molecules/PaymentModal';
import Header from '../organism/Header';
import Sidebar from '../organism/Sidebar';
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
const [open, setOpen] = React.useState(true);
const [openMobile, setOpenMobile] = React.useState(false);
const [open, setOpen] = useState(true);
const [openMobile, setOpenMobile] = useState(false);
const pathname = usePathname();
const user = useAppSelector((state) => state.auth.user);
const dispatch = useAppDispatch();
const [verifyAcuity, { isLoading }] = useVerifyProfileMutation();
const [isAcuityModalOpen, setIsAcuityModalOpen] = useState(false);
const [acuityUrl, setAcuityUrl] = useState('');
const handleDrawerOpen = () => {
setOpen((prev) => !prev);
};
......@@ -25,9 +35,7 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
const handleMobileMenuToggle = () => {
setOpenMobile((prev) => !prev);
}
// const handleDrawerClose = () => {
// setOpen(false);
// };
const DrawerHeader = styled('div')(({ theme }) => ({
display: 'flex',
alignItems: 'center',
......@@ -55,8 +63,39 @@ export default function DashboardLayout({ children }: { children: React.ReactNod
mb: { xs: '16px', lg: 0 }
}} />
<div className="content_box px-4 pt-4 pb-12 lg:pl-11 lg:pr-12 lg:pt-8 lg:pb-16">
{/* {pathname !== '/' && <Breadcrumb />} */}
{children}</div>
{!user?.is_acuity_verified ? <ImportantBlock title='Profile Unverified' message='Your profile is not yet verified. Please complete the verification process.' onAction={async () => {
try {
const response = await verifyAcuity().unwrap();
dispatch(showToast({ message: 'Verification successful.', variant: ToastVariant.SUCCESS }));
if (response?.data?.redirection_url) {
setAcuityUrl(response.data.redirection_url);
setIsAcuityModalOpen(true);
}
}
catch (err: any) {
dispatch(showToast({ message: err?.data?.message || 'Verification failed. Please try again.', variant: ToastVariant.ERROR }))
}
}} actionText={isLoading ? 'Verifying...' : 'Verify Now'} /> : ""}
{children}
<PaymentModal
url={acuityUrl}
isOpen={isAcuityModalOpen}
onClose={() => setIsAcuityModalOpen(false)}
onSuccess={() => {
setIsAcuityModalOpen(false);
dispatch(showToast({ message: 'Verification complete!', variant: ToastVariant.SUCCESS, autoTime: true }));
}}
onError={(error: { message: string }) => {
console.error('Acuity verification error', error);
dispatch(showToast({ message: error.message || 'Verification failed', variant: ToastVariant.ERROR, autoTime: true }));
}}
successMessage="verified"
title="Acuity identity verification"
maxWidth="md"
height={700}
/>
</div>
</div>
</Box>
)
......
'use client';
import { Alert, AlertTitle, Box, Button, Stack, Typography } from '@mui/material';
type Variant = 'warning' | 'info' | 'error' | 'success';
interface ImportantBlockProps {
title: string;
message: string | React.ReactNode;
actionText?: string;
onAction?: () => void;
variant?: Variant;
}
export default function ImportantBlock({
title,
message,
actionText,
onAction,
}: ImportantBlockProps) {
return (
<Alert
sx={{
borderRadius: 3,
mb: 2,
alignItems: 'flex-start',
'& .MuiAlert-message': { width: '100%' },
background: (theme) => theme.palette.warning.main,
color: (theme) => theme.palette.primary.contrastText,
}}
icon={false}
>
<Stack direction={{ sm: 'row' }} justifyContent="space-between" alignItems={{ xs: 'flex-start', sm: 'center' }} spacing={2} width="100%">
<Box>
<AlertTitle sx={{ fontWeight: 700 }}>{title}</AlertTitle>
<Typography variant="body2" sx={{ mb: actionText ? 2 : 0 }}>
{message}
</Typography>
</Box>
{actionText && onAction && (
<Stack direction="row" spacing={1}>
<Button
size="small"
variant="contained"
color='secondary'
onClick={onAction}
>
{actionText}
</Button>
</Stack>
)}
</Stack>
</Alert>
);
}
\ No newline at end of file
'use client';
import { useAppDispatch, useAppSelector } from '@/hooks/hook';
import { useLazyGetMeQuery } from '@/services/authApi';
import { setTokens } from '@/slice/authSlice';
import { Box, CircularProgress, Dialog, DialogContent, Typography } from '@mui/material';
import Cookies from 'js-cookie';
import { useRouter } from 'next/navigation';
import { useEffect, useRef, useState } from 'react';
import { useCallback, useEffect, useRef, useState } from 'react';
export interface PaymentModalProps {
url: string;
......@@ -31,7 +35,7 @@ export default function PaymentModal({
onSuccess,
onError,
successMessage = 'success',
successRedirectPaths = ['/login', '/success'],
successRedirectPaths = ['/login', '/success', '/verified'],
title = 'Processing Payment',
maxWidth = 'sm',
height = 600,
......@@ -42,6 +46,31 @@ export default function PaymentModal({
const [error, setError] = useState<PaymentError | null>(null);
const [hasDetectedSuccess, setHasDetectedSuccess] = useState(false);
const route = useRouter();
const dispatch = useAppDispatch();
const access_token = useAppSelector((state) => state.auth.access_token);
const [fetchMe] = useLazyGetMeQuery();
const syncUserFromServer = useCallback(async () => {
try {
const result = await fetchMe().unwrap();
const user = result.data?.user;
const token = result.data?.access_token || access_token;
console.log("inside sync", {
user, token
})
if (!user) return;
dispatch(setTokens({ access_token: token, user }));
Cookies.set('user', JSON.stringify(user), {
expires: 1,
secure: process.env.NODE_ENV === 'production',
sameSite: 'Strict',
});
} catch (error) {
console.error('[PaymentModal] syncUserFromServer failed', error);
}
}, [fetchMe, dispatch, access_token]);
useEffect(() => {
if (!isOpen) {
setIsLoading(true);
......@@ -50,7 +79,7 @@ export default function PaymentModal({
return;
}
const checkRedirectSuccess = (): void => {
const checkRedirectSuccess = async (): Promise<void> => {
if (hasDetectedSuccess || !iframeRef.current?.contentWindow) return;
try {
......@@ -70,22 +99,17 @@ export default function PaymentModal({
console.log('[PaymentModal] Detected success redirect URL:', currentUrl);
setHasDetectedSuccess(true);
setIsLoading(false);
if (!isRegistrationFlow) await syncUserFromServer();
onSuccess?.();
setTimeout(() => onClose(), 300);
}
} catch {
// cross-origin iframe URL access will throw during external provider flow, ignore until same-origin
}
};
const handleMessage = (event: MessageEvent): void => {
const handleMessage = async (event: MessageEvent): Promise<void> => {
try {
// Ignore messages from React DevTools and other injected frames
if (event.source !== iframeRef.current?.contentWindow) {
console.debug('[PaymentModal] Ignoring message from non-iframe source', event.origin);
return;
}
// Security: Verify message origin; allow provider origin and same-host fallback
const paymentOrigin = new URL(url).origin;
const trustedOrigins = new Set([paymentOrigin, window.location.origin]);
if (!trustedOrigins.has(event.origin)) {
......@@ -117,15 +141,16 @@ export default function PaymentModal({
console.log('[PaymentModal] Payment successful! Closing modal...');
setHasDetectedSuccess(true);
setIsLoading(false);
onSuccess?.();
setTimeout(() => onClose(), 500); // Small delay for animation
if (isRegistrationFlow) {
route.push('/login');
} else {
await syncUserFromServer();
}
onSuccess?.();
setTimeout(() => onClose(), 500);
return;
}
// Check for error status
const isError =
data.status === 'error' ||
data.type === 'payment:error' ||
......@@ -165,7 +190,7 @@ export default function PaymentModal({
window.clearTimeout(readyTimeout);
window.removeEventListener('message', handleMessage);
};
}, [isOpen, url, onClose, onSuccess, onError, successMessage, successRedirectPaths, hasDetectedSuccess]);
}, [isOpen, url, onClose, onSuccess, onError, successMessage, successRedirectPaths, hasDetectedSuccess, isRegistrationFlow, route, syncUserFromServer]);
const handleIframeLoad = (): void => {
console.log('[PaymentModal] iframe loaded');
......
......@@ -136,7 +136,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel,
</span>
</div>}
{isAdmin? "":<>
{isAdmin ? "" : <>
<div className="input__field col-span-1">
<InputLabel htmlFor="address">Address Line 1<span className="text-red-500">*</span></InputLabel>
<OutlinedInput
......@@ -292,7 +292,7 @@ export default function AddPlayerForm({ formik, id, data, loading, buttonLabel,
<span className="error">{formik.touched.gender && formik.errors.gender}</span>
</div>
{isAdmin ? <div className="input__field">
{!isAdmin ? <div className="input__field">
<InputLabel htmlFor="postal_code">Zip Code <span className="text-red-500">*</span></InputLabel>
<OutlinedInput
fullWidth
......
......@@ -75,8 +75,21 @@ export const authApi = createApi({
method: "POST",
body: { age_verify_uuid }
})
}),
getMe: builder.query<LoginResponse, void>({
query: () => ({
url: `/api/auth/me`,
method: "GET",
}),
}),
verifyProfile: builder.mutation<{ data: { redirection_url: string } }, void>({
query: () => ({
url: `/api/acuity/verify`,
method: "POST",
}),
})
})
})
export const { useLoginMutation, useRegisterUserMutation, useSendVerificationLinkAgainMutation, useForgotPasswordMutation, useVerifyOTPMutation, useResetPasswordMutation, useVerifyEmailMutation, useGetAgeGateUuidMutation, useVerifyAgeGateMutation } = authApi;
\ No newline at end of file
export const { useLoginMutation, useRegisterUserMutation, useSendVerificationLinkAgainMutation, useForgotPasswordMutation, useVerifyOTPMutation, useResetPasswordMutation, useVerifyEmailMutation, useGetAgeGateUuidMutation, useVerifyAgeGateMutation, useGetMeQuery, useLazyGetMeQuery, useVerifyProfileMutation } = authApi;
\ No newline at end of file
......@@ -26,7 +26,6 @@ export const userApi = createApi({
invalidatesTags: ['user', "wallet"]
}),
getUserGameCredentials: builder.query<CredentialsResponseProps, void>({
query: () => ({
url: `/api/credentials`,
......@@ -64,7 +63,6 @@ export const userApi = createApi({
providesTags: ['user', "wallet"],
}),
})
})
export const { useAddUserWalletMutation, useUpdateUserProfileMutation, useGetUserGameCredentialsQuery, useChangeUserGamePasswordMutation, useUpdateUserGamePasswordMutation, useGetGamesPasswordStatusQuery } = userApi;
\ No newline at end of file
export const { useAddUserWalletMutation, useUpdateUserProfileMutation, useGetUserGameCredentialsQuery, useChangeUserGamePasswordMutation, useUpdateUserGamePasswordMutation, useGetGamesPasswordStatusQuery} = userApi;
\ No newline at end of file
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