Refactor profile screen layout and user preference handling
Android Release Build / build-android (push) Successful in 13m44s
Android Release Build / build-android (push) Successful in 13m44s
This commit is contained in:
@@ -15,6 +15,7 @@ export default function HomeScreen({ preferences, recentProducts, shoppingList,
|
||||
.sort((a, b) => (b.scanCount || 0) - (a.scanCount || 0))
|
||||
.slice(0, 3);
|
||||
const openItems = shoppingList?.items?.filter((item) => !item.checked).length || 0;
|
||||
const completedItems = (shoppingList?.items?.length || 0) - openItems;
|
||||
|
||||
return (
|
||||
<ScreenContainer>
|
||||
@@ -36,7 +37,7 @@ export default function HomeScreen({ preferences, recentProducts, shoppingList,
|
||||
<View style={styles.listShortcutText}>
|
||||
<Text style={styles.listShortcutTitle}>Dein Einkauf</Text>
|
||||
<Text style={styles.listShortcutCopy}>
|
||||
{shoppingList?.items?.length ? `${openItems} noch offen · ${shoppingList.items.length} insgesamt` : 'Deine Liste ist noch leer'}
|
||||
{shoppingList?.items?.length ? `${completedItems} von ${shoppingList.items.length} erledigt · ${openItems} noch offen` : 'Deine Liste ist noch leer'}
|
||||
</Text>
|
||||
</View>
|
||||
<Text style={styles.listShortcutTotal}>
|
||||
|
||||
@@ -54,7 +54,17 @@ export default function ScanScreen({ preferences, productCache, onScanBarcode, o
|
||||
setIsSearching(true);
|
||||
setSearchError('');
|
||||
try {
|
||||
const results = await searchProducts(manualSearchQuery, productCache, preferences.offlineModeEnabled);
|
||||
const query = manualSearchQuery.trim();
|
||||
if (/^\d{8,14}$/.test(query)) {
|
||||
const result = await onScanBarcode(query);
|
||||
if (result.status !== 'found') {
|
||||
setManualResults([]);
|
||||
setHasSearched(false);
|
||||
setSearchError(result.errorMessage || 'Zu diesem Barcode wurde kein Produkt gefunden.');
|
||||
}
|
||||
return;
|
||||
}
|
||||
const results = await searchProducts(query, productCache, preferences.offlineModeEnabled);
|
||||
setManualResults(results);
|
||||
setHasSearched(true);
|
||||
} catch (error) {
|
||||
|
||||
@@ -15,6 +15,7 @@ export default function ShoppingListScreen({
|
||||
shoppingList,
|
||||
lastDeletedItem,
|
||||
onToggleItem,
|
||||
onChangeItemQuantity,
|
||||
onDeleteItem,
|
||||
onUndoDelete,
|
||||
onUpdateItemPrice,
|
||||
@@ -25,7 +26,12 @@ export default function ShoppingListScreen({
|
||||
const [isConfirming, setIsConfirming] = useState(false);
|
||||
const [wasCompleted, setWasCompleted] = useState(false);
|
||||
const openItems = shoppingList.items.filter((item) => !item.checked).length;
|
||||
const completedItems = shoppingList.items.length - openItems;
|
||||
const openTotal = shoppingList.items.reduce((sum, item) =>
|
||||
sum + (!item.checked && typeof item.estimatedPrice === 'number' ? item.estimatedPrice * item.quantity : 0), 0);
|
||||
const progress = shoppingList.items.length ? completedItems / shoppingList.items.length : 0;
|
||||
const itemsWithoutPrice = shoppingList.items.filter((item) => typeof item.estimatedPrice !== 'number').length;
|
||||
const openItemsWithoutPrice = shoppingList.items.filter((item) => !item.checked && typeof item.estimatedPrice !== 'number').length;
|
||||
const budget = preferences.maxBudgetPerShoppingTrip;
|
||||
const hasBudget = typeof budget === 'number' && budget > 0;
|
||||
const budgetShare = hasBudget ? shoppingList.estimatedTotal / budget : 0;
|
||||
@@ -59,6 +65,18 @@ export default function ShoppingListScreen({
|
||||
<Text style={styles.totalLabel}>{itemsWithoutPrice ? 'Bekannte Summe' : 'Voraussichtliche Summe'}</Text>
|
||||
<Text style={styles.totalValue}>{formatPrice(shoppingList.estimatedTotal, shoppingList.currency)}</Text>
|
||||
{itemsWithoutPrice ? <Text style={styles.summaryCopy}>{itemsWithoutPrice} {itemsWithoutPrice === 1 ? 'Produkt ohne Preis ist' : 'Produkte ohne Preis sind'} nicht eingerechnet.</Text> : null}
|
||||
{shoppingList.items.length > 0 ? (
|
||||
<View style={styles.shoppingProgress}>
|
||||
<View style={styles.progressHeader}>
|
||||
<Text style={styles.progressLabel}>{completedItems} von {shoppingList.items.length} erledigt</Text>
|
||||
<Text style={styles.progressLabel}>{Math.round(progress * 100)} %</Text>
|
||||
</View>
|
||||
<View style={styles.progressTrack}>
|
||||
<View style={[styles.progressFill, styles.goodFill, { width: `${progress * 100}%` }]} />
|
||||
</View>
|
||||
<Text style={styles.remainingCopy}>Noch offen: {formatPrice(openTotal, shoppingList.currency)}{openItemsWithoutPrice ? ` plus ${openItemsWithoutPrice} Artikel ohne Preis` : ''}</Text>
|
||||
</View>
|
||||
) : null}
|
||||
{hasBudget ? <View style={styles.budgetBox}>
|
||||
<View style={styles.budgetHeader}>
|
||||
<Text style={styles.budgetLabel}>Anteil am Budget pro {budgetPeriodLabels[preferences.budgetPeriod] || 'Woche'}</Text>
|
||||
@@ -111,15 +129,16 @@ export default function ShoppingListScreen({
|
||||
<SecondaryButton label="Produkt scannen" onPress={onStartScan} />
|
||||
</View>
|
||||
) : (
|
||||
shoppingList.items.map((item) => (
|
||||
<ShoppingListItem
|
||||
item={item}
|
||||
key={item.id}
|
||||
onDelete={() => onDeleteItem(item.id)}
|
||||
onToggle={() => onToggleItem(item.id)}
|
||||
onUpdatePrice={onUpdateItemPrice}
|
||||
/>
|
||||
))
|
||||
<>
|
||||
{openItems > 0 ? <Text style={styles.groupTitle}>Noch einkaufen · {openItems}</Text> : null}
|
||||
{shoppingList.items.filter((item) => !item.checked).map((item) => (
|
||||
<ShoppingListItem item={item} key={item.id} onDelete={() => onDeleteItem(item.id)} onToggle={() => onToggleItem(item.id)} onChangeQuantity={(change) => onChangeItemQuantity(item.id, change)} onUpdatePrice={onUpdateItemPrice} />
|
||||
))}
|
||||
{completedItems > 0 ? <Text style={styles.groupTitle}>Erledigt · {completedItems}</Text> : null}
|
||||
{shoppingList.items.filter((item) => item.checked).map((item) => (
|
||||
<ShoppingListItem item={item} key={item.id} onDelete={() => onDeleteItem(item.id)} onToggle={() => onToggleItem(item.id)} onChangeQuantity={(change) => onChangeItemQuantity(item.id, change)} onUpdatePrice={onUpdateItemPrice} />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
|
||||
{shoppingList.items.length > 0 ? (
|
||||
@@ -154,6 +173,11 @@ function formatAmount(value, unit) {
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
shoppingProgress: { marginTop: 18 },
|
||||
progressHeader: { flexDirection: 'row', justifyContent: 'space-between' },
|
||||
progressLabel: { color: colors.primaryDark, fontSize: 13, fontWeight: '800' },
|
||||
remainingCopy: { color: colors.muted, fontSize: 13, marginTop: 8 },
|
||||
groupTitle: { color: colors.text, fontSize: 16, fontWeight: '800', marginTop: 4 },
|
||||
summary: {
|
||||
backgroundColor: colors.surface,
|
||||
borderColor: colors.border,
|
||||
|
||||
Reference in New Issue
Block a user