2024-01-24 13:42:54 +00:00
import { observer } from "mobx-react-lite" ;
import { useRouter } from "next/router" ;
import size from "lodash/size" ;
2024-01-29 15:08:32 +00:00
import { useTheme } from "next-themes" ;
2024-01-24 13:42:54 +00:00
// hooks
import { useApplication , useIssues , useUser } from "hooks/store" ;
// components
import { EmptyState , getEmptyStateImagePath } from "components/empty-state" ;
// constants
import { EUserProjectRoles } from "constants/project" ;
import { EIssueFilterType , EIssuesStoreType } from "constants/issue" ;
// types
import { IIssueFilterOptions } from "@plane/types" ;
interface EmptyStateProps {
title : string ;
image : string ;
description? : string ;
comicBox ? : { title : string ; description : string } ;
primaryButton ? : { text : string ; icon? : React.ReactNode ; onClick : ( ) = > void } ;
secondaryButton ? : { text : string ; onClick : ( ) = > void } ;
size ? : "lg" | "sm" | undefined ;
disabled? : boolean | undefined ;
}
export const ProjectEmptyState : React.FC = observer ( ( ) = > {
// router
const router = useRouter ( ) ;
const { workspaceSlug , projectId } = router . query ;
2024-01-29 15:08:32 +00:00
// theme
const { resolvedTheme } = useTheme ( ) ;
2024-01-24 13:42:54 +00:00
// store hooks
const {
commandPalette : commandPaletteStore ,
eventTracker : { setTrackElement } ,
} = useApplication ( ) ;
const {
membership : { currentProjectRole } ,
currentUser ,
} = useUser ( ) ;
const { issuesFilter } = useIssues ( EIssuesStoreType . PROJECT ) ;
const userFilters = issuesFilter ? . issueFilters ? . filters ;
const activeLayout = issuesFilter ? . issueFilters ? . displayFilters ? . layout ;
2024-01-29 15:08:32 +00:00
const isLightMode = resolvedTheme ? resolvedTheme === "light" : currentUser ? . theme . theme === "light" ;
const currentLayoutEmptyStateImagePath = getEmptyStateImagePath ( "empty-filters" , activeLayout ? ? "list" , isLightMode ) ;
const EmptyStateImagePath = getEmptyStateImagePath ( "onboarding" , "issues" , isLightMode ) ;
2024-01-24 13:42:54 +00:00
const issueFilterCount = size (
Object . fromEntries (
2024-01-30 08:29:07 +00:00
Object . entries ( userFilters ? ? { } ) . filter ( ( [ , value ] ) = > value && Array . isArray ( value ) && value . length > 0 )
2024-01-24 13:42:54 +00:00
)
) ;
const handleClearAllFilters = ( ) = > {
if ( ! workspaceSlug || ! projectId ) return ;
const newFilters : IIssueFilterOptions = { } ;
Object . keys ( userFilters ? ? { } ) . forEach ( ( key ) = > {
newFilters [ key as keyof IIssueFilterOptions ] = null ;
} ) ;
issuesFilter . updateFilters ( workspaceSlug . toString ( ) , projectId . toString ( ) , EIssueFilterType . FILTERS , {
. . . newFilters ,
} ) ;
} ;
const isEditingAllowed = ! ! currentProjectRole && currentProjectRole >= EUserProjectRoles . MEMBER ;
const emptyStateProps : EmptyStateProps =
issueFilterCount > 0
? {
title : "No issues found matching the filters applied" ,
image : currentLayoutEmptyStateImagePath ,
secondaryButton : {
text : "Clear all filters" ,
onClick : handleClearAllFilters ,
} ,
}
: {
title : "Create an issue and assign it to someone, even yourself" ,
description :
"Think of issues as jobs, tasks, work, or JTBD. Which we like. An issue and its sub-issues are usually time-based actionables assigned to members of your team. Your team creates, assigns, and completes issues to move your project towards its goal." ,
image : EmptyStateImagePath ,
comicBox : {
title : "Issues are building blocks in Plane." ,
description :
"Redesign the Plane UI, Rebrand the company, or Launch the new fuel injection system are examples of issues that likely have sub-issues." ,
} ,
primaryButton : {
text : "Create your first issue" ,
onClick : ( ) = > {
setTrackElement ( "PROJECT_EMPTY_STATE" ) ;
commandPaletteStore . toggleCreateIssueModal ( true , EIssuesStoreType . PROJECT ) ;
} ,
} ,
size : "lg" ,
disabled : ! isEditingAllowed ,
} ;
return (
< div className = "relative h-full w-full overflow-y-auto" >
< EmptyState { ...emptyStateProps } / >
< / div >
) ;
} ) ;