feat: share knop op dashboard kaart — deelt kaart als PNG via expo-sharing
This commit is contained in:
parent
86d6cde478
commit
dc85cd3ff0
1 changed files with 129 additions and 27 deletions
|
|
@ -1,5 +1,7 @@
|
|||
import React from 'react'
|
||||
import { View, Text, StyleSheet } from 'react-native'
|
||||
import React, { useRef } from 'react'
|
||||
import { View, Text, StyleSheet, TouchableOpacity } from 'react-native'
|
||||
import ViewShot from 'react-native-view-shot'
|
||||
import * as Sharing from 'expo-sharing'
|
||||
import { Measurement } from '../types'
|
||||
|
||||
type Props = { measurements: Measurement[] }
|
||||
|
|
@ -16,6 +18,8 @@ const rows: { label: string; key: keyof Measurement; suffix: string }[] = [
|
|||
]
|
||||
|
||||
export default function LatestMeasurementCard({ measurements }: Props) {
|
||||
const viewShotRef = useRef<ViewShot>(null)
|
||||
|
||||
if (measurements.length === 0) {
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
|
|
@ -28,47 +32,70 @@ export default function LatestMeasurementCard({ measurements }: Props) {
|
|||
const previous = measurements[1]
|
||||
const diff = previous ? (latest.weight - previous.weight) : null
|
||||
|
||||
const handleShare = async () => {
|
||||
try {
|
||||
const uri = await viewShotRef.current?.capture?.()
|
||||
if (uri) {
|
||||
await Sharing.shareAsync(uri, { mimeType: 'image/png' })
|
||||
}
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
{previous && (
|
||||
<View style={styles.previous}>
|
||||
<Text style={styles.previousTitle}>Voorlaatste meting</Text>
|
||||
<Text style={styles.previousDate}>
|
||||
{new Date(previous.measuredAt).toLocaleDateString('nl-NL')} — {previous.weight.toFixed(1)} kg
|
||||
</Text>
|
||||
<Text style={styles.diffLabel}>
|
||||
Verschil {diff !== null && (diff > 0 ? '+' : '')}{diff?.toFixed(1)} kg
|
||||
</Text>
|
||||
<View style={styles.divider} />
|
||||
</View>
|
||||
)}
|
||||
<View style={styles.header}>
|
||||
<View style={{ flex: 1 }} />
|
||||
<TouchableOpacity onPress={handleShare} hitSlop={{ top: 8, bottom: 8, left: 8, right: 8 }}>
|
||||
<Text style={styles.shareIcon}>↗</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<Text style={styles.title}>Laatste meting</Text>
|
||||
<Text style={styles.date}>{new Date(latest.measuredAt).toLocaleDateString('nl-NL')}</Text>
|
||||
{rows.map(r => (
|
||||
<View key={r.key} style={styles.row}>
|
||||
<Text style={styles.rowLabel}>{r.label}</Text>
|
||||
<Text style={styles.rowValue}>
|
||||
{typeof latest[r.key] === 'number'
|
||||
? (latest[r.key] as number).toFixed(1)
|
||||
: latest[r.key]}{' '}
|
||||
{r.suffix}
|
||||
</Text>
|
||||
<ViewShot ref={viewShotRef} options={{ format: 'png', quality: 1 }}>
|
||||
<View style={styles.shotContent}>
|
||||
{previous && (
|
||||
<View style={styles.previous}>
|
||||
<Text style={styles.previousTitle}>Voorlaatste meting</Text>
|
||||
<Text style={styles.previousDate}>
|
||||
{new Date(previous.measuredAt).toLocaleDateString('nl-NL')} — {previous.weight.toFixed(1)} kg
|
||||
</Text>
|
||||
<Text style={styles.diffLabel}>
|
||||
Verschil {diff !== null && (diff > 0 ? '+' : '')}{diff?.toFixed(1)} kg
|
||||
</Text>
|
||||
<View style={styles.divider} />
|
||||
</View>
|
||||
)}
|
||||
|
||||
<Text style={styles.title}>Laatste meting</Text>
|
||||
<Text style={styles.date}>{new Date(latest.measuredAt).toLocaleDateString('nl-NL')}</Text>
|
||||
{rows.map(r => (
|
||||
<View key={r.key} style={styles.row}>
|
||||
<Text style={styles.rowLabel}>{r.label}</Text>
|
||||
<Text style={styles.rowValue}>
|
||||
{typeof latest[r.key] === 'number'
|
||||
? (latest[r.key] as number).toFixed(1)
|
||||
: latest[r.key]}{' '}
|
||||
{r.suffix}
|
||||
</Text>
|
||||
</View>
|
||||
))}
|
||||
</View>
|
||||
))}
|
||||
</ViewShot>
|
||||
</View>
|
||||
)
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: { backgroundColor: '#fff', borderRadius: 12, padding: 16, margin: 16, shadowColor: '#000', shadowOpacity: 0.1, shadowRadius: 8, elevation: 3 },
|
||||
header: { flexDirection: 'row', alignItems: 'center', marginBottom: 8 },
|
||||
shareIcon: { fontSize: 22, color: '#2196F3' },
|
||||
shotContent: { backgroundColor: '#fff', padding: 16 },
|
||||
title: { fontSize: 18, fontWeight: '700', marginBottom: 4 },
|
||||
date: { fontSize: 14, color: '#666', marginBottom: 12 },
|
||||
row: { flexDirection: 'row', paddingVertical: 4 },
|
||||
rowLabel: { fontSize: 14, color: '#555', flex: 1 },
|
||||
rowValue: { fontSize: 14, fontWeight: '600' },
|
||||
emptyText: { fontSize: 16, color: '#999', textAlign: 'center', padding: 20 },
|
||||
previous: { marginTop: 4 },
|
||||
previous: { marginBottom: 4 },
|
||||
divider: { height: 1, backgroundColor: '#eee', marginVertical: 12 },
|
||||
previousTitle: { fontSize: 18, fontWeight: '700', marginBottom: 4 },
|
||||
previousDate: { fontSize: 14, color: '#666', marginBottom: 4 },
|
||||
|
|
|
|||
Loading…
Reference in a new issue