import React, { useState, useEffect, useCallback } from "react"; import { ReviewItem, ReviewWorkflow, ReviewStatus, ReviewType, ContentType, UserRole, ReviewChecklistItem, ReviewAction, ReviewStage, } from "../types/review"; interface ReviewWorkflowEngineProps { siteId: string; userId: string; userRole: UserRole; className?: string; } interface WorkflowState { workflows: ReviewWorkflow[]; activeReviews: ReviewItem[]; pendingActions: ReviewAction[]; isLoading: boolean; error: string | null; } export const ReviewWorkflowEngine: React.FC = ({ siteId, userId, userRole, className = "", }) => { const [state, setState] = useState({ workflows: [], activeReviews: [], pendingActions: [], isLoading: false, error: null, }); // Mock workflows for demo const mockWorkflows: ReviewWorkflow[] = [ { id: "standard-content-review", name: "Standard Content Review", description: "Standard review process for content updates", contentTypes: ["hero_section", "cta_section", "features_section"], reviewTypes: ["content_update", "content_creation"], stages: [ { id: "editor-review", name: "Editor Review", description: "Initial content review by editor", order: 1, requiredRoles: ["editor"], minimumApprovers: 1, requiredChecklist: ["content-quality", "brand-guidelines"], stageSLAHours: 24, autoApprove: false, onEntry: [], onExit: [], onTimeout: [], onApproval: [], onRejection: [], }, { id: "reviewer-approval", name: "Reviewer Approval", description: "Final approval by content reviewer", order: 2, requiredRoles: ["reviewer", "approver"], minimumApprovers: 1, requiredChecklist: ["seo-check", "accessibility-check"], stageSLAHours: 48, autoApprove: false, onEntry: [], onExit: [], onTimeout: [], onApproval: [], onRejection: [], }, ], currentStage: 0, autoAssignment: true, parallelReview: false, requireAllApprovals: true, escalationEnabled: true, escalationThresholdHours: 72, slaHours: 72, reminderIntervals: [24, 48], active: true, version: 1, createdBy: "system", createdAt: new Date(), updatedAt: new Date(), }, ]; // Mock active reviews const mockActiveReviews: ReviewItem[] = [ { id: "review-001", title: "Hero Section Update", description: "Update hero section content for summer campaign", contentType: "hero_section", reviewType: "content_update", status: "under_review", priority: "medium", contentId: "hero-main", siteId, version: 2, currentContent: { title: "Welcome to AgentC", subtitle: "Build amazing websites with AI", ctaText: "Get Started", }, proposedChanges: { title: "Summer Sale - 50% Off AgentC", subtitle: "Build amazing websites with AI - Limited Time Offer", ctaText: "Start Building Now", }, changesSummary: "Updated messaging for summer campaign promotion", submittedBy: "content-manager", submittedAt: new Date(Date.now() - 86400000), // 1 day ago assignedTo: userId, assignedAt: new Date(Date.now() - 43200000), // 12 hours ago reviewNotes: "", approvalNotes: "", reviewChecklist: [ { id: "content-quality", category: "Content Quality", requirement: "Content follows brand voice and tone guidelines", checked: false, required: true, }, { id: "brand-guidelines", category: "Brand Guidelines", requirement: "Content adheres to brand messaging standards", checked: false, required: true, }, { id: "seo-check", category: "SEO", requirement: "Content is optimized for search engines", checked: false, required: true, }, { id: "accessibility-check", category: "Accessibility", requirement: "Content meets accessibility standards", checked: false, required: false, }, ], requiresLegalReview: false, requiresSEOReview: true, requiresAccessibilityReview: false, estimatedReviewTime: 60, deadlineDate: new Date(Date.now() + 172800000), // 2 days from now tags: ["hero", "campaign", "summer-sale"], workflowStage: "editor-review", nextActionRequired: "Complete review checklist and approve/reject", escalationLevel: 0, createdAt: new Date(Date.now() - 86400000), updatedAt: new Date(Date.now() - 43200000), }, ]; const loadWorkflows = useCallback(async () => { setState((prev) => ({ ...prev, isLoading: true, error: null })); try { // Simulate API call await new Promise((resolve) => setTimeout(resolve, 1000)); setState((prev) => ({ ...prev, workflows: mockWorkflows, activeReviews: mockActiveReviews, isLoading: false, })); } catch (error) { setState((prev) => ({ ...prev, isLoading: false, error: error instanceof Error ? error.message : "Failed to load workflows", })); } }, [siteId]); const handleApproveReview = useCallback( async (reviewId: string, notes: string) => { try { setState((prev) => ({ ...prev, activeReviews: prev.activeReviews.map((review) => review.id === reviewId ? { ...review, status: "approved" as ReviewStatus, approvalNotes: notes, reviewedBy: userId, reviewedAt: new Date(), approvedBy: userId, approvedAt: new Date(), } : review ), })); } catch (error) { setState((prev) => ({ ...prev, error: error instanceof Error ? error.message : "Failed to approve review", })); } }, [userId] ); const handleRejectReview = useCallback( async (reviewId: string, reason: string) => { try { setState((prev) => ({ ...prev, activeReviews: prev.activeReviews.map((review) => review.id === reviewId ? { ...review, status: "rejected" as ReviewStatus, rejectionReason: reason, reviewedBy: userId, reviewedAt: new Date(), } : review ), })); } catch (error) { setState((prev) => ({ ...prev, error: error instanceof Error ? error.message : "Failed to reject review", })); } }, [userId] ); const handleChecklistUpdate = useCallback( (reviewId: string, checklistItemId: string, checked: boolean) => { setState((prev) => ({ ...prev, activeReviews: prev.activeReviews.map((review) => review.id === reviewId ? { ...review, reviewChecklist: review.reviewChecklist.map((item) => item.id === checklistItemId ? { ...item, checked, checkedBy: checked ? userId : undefined, checkedAt: checked ? new Date() : undefined, } : item ), } : review ), })); }, [userId] ); useEffect(() => { loadWorkflows(); }, [loadWorkflows]); if (state.isLoading) { return (
Loading review workflows...
); } if (state.error) { return (

Error

{state.error}

); } return (
{/* Workflow Status Overview */}

Review Workflow Status

Active Reviews

{ state.activeReviews.filter((r) => ["under_review", "pending_review"].includes(r.status) ).length }

Approved Today

{ state.activeReviews.filter( (r) => r.status === "approved" && r.approvedAt && new Date(r.approvedAt).toDateString() === new Date().toDateString() ).length }

Overdue

{ state.activeReviews.filter( (r) => r.deadlineDate && new Date(r.deadlineDate) < new Date() && !["approved", "published", "archived"].includes(r.status) ).length }

{/* Active Reviews List */}

Active Reviews

{state.activeReviews.map((review) => ( ))}
{/* Workflow Configuration */}

Configured Workflows

{state.workflows.map((workflow) => (

{workflow.name}

{workflow.active ? "Active" : "Inactive"}

{workflow.description}

Content Types: {workflow.contentTypes.join(", ")}
SLA: {workflow.slaHours}h
Stages: {workflow.stages.length}
))}
); }; interface ReviewItemCardProps { review: ReviewItem; currentUserId: string; currentUserRole: UserRole; onApprove: (reviewId: string, notes: string) => void; onReject: (reviewId: string, reason: string) => void; onChecklistUpdate: ( reviewId: string, checklistItemId: string, checked: boolean ) => void; } const ReviewItemCard: React.FC = ({ review, currentUserId, currentUserRole, onApprove, onReject, onChecklistUpdate, }) => { const [showDetails, setShowDetails] = useState(false); const [approvalNotes, setApprovalNotes] = useState(""); const [rejectionReason, setRejectionReason] = useState(""); const getStatusColor = (status: ReviewStatus) => { switch (status) { case "pending_review": return "bg-yellow-100 text-yellow-800"; case "under_review": return "bg-blue-100 text-blue-800"; case "approved": return "bg-green-100 text-green-800"; case "rejected": return "bg-red-100 text-red-800"; case "published": return "bg-purple-100 text-purple-800"; default: return "bg-gray-100 text-gray-800"; } }; const getPriorityColor = (priority: string) => { switch (priority) { case "urgent": return "bg-red-100 text-red-800"; case "high": return "bg-orange-100 text-orange-800"; case "medium": return "bg-yellow-100 text-yellow-800"; case "low": return "bg-green-100 text-green-800"; default: return "bg-gray-100 text-gray-800"; } }; const canUserReview = (userRole: UserRole, reviewStage: string) => { // Simplified permission check if (userRole === "admin" || userRole === "super_admin") return true; if (reviewStage === "editor-review" && userRole === "editor") return true; if ( reviewStage === "reviewer-approval" && (userRole === "reviewer" || userRole === "approver") ) return true; return false; }; const requiredItemsCompleted = review.reviewChecklist .filter((item) => item.required) .every((item) => item.checked); return (

{review.title}

{review.status.replace("_", " ")} {review.priority}

{review.description}

Type: {review.contentType.replace("_", " ")} Version: {review.version} Submitted: {new Date(review.submittedAt).toLocaleDateString()} {review.deadlineDate && ( Deadline: {new Date(review.deadlineDate).toLocaleDateString()} )}
{showDetails && (
{/* Changes Preview */}

Proposed Changes

Changes Summary:

{review.changesSummary}

Proposed Content:
                      {JSON.stringify(review.proposedChanges, null, 2)}
                    
{/* Review Checklist */}

Review Checklist

{review.reviewChecklist.map((item) => (
onChecklistUpdate(review.id, item.id, e.target.checked) } disabled={ !canUserReview(currentUserRole, review.workflowStage) } className="mt-1 h-4 w-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500" />
{item.category}
{item.checked && item.checkedBy && (
✓ Checked by {item.checkedBy} on{" "} {item.checkedAt && new Date(item.checkedAt).toLocaleDateString()}
)}
))}
{/* Review Actions */} {canUserReview(currentUserRole, review.workflowStage) && review.status === "under_review" && (

Review Actions