| 1 | import type { MenuAction } from "@react-native-menu/menu"; |
| 2 | import { useCallback, useMemo } from "react"; |
| 3 | import { NativeStackScreenOptions } from "../../native/StackHeader"; |
| 4 | import { MaterialThreadListToolbar } from "./MaterialThreadListToolbar"; |
| 5 | import type { HomeHeaderProps } from "./HomeHeader.types"; |
| 6 | |
| 7 | export type { HomeHeaderEnvironment } from "./HomeHeader.types"; |
| 8 | |
| 9 | function checkedMenuState(checked: boolean) { |
| 10 | return checked ? ("on" as const) : undefined; |
| 11 | } |
| 12 | |
| 13 | export function HomeHeader(props: HomeHeaderProps) { |
| 14 | // The list uses a fixed creation order and ignores sort/group options, so |
| 15 | // the filter menu only carries the filters and the "customized" icon state |
| 16 | // keys off those alone. |
| 17 | const hasCustomListOptions = |
| 18 | props.selectedEnvironmentId !== null || props.selectedProjectKey !== null; |
| 19 | const menuActions = useMemo<MenuAction[]>( |
| 20 | () => [ |
| 21 | { |
| 22 | id: "environment", |
| 23 | title: "Environment", |
| 24 | subactions: [ |
| 25 | { |
| 26 | id: "environment:all", |
| 27 | title: "All environments", |
| 28 | state: checkedMenuState(props.selectedEnvironmentId === null), |
| 29 | }, |
| 30 | ...props.environments.map((environment) => ({ |
| 31 | id: `environment:${environment.environmentId}`, |
| 32 | title: environment.label, |
| 33 | state: checkedMenuState(props.selectedEnvironmentId === environment.environmentId), |
| 34 | })), |
| 35 | ], |
| 36 | }, |
| 37 | ...(props.projects.length === 0 |
| 38 | ? [] |
| 39 | : ([ |
| 40 | { |
| 41 | id: "project", |
| 42 | title: "Project", |
| 43 | subactions: [ |
| 44 | { |
| 45 | id: "project:all", |
| 46 | title: "All projects", |
| 47 | state: checkedMenuState(props.selectedProjectKey === null), |
| 48 | }, |
| 49 | ...props.projects.map((project) => ({ |
| 50 | id: `project:${project.key}`, |
| 51 | title: project.label, |
| 52 | state: checkedMenuState(props.selectedProjectKey === project.key), |
| 53 | })), |
| 54 | ], |
| 55 | }, |
| 56 | ] satisfies MenuAction[])), |
| 57 | ], |
| 58 | [props.environments, props.projects, props.selectedEnvironmentId, props.selectedProjectKey], |
| 59 | ); |
| 60 | const handleMenuAction = useCallback( |
| 61 | (event: { nativeEvent: { event: string } }) => { |
| 62 | const id = event.nativeEvent.event; |
| 63 | if (id === "environment:all") { |
| 64 | props.onEnvironmentChange(null); |
| 65 | return; |
| 66 | } |
| 67 | |
| 68 | if (id.startsWith("environment:")) { |
| 69 | const environmentId = id.slice("environment:".length); |
| 70 | const environment = props.environments.find( |
| 71 | (candidate) => candidate.environmentId === environmentId, |
| 72 | ); |
| 73 | if (environment) { |
| 74 | props.onEnvironmentChange(environment.environmentId); |
| 75 | } |
| 76 | return; |
| 77 | } |
| 78 | |
| 79 | if (id === "project:all") { |
| 80 | props.onProjectChange(null); |
| 81 | return; |
| 82 | } |
| 83 | |
| 84 | if (id.startsWith("project:")) { |
| 85 | const projectKey = id.slice("project:".length); |
| 86 | if (props.projects.some((project) => project.key === projectKey)) { |
| 87 | props.onProjectChange(projectKey); |
| 88 | } |
| 89 | return; |
| 90 | } |
| 91 | }, |
| 92 | [props], |
| 93 | ); |
| 94 | |
| 95 | return ( |
| 96 | <> |
| 97 | <NativeStackScreenOptions options={{ headerShown: false }} /> |
| 98 | <MaterialThreadListToolbar |
| 99 | searchQuery={props.searchQuery} |
| 100 | onSearchQueryChange={props.onSearchQueryChange} |
| 101 | filterActions={menuActions} |
| 102 | filterCustomized={hasCustomListOptions} |
| 103 | onFilterAction={handleMenuAction} |
| 104 | onOpenSettings={props.onOpenSettings} |
| 105 | onOpenEnvironments={props.onOpenEnvironments} |
| 106 | /> |
| 107 | </> |
| 108 | ); |
| 109 | } |