Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/app/admin/billing/components/BillingSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useEffect, useState } from 'react';

import CancelConfirmModal from '@/components/ui/CancelConfirmModal';
import { useGetPlansQuery } from '@/features/public/publicApiSlice';
import { useVerificationCheck } from '@/features/settings/hooks/useVerificationCheck';
import {
useChangePlan,
useCreateSubscription,
Expand Down Expand Up @@ -71,6 +72,7 @@ export default function BillingSection() {
const { downgrade } = useDowngradeToFree();
const { subscription, isSubscribed, isCancelled, currentPlanId } =
useSubscription();
const { blockOperationWithAlert } = useVerificationCheck();

const tierOrder = { FREE: 0, BASIC: 1, PRO: 2 };
const sortedPlans = [...plans].sort(
Expand Down Expand Up @@ -108,6 +110,11 @@ export default function BillingSection() {
tier: 'FREE' | 'BASIC' | 'PRO',
planId: string,
): Promise<void> => {
// Check verification before any plan operations with detailed message
if (!blockOperationWithAlert('switch plans')) {
return;
}

if (label.startsWith('Go with')) {
if (!subscription || subscription.status === 'cancelled') {
await create(planId);
Expand Down
7 changes: 7 additions & 0 deletions src/app/admin/booking/components/TaskManager/BookingModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { type Service } from '@/features/service/serviceApi';
import { useCreateServiceBookingMutation } from '@/features/service/serviceBookingApi';
import type { ServiceManagement } from '@/features/service-management/serviceManagementApi';
import { useGetServiceFormFieldsQuery } from '@/features/service-management/serviceManagementApi';
import { useVerificationCheck } from '@/features/settings/hooks/useVerificationCheck';
import { useAppSelector } from '@/redux/hooks';
interface Props {
onClose: () => void;
Expand Down Expand Up @@ -297,6 +298,7 @@ const BookingModal: React.FC<Props> = ({
>({});
const [createServiceBooking] = useCreateServiceBookingMutation();
const user = useAppSelector(state => state.auth.user);
const { blockOperationWithAlert } = useVerificationCheck();

// Get custom form fields for the selected service
const { data: customFormFields = [] } = useGetServiceFormFieldsQuery(
Expand Down Expand Up @@ -445,6 +447,11 @@ const BookingModal: React.FC<Props> = ({

const handleCreate = async (): Promise<void> => {
try {
// Check verification before creating booking
if (!blockOperationWithAlert('create a booking')) {
return;
}

if (!user) {
throw new Error('User is missing, please login again.');
}
Expand Down
153 changes: 153 additions & 0 deletions src/app/admin/overview/components/VerificationReminder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
'use client';

import {
Alert,
AlertTitle,
Box,
Button,
Chip,
Typography,
} from '@mui/material';
import { useRouter } from 'next/navigation';
import React from 'react';

import { useGetVerificationQuery } from '@/features/settings/settingsApi';

interface VerificationReminderProps {
userId: string;
}

export default function VerificationReminder({
userId,
}: VerificationReminderProps) {
const router = useRouter();
const { data: verificationData, isLoading } = useGetVerificationQuery(
userId,
{
skip: !userId,
},
);

if (isLoading || !verificationData) {
return null;
}

// Check if both email and phone are verified
const isFullyVerified =
verificationData.emailVerified && verificationData.mobileVerified;

if (isFullyVerified) {
return null; // Don't show reminder if fully verified
}

const handleGoToSettings = () => {
router.push('/admin/settings');
};

const unverifiedCount = [
!verificationData.emailVerified,
!verificationData.mobileVerified,
].filter(Boolean).length;

return (
<Box sx={{ mb: 3 }}>
<Alert
severity="warning"
sx={{
borderRadius: 2,
border: '2px solid #ff9800',
backgroundColor: '#fff8e1',
'& .MuiAlert-message': {
width: '100%',
},
}}
>
<AlertTitle sx={{ color: '#f57c00', fontWeight: 'bold' }}>
⚠️ Account Verification Required - {unverifiedCount} Item
{unverifiedCount > 1 ? 's' : ''} Pending
</AlertTitle>

<Typography variant="body1" sx={{ mb: 2, fontWeight: 500 }}>
<strong>Important:</strong> Your account requires verification to
access all features and ensure security.
<br />
<strong>Impact:</strong> Some operations are currently blocked until
verification is complete.
</Typography>

<Box sx={{ display: 'flex', flexDirection: 'column', gap: 1.5, mb: 3 }}>
{!verificationData.emailVerified && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Chip
label="UNVERIFIED"
sx={{
backgroundColor: '#ff9800',
color: 'white',
fontWeight: 'bold'
}}
size="small"
/>
<Typography variant="body2" color="text.secondary">
Email: {verificationData.email ?? 'Not provided'}
</Typography>
</Box>
)}
{!verificationData.mobileVerified && (
<Box sx={{ display: 'flex', alignItems: 'center', gap: 1 }}>
<Chip
label="UNVERIFIED"
sx={{
backgroundColor: '#ff9800',
color: 'white',
fontWeight: 'bold'
}}
size="small"
/>
<Typography variant="body2" color="text.secondary">
Phone: {verificationData.mobile ?? 'Not provided'}
</Typography>
</Box>
)}
</Box>

<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
<Button
variant="contained"
size="medium"
onClick={handleGoToSettings}
sx={{
backgroundColor: '#ff9800',
color: 'white',
fontWeight: 'bold',
px: 3,
'&:hover': {
backgroundColor: '#f57c00',
},
}}
>
Complete Verification Now
</Button>

<Button
variant="outlined"
size="medium"
onClick={() => window.open('/admin/settings', '_blank')}
sx={{
borderColor: '#ff9800',
color: '#ff9800',
fontWeight: 'bold',
px: 3,
'&:hover': {
borderColor: '#f57c00',
backgroundColor: '#fff8e1',
},
}}
>
Open Settings in New Tab
</Button>
</Box>
</Alert>
</Box>
);
}

6 changes: 6 additions & 0 deletions src/app/admin/overview/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import React, { useEffect } from 'react';
import { AdminPageLayout } from '@/components/layout/admin-layout';
import ProFeatureModal from '@/components/ui/ProFeatureModal';
import { useSubscription } from '@/features/subscription/useSubscription';
import { useAppSelector } from '@/redux/hooks';
import { getPlanTier, isFreeOrBasicPlan, isProPlan } from '@/utils/planUtils';

import ActivitySection from './components/ActivitySection';
import CampaignProgressSection from './components/CompaignProgressSection';
import RecentService from './components/RecentService';
import VerificationReminder from './components/VerificationReminder';

const styles = {
contentContainer: {
Expand All @@ -36,6 +38,7 @@ const styles = {
};

export default function OverviewPage() {
const user = useAppSelector(state => state.auth.user);
const { subscription } = useSubscription();
const params = useSearchParams();
const router = useRouter();
Expand Down Expand Up @@ -66,6 +69,9 @@ export default function OverviewPage() {
return (
<>
<AdminPageLayout title="Overview" padding="normal" background="solid">
{/* Verification Reminder */}
{user?._id && <VerificationReminder userId={user._id} />}

<Box sx={styles.contentContainer}>
<ActivitySection />
</Box>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
useSaveServiceFormFieldsMutation,
useUpdateServiceMutation,
} from '@/features/service-management/serviceManagementApi';
import { useVerificationCheck } from '@/features/settings/hooks/useVerificationCheck';
import { useAppSelector } from '@/redux/hooks';
import theme from '@/theme';

Expand Down Expand Up @@ -232,6 +233,7 @@ export default function EditServiceModal({
const [createService, { isLoading: isCreating }] = useCreateServiceMutation();
const [updateService, { isLoading: isUpdating }] = useUpdateServiceMutation();
const [saveServiceFormFields] = useSaveServiceFormFieldsMutation();
const { blockOperationWithAlert } = useVerificationCheck();

// 获取现有的表单字段
const { data: existingFormFields = [] } = useGetServiceFormFieldsQuery(
Expand Down Expand Up @@ -309,6 +311,11 @@ export default function EditServiceModal({

const handleSubmit = async (): Promise<void> => {
try {
// Check verification before creating/updating service
if (!blockOperationWithAlert('create or update a service')) {
return;
}

// Validation before submission
if (!formData.name.trim()) {
alert('Please enter a service name');
Expand Down
Loading