Files
ALwrity/frontend/src/components/MainDashboard/ContentLifecyclePillars.tsx
2025-12-12 21:43:09 +05:30

556 lines
19 KiB
TypeScript

import React, { useState, useEffect } from 'react';
import {
Box,
Container,
Typography,
CardContent,
Chip,
Tooltip,
Paper
} from '@mui/material';
import { motion, AnimatePresence } from 'framer-motion';
import GeneratePillarChips from './components/GeneratePillarChips';
import PublishPillarChips from './components/PublishPillarChips';
import AnalyzePillarChips from './components/AnalyzePillarChips';
import EngagePillarChips from './components/EngagePillarChips';
import EnhancedTodayChip from './components/EnhancedTodayChip';
import OnboardingModal from './components/OnboardingModal';
import WorkflowHeroSection from './components/WorkflowHeroSection';
import { pillarData } from './components/PillarData';
import { useWorkflowStore } from '../../stores/workflowStore';
// Enhanced Glassomorphic Chip Component with Popping Effects
const ChipWithTooltip: React.FC<{
chip: any;
delay?: number;
onOnboardingClick?: () => void;
}> = ({ chip, delay = 0, onOnboardingClick }) => {
const [currentIndex, setCurrentIndex] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCurrentIndex((prev) => (prev + 1) % chip.bubbles.length);
}, 2000 + delay * 300);
return () => clearInterval(interval);
}, [chip.bubbles.length, delay]);
const IconComponent = chip.icon;
const handleClick = () => {
if (chip.label === 'On-Boarding' && onOnboardingClick) {
onOnboardingClick();
}
};
return (
<Tooltip
title={
<Box>
<Typography variant="body2" sx={{ fontWeight: 600, mb: 1 }}>
{chip.label}
</Typography>
<AnimatePresence mode="wait">
<motion.div
key={currentIndex}
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.3 }}
>
<Typography variant="caption" sx={{ color: 'white' }}>
{chip.bubbles[currentIndex]}
</Typography>
</motion.div>
</AnimatePresence>
</Box>
}
arrow
placement="top"
>
<Box
sx={{
position: 'relative',
cursor: 'pointer',
transition: 'all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275)',
'&:hover': {
transform: 'translateY(-4px) scale(1.05)',
'& .chip-glow': {
opacity: 1,
transform: 'scale(1.2)'
},
'& .chip-shadow': {
opacity: 0.6,
transform: 'translateY(8px) scale(1.1)'
}
}
}}
onClick={handleClick}
>
{/* Glow Effect */}
<Box
className="chip-glow"
sx={{
position: 'absolute',
top: -8,
left: -8,
right: -8,
bottom: -8,
background: chip.gradient || chip.color,
borderRadius: '20px',
opacity: 0,
transition: 'all 0.4s ease',
filter: 'blur(12px)',
zIndex: -2
}}
/>
{/* Shadow Effect */}
<Box
className="chip-shadow"
sx={{
position: 'absolute',
top: 4,
left: 2,
right: -2,
bottom: -4,
background: 'rgba(0,0,0,0.3)',
borderRadius: '16px',
opacity: 0.3,
transition: 'all 0.4s ease',
filter: 'blur(8px)',
zIndex: -1
}}
/>
{/* Main Chip */}
<Chip
icon={<IconComponent sx={{ fontSize: 14 }} />}
label={
<Box sx={{ display: 'flex', alignItems: 'center', gap: 0.5 }}>
<Typography variant="caption" sx={{ fontWeight: 600, fontSize: '0.7rem' }}>
{chip.label}
</Typography>
{chip.value && (
<Box
sx={{
backgroundColor: 'rgba(255,255,255,0.9)',
color: chip.color,
borderRadius: '50%',
width: 16,
height: 16,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: '0.6rem',
fontWeight: 700,
boxShadow: '0 2px 4px rgba(0,0,0,0.2)'
}}
>
{chip.value}
</Box>
)}
</Box>
}
size="small"
sx={{
background: `linear-gradient(135deg,
rgba(255,255,255,0.25) 0%,
rgba(255,255,255,0.1) 50%,
rgba(255,255,255,0.05) 100%)`,
backdropFilter: 'blur(20px)',
border: '1px solid rgba(255,255,255,0.3)',
color: 'white',
fontSize: '0.7rem',
fontWeight: 600,
height: 28,
minWidth: 100,
position: 'relative',
overflow: 'hidden',
'&::before': {
content: '""',
position: 'absolute',
top: 0,
left: '-100%',
width: '100%',
height: '100%',
background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent)',
transition: 'left 0.6s ease',
zIndex: 1
},
'&:hover::before': {
left: '100%'
},
'& .MuiChip-label': {
px: 1,
zIndex: 2,
position: 'relative'
},
'& .MuiChip-icon': {
zIndex: 2,
position: 'relative'
},
'&:hover': {
background: `linear-gradient(135deg,
rgba(255,255,255,0.35) 0%,
rgba(255,255,255,0.2) 50%,
rgba(255,255,255,0.1) 100%)`,
border: '1px solid rgba(255,255,255,0.5)',
boxShadow: `0 8px 32px ${chip.color}40,
0 4px 16px rgba(0,0,0,0.1),
inset 0 1px 0 rgba(255,255,255,0.3)`
}
}}
/>
</Box>
</Tooltip>
);
};
// Enhanced Pillar Component with Progressive Disclosure
const PillarCard: React.FC<{
pillar: typeof pillarData[0];
index: number;
onOnboardingClick?: () => void;
}> = ({ pillar, index, onOnboardingClick }) => {
const IconComponent = pillar.icon;
const [isHovered, setIsHovered] = useState(false);
const { currentWorkflow } = useWorkflowStore();
// Use live workflow tasks if available
const liveTasksForPillar = (currentWorkflow?.tasks && currentWorkflow.tasks.length > 0
? currentWorkflow.tasks
: pillar.todayTasks || []).filter((t: any) => t.pillarId === pillar.id);
const totalForPillar = liveTasksForPillar.length;
const doneForPillar = liveTasksForPillar.filter((t: any) => t.status === 'completed' || t.status === 'skipped').length;
return (
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: index * 0.1 }}
whileHover={{ y: -5, scale: 1.02 }}
>
<Paper
elevation={8}
sx={{
height: isHovered ? 280 : 120, // Dynamic height based on hover state
background: pillar.gradient,
color: 'white',
cursor: 'pointer',
transition: 'all 0.4s cubic-bezier(0.4, 0, 0.2, 1)',
position: 'relative',
overflow: 'hidden',
// Large tick when pillar tasks complete (uses live store counts)
'&::after': {
content: doneForPillar > 0 && doneForPillar === totalForPillar ? '"✓"' : '""',
position: 'absolute',
top: '50%',
left: '50%',
transform: 'translate(-50%, -50%)',
fontSize: '64px',
color: 'rgba(255,255,255,0.9)',
textShadow: '0 4px 12px rgba(0,0,0,0.5)',
pointerEvents: 'none',
zIndex: 10, // Ensure tick is above all content
fontWeight: 'bold'
},
'&::before': {
content: '""',
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
background: 'linear-gradient(45deg, rgba(255,255,255,0.1) 0%, transparent 50%)',
opacity: isHovered ? 1 : 0,
transition: 'opacity 0.3s ease'
},
'&:hover': {
boxShadow: `0 12px 24px ${pillar.color}40`
}
}}
onMouseEnter={() => setIsHovered(true)}
onMouseLeave={() => setIsHovered(false)}
>
{/* Shooting star border animation */}
<Box
sx={{
position: 'absolute',
top: 0,
left: 0,
right: 0,
bottom: 0,
borderRadius: 'inherit',
overflow: 'hidden',
zIndex: 1,
'&::before': {
content: '""',
position: 'absolute',
top: 0,
left: '-100%',
width: '100%',
height: '2px',
background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.8), transparent)',
animation: 'shootingStar 8s linear infinite',
},
'@keyframes shootingStar': {
'0%': { left: '-100%' },
'100%': { left: '100%' },
},
}}
/>
<CardContent sx={{ p: 1.5, height: '100%', display: 'flex', flexDirection: 'column', position: 'relative', zIndex: 2 }}>
{/* Header */}
<Box sx={{ display: 'flex', alignItems: 'center', mb: 1, position: 'relative' }}>
<Box
sx={{
p: 0.6,
borderRadius: '50%',
backgroundColor: 'rgba(255,255,255,0.2)',
mr: 1,
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
<IconComponent sx={{ fontSize: 16, color: 'white' }} />
</Box>
<Typography variant="h6" sx={{ fontWeight: 700, fontSize: '1rem' }}>
{pillar.title}
</Typography>
{/* Pillar task count badge */}
<Box sx={{ ml: 1, position: 'relative' }}>
<Box
sx={{
backgroundColor: 'rgba(255,255,255,0.9)',
color: pillar.color,
borderRadius: '12px',
px: 0.75,
py: 0.1,
fontSize: '0.65rem',
fontWeight: 800,
boxShadow: '0 2px 6px rgba(0,0,0,0.2)'
}}
>
{totalForPillar}
</Box>
</Box>
{/* More Options Indicator */}
{!isHovered && (
<motion.div
animate={{ opacity: [0.5, 1, 0.5] }}
transition={{ duration: 2, repeat: Infinity, ease: 'easeInOut' }}
style={{ marginLeft: 'auto' }}
>
<Typography variant="caption" sx={{ fontSize: '0.6rem', opacity: 0.7 }}>
</Typography>
</motion.div>
)}
</Box>
{/* Chips Layout with Progressive Disclosure */}
{pillar.id === 'generate' ? (
<GeneratePillarChips index={index} isHovered={isHovered} />
) : pillar.id === 'publish' ? (
<PublishPillarChips isHovered={isHovered} pillarColor={pillar.color} />
) : pillar.id === 'analyze' ? (
<AnalyzePillarChips isHovered={isHovered} pillarColor={pillar.color} />
) : pillar.id === 'engage' ? (
<EngagePillarChips isHovered={isHovered} pillarColor={pillar.color} />
) : (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
gap: 1,
flexGrow: 1,
justifyContent: isHovered ? 'center' : 'flex-start'
}}
>
{/* Today Chip - Always Visible */}
<EnhancedTodayChip
pillarId={pillar.id}
pillarTitle={pillar.title}
pillarColor={pillar.color}
tasks={pillar.todayTasks}
delay={index * 5}
/>
{/* Additional Chips - Progressive Disclosure */}
<AnimatePresence>
{isHovered && (
<motion.div
initial={{ opacity: 0, height: 0 }}
animate={{ opacity: 1, height: 'auto' }}
exit={{ opacity: 0, height: 0 }}
transition={{ duration: 0.3, ease: 'easeInOut' }}
style={{ overflow: 'hidden' }}
>
<Box sx={{ display: 'flex', flexDirection: 'column', gap: 0.5, mt: 0.5 }}>
{pillar.id === 'plan' ? (
<>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, delay: 0.1 }}
>
<ChipWithTooltip chip={pillar.chips.onboarding} delay={index * 5 + 1} onOnboardingClick={onOnboardingClick} />
</motion.div>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, delay: 0.2 }}
>
<ChipWithTooltip chip={pillar.chips.strategy} delay={index * 5 + 2} />
</motion.div>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, delay: 0.3 }}
>
<ChipWithTooltip chip={pillar.chips.calendar} delay={index * 5 + 3} />
</motion.div>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, delay: 0.4 }}
>
<ChipWithTooltip chip={pillar.chips.review} delay={index * 5 + 4} />
</motion.div>
</>
) : pillar.id === 'remarket' ? (
<>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, delay: 0.1 }}
>
<ChipWithTooltip chip={pillar.chips.good} delay={index * 5 + 1} />
</motion.div>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, delay: 0.2 }}
>
<ChipWithTooltip chip={pillar.chips.bad} delay={index * 5 + 2} />
</motion.div>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, delay: 0.3 }}
>
<ChipWithTooltip chip={pillar.chips.ugly} delay={index * 5 + 3} />
</motion.div>
<motion.div
initial={{ opacity: 0, x: -20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, delay: 0.4 }}
>
<ChipWithTooltip chip={pillar.chips.review} delay={index * 5 + 4} />
</motion.div>
</>
) : null}
</Box>
</motion.div>
)}
</AnimatePresence>
</Box>
)}
</CardContent>
</Paper>
</motion.div>
);
};
// Main Content Lifecycle Pillars Component
const ContentLifecyclePillars: React.FC = () => {
const [onboardingModalOpen, setOnboardingModalOpen] = useState(false);
// Workflow store hooks
const {
currentWorkflow,
isLoading: workflowLoading,
startWorkflow,
} = useWorkflowStore();
const handleOnboardingClick = () => {
setOnboardingModalOpen(true);
};
const handleCloseModal = () => {
setOnboardingModalOpen(false);
};
const handleStartWorkflow = async () => {
try {
if (currentWorkflow) {
await startWorkflow(currentWorkflow.id);
}
} catch (error) {
console.error('Failed to start workflow:', error);
}
};
// Check if workflow is active (in progress or completed)
const isWorkflowActive = currentWorkflow?.workflowStatus === 'in_progress' ||
currentWorkflow?.workflowStatus === 'completed';
return (
<>
<Box
sx={{
py: 3,
background: 'linear-gradient(135deg, rgba(255,255,255,0.05) 0%, rgba(255,255,255,0.02) 100%)',
backdropFilter: 'blur(8px)',
borderRadius: 2,
mb: 4,
position: 'relative', // For hero section positioning
minHeight: '200px', // Reserve space for hero section to prevent layout shift
}}
>
<Container maxWidth="xl">
{/* Pillars Grid */}
<Box
sx={{
display: 'grid',
gridTemplateColumns: {
xs: 'repeat(2, 1fr)',
sm: 'repeat(3, 1fr)',
md: 'repeat(6, 1fr)'
},
gap: 2,
overflow: 'visible'
}}
>
{pillarData.map((pillar, index) => (
<PillarCard
key={pillar.id}
pillar={pillar}
index={index}
onOnboardingClick={handleOnboardingClick}
/>
))}
</Box>
</Container>
{/* Hero Section Overlay */}
<WorkflowHeroSection
onStartWorkflow={handleStartWorkflow}
isWorkflowActive={isWorkflowActive}
isLoading={workflowLoading}
/>
</Box>
{/* Onboarding Modal */}
<OnboardingModal
open={onboardingModalOpen}
onClose={handleCloseModal}
/>
</>
);
};
export default ContentLifecyclePillars;