Skip to content
Merged
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
91 changes: 28 additions & 63 deletions Zero/apps/mail/components/mail/email-scoring-modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,55 +6,44 @@ import {
DialogDescription,
} from '@/components/ui/dialog';
import { Spinner } from '@/components/ui/spinner';
import { Button } from '@/components/ui/button';
import { CheckCircle2 } from 'lucide-react';
import { CheckCircle2, XCircle } from 'lucide-react';
import { useEffect } from 'react';

type ProgressStep =
| 'reading_input'
| 'calculating_score'
| 'creating_recommendations'
| 'completed';
type ProgressStep = 'reading_input' | 'calculating_score' | 'completed';

interface EmailScoringModalProps {
open: boolean;
onOpenChange: (open: boolean) => void;
progressStep: ProgressStep;
score?: number;
recommendations?: string[];
onOk?: () => void;
pass?: boolean;
}

const STEP_LABELS: Record<ProgressStep, string> = {
reading_input: 'Reading input...',
calculating_score: 'Calculating score...',
creating_recommendations: 'Creating recommendations...',
completed: 'Completed',
reading_input: 'Reading reply...',
calculating_score: 'Evaluating...',
completed: 'Done',
};

export function EmailScoringModal({
open,
onOpenChange,
progressStep,
score,
recommendations = [],
onOk,
pass,
}: EmailScoringModalProps) {
const isCompleted = progressStep === 'completed';
const isSuccess = isCompleted && score !== undefined && score >= 70;
const showRecommendations = isCompleted && score !== undefined && score < 70;
const isPass = isCompleted && pass === true;
const isFail = isCompleted && pass === false;

// Auto-dismiss success message after 2 seconds
useEffect(() => {
if (isSuccess && open) {
if (isCompleted && open) {
const timer = setTimeout(() => {
onOpenChange(false);
}, 2000);
return () => clearTimeout(timer);
}
}, [isSuccess, open, onOpenChange]);
}, [isCompleted, open, onOpenChange]);

const steps: ProgressStep[] = ['reading_input', 'calculating_score', 'creating_recommendations'];
const steps: ProgressStep[] = ['reading_input', 'calculating_score'];
const currentStepIndex = steps.indexOf(progressStep);

return (
Expand All @@ -63,32 +52,26 @@ export function EmailScoringModal({
showOverlay
className="bg-panelLight dark:bg-panelDark w-full max-w-[500px]"
onPointerDownOutside={(e) => {
// Prevent closing during loading
if (!isCompleted) {
e.preventDefault();
}
}}
onEscapeKeyDown={(e) => {
// Prevent closing during loading
if (!isCompleted) {
e.preventDefault();
}
}}
>
<DialogHeader>
<DialogTitle className="text-center">
{isSuccess
? 'Email Verified'
: showRecommendations
? 'Improvement Suggestions'
: 'Evaluating Email'}
{isPass ? 'Reply approved' : isFail ? 'Reply not approved' : 'Checking reply'}
</DialogTitle>
<DialogDescription className="sr-only">
{isSuccess
? 'Your email response has been verified and funds have been released'
: showRecommendations
? 'Email quality score and improvement suggestions'
: 'Email is being evaluated for quality'}
{isPass
? 'Reply passed the quality check; funds will be released to your wallet'
: isFail
? 'Reply did not pass the quality check; funds will be returned to the sender'
: 'Reply is being checked'}
</DialogDescription>
</DialogHeader>

Expand All @@ -97,12 +80,12 @@ export function EmailScoringModal({
<div className="space-y-6">
{steps.map((step, index) => {
const isActive = index === currentStepIndex;
const isCompleted = index < currentStepIndex;
const isStepCompleted = index < currentStepIndex;

return (
<div key={step} className="flex items-center gap-4">
<div className="flex-shrink-0">
{isCompleted ? (
{isStepCompleted ? (
<CheckCircle2 className="h-6 w-6 text-green-500" />
) : isActive ? (
<Spinner size={24} color="currentColor" />
Expand All @@ -115,7 +98,7 @@ export function EmailScoringModal({
className={`text-sm ${
isActive
? 'font-medium text-black dark:text-white'
: isCompleted
: isStepCompleted
? 'text-gray-600 dark:text-gray-400'
: 'text-gray-400 dark:text-gray-500'
}`}
Expand All @@ -129,39 +112,21 @@ export function EmailScoringModal({
</div>
)}

{isSuccess && (
{isPass && (
<div className="flex flex-col items-center justify-center space-y-4 py-4">
<CheckCircle2 className="h-16 w-16 text-green-500" />
<p className="text-center text-base font-medium text-black dark:text-white">
Your response has been verified! Funds have been released to your wallet.
Reply approved — funds released to your wallet.
</p>
</div>
)}

{showRecommendations && (
<div className="space-y-4">
<p className="text-sm text-gray-600 dark:text-gray-400">
Your email scored {score}/100. Here are some suggestions to improve:
{isFail && (
<div className="flex flex-col items-center justify-center space-y-4 py-4">
<XCircle className="h-16 w-16 text-red-500" />
<p className="text-center text-base font-medium text-black dark:text-white">
Reply didn't pass the quality check — funds returning to sender.
</p>
<ul className="space-y-2">
{recommendations.length > 0 ? (
recommendations.map((rec) => (
<li key={rec} className="flex items-start gap-2">
<span className="mt-1 text-gray-500 dark:text-gray-400">•</span>
<span className="text-sm text-black dark:text-white">{rec}</span>
</li>
))
) : (
<li className="text-sm text-gray-500 dark:text-gray-400">
No specific recommendations available.
</li>
)}
</ul>
<div className="flex justify-end pt-4">
<Button onClick={onOk || (() => onOpenChange(false))} variant="default">
Ok
</Button>
</div>
</div>
)}
</div>
Expand Down
Loading
Loading