Refactor profile screen layout and user preference handling
Android Release Build / build-android (push) Failing after 8m45s

This commit is contained in:
2026-10-16 16:29:48 +02:00
parent 6bd596004d
commit 2e9ce5ee1f
+179
View File
@@ -0,0 +1,179 @@
import { StyleSheet, Text, View } from 'react-native';
import AppHeader from '../components/layout/AppHeader';
import ScreenContainer from '../components/layout/ScreenContainer';
import ProductScoreBadge from '../components/product/ProductScoreBadge';
import { calculateProductRating } from '../services/ratingService';
import { colors } from '../utils/constants';
const labels = {
allergies: 'Allergien',
budget: 'Budget',
ingredients: 'Zutaten',
nutrition: 'Ernährung',
sustainability: 'Nachhaltigkeit'
};
const defaultDetails = {
allergies: {
positive: 'Keine blockierten Allergene und vollständige Allergenangaben verbessern diese Bewertung.',
penalty: 'Treffer mit deinen vermiedenen Allergenen setzen diese Kategorie hart nach unten. Fehlende Allergenangaben werden als Unsicherheit markiert.'
},
budget: {
positive: 'Ein niedriger Anteil am Budget pro Zeitraum verbessert diese Bewertung.',
penalty: 'Ein hoher Preis relativ zu deinem Budget reduziert die Bewertung. Fehlende Preise werden als ungenaue Prüfung markiert.'
},
ingredients: {
positive: 'Keine kritischen Zusatzstoffe, kein Palmöl und passende Vegan-/Vegetarisch-Analyse verbessern diese Bewertung.',
penalty: 'Kritische Zusatzstoffe, Palmöl, viele Zusatzstoffe oder ein Konflikt mit deinem Ernährungsziel reduzieren diese Bewertung.'
},
nutrition: {
positive: 'Guter Nutri-Score, niedrige kritische Nährwert-Level und passende Werte für dein Ernährungsziel verbessern diese Bewertung.',
penalty: 'Hohe Werte bei Zucker, Salz, Fett oder gesättigten Fettsäuren sowie Konflikte mit Low-Sugar- oder High-Protein-Zielen reduzieren diese Bewertung.'
},
sustainability: {
positive: 'Guter Eco-Score, niedriger CO2-Fussabdruck, regionale Herkunft, bessere Verpackung und Bio bei Bio-Präferenz verbessern diese Bewertung.',
penalty: 'Schwacher Eco-Score, hoher CO2-Fussabdruck, belastende Verpackung, weite Herkunft oder fehlendes Bio bei Bio-Präferenz reduzieren diese Bewertung.'
}
};
export default function RatingCriteriaDetailScreen({ product, preferences, category, onBack }) {
const rating = calculateProductRating(product, preferences);
const categoryRating = rating.categoryScores[category];
const title = labels[category] || category;
const fallbackDetails = defaultDetails[category] || defaultDetails.ingredients;
return (
<ScreenContainer>
<AppHeader title={title} subtitle="Bewertungsdetail" onBack={onBack} />
<View style={styles.summaryPanel}>
<View style={styles.summaryRow}>
<View style={styles.summaryCopy}>
<Text style={styles.eyebrow}>Kriterium</Text>
<Text style={styles.title}>{title}</Text>
<Text style={styles.message}>{categoryRating.message}</Text>
</View>
<ProductScoreBadge status={categoryRating.status} score={categoryRating.score} />
</View>
</View>
{(categoryRating.missingData || []).length > 0 ? (
<View style={styles.panel}>
<Text style={styles.panelTitle}>Fehlende Daten</Text>
{categoryRating.missingData.map((message) => (
<Text key={message} style={styles.warningText}>{message}</Text>
))}
</View>
) : null}
{(categoryRating.details || []).length > 0 ? (
<View style={styles.panel}>
<Text style={styles.panelTitle}>So entsteht die Bewertung</Text>
{categoryRating.details.map((detail) => (
<View key={`${detail.title}-${detail.meta || ''}`} style={styles.detailItem}>
<Text style={detail.type === 'positive' ? styles.positiveTitle : styles.penaltyTitle}>
{detail.title}
</Text>
<Text style={styles.detailBody}>{detail.body}</Text>
{detail.meta ? <Text style={styles.detailMeta}>{detail.meta}</Text> : null}
</View>
))}
</View>
) : null}
<View style={styles.panel}>
<Text style={styles.panelTitle}>Was die Bewertung verbessert</Text>
<Text style={styles.detailBody}>{fallbackDetails.positive}</Text>
</View>
<View style={styles.panel}>
<Text style={styles.panelTitle}>Was die Bewertung senkt</Text>
<Text style={styles.detailBody}>{fallbackDetails.penalty}</Text>
</View>
</ScreenContainer>
);
}
const styles = StyleSheet.create({
summaryPanel: {
backgroundColor: colors.surface,
borderColor: colors.border,
borderRadius: 18,
borderWidth: 1,
padding: 16
},
summaryRow: {
alignItems: 'flex-start',
flexDirection: 'row',
gap: 12
},
summaryCopy: {
flex: 1
},
eyebrow: {
color: colors.primary,
fontSize: 12,
fontWeight: '800',
textTransform: 'uppercase'
},
title: {
color: colors.text,
fontSize: 23,
fontWeight: '800',
lineHeight: 29,
marginTop: 4
},
message: {
color: colors.muted,
fontSize: 15,
lineHeight: 21,
marginTop: 8
},
panel: {
backgroundColor: colors.surface,
borderColor: colors.border,
borderRadius: 18,
borderWidth: 1,
gap: 10,
padding: 16
},
panelTitle: {
color: colors.text,
fontSize: 16,
fontWeight: '800'
},
detailItem: {
borderTopColor: colors.border,
borderTopWidth: 1,
gap: 5,
paddingTop: 10
},
positiveTitle: {
color: colors.success,
fontSize: 14,
fontWeight: '800'
},
penaltyTitle: {
color: colors.danger,
fontSize: 14,
fontWeight: '800'
},
detailBody: {
color: colors.muted,
fontSize: 14,
lineHeight: 20
},
detailMeta: {
color: colors.text,
fontSize: 13,
fontWeight: '700',
lineHeight: 19
},
warningText: {
color: colors.warning,
fontSize: 13,
fontWeight: '700',
lineHeight: 19
}
});