feat(个人中心): 优化会员横幅组件,支持深色模式与国际化;新增医疗记录卡片组件,完善健康档案功能
This commit is contained in:
@@ -131,10 +131,13 @@ export function HealthHistoryTab() {
|
||||
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
|
||||
const [currentEditingId, setCurrentEditingId] = useState<string | null>(null);
|
||||
|
||||
// 初始化时从服务端获取健康史数据
|
||||
// 初始化时从服务端获取健康史数据(如果父组件未加载)
|
||||
useEffect(() => {
|
||||
dispatch(fetchHealthHistory());
|
||||
}, [dispatch]);
|
||||
// 只在数据为空时才主动拉取,避免重复请求
|
||||
if (!historyData || Object.keys(historyData).length === 0) {
|
||||
dispatch(fetchHealthHistory());
|
||||
}
|
||||
}, [dispatch, historyData]);
|
||||
|
||||
const historyItems = [
|
||||
{ title: t('health.tabs.healthProfile.history.allergy'), key: 'allergy' },
|
||||
|
||||
@@ -1,49 +1,647 @@
|
||||
import { MedicalRecordCard } from '@/components/health/MedicalRecordCard';
|
||||
import { palette } from '@/constants/Colors';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { MedicalRecordItem, MedicalRecordType } from '@/services/healthProfile';
|
||||
import {
|
||||
addNewMedicalRecord,
|
||||
deleteMedicalRecordItem,
|
||||
fetchMedicalRecords,
|
||||
selectHealthLoading,
|
||||
selectMedicalRecords,
|
||||
} from '@/store/healthSlice';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import React from 'react';
|
||||
import { StyleSheet, Text, View } from 'react-native';
|
||||
import dayjs from 'dayjs';
|
||||
import * as DocumentPicker from 'expo-document-picker';
|
||||
import { Image } from 'expo-image';
|
||||
import * as ImagePicker from 'expo-image-picker';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
FlatList,
|
||||
Modal,
|
||||
Platform,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import ImageViewing from 'react-native-image-viewing';
|
||||
import DateTimePickerModal from 'react-native-modal-datetime-picker';
|
||||
|
||||
export function MedicalRecordsTab() {
|
||||
const dispatch = useAppDispatch();
|
||||
const medicalRecords = useAppSelector(selectMedicalRecords);
|
||||
const records = medicalRecords?.records || [];
|
||||
const prescriptions = medicalRecords?.prescriptions || [];
|
||||
const isLoading = useAppSelector(selectHealthLoading);
|
||||
|
||||
const [activeTab, setActiveTab] = useState<MedicalRecordType>('medical_record');
|
||||
const [isModalVisible, setModalVisible] = useState(false);
|
||||
const [isDatePickerVisible, setDatePickerVisibility] = useState(false);
|
||||
|
||||
// Form State
|
||||
const [title, setTitle] = useState('');
|
||||
const [date, setDate] = useState(new Date());
|
||||
const [images, setImages] = useState<string[]>([]);
|
||||
const [note, setNote] = useState('');
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
||||
// Image Viewer State
|
||||
const [viewerVisible, setViewerVisible] = useState(false);
|
||||
const [currentViewerImages, setCurrentViewerImages] = useState<{ uri: string }[]>([]);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchMedicalRecords());
|
||||
}, [dispatch]);
|
||||
|
||||
const currentList = activeTab === 'medical_record' ? records : prescriptions;
|
||||
|
||||
const handleTabPress = (tab: MedicalRecordType) => {
|
||||
setActiveTab(tab);
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setTitle('');
|
||||
setDate(new Date());
|
||||
setImages([]);
|
||||
setNote('');
|
||||
};
|
||||
|
||||
const openAddModal = () => {
|
||||
resetForm();
|
||||
setModalVisible(true);
|
||||
};
|
||||
|
||||
const handlePickImage = async () => {
|
||||
const { status } = await ImagePicker.requestMediaLibraryPermissionsAsync();
|
||||
if (status !== 'granted') {
|
||||
Alert.alert('需要权限', '请允许访问相册以上传图片');
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await ImagePicker.launchImageLibraryAsync({
|
||||
mediaTypes: ImagePicker.MediaTypeOptions.Images,
|
||||
allowsEditing: true,
|
||||
quality: 0.8,
|
||||
});
|
||||
|
||||
if (!result.canceled && result.assets && result.assets.length > 0) {
|
||||
setImages([...images, result.assets[0].uri]);
|
||||
}
|
||||
};
|
||||
|
||||
const handleTakePhoto = async () => {
|
||||
const { status } = await ImagePicker.requestCameraPermissionsAsync();
|
||||
if (status !== 'granted') {
|
||||
Alert.alert('需要权限', '请允许访问相机以拍摄照片');
|
||||
return;
|
||||
}
|
||||
|
||||
const result = await ImagePicker.launchCameraAsync({
|
||||
allowsEditing: true,
|
||||
quality: 0.8,
|
||||
});
|
||||
|
||||
if (!result.canceled && result.assets && result.assets.length > 0) {
|
||||
setImages([...images, result.assets[0].uri]);
|
||||
}
|
||||
};
|
||||
|
||||
const handlePickDocument = async () => {
|
||||
try {
|
||||
const result = await DocumentPicker.getDocumentAsync({
|
||||
type: ['application/pdf', 'image/*'],
|
||||
copyToCacheDirectory: true,
|
||||
multiple: false,
|
||||
});
|
||||
|
||||
if (!result.canceled && result.assets && result.assets.length > 0) {
|
||||
setImages([...images, result.assets[0].uri]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error picking document:', error);
|
||||
Alert.alert('错误', '选择文件失败');
|
||||
}
|
||||
};
|
||||
|
||||
const handleSubmit = async () => {
|
||||
if (!title.trim()) {
|
||||
Alert.alert('提示', '请输入标题');
|
||||
return;
|
||||
}
|
||||
if (images.length === 0) {
|
||||
Alert.alert('提示', '请至少上传一张图片');
|
||||
return;
|
||||
}
|
||||
|
||||
setIsSubmitting(true);
|
||||
try {
|
||||
await dispatch(addNewMedicalRecord({
|
||||
type: activeTab,
|
||||
title,
|
||||
date: dayjs(date).format('YYYY-MM-DD'),
|
||||
images,
|
||||
note,
|
||||
})).unwrap();
|
||||
setModalVisible(false);
|
||||
} catch (error) {
|
||||
Alert.alert('错误', '保存失败,请重试');
|
||||
} finally {
|
||||
setIsSubmitting(false);
|
||||
}
|
||||
};
|
||||
|
||||
const handleDelete = (item: MedicalRecordItem) => {
|
||||
Alert.alert(
|
||||
'确认删除',
|
||||
'确定要删除这条记录吗?',
|
||||
[
|
||||
{ text: '取消', style: 'cancel' },
|
||||
{
|
||||
text: '删除',
|
||||
style: 'destructive',
|
||||
onPress: () => dispatch(deleteMedicalRecordItem({ id: item.id, type: item.type })),
|
||||
},
|
||||
]
|
||||
);
|
||||
};
|
||||
|
||||
const handleViewImages = (item: MedicalRecordItem) => {
|
||||
if (item.images && item.images.length > 0) {
|
||||
setCurrentViewerImages(item.images.map(uri => ({ uri })));
|
||||
setViewerVisible(true);
|
||||
}
|
||||
};
|
||||
|
||||
const renderItem = ({ item }: { item: MedicalRecordItem }) => (
|
||||
<MedicalRecordCard
|
||||
item={item}
|
||||
onPress={handleViewImages}
|
||||
onDelete={handleDelete}
|
||||
/>
|
||||
);
|
||||
|
||||
return (
|
||||
<View style={styles.card}>
|
||||
<View style={styles.emptyState}>
|
||||
<Ionicons name="folder-open-outline" size={48} color="#E5E7EB" />
|
||||
<Text style={styles.emptyText}>暂无就医资料</Text>
|
||||
<Text style={styles.emptySubtext}>上传您的病历、处方单等资料</Text>
|
||||
<View style={styles.container}>
|
||||
{/* Segmented Control */}
|
||||
<View style={styles.segmentContainer}>
|
||||
<TouchableOpacity
|
||||
style={[styles.segmentButton, activeTab === 'medical_record' && styles.segmentButtonActive]}
|
||||
onPress={() => handleTabPress('medical_record')}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Text style={[styles.segmentText, activeTab === 'medical_record' && styles.segmentTextActive]}>
|
||||
病历资料
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
<TouchableOpacity
|
||||
style={[styles.segmentButton, activeTab === 'prescription' && styles.segmentButtonActive]}
|
||||
onPress={() => handleTabPress('prescription')}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<Text style={[styles.segmentText, activeTab === 'prescription' && styles.segmentTextActive]}>
|
||||
处方单据
|
||||
</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Content List */}
|
||||
<View style={styles.contentContainer}>
|
||||
{isLoading && records.length === 0 && prescriptions.length === 0 ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color={palette.purple[500]} />
|
||||
</View>
|
||||
) : currentList.length > 0 ? (
|
||||
<FlatList
|
||||
data={currentList}
|
||||
renderItem={renderItem}
|
||||
keyExtractor={(item) => item.id}
|
||||
showsVerticalScrollIndicator={false}
|
||||
contentContainerStyle={styles.listContent}
|
||||
scrollEnabled={false} // Since it's inside a parent ScrollView
|
||||
/>
|
||||
) : (
|
||||
<View style={styles.emptyState}>
|
||||
<View style={styles.emptyIconContainer}>
|
||||
<Ionicons
|
||||
name={activeTab === 'medical_record' ? "folder-open-outline" : "receipt-outline"}
|
||||
size={48}
|
||||
color={palette.gray[300]}
|
||||
/>
|
||||
</View>
|
||||
<Text style={styles.emptyText}>
|
||||
{activeTab === 'medical_record' ? '暂无病历资料' : '暂无处方单据'}
|
||||
</Text>
|
||||
<Text style={styles.emptySubtext}>
|
||||
{activeTab === 'medical_record' ? '上传您的检查报告、诊断证明等' : '上传您的处方单、用药清单等'}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
|
||||
{/* Add Button */}
|
||||
<TouchableOpacity
|
||||
style={styles.fab}
|
||||
onPress={openAddModal}
|
||||
activeOpacity={0.9}
|
||||
>
|
||||
<LinearGradient
|
||||
colors={[palette.purple[500], palette.purple[700]]}
|
||||
style={styles.fabGradient}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
>
|
||||
<Ionicons name="add" size={28} color="#FFFFFF" />
|
||||
</LinearGradient>
|
||||
</TouchableOpacity>
|
||||
|
||||
{/* Add/Edit Modal */}
|
||||
<Modal
|
||||
visible={isModalVisible}
|
||||
animationType="slide"
|
||||
presentationStyle="pageSheet"
|
||||
onRequestClose={() => setModalVisible(false)}
|
||||
>
|
||||
<View style={styles.modalContainer}>
|
||||
<View style={styles.modalHeader}>
|
||||
<TouchableOpacity onPress={() => setModalVisible(false)} style={styles.modalCloseButton}>
|
||||
<Text style={styles.modalCloseText}>取消</Text>
|
||||
</TouchableOpacity>
|
||||
<Text style={styles.modalTitle}>
|
||||
{activeTab === 'medical_record' ? '添加病历' : '添加处方'}
|
||||
</Text>
|
||||
<TouchableOpacity
|
||||
onPress={handleSubmit}
|
||||
style={[styles.modalSaveButton, isSubmitting && styles.modalSaveButtonDisabled]}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{isSubmitting ? (
|
||||
<ActivityIndicator size="small" color="#FFFFFF" />
|
||||
) : (
|
||||
<Text style={styles.modalSaveText}>保存</Text>
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.formContainer}>
|
||||
{/* Title Input */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>标题 <Text style={styles.required}>*</Text></Text>
|
||||
<TextInput
|
||||
style={styles.input}
|
||||
placeholder={activeTab === 'medical_record' ? "例如:血常规检查" : "例如:感冒药处方"}
|
||||
value={title}
|
||||
onChangeText={setTitle}
|
||||
placeholderTextColor={palette.gray[400]}
|
||||
/>
|
||||
</View>
|
||||
|
||||
{/* Date Picker */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>日期</Text>
|
||||
<TouchableOpacity
|
||||
style={styles.dateInput}
|
||||
onPress={() => setDatePickerVisibility(true)}
|
||||
>
|
||||
<Text style={styles.dateText}>{dayjs(date).format('YYYY年MM月DD日')}</Text>
|
||||
<Ionicons name="calendar-outline" size={20} color={palette.gray[500]} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
{/* Images */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>图片资料 <Text style={styles.required}>*</Text></Text>
|
||||
<View style={styles.imageGrid}>
|
||||
{images.map((uri, index) => {
|
||||
const isPdf = uri.toLowerCase().endsWith('.pdf');
|
||||
return (
|
||||
<View key={index} style={styles.imagePreviewContainer}>
|
||||
{isPdf ? (
|
||||
<View style={[styles.imagePreview, styles.pdfPreview]}>
|
||||
<Ionicons name="document-text" size={32} color="#EF4444" />
|
||||
<Text style={styles.pdfText} numberOfLines={1}>PDF</Text>
|
||||
</View>
|
||||
) : (
|
||||
<Image
|
||||
source={{ uri }}
|
||||
style={styles.imagePreview}
|
||||
contentFit="cover"
|
||||
/>
|
||||
)}
|
||||
<TouchableOpacity
|
||||
style={styles.removeImageButton}
|
||||
onPress={() => setImages(images.filter((_, i) => i !== index))}
|
||||
>
|
||||
<Ionicons name="close-circle" size={20} color={palette.error[500]} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
})}
|
||||
|
||||
{images.length < 9 && (
|
||||
<TouchableOpacity style={styles.addImageButton} onPress={() => {
|
||||
Alert.alert(
|
||||
'上传文件',
|
||||
'请选择上传方式',
|
||||
[
|
||||
{ text: '拍照', onPress: handleTakePhoto },
|
||||
{ text: '从相册选择', onPress: handlePickImage },
|
||||
{ text: '选择文档 (PDF)', onPress: handlePickDocument },
|
||||
{ text: '取消', style: 'cancel' },
|
||||
]
|
||||
);
|
||||
}}>
|
||||
<Ionicons name="add" size={32} color={palette.purple[500]} />
|
||||
<Text style={styles.addImageText}>上传</Text>
|
||||
</TouchableOpacity>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* Note */}
|
||||
<View style={styles.inputGroup}>
|
||||
<Text style={styles.label}>备注</Text>
|
||||
<TextInput
|
||||
style={[styles.input, styles.textArea]}
|
||||
placeholder="添加备注信息..."
|
||||
value={note}
|
||||
onChangeText={setNote}
|
||||
multiline
|
||||
numberOfLines={4}
|
||||
placeholderTextColor={palette.gray[400]}
|
||||
textAlignVertical="top"
|
||||
/>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
</View>
|
||||
|
||||
<DateTimePickerModal
|
||||
isVisible={isDatePickerVisible}
|
||||
mode="date"
|
||||
onConfirm={(d) => {
|
||||
setDate(d);
|
||||
setDatePickerVisibility(false);
|
||||
}}
|
||||
onCancel={() => setDatePickerVisibility(false)}
|
||||
maximumDate={new Date()}
|
||||
locale="zh_CN"
|
||||
confirmTextIOS="确定"
|
||||
cancelTextIOS="取消"
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<ImageViewing
|
||||
images={currentViewerImages}
|
||||
imageIndex={0}
|
||||
visible={viewerVisible}
|
||||
onRequestClose={() => setViewerVisible(false)}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
card: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 20,
|
||||
padding: 40,
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
segmentContainer: {
|
||||
flexDirection: 'row',
|
||||
backgroundColor: '#F3F4F6',
|
||||
borderRadius: 12,
|
||||
padding: 4,
|
||||
marginBottom: 16,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.03,
|
||||
shadowRadius: 6,
|
||||
elevation: 1,
|
||||
minHeight: 200,
|
||||
},
|
||||
segmentButton: {
|
||||
flex: 1,
|
||||
paddingVertical: 10,
|
||||
alignItems: 'center',
|
||||
borderRadius: 10,
|
||||
},
|
||||
segmentButtonActive: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 2,
|
||||
elevation: 1,
|
||||
},
|
||||
segmentText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
color: '#6B7280',
|
||||
fontFamily: 'AliRegular',
|
||||
},
|
||||
segmentTextActive: {
|
||||
color: palette.purple[600],
|
||||
fontWeight: '600',
|
||||
fontFamily: 'AliBold',
|
||||
},
|
||||
contentContainer: {
|
||||
minHeight: 300,
|
||||
},
|
||||
loadingContainer: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
paddingVertical: 40,
|
||||
},
|
||||
listContent: {
|
||||
paddingBottom: 80,
|
||||
},
|
||||
emptyState: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginTop: 40,
|
||||
paddingHorizontal: 40,
|
||||
},
|
||||
emptyIconContainer: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 40,
|
||||
backgroundColor: '#F9FAFB',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
marginBottom: 16,
|
||||
},
|
||||
emptyText: {
|
||||
marginTop: 16,
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
color: '#374151',
|
||||
marginBottom: 8,
|
||||
fontFamily: 'AliBold',
|
||||
},
|
||||
emptySubtext: {
|
||||
marginTop: 8,
|
||||
fontSize: 13,
|
||||
color: '#9CA3AF',
|
||||
textAlign: 'center',
|
||||
lineHeight: 20,
|
||||
fontFamily: 'AliRegular',
|
||||
},
|
||||
fab: {
|
||||
position: 'absolute',
|
||||
right: 16,
|
||||
bottom: 16,
|
||||
width: 56,
|
||||
height: 56,
|
||||
borderRadius: 28,
|
||||
shadowColor: palette.purple[500],
|
||||
shadowOffset: { width: 0, height: 4 },
|
||||
shadowOpacity: 0.3,
|
||||
shadowRadius: 8,
|
||||
elevation: 6,
|
||||
},
|
||||
fabGradient: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: 28,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
// Modal Styles
|
||||
modalContainer: {
|
||||
flex: 1,
|
||||
backgroundColor: '#F9FAFB',
|
||||
},
|
||||
modalHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
paddingHorizontal: 16,
|
||||
paddingVertical: 12,
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderBottomWidth: StyleSheet.hairlineWidth,
|
||||
borderBottomColor: '#E5E7EB',
|
||||
paddingTop: Platform.OS === 'ios' ? 12 : 12,
|
||||
},
|
||||
modalCloseButton: {
|
||||
padding: 8,
|
||||
},
|
||||
modalCloseText: {
|
||||
fontSize: 16,
|
||||
color: '#6B7280',
|
||||
fontFamily: 'AliRegular',
|
||||
},
|
||||
modalTitle: {
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
color: '#111827',
|
||||
fontFamily: 'AliBold',
|
||||
},
|
||||
modalSaveButton: {
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 6,
|
||||
backgroundColor: palette.purple[600],
|
||||
borderRadius: 6,
|
||||
},
|
||||
modalSaveButtonDisabled: {
|
||||
opacity: 0.6,
|
||||
},
|
||||
modalSaveText: {
|
||||
fontSize: 14,
|
||||
fontWeight: '600',
|
||||
color: '#FFFFFF',
|
||||
fontFamily: 'AliBold',
|
||||
},
|
||||
formContainer: {
|
||||
padding: 16,
|
||||
},
|
||||
inputGroup: {
|
||||
marginBottom: 20,
|
||||
},
|
||||
label: {
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
color: '#374151',
|
||||
marginBottom: 8,
|
||||
fontFamily: 'AliRegular',
|
||||
},
|
||||
required: {
|
||||
color: palette.error[500],
|
||||
},
|
||||
input: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
fontSize: 16,
|
||||
color: '#111827',
|
||||
borderWidth: 1,
|
||||
borderColor: '#E5E7EB',
|
||||
fontFamily: 'AliRegular',
|
||||
},
|
||||
textArea: {
|
||||
height: 100,
|
||||
textAlignVertical: 'top',
|
||||
},
|
||||
dateInput: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 12,
|
||||
paddingHorizontal: 12,
|
||||
paddingVertical: 12,
|
||||
borderWidth: 1,
|
||||
borderColor: '#E5E7EB',
|
||||
},
|
||||
dateText: {
|
||||
fontSize: 16,
|
||||
color: '#111827',
|
||||
fontFamily: 'AliRegular',
|
||||
},
|
||||
imageGrid: {
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
gap: 12,
|
||||
},
|
||||
imagePreviewContainer: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 8,
|
||||
overflow: 'hidden',
|
||||
position: 'relative',
|
||||
},
|
||||
imagePreview: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
},
|
||||
pdfPreview: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: '#F3F4F6',
|
||||
},
|
||||
pdfText: {
|
||||
fontSize: 10,
|
||||
marginTop: 4,
|
||||
color: '#EF4444',
|
||||
fontWeight: '600',
|
||||
},
|
||||
removeImageButton: {
|
||||
position: 'absolute',
|
||||
top: 2,
|
||||
right: 2,
|
||||
backgroundColor: 'rgba(255,255,255,0.8)',
|
||||
borderRadius: 10,
|
||||
},
|
||||
addImageButton: {
|
||||
width: 80,
|
||||
height: 80,
|
||||
borderRadius: 8,
|
||||
borderWidth: 1,
|
||||
borderColor: palette.purple[200],
|
||||
borderStyle: 'dashed',
|
||||
backgroundColor: palette.purple[50],
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
addImageText: {
|
||||
fontSize: 12,
|
||||
color: palette.purple[600],
|
||||
marginTop: 4,
|
||||
fontFamily: 'AliRegular',
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user