import { Text } from '@/aesthetics/Text';
import { font, radius, spacing, useColors } from '@/aesthetics/styles';
import { useStrings } from '@/common/hooks/useStrings';
import type {
NutrientKey,
Nutrition,
NutritionDisplayMode,
NutritionSortMode,
} from '@/types/nutrition';
import { ArrowDownUp, ChevronDown } from 'lucide-react-native';
import { useMemo, useState } from 'react';
import { Pressable, StyleSheet, View, useWindowDimensions } from 'react-native';
import { NUTRIENT_META } from '@/common/constants/nutrition';
import { getNutrientsByMode, sortNutrients } from '@/see-log/utils/nutrition';
import { NutrientTile } from './NutrientTile';
type NutrientBreakdownProps = {
consumed: Nutrition;
targets: Nutrition;
displayMode: NutritionDisplayMode;
sortMode: NutritionSortMode;
onChangeDisplayMode: (mode: NutritionDisplayMode) => void;
onChangeSortMode: (mode: NutritionSortMode) => void;
};
const GAP = spacing.xs;
const TILES_PER_ROW = 3;
const INITIAL_ROWS = 3;
const CARD_BORDER = 2;
const CONTAINER_PADDING = spacing.xl * 4 + CARD_BORDER;
function TileGrid({
keys,
consumed,
targets,
tileWidth,
}: {
keys: NutrientKey[];
consumed: Nutrition;
targets: Nutrition;
tileWidth: number;
}) {
return (
{keys.map(k => {
const meta = NUTRIENT_META[k];
const consumedValue = consumed[k] ?? 0;
const targetValue = targets[k] ?? 100;
const pct = Math.min((consumedValue / targetValue) * 100, 100);
return (
);
})}
);
}
export function NutrientBreakdown({
consumed,
targets,
displayMode,
sortMode,
onChangeDisplayMode,
onChangeSortMode,
}: NutrientBreakdownProps) {
const c = useColors();
const strings = useStrings();
const { width: screenWidth } = useWindowDimensions();
const [expanded, setExpanded] = useState(false);
const tileWidth = (screenWidth - CONTAINER_PADDING - GAP * (TILES_PER_ROW - 1)) / TILES_PER_ROW;
const { level1, level2, level3 } = useMemo(() => {
const byLevel = getNutrientsByMode(displayMode);
return {
level1: sortNutrients(byLevel.level1, sortMode, consumed, targets),
level2: sortNutrients(byLevel.level2, sortMode, consumed, targets),
level3: sortNutrients(byLevel.level3, sortMode, consumed, targets),
};
}, [displayMode, sortMode, consumed, targets]);
const isNutrientsMode = displayMode === 'nutrients';
const initialVisible = INITIAL_ROWS * TILES_PER_ROW;
const hiddenCount =
level1.length - initialVisible + (isNutrientsMode ? level2.length + level3.length : 0);
const visibleLevel1 = expanded ? level1 : level1.slice(0, initialVisible);
return (
{(['nutrients', 'usa_gov_dga'] as const).map(mode => (
onChangeDisplayMode(mode)}
style={[styles.modeTab, displayMode === mode && { backgroundColor: c.surface }]}
>
{mode === 'nutrients'
? strings.seeLog.nutrients
: strings.seeLog.nutrientBreakdown.usRealFood}
))}
{strings.seeLog.nutrientBreakdown.important}
onChangeSortMode(sortMode === 'default' ? 'least_filled' : 'default')}
style={({ pressed }) => [
styles.sortButton,
{ backgroundColor: c.tagBg },
pressed && { opacity: 0.7 },
]}
>
{sortMode === 'default'
? strings.seeLog.sorting.default
: strings.seeLog.sorting.priority}
{expanded && isNutrientsMode && level2.length > 0 && (
{strings.seeLog.nutrientBreakdown.hardToEat}
)}
{expanded && isNutrientsMode && level3.length > 0 && (
{strings.seeLog.nutrientBreakdown.more}
)}
{hiddenCount > 0 && (
setExpanded(e => !e)}
style={({ pressed }) => [styles.expandButton, pressed && { opacity: 0.7 }]}
>
{expanded
? strings.seeLog.nutrientBreakdown.showLess
: strings.seeLog.nutrientBreakdown.showMore(hiddenCount)}
)}
);
}
const styles = StyleSheet.create({
modeTabs: {
flexDirection: 'row',
padding: 3,
borderRadius: radius.md,
marginBottom: spacing.lg,
},
sectionHeaderRow: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
marginBottom: spacing.sm,
},
modeTab: {
flex: 1,
paddingVertical: spacing.sm,
borderRadius: radius.sm,
alignItems: 'center',
},
modeTabText: {
fontSize: font.sm,
fontWeight: '500',
},
grid: {
width: '100%',
flexDirection: 'row',
flexWrap: 'wrap',
gap: GAP,
},
expandButton: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: spacing.xs,
marginTop: spacing.lg,
},
expandText: {
fontSize: font.sm,
fontWeight: '500',
},
sortButton: {
flexDirection: 'row',
alignItems: 'center',
gap: spacing.xs,
paddingHorizontal: spacing.sm,
paddingVertical: spacing.sm,
borderRadius: radius.md,
},
sortButtonText: {
fontSize: font.xs,
fontWeight: '500',
},
sectionHeader: {
fontSize: font.md,
fontWeight: '600',
marginTop: spacing.lg,
marginBottom: spacing.sm,
},
firstSectionHeader: {
marginTop: 0,
marginBottom: 0,
},
});