import { FlaskConical } from 'lucide-react'; import React, { useState, useCallback, useEffect, useMemo } from 'react'; import { useSelect, useDispatch } from '@wordpress/data'; import { __, sprintf } from '@wordpress/i18n'; import { ExperimentRowSkeleton } from './components/ExperimentRowSkeleton'; import ExperimentsList from './components/ExperimentsList'; import { store, QueryArgs } from './data/store'; import { VerticalDivider } from '@/accelerate/components/shared/HeaderRow'; import { DataContainer } from '@/components/DataContainer'; import { EmptyState } from '@/components/EmptyState'; import { SearchField } from '@/components/SearchField'; import { AnimatedTabs } from '@/components/ui/animated-tabs'; import { Button } from '@/components/ui/button'; import { usePersistentState } from '@/data/hooks'; import type { DataState } from '@/types/component-states'; const STATUS_OPTIONS = [ { value: 'all', label: __( 'All', 'altis' ), }, { value: 'active', label: __( 'Active', 'altis' ), }, { value: 'completed', label: __( 'Completed', 'altis' ), }, { value: 'draft', label: __( 'Draft', 'altis' ), }, ] as const; const TYPE_OPTIONS = [ { value: 'all', label: __( 'All', 'altis' ), }, { value: 'block', label: __( 'A/B Blocks', 'altis' ), }, { value: 'personalization', label: __( 'Personalization', 'altis' ), }, { value: 'post_tests', label: __( 'Post Tests', 'altis' ), }, ] as const; type StatusFilter = typeof STATUS_OPTIONS[number]['value']; type TypeFilter = typeof TYPE_OPTIONS[number]['value']; export default function Dashboard() { const [ statusFilter, setStatusFilter ] = usePersistentState( 'experiments-status', 'all' ); const [ typeFilter, setTypeFilter ] = usePersistentState( 'experiments-type', 'all' ); const [ search, setSearch ] = useState( '' ); const [ page, setPage ] = useState( 1 ); const queryArgs: QueryArgs = useMemo( () => { const args: QueryArgs = { page, per_page: 20, }; if ( statusFilter !== 'all' ) { args.status = statusFilter; } if ( typeFilter !== 'all' ) { args.type = typeFilter; } if ( search ) { args.search = search; } return args; }, [ statusFilter, typeFilter, search, page ] ); const { fetchExperiments } = useDispatch( store ); useEffect( () => { fetchExperiments( queryArgs ); }, [ queryArgs, fetchExperiments ] ); const { experiments, pagination, isLoading, error } = useSelect( select => { const storeSelect = select( store ); return { experiments: storeSelect.getExperiments(), pagination: storeSelect.getPagination(), isLoading: storeSelect.getIsLoading(), error: storeSelect.getError(), }; }, [] ); const dataState: DataState = useMemo( () => { if ( isLoading ) { return 'loading'; } if ( error ) { return 'error'; } if ( experiments.length === 0 ) { return 'empty'; } return 'loaded'; }, [ isLoading, error, experiments ] ); const handleStatusChange = useCallback( ( value: StatusFilter ) => { setStatusFilter( value ); setPage( 1 ); }, [ setStatusFilter ] ); const handleTypeChange = useCallback( ( value: TypeFilter ) => { setTypeFilter( value ); setPage( 1 ); }, [ setTypeFilter ] ); const handleSearch = useCallback( ( value: string ) => { setSearch( value ); setPage( 1 ); }, [] ); const emptyTitle = useMemo( () => { if ( search ) { return __( 'No matching experiments', 'altis' ); } const typeLabels: Record = { all: '', block: __( 'A/B block', 'altis' ), personalization: __( 'personalization', 'altis' ), post_tests: __( 'post test', 'altis' ), }; const typeLabel = typeLabels[ typeFilter ]; const statusLabels: Record = { all: '', active: __( 'active', 'altis' ), completed: __( 'completed', 'altis' ), draft: __( 'draft', 'altis' ), }; const statusLabel = statusLabels[ statusFilter ]; if ( statusLabel && typeLabel ) { /* translators: 1: status (e.g. "active"), 2: type (e.g. "A/B block") */ return sprintf( __( 'No %1$s %2$s experiments yet', 'altis' ), statusLabel, typeLabel ); } if ( statusLabel ) { /* translators: %s: status (e.g. "active") */ return sprintf( __( 'No %s experiments yet', 'altis' ), statusLabel ); } if ( typeLabel ) { /* translators: %s: type (e.g. "A/B block") */ return sprintf( __( 'No %s experiments yet', 'altis' ), typeLabel ); } return __( 'No experiments yet', 'altis' ); }, [ statusFilter, typeFilter, search ] ); const emptyDescription = useMemo( () => { if ( search ) { return __( 'Try a different search term or adjust your filters.', 'altis' ); } return __( 'Create A/B tests and personalization blocks in the editor to see them here.', 'altis' ); }, [ search ] ); return (
window.open( 'https://developer.acceleratewp.com/experiments/', '_blank' ) } > { __( 'Learn more', 'altis' ) } } description={ emptyDescription } icon={ } title={ emptyTitle } /> } skeleton={ } state={ dataState } > 1 ? (
{ /* translators: %1$d: current page, %2$d: total pages */ } { sprintf( __( 'Page %1$d of %2$d', 'altis' ), page, pagination.pages ) }
) : undefined } />
); }