618 lines
20 KiB
TypeScript
618 lines
20 KiB
TypeScript
import { HealthProgressRing } from '@/components/health/HealthProgressRing';
|
|
import { BasicInfoTab } from '@/components/health/tabs/BasicInfoTab';
|
|
import { CheckupRecordsTab } from '@/components/health/tabs/CheckupRecordsTab';
|
|
import { HealthHistoryTab } from '@/components/health/tabs/HealthHistoryTab';
|
|
import { MedicalRecordsTab } from '@/components/health/tabs/MedicalRecordsTab';
|
|
import { ConfirmationSheet } from '@/components/ui/ConfirmationSheet';
|
|
import { HeaderBar } from '@/components/ui/HeaderBar';
|
|
import { Colors } from '@/constants/Colors';
|
|
import { ROUTES } from '@/constants/Routes';
|
|
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
|
import { useAuthGuard } from '@/hooks/useAuthGuard';
|
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
import { useI18n } from '@/hooks/useI18n';
|
|
import {
|
|
fetchFamilyGroup,
|
|
joinFamilyGroup,
|
|
selectFamilyGroup,
|
|
} from '@/store/familyHealthSlice';
|
|
import {
|
|
fetchHealthHistory,
|
|
selectHealthHistoryProgress
|
|
} from '@/store/healthSlice';
|
|
import { DEFAULT_MEMBER_NAME } from '@/store/userSlice';
|
|
import { Toast } from '@/utils/toast.utils';
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { GlassView, isLiquidGlassAvailable } from 'expo-glass-effect';
|
|
import { Image } from 'expo-image';
|
|
import { LinearGradient } from 'expo-linear-gradient';
|
|
import { Stack, useRouter } from 'expo-router';
|
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
import { Pressable, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from 'react-native';
|
|
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
|
|
|
export default function HealthProfileScreen() {
|
|
const router = useRouter();
|
|
const insets = useSafeAreaInsets();
|
|
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
|
|
const colorTokens = Colors[theme];
|
|
const { t } = useI18n();
|
|
const dispatch = useAppDispatch();
|
|
const { ensureLoggedIn } = useAuthGuard();
|
|
const glassAvailable = isLiquidGlassAvailable();
|
|
|
|
const [activeTab, setActiveTab] = useState(0);
|
|
const [joinModalVisible, setJoinModalVisible] = useState(false);
|
|
const [inviteCodeInput, setInviteCodeInput] = useState('');
|
|
const [selectedRelationship, setSelectedRelationship] = useState('');
|
|
const [isJoining, setIsJoining] = useState(false);
|
|
const [joinError, setJoinError] = useState<string | null>(null);
|
|
|
|
// Redux state
|
|
const familyGroup = useAppSelector(selectFamilyGroup);
|
|
const medicalRecords = useAppSelector((state) => state.health.medicalRecords);
|
|
const records = medicalRecords?.records || [];
|
|
const prescriptions = medicalRecords?.prescriptions || [];
|
|
|
|
// Calculate Medical Records Count
|
|
const medicalRecordsCount = useMemo(() => records.length + prescriptions.length, [records, prescriptions]);
|
|
|
|
// 亲属关系选项
|
|
const relationshipOptions = useMemo(() => [
|
|
{ key: 'spouse', label: t('familyGroup.relationships.spouse') },
|
|
{ key: 'father', label: t('familyGroup.relationships.father') },
|
|
{ key: 'mother', label: t('familyGroup.relationships.mother') },
|
|
{ key: 'son', label: t('familyGroup.relationships.son') },
|
|
{ key: 'daughter', label: t('familyGroup.relationships.daughter') },
|
|
{ key: 'grandfather', label: t('familyGroup.relationships.grandfather') },
|
|
{ key: 'grandmother', label: t('familyGroup.relationships.grandmother') },
|
|
{ key: 'grandson', label: t('familyGroup.relationships.grandson') },
|
|
{ key: 'granddaughter', label: t('familyGroup.relationships.granddaughter') },
|
|
{ key: 'brother', label: t('familyGroup.relationships.brother') },
|
|
{ key: 'sister', label: t('familyGroup.relationships.sister') },
|
|
{ key: 'uncle', label: t('familyGroup.relationships.uncle') },
|
|
{ key: 'aunt', label: t('familyGroup.relationships.aunt') },
|
|
{ key: 'nephew', label: t('familyGroup.relationships.nephew') },
|
|
{ key: 'niece', label: t('familyGroup.relationships.niece') },
|
|
{ key: 'cousin', label: t('familyGroup.relationships.cousin') },
|
|
{ key: 'other', label: t('familyGroup.relationships.other') },
|
|
], [t]);
|
|
|
|
// Mock user data - in a real app this would come from Redux/Context
|
|
const userProfile = useAppSelector((state) => state.user.profile);
|
|
const displayName = userProfile.name?.trim() ? userProfile.name : DEFAULT_MEMBER_NAME;
|
|
const avatarUrl = userProfile.avatar || 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/seal-avatar/2.jpeg';
|
|
|
|
// 从 Redux 获取健康史进度
|
|
const healthHistoryProgress = useAppSelector(selectHealthHistoryProgress);
|
|
|
|
// Mock health data
|
|
const healthData = {
|
|
bmi: userProfile.weight && userProfile.height ? (parseFloat(userProfile.weight) / Math.pow(parseFloat(userProfile.height) / 100, 2)).toFixed(1) : '--',
|
|
height: userProfile.height ? `${parseFloat(userProfile.height).toFixed(1)}` : '--',
|
|
weight: userProfile.weight ? `${parseFloat(userProfile.weight).toFixed(1)}` : '--',
|
|
waist: userProfile.waistCircumference ? `${parseFloat(userProfile.waistCircumference.toString()).toFixed(1)}` : '--',
|
|
status: '健康状况良好',
|
|
statusDesc: '请继续保持良好的生活习惯',
|
|
statusMessage: '您的健康状况不错哦~'
|
|
};
|
|
|
|
// Calculate Basic Info completion percentage
|
|
const basicInfoProgress = useMemo(() => {
|
|
let filledCount = 0;
|
|
const totalFields = 3; // height, weight, waist
|
|
|
|
if (userProfile.height && parseFloat(userProfile.height) > 0) filledCount++;
|
|
if (userProfile.weight && parseFloat(userProfile.weight) > 0) filledCount++;
|
|
if (userProfile.waistCircumference && parseFloat(userProfile.waistCircumference.toString()) > 0) filledCount++;
|
|
|
|
return Math.round((filledCount / totalFields) * 100);
|
|
}, [userProfile.height, userProfile.weight, userProfile.waistCircumference]);
|
|
|
|
// 初始化获取家庭组信息和健康史数据
|
|
useEffect(() => {
|
|
dispatch(fetchFamilyGroup());
|
|
dispatch(fetchHealthHistory());
|
|
}, [dispatch]);
|
|
|
|
// 重置弹窗状态
|
|
useEffect(() => {
|
|
if (!joinModalVisible) {
|
|
setInviteCodeInput('');
|
|
setSelectedRelationship('');
|
|
setJoinError(null);
|
|
}
|
|
}, [joinModalVisible]);
|
|
|
|
// 打开加入弹窗
|
|
const handleOpenJoin = useCallback(async () => {
|
|
const ok = await ensureLoggedIn();
|
|
if (!ok) return;
|
|
setJoinModalVisible(true);
|
|
}, [ensureLoggedIn]);
|
|
|
|
// 提交加入家庭组
|
|
const handleSubmitJoin = useCallback(async () => {
|
|
if (isJoining) return;
|
|
const ok = await ensureLoggedIn();
|
|
if (!ok) return;
|
|
|
|
const code = inviteCodeInput.trim().toUpperCase();
|
|
|
|
if (!code) {
|
|
setJoinError(t('familyGroup.errors.emptyCode'));
|
|
return;
|
|
}
|
|
if (!selectedRelationship) {
|
|
setJoinError(t('familyGroup.errors.emptyRelationship'));
|
|
return;
|
|
}
|
|
|
|
// 获取选中关系的显示文本
|
|
const relationshipLabel = relationshipOptions.find(r => r.key === selectedRelationship)?.label || selectedRelationship;
|
|
|
|
setIsJoining(true);
|
|
setJoinError(null);
|
|
|
|
try {
|
|
await dispatch(joinFamilyGroup({ inviteCode: code, relationship: relationshipLabel })).unwrap();
|
|
await dispatch(fetchFamilyGroup());
|
|
setJoinModalVisible(false);
|
|
Toast.success(t('familyGroup.success'));
|
|
} catch (error) {
|
|
const message = typeof error === 'string' ? error : '加入失败,请检查邀请码是否正确';
|
|
setJoinError(message);
|
|
} finally {
|
|
setIsJoining(false);
|
|
}
|
|
}, [dispatch, ensureLoggedIn, inviteCodeInput, isJoining, selectedRelationship, relationshipOptions, t]);
|
|
|
|
const gradientColors: [string, string] =
|
|
theme === 'dark'
|
|
? ['#1f2230', '#10131e']
|
|
: [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd];
|
|
|
|
const tabs = [
|
|
t('health.tabs.healthProfile.basicInfo'),
|
|
t('health.tabs.healthProfile.healthHistory'),
|
|
// t('health.tabs.healthProfile.medicalRecords'),
|
|
t('health.tabs.healthProfile.checkupRecords'),
|
|
t('health.tabs.healthProfile.medicineBox')
|
|
];
|
|
const tabIcons = ["person", "time", "folder", "clipboard", "medkit"];
|
|
|
|
const handleTabPress = (index: number) => {
|
|
if (index === 3) {
|
|
// Handle Medicine Box tab specially
|
|
router.push('/medications/manage-medications');
|
|
return;
|
|
}
|
|
setActiveTab(index);
|
|
};
|
|
|
|
const renderActiveTab = () => {
|
|
switch (activeTab) {
|
|
case 0:
|
|
return <BasicInfoTab healthData={healthData} />;
|
|
case 1:
|
|
return <HealthHistoryTab />;
|
|
case 2:
|
|
return <MedicalRecordsTab />;
|
|
case 3:
|
|
return <CheckupRecordsTab />;
|
|
default:
|
|
return <BasicInfoTab healthData={healthData} />;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<View style={[styles.container, { backgroundColor: colorTokens.pageBackgroundEmphasis }]}>
|
|
<Stack.Screen options={{ headerShown: false }} />
|
|
<LinearGradient colors={gradientColors} style={StyleSheet.absoluteFillObject} />
|
|
|
|
<HeaderBar
|
|
title={t('health.tabs.healthProfile.title')}
|
|
transparent
|
|
right={
|
|
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
|
|
{/* 加入家庭组按钮 - 仅在未加入家庭组时显示 */}
|
|
{!familyGroup && (
|
|
<TouchableOpacity activeOpacity={0.85} onPress={handleOpenJoin} style={{ marginRight: 10 }}>
|
|
{glassAvailable ? (
|
|
<GlassView
|
|
style={styles.joinButtonGlass}
|
|
glassEffectStyle="regular"
|
|
tintColor="rgba(255,255,255,0.18)"
|
|
isInteractive
|
|
>
|
|
<Text style={styles.joinButtonLabel}>加入</Text>
|
|
</GlassView>
|
|
) : (
|
|
<View style={[styles.joinButtonGlass, styles.joinButtonFallback]}>
|
|
<Text style={[styles.joinButtonLabel, { color: colorTokens.text }]}>加入</Text>
|
|
</View>
|
|
)}
|
|
</TouchableOpacity>
|
|
)}
|
|
<TouchableOpacity style={{ marginRight: 12 }}>
|
|
<Ionicons name="settings-outline" size={22} color="#1F2937" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
}
|
|
/>
|
|
|
|
<ScrollView
|
|
contentContainerStyle={[styles.scrollContent, { paddingTop: insets.top + 60 }]}
|
|
showsVerticalScrollIndicator={false}
|
|
>
|
|
{/* Top Section with Avatar and Status */}
|
|
<View style={styles.topSection}>
|
|
<View style={styles.avatarRow}>
|
|
<View style={styles.miniAvatarContainer}>
|
|
<Image source={{ uri: avatarUrl }} style={styles.miniAvatar} />
|
|
<Text style={styles.miniAvatarName}>{displayName}</Text>
|
|
</View>
|
|
<TouchableOpacity
|
|
style={styles.addButton}
|
|
onPress={() => router.push(ROUTES.HEALTH_FAMILY_INVITE)}
|
|
>
|
|
<Ionicons name="add" size={16} color="#6B7280" />
|
|
</TouchableOpacity>
|
|
</View>
|
|
|
|
{/* Action Buttons - Replaced with HealthProgressRing */}
|
|
<View style={styles.actionButtonsRow}>
|
|
<HealthProgressRing
|
|
title={t('health.tabs.healthProfile.basicInfo')}
|
|
progress={basicInfoProgress}
|
|
gradientColors={['#9B8AFB', '#5B4CFF']}
|
|
/>
|
|
<HealthProgressRing
|
|
title={t('health.tabs.healthProfile.healthHistory')}
|
|
progress={healthHistoryProgress}
|
|
gradientColors={['#E0E7FF', '#C7D2FE']}
|
|
label={healthHistoryProgress.toString()}
|
|
suffix="%"
|
|
/>
|
|
<HealthProgressRing
|
|
title={t('health.tabs.healthProfile.medicalRecords')}
|
|
progress={0}
|
|
gradientColors={['#E0E7FF', '#C7D2FE']}
|
|
label={medicalRecordsCount.toString()}
|
|
suffix="份"
|
|
/>
|
|
</View>
|
|
</View>
|
|
|
|
{/* Family Invite Banner */}
|
|
<TouchableOpacity
|
|
style={styles.inviteBanner}
|
|
activeOpacity={0.9}
|
|
onPress={() => router.push(ROUTES.HEALTH_FAMILY_INVITE)}
|
|
>
|
|
<View style={styles.inviteContent}>
|
|
<View style={styles.inviteIconContainer}>
|
|
<Ionicons name="home" size={18} color="#5B4CFF" />
|
|
</View>
|
|
<Text style={styles.inviteText}>{t('health.tabs.healthProfile.subtitle')}</Text>
|
|
<Ionicons name="chevron-forward" size={18} color="#6B7280" />
|
|
</View>
|
|
</TouchableOpacity>
|
|
|
|
{/* Tab/Segment Control */}
|
|
<View style={styles.segmentControl}>
|
|
{tabs.map((tab, index) => (
|
|
<TouchableOpacity
|
|
key={index}
|
|
style={styles.segmentItem}
|
|
onPress={() => handleTabPress(index)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<View style={[styles.segmentIconPlaceholder, index === activeTab && styles.segmentIconActive]}>
|
|
<Ionicons
|
|
name={tabIcons[index] as any}
|
|
size={20}
|
|
color={index === activeTab ? "#5B4CFF" : "#6B7280"}
|
|
/>
|
|
</View>
|
|
<Text style={[styles.segmentText, index === activeTab && styles.segmentTextActive]}>{tab}</Text>
|
|
</TouchableOpacity>
|
|
))}
|
|
</View>
|
|
|
|
{/* Active Tab Content */}
|
|
{renderActiveTab()}
|
|
|
|
{/* Privacy Notice Footer */}
|
|
<View style={styles.privacyNoticeContainer}>
|
|
<View style={styles.privacyIconWrapper}>
|
|
<Ionicons name="shield-checkmark" size={16} color="#9CA3AF" />
|
|
</View>
|
|
<Text style={styles.privacyNoticeText}>
|
|
{t('health.tabs.healthProfile.privacyNotice')}
|
|
</Text>
|
|
</View>
|
|
|
|
</ScrollView>
|
|
|
|
{/* 加入家庭组弹窗 */}
|
|
<ConfirmationSheet
|
|
visible={joinModalVisible}
|
|
onClose={() => setJoinModalVisible(false)}
|
|
onConfirm={handleSubmitJoin}
|
|
title={t('familyGroup.joinTitle')}
|
|
description={t('familyGroup.joinDescription')}
|
|
confirmText={isJoining ? t('familyGroup.joining') : t('familyGroup.joinButton')}
|
|
cancelText={t('familyGroup.cancel')}
|
|
loading={isJoining}
|
|
content={
|
|
<View style={styles.joinModalContent}>
|
|
{/* 邀请码输入 */}
|
|
<TextInput
|
|
style={styles.inviteCodeInput}
|
|
placeholder={t('familyGroup.inviteCodePlaceholder')}
|
|
placeholderTextColor="#9ca3af"
|
|
value={inviteCodeInput}
|
|
onChangeText={(text) => setInviteCodeInput(text.toUpperCase())}
|
|
autoCapitalize="characters"
|
|
autoCorrect={false}
|
|
keyboardType="default"
|
|
maxLength={12}
|
|
/>
|
|
|
|
{/* 关系选择标签 */}
|
|
<Text style={styles.relationshipLabel}>{t('familyGroup.relationshipLabel')}</Text>
|
|
|
|
{/* 关系选项网格 - 固定高度可滚动 */}
|
|
<ScrollView
|
|
style={styles.relationshipScrollView}
|
|
contentContainerStyle={styles.relationshipGrid}
|
|
showsVerticalScrollIndicator={true}
|
|
nestedScrollEnabled
|
|
keyboardShouldPersistTaps="handled"
|
|
>
|
|
{relationshipOptions.map((option) => {
|
|
const isSelected = selectedRelationship === option.key;
|
|
return (
|
|
<Pressable
|
|
key={option.key}
|
|
style={[
|
|
styles.relationshipChip,
|
|
isSelected && styles.relationshipChipSelected,
|
|
]}
|
|
onPress={() => setSelectedRelationship(option.key)}
|
|
>
|
|
<Text
|
|
style={[
|
|
styles.relationshipChipText,
|
|
isSelected && styles.relationshipChipTextSelected,
|
|
]}
|
|
>
|
|
{option.label}
|
|
</Text>
|
|
</Pressable>
|
|
);
|
|
})}
|
|
</ScrollView>
|
|
|
|
{/* 错误提示 */}
|
|
{joinError && joinModalVisible ? (
|
|
<Text style={styles.modalError}>{joinError}</Text>
|
|
) : null}
|
|
</View>
|
|
}
|
|
/>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
},
|
|
scrollContent: {
|
|
paddingHorizontal: 16,
|
|
paddingBottom: 100,
|
|
},
|
|
topSection: {
|
|
marginBottom: 20,
|
|
},
|
|
avatarRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginBottom: 10,
|
|
},
|
|
miniAvatarContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: '#5B4CFF',
|
|
paddingVertical: 4,
|
|
paddingHorizontal: 4,
|
|
paddingRight: 12,
|
|
borderRadius: 20,
|
|
},
|
|
miniAvatar: {
|
|
width: 24,
|
|
height: 24,
|
|
borderRadius: 12,
|
|
marginRight: 6,
|
|
borderWidth: 1,
|
|
borderColor: '#FFF',
|
|
},
|
|
miniAvatarName: {
|
|
color: '#FFF',
|
|
fontSize: 12,
|
|
fontWeight: 'bold',
|
|
},
|
|
addButton: {
|
|
width: 28,
|
|
height: 28,
|
|
borderRadius: 14,
|
|
backgroundColor: '#FFFFFF',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginLeft: 8,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 1 },
|
|
shadowOpacity: 0.1,
|
|
shadowRadius: 2,
|
|
elevation: 2,
|
|
},
|
|
actionButtonsRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-around',
|
|
marginTop: 24,
|
|
marginBottom: 12,
|
|
},
|
|
inviteBanner: {
|
|
backgroundColor: '#FFFFFF',
|
|
borderRadius: 20,
|
|
padding: 16,
|
|
marginBottom: 20,
|
|
shadowColor: '#5B4CFF',
|
|
shadowOffset: { width: 0, height: 4 },
|
|
shadowOpacity: 0.05,
|
|
shadowRadius: 8,
|
|
elevation: 2,
|
|
},
|
|
inviteContent: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
inviteIconContainer: {
|
|
marginRight: 8,
|
|
},
|
|
inviteText: {
|
|
flex: 1,
|
|
fontSize: 13,
|
|
color: '#1F2138',
|
|
fontWeight: '600',
|
|
},
|
|
segmentControl: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
marginBottom: 16,
|
|
paddingHorizontal: 18,
|
|
},
|
|
segmentItem: {
|
|
alignItems: 'center',
|
|
},
|
|
segmentIconPlaceholder: {
|
|
width: 48,
|
|
height: 48,
|
|
borderRadius: 12,
|
|
backgroundColor: '#F3F4F6',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginBottom: 4,
|
|
},
|
|
segmentIconActive: {
|
|
backgroundColor: '#E0E7FF',
|
|
},
|
|
segmentText: {
|
|
fontSize: 14,
|
|
color: '#6B7280',
|
|
},
|
|
segmentTextActive: {
|
|
color: '#5B4CFF',
|
|
fontWeight: 'bold',
|
|
},
|
|
privacyNoticeContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
paddingVertical: 20,
|
|
paddingHorizontal: 16,
|
|
marginTop: 32,
|
|
marginBottom: 16,
|
|
},
|
|
privacyIconWrapper: {
|
|
marginRight: 6,
|
|
},
|
|
privacyNoticeText: {
|
|
fontSize: 12,
|
|
color: '#9CA3AF',
|
|
textAlign: 'center',
|
|
lineHeight: 18,
|
|
},
|
|
joinButtonGlass: {
|
|
paddingHorizontal: 14,
|
|
paddingVertical: 8,
|
|
borderRadius: 16,
|
|
minWidth: 60,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
borderWidth: StyleSheet.hairlineWidth,
|
|
borderColor: 'rgba(255,255,255,0.45)',
|
|
},
|
|
joinButtonLabel: {
|
|
fontSize: 12,
|
|
fontWeight: '700',
|
|
color: '#0f1528',
|
|
letterSpacing: 0.5,
|
|
fontFamily: 'AliBold',
|
|
},
|
|
joinButtonFallback: {
|
|
backgroundColor: 'rgba(255,255,255,0.7)',
|
|
},
|
|
// 加入家庭组弹窗样式
|
|
joinModalContent: {
|
|
gap: 12,
|
|
},
|
|
inviteCodeInput: {
|
|
backgroundColor: '#f8fafc',
|
|
borderRadius: 14,
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 14,
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
letterSpacing: 2,
|
|
color: '#0f1528',
|
|
textAlign: 'center',
|
|
},
|
|
relationshipLabel: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: '#374151',
|
|
marginTop: 4,
|
|
marginBottom: 2,
|
|
},
|
|
relationshipScrollView: {
|
|
maxHeight: 160,
|
|
borderRadius: 12,
|
|
backgroundColor: '#fafafa',
|
|
},
|
|
relationshipGrid: {
|
|
flexDirection: 'row',
|
|
flexWrap: 'wrap',
|
|
gap: 8,
|
|
padding: 8,
|
|
},
|
|
relationshipChip: {
|
|
paddingHorizontal: 14,
|
|
paddingVertical: 8,
|
|
borderRadius: 20,
|
|
backgroundColor: '#f3f4f6',
|
|
borderWidth: 1.5,
|
|
borderColor: 'transparent',
|
|
},
|
|
relationshipChipSelected: {
|
|
backgroundColor: '#ede9fe',
|
|
borderColor: '#8b5cf6',
|
|
},
|
|
relationshipChipText: {
|
|
fontSize: 14,
|
|
color: '#6b7280',
|
|
fontWeight: '500',
|
|
},
|
|
relationshipChipTextSelected: {
|
|
color: '#7c3aed',
|
|
fontWeight: '600',
|
|
},
|
|
modalError: {
|
|
marginTop: 6,
|
|
fontSize: 12,
|
|
color: '#ef4444',
|
|
},
|
|
});
|