feat(my-plants): grouped card style for date groups

Aligne le rendu des date groups sur le pattern PracticalGuides : items
encapsulés dans une card blanche rounded-16, séparés par une ligne grise
indentée.

- ScanListItem : nouvelles props grouped + showSeparator → désactive
  borderRadius/margins/border individuels et active la ligne séparatrice
  alignée sous le texte
- DateGroupAccordion : wrappe les ScanListItem dans une View card avec
  shadow iOS / elevation Android

Le même pattern est réutilisé par RecentScans (Home) — voir commit suivant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yanis 2026-05-01 00:02:40 +02:00
parent 3781b1c0f4
commit 4ebbc692ff
2 changed files with 57 additions and 13 deletions

View file

@ -1,5 +1,5 @@
import { useEffect } from 'react'; import { useEffect } from 'react';
import { View, TouchableOpacity, Text, StyleSheet } from 'react-native'; import { View, TouchableOpacity, Text, StyleSheet, Platform } from 'react-native';
import Animated, { import Animated, {
useAnimatedStyle, useAnimatedStyle,
useSharedValue, useSharedValue,
@ -63,15 +63,19 @@ export function DateGroupAccordion({
{/* Content */} {/* Content */}
{isOpen && ( {isOpen && (
<View style={styles.content}> <View style={styles.content}>
{scans.map((scan) => ( <View style={styles.card}>
<ScanListItem {scans.map((scan, index) => (
key={scan.id} <ScanListItem
scan={scan} key={scan.id}
onPress={() => onPressScan(scan)} scan={scan}
onToggleFavorite={() => onToggleFavorite(scan.id)} onPress={() => onPressScan(scan)}
onDelete={() => onDeleteScan(scan.id)} onToggleFavorite={() => onToggleFavorite(scan.id)}
/> onDelete={() => onDeleteScan(scan.id)}
))} grouped
showSeparator={index < scans.length - 1}
/>
))}
</View>
</View> </View>
)} )}
</View> </View>
@ -107,7 +111,24 @@ const styles = StyleSheet.create({
color: '#8E8E93', color: '#8E8E93',
}, },
content: { content: {
paddingTop: 4, paddingTop: 8,
paddingBottom: 8, paddingBottom: 8,
paddingHorizontal: 20,
},
card: {
backgroundColor: '#FFFFFF',
borderRadius: 16,
overflow: 'hidden',
borderWidth: 1,
borderColor: '#F0F0F0',
...Platform.select({
ios: {
shadowColor: '#000',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.04,
shadowRadius: 8,
},
android: { elevation: 2 },
}),
}, },
}); });

View file

@ -19,6 +19,8 @@ interface ScanListItemProps {
onPress: () => void; onPress: () => void;
onToggleFavorite: () => void; onToggleFavorite: () => void;
onDelete: () => void; onDelete: () => void;
grouped?: boolean;
showSeparator?: boolean;
} }
const STATUS_FILL: Record<ScanStatus, string> = { const STATUS_FILL: Record<ScanStatus, string> = {
@ -46,7 +48,14 @@ function getPlantName(scan: ScanRecord, t: (key: string) => string): string {
return t('result.notVine'); return t('result.notVine');
} }
export function ScanListItem({ scan, onPress, onToggleFavorite, onDelete }: ScanListItemProps) { export function ScanListItem({
scan,
onPress,
onToggleFavorite,
onDelete,
grouped = false,
showSeparator = false,
}: ScanListItemProps) {
const { t } = useTranslation(); const { t } = useTranslation();
const swipeableRef = useRef<Swipeable>(null); const swipeableRef = useRef<Swipeable>(null);
const isFav = scan.isFavorite === true; const isFav = scan.isFavorite === true;
@ -117,7 +126,7 @@ export function ScanListItem({ scan, onPress, onToggleFavorite, onDelete }: Scan
friction={2} friction={2}
> >
<TouchableOpacity <TouchableOpacity
style={styles.container} style={[styles.container, grouped && styles.containerGrouped]}
onPress={() => { onPress={() => {
hapticLight(); hapticLight();
onPress(); onPress();
@ -160,6 +169,7 @@ export function ScanListItem({ scan, onPress, onToggleFavorite, onDelete }: Scan
)} )}
</View> </View>
</TouchableOpacity> </TouchableOpacity>
{grouped && showSeparator && <View style={styles.separator} />}
</Swipeable> </Swipeable>
); );
} }
@ -176,6 +186,19 @@ const styles = StyleSheet.create({
borderWidth: 1, borderWidth: 1,
borderColor: '#F0F0F0', borderColor: '#F0F0F0',
}, },
containerGrouped: {
borderRadius: 0,
marginHorizontal: 0,
marginVertical: 0,
borderWidth: 0,
paddingVertical: 14,
paddingHorizontal: 16,
},
separator: {
height: 1,
backgroundColor: '#F0F0F0',
marginLeft: 92,
},
imageWrapper: { imageWrapper: {
width: 64, width: 64,
height: 64, height: 64,