Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 | 1x 1x 1x 1x 1x 1x 3x 3x 3x 3x 3x 6x 6x 6x 2x 3x | import React, { useMemo } from 'react';
import { ScrollView, StyleSheet, Text, TouchableOpacity } from 'react-native';
import { Feather } from '@expo/vector-icons';
import { useTranslation } from 'react-i18next';
import { EventCategory } from '@/models/event';
import { useTheme } from '@/theme';
import type { Theme } from '@/theme';
interface CategoryChipsProps {
categories: readonly EventCategory[];
selectedCategoryIds: readonly number[];
onToggleCategory: (categoryId: number) => void;
onClearCategories: () => void;
}
export default function CategoryChips({
categories,
selectedCategoryIds,
onToggleCategory,
onClearCategories,
}: CategoryChipsProps) {
const { theme } = useTheme();
const { t } = useTranslation();
const styles = useMemo(() => makeStyles(theme), [theme]);
const hasSelection = selectedCategoryIds.length > 0;
return (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.container}
>
<TouchableOpacity
style={[styles.chip, !hasSelection && styles.chipSelected]}
onPress={onClearCategories}
activeOpacity={0.8}
accessibilityRole="button"
accessibilityLabel={t('home.categoryChips.clearAccessibility')}
testID="category-chip-clear-all"
>
<Text
style={[
styles.chipText,
!hasSelection && styles.chipTextSelected,
]}
numberOfLines={1}
>
{t('home.categoryChips.all')}
</Text>
</TouchableOpacity>
{categories.map((category) => {
const isSelected = selectedCategoryIds.includes(category.id);
const categoryLabel = t(`events.categories.${category.name}`, {
defaultValue: category.name,
});
return (
<TouchableOpacity
key={category.id}
style={[styles.chip, isSelected && styles.chipSelected]}
onPress={() => onToggleCategory(category.id)}
activeOpacity={0.8}
accessibilityRole="button"
accessibilityLabel={
isSelected
? t('home.categoryChips.removeAccessibility', {
category: categoryLabel,
})
: t('home.categoryChips.addAccessibility', {
category: categoryLabel,
})
}
testID={`category-chip-${category.id}`}
>
<Text
style={[styles.chipText, isSelected && styles.chipTextSelected]}
numberOfLines={1}
>
{categoryLabel}
</Text>
{isSelected ? (
<Feather name="x" size={14} color={theme.textOnPrimary} />
) : null}
</TouchableOpacity>
);
})}
</ScrollView>
);
}
function makeStyles(t: Theme) {
return StyleSheet.create({
container: {
paddingBottom: 6,
paddingRight: 12,
},
chip: {
height: 38,
paddingHorizontal: 16,
marginRight: 10,
borderRadius: 19,
backgroundColor: t.surface,
borderWidth: 1,
borderColor: t.border,
alignItems: 'center',
justifyContent: 'center',
flexDirection: 'row',
gap: 6,
},
chipSelected: {
backgroundColor: t.primary,
borderColor: t.primary,
},
chipText: {
color: t.text,
fontSize: 14,
fontWeight: '600',
},
chipTextSelected: {
color: t.textOnPrimary,
},
});
}
|