import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser'; import { Accordion, AccordionDetails, AccordionSummary, Button, styled, Typography, } from '@mui/material'; import { WelcomeDialog } from './WelcomeDialog'; import { useLocalStorageState } from 'hooks/useLocalStorageState'; import { usePersonalDashboard } from 'hooks/api/getters/usePersonalDashboard/usePersonalDashboard'; import { usePersonalDashboardProjectDetails } from 'hooks/api/getters/usePersonalDashboard/usePersonalDashboardProjectDetails'; import { MyProjects } from './MyProjects'; import ExpandMore from '@mui/icons-material/ExpandMore'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; import useSplashApi from 'hooks/api/actions/useSplashApi/useSplashApi'; import { useAuthSplash } from 'hooks/api/getters/useAuth/useAuthSplash'; import { useDashboardState } from './useDashboardState'; import { MyFlags } from './MyFlags'; import { usePageTitle } from 'hooks/usePageTitle'; import { fromPersonalDashboardProjectDetailsOutput } from './RemoteData'; import { useEffect } from 'react'; import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig'; import { InfoSection } from './InfoSection'; import { EventTimeline } from 'component/events/EventTimeline/EventTimeline'; import { AccordionContent } from './SharedComponents'; import { Link } from 'react-router-dom'; import { useUiFlag } from 'hooks/useUiFlag'; const WelcomeSection = styled('div')(({ theme }) => ({ display: 'flex', justifyContent: 'space-between', gap: theme.spacing(1), flexFlow: 'row wrap', alignItems: 'baseline', })); const ViewKeyConceptsButton = styled(Button)({ fontWeight: 'normal', padding: 0, margin: 0, }); const SectionAccordion = styled(Accordion, { shouldForwardProp: (prop) => prop !== 'withSummaryContentBorder', })<{ withSummaryContentBorder?: boolean }>( ({ theme, withSummaryContentBorder = true }) => { const borderStyle = `1px solid ${theme.palette.divider}`; return { border: `1px solid ${theme.palette.divider}`, borderRadius: theme.shape.borderRadiusMedium, backgroundColor: theme.palette.background.paper, boxShadow: 'none', '& .expanded': { '&:before': { opacity: '0 !important', }, }, ...(withSummaryContentBorder && { // add a top border to the region when the accordion is collapsed. // This retains the border between the summary and the region // during the collapsing animation "[aria-expanded='false']+.MuiCollapse-root .MuiAccordion-region": { borderTop: borderStyle, }, // add the border to the region for the accordion is expanded "&>.MuiAccordionSummary-root[aria-expanded='true']": { borderBottom: borderStyle, }, }), overflow: 'hidden', }; }, ); const StyledAccordionSummary = styled(AccordionSummary)(({ theme }) => ({ border: 'none', padding: theme.spacing(2, 4), margin: 0, // increase specificity to override the default margin '&>.MuiAccordionSummary-content.MuiAccordionSummary-content': { margin: '0', }, })); const StyledAccordionDetails = styled(AccordionDetails)({ padding: 0, }); const MainContent = styled('div')(({ theme }) => ({ display: 'flex', flexDirection: 'column', gap: theme.spacing(2), })); const AccordionSummaryText = styled('div')(({ theme }) => ({ display: 'flex', flexDirection: 'column', gap: theme.spacing(0.5), })); const AccordionSummaryHeader = styled('h3')(({ theme }) => ({ color: theme.palette.text.primary, fontSize: theme.typography.body1.fontSize, fontWeight: theme.typography.body2.fontWeight, margin: 0, })); const AccordionSummarySubtitle = styled(Typography)(({ theme }) => ({ color: theme.palette.text.secondary, fontSize: theme.typography.body2.fontSize, fontWeight: theme.typography.body2.fontWeight, })); const EventTimelinePanel = () => { const { toggleSectionState, expandTimeline } = useDashboardState(); const { trackEvent } = usePlausibleTracker(); const signalsLink = '/integrations/signals'; return ( toggleSectionState('timeline')} withSummaryContentBorder={false} > } id='timeline-panel-header' aria-controls='timeline-panel-content' > Event timeline Overview of recent activities across all projects in Unleash. Make debugging easier and{' '} { trackEvent('event-timeline', { props: { eventType: 'signals clicked', }, }); }} > include external signals {' '} to get a fuller overview. ); }; const FlagPanel = () => { const { personalDashboard, refetch: refetchDashboard } = usePersonalDashboard(); const projects = personalDashboard?.projects || []; const { activeFlag, setActiveFlag, toggleSectionState, expandFlags } = useDashboardState({ flags: personalDashboard?.flags ?? [] }); return ( toggleSectionState('flags')} > } id='flags-panel-header' aria-controls='flags-panel-content' > My feature flags Feature flags you have created or favorited 0} flagData={ personalDashboard?.flags.length ? { state: 'flags' as const, activeFlag, flags: personalDashboard.flags, } : { state: 'no flags' as const } } setActiveFlag={setActiveFlag} refetchDashboard={refetchDashboard} /> ); }; const ProjectPanel = () => { const { personalDashboard } = usePersonalDashboard(); const projects = personalDashboard?.projects || []; const { activeProject, setActiveProject, toggleSectionState, expandProjects, } = useDashboardState({ projects }); const personalDashboardProjectDetails = fromPersonalDashboardProjectDetailsOutput( usePersonalDashboardProjectDetails(activeProject), ); return ( toggleSectionState('projects')} > } id='projects-panel-header' aria-controls='projects-panel-content' > My projects Favorite projects, projects you own, and projects you are a member of ); }; export const PersonalDashboard = () => { const { user } = useAuthUser(); const { trackEvent } = usePlausibleTracker(); const { setSplashSeen } = useSplashApi(); const { splash } = useAuthSplash(); const { isOss } = useUiConfig(); const name = user?.name || ''; const showTimelinePanel = useUiFlag('frontendHeaderRedesign'); usePageTitle(name ? `Dashboard: ${name}` : 'Dashboard'); const [welcomeDialog, setWelcomeDialog] = useLocalStorageState< 'open' | 'closed' >( 'welcome-dialog:v1', splash?.personalDashboardKeyConcepts ? 'closed' : 'open', ); useEffect(() => { trackEvent('personal-dashboard', { props: { eventType: 'seen', }, }); }, []); return ( {isOss() ? : null} Welcome {name} { trackEvent('personal-dashboard', { props: { eventType: 'open key concepts', }, }); setWelcomeDialog('open'); }} > View key concepts {showTimelinePanel && } { setSplashSeen('personalDashboardKeyConcepts'); setWelcomeDialog('closed'); }} /> ); };