import { RouteProp, useNavigation, useRoute } from '@react-navigation/native' import React, { useCallback, useMemo } from 'react' import { Alert, ScrollView, StyleSheet, View } from 'react-native' import { Heading, TextButton, ToggleButton } from '../../../components' import { useAtFontScaleBreakpoint, useCanCreateConversations, useCurrentPersonCache, useDirectMessagesEligible, useHasDirectMessages, useNewConversationEntry, useTheme, } from '../../../hooks' import { useMarkAllRead } from '../../../hooks/use_conversations_actions' import { useCanDisplayGroups } from '../../../hooks/use_groups' import { useNewConversationFromFilter } from '../../../hooks/use_new_conversation_from_filter' import { GraphId } from '../../../types/resources/group_resource' import { MAX_FONT_SIZE_MULTIPLIER_LANDMARK } from '../../../utils' import { Haptic } from '../../../utils/native_adapters' import { ConversationFiltersParams } from '../../conversation_filters/screen_props' import { ConversationsScreenProps } from '../conversations_screen' import { ChatGroupBadge } from './chat_group_badge' import { ListHeaderActionButton } from './list_header_action_button' const ROW_PADDING_HORIZONTAL = 16 enum FilterTypes { All = 'All', Groups = 'Groups', Teams = 'Teams', DMs = 'DMs', More = 'More', } export const ListHeaderComponent = () => { const navigation = useNavigation() const canFilterByTeams = useCanDisplayGroups({ source_app_name: 'Services', source_type: 'Team' }) const canFilterByGroups = useCanDisplayGroups({ source_app_name: 'Groups', source_type: 'Group' }) const directMessagesEligible = useDirectMessagesEligible() const hasDirectMessages = useHasDirectMessages() const canFilterByDMs = directMessagesEligible && hasDirectMessages const route = useRoute>() const { chat_group_graph_id, group_source_app_name = '', show_direct_messages, show_archived, } = route.params || {} const currentPersonCache = useCurrentPersonCache() const { markAllRead, isPending } = useMarkAllRead() const canCreateConversations = useCanCreateConversations() const entryMode = useNewConversationEntry() const newConversationFromFilter = useNewConversationFromFilter( chat_group_graph_id as GraphId | undefined ) const active: FilterTypes = useMemo(() => { if (chat_group_graph_id || show_archived) { return FilterTypes.More } else if (/groups/i.test(group_source_app_name)) { return FilterTypes.Groups } else if (/services/i.test(group_source_app_name)) { return FilterTypes.Teams } else if (show_direct_messages) { return FilterTypes.DMs } return FilterTypes.All }, [chat_group_graph_id, group_source_app_name, show_direct_messages, show_archived]) const handleNewConversationNavigation = useCallback(() => { if (newConversationFromFilter || entryMode === 'select_type') { return navigation.navigate('ConversationSelectType', { ...route.params, newConversationFromFilter, }) } if (entryMode === 'groups') { return navigation.navigate('New', { screen: 'ConversationSelectGroupRecipients', params: { ...route.params }, }) } if (entryMode === 'teams') { return navigation.navigate('New', { screen: 'ConversationSelectTeamsILeadRecipients', params: { ...route.params }, }) } if (entryMode === 'direct_message') { return navigation.navigate('New', { screen: 'ConversationSelectDirectMessageRecipients', params: { ...route.params }, }) } }, [navigation, route.params, entryMode, newConversationFromFilter]) const handleSetFilter = useCallback( (params: ConversationFiltersParams) => { navigation.setParams({ title: undefined, chat_group_graph_id: undefined, group_source_app_name: undefined, show_direct_messages: undefined, show_archived: undefined, ...params, }) }, [navigation] ) const handleChatSettings = useCallback(() => { navigation.navigate('ChatSettings', {}) }, [navigation]) const handleOpenConversationFilters = useCallback(() => { navigation.navigate('ConversationFilters', { chat_group_graph_id, group_source_app_name, show_direct_messages, show_archived, }) }, [navigation, chat_group_graph_id, group_source_app_name, show_direct_messages, show_archived]) const handleMarkAllRead = useCallback(() => { currentPersonCache.update({ unreadCount: 0 }) Haptic.notificationSuccess() markAllRead() }, [currentPersonCache, markAllRead]) const alertMarkAllRead = useCallback(() => { if (active === FilterTypes.All) return handleMarkAllRead() Alert.alert('Mark all read', 'This includes conversations not shown by the current filter.', [ { text: 'Cancel' }, { text: 'OK', onPress: () => handleMarkAllRead() }, ]) }, [active, handleMarkAllRead]) const hasSomeSourceFilterCapability = canFilterByTeams || canFilterByGroups const hasMultiSourceFilterCapabilities = canFilterByTeams && canFilterByGroups const showFilterRow = hasMultiSourceFilterCapabilities || canFilterByDMs const shouldShowHeaderFiltersButton = hasSomeSourceFilterCapability && !showFilterRow const moreFiltersButtonA11yLabel = shouldShowHeaderFiltersButton ? 'View filters' : 'View more filters' const moreFiltersButtonProps = { onPress: handleOpenConversationFilters, active: active === FilterTypes.More, iconNameRight: 'general.threeReducingHorizontalBars' as const, accessibilityLabel: moreFiltersButtonA11yLabel, } const styles = useStyles({ shouldShowHeaderFiltersButton }) return ( Conversations {!show_archived && ( Mark all read )} {canCreateConversations && ( )} {shouldShowHeaderFiltersButton && } {showFilterRow && ( handleSetFilter({})} accessibilityLabel="Show all conversations" style={styles.filterButton} /> {canFilterByGroups && ( handleSetFilter({ group_source_app_name: 'Groups' })} accessibilityLabel="Filter to group conversations" style={styles.filterButton} /> )} {canFilterByTeams && ( handleSetFilter({ group_source_app_name: 'Services' })} accessibilityLabel="Filter to team conversations" style={styles.filterButton} /> )} {canFilterByDMs && ( handleSetFilter({ show_direct_messages: true })} accessibilityLabel="Filter to direct message conversations" style={styles.filterButton} /> )} )} ) } const useStyles = ({ shouldShowHeaderFiltersButton, }: { shouldShowHeaderFiltersButton: boolean }) => { const theme = useTheme() const atFontScaleBreakpoint = useAtFontScaleBreakpoint( shouldShowHeaderFiltersButton ? 1.2 : undefined ) return StyleSheet.create({ listHeader: { borderBottomWidth: 1, borderBottomColor: theme.colors.fillColorNeutral050Base, paddingBottom: 16, gap: 16, }, headingRow: { gap: 12, flexDirection: atFontScaleBreakpoint ? 'column' : 'row', alignItems: atFontScaleBreakpoint ? 'flex-start' : 'center', justifyContent: 'space-between', paddingBottom: atFontScaleBreakpoint ? 4 : 0, paddingHorizontal: ROW_PADDING_HORIZONTAL, }, titleContainer: { gap: 8, }, actionsContainer: { flexDirection: 'row', gap: 8, alignItems: 'center', }, markAllReadRow: { paddingBottom: 4, }, filterRow: { flexDirection: 'row', justifyContent: 'flex-start', gap: 8, paddingHorizontal: ROW_PADDING_HORIZONTAL, flexGrow: 1, }, filterButton: { flex: 1, minWidth: 65, }, }) }