You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
698 lines
19 KiB
698 lines
19 KiB
import { Ionicons } from '@expo/vector-icons';
|
|
import { useRouter } from 'expo-router';
|
|
import {
|
|
ActivityIndicator,
|
|
Pressable,
|
|
ScrollView,
|
|
StyleSheet,
|
|
Text,
|
|
TextInput,
|
|
View,
|
|
} from 'react-native';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
import { useEnterpriseCommunication } from '../../src/hooks';
|
|
import { ENTERPRISE_DISPLAY_NAME } from '../../src/constants';
|
|
import { colors , spacing } from '../../src/theme';
|
|
import type { EnterpriseChatItem, EnterpriseCommunicationTab, PendingTask } from '../../src/types';
|
|
|
|
/* ===================== 子组件:顶部导航 ===================== */
|
|
|
|
function Header({ companyName, onBack }: { companyName: string; onBack: () => void }) {
|
|
const router = useRouter();
|
|
return (
|
|
<View style={styles.header}>
|
|
<Pressable style={styles.headerBtn} onPress={onBack} hitSlop={8}>
|
|
<Ionicons name="chevron-back" size={24} color={colors.textPrimary} />
|
|
</Pressable>
|
|
<View style={styles.headerCenter}>
|
|
<Text style={styles.headerCompany}>{companyName}</Text>
|
|
<Text style={styles.headerTitle}>沟通</Text>
|
|
</View>
|
|
<Pressable
|
|
style={styles.startBtn}
|
|
onPress={() => router.navigate('/talent-recommendation')}
|
|
hitSlop={6}
|
|
>
|
|
<Ionicons name="add" size={16} color={colors.white} />
|
|
<Text style={styles.startBtnText}>发起沟通</Text>
|
|
</Pressable>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:Tab 栏 ===================== */
|
|
|
|
function TabBar({
|
|
tabs,
|
|
active,
|
|
onChange,
|
|
}: {
|
|
tabs: EnterpriseCommunicationTab[];
|
|
active: string;
|
|
onChange: (key: string) => void;
|
|
}) {
|
|
return (
|
|
<View style={styles.tabBar}>
|
|
{tabs.map((tab) => {
|
|
const isActive = tab.key === active;
|
|
return (
|
|
<Pressable key={tab.key} style={styles.tabItem} onPress={() => onChange(tab.key)}>
|
|
<Text style={[styles.tabLabel, isActive && styles.tabLabelActive]}>
|
|
{tab.label}
|
|
<Text style={[styles.tabCount, isActive && styles.tabCountActive]}>({tab.count})</Text>
|
|
</Text>
|
|
<View style={[styles.tabIndicator, isActive && styles.tabIndicatorActive]} />
|
|
</Pressable>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:待处理任务 ===================== */
|
|
|
|
function PendingTasks({
|
|
tasks,
|
|
onPressTask,
|
|
}: {
|
|
tasks: PendingTask[];
|
|
onPressTask: (task: PendingTask) => void;
|
|
}) {
|
|
return (
|
|
<View style={styles.pendingCard}>
|
|
<Text style={styles.pendingTitle}>待处理</Text>
|
|
<View style={styles.pendingGrid}>
|
|
{tasks.map((task) => {
|
|
const token =
|
|
task.color === 'action'
|
|
? colors.action
|
|
: task.color === 'compareOrange'
|
|
? colors.compareOrange
|
|
: colors.primary;
|
|
return (
|
|
<Pressable
|
|
key={task.id}
|
|
style={styles.pendingItem}
|
|
onPress={() => onPressTask(task)}
|
|
>
|
|
<View style={[styles.pendingIconWrap, { backgroundColor: token + '15' }]}>
|
|
<Ionicons name={task.icon as keyof typeof Ionicons.glyphMap} size={22} color={token} />
|
|
</View>
|
|
<View style={styles.pendingBody}>
|
|
<View style={styles.pendingLabelRow}>
|
|
<Text style={styles.pendingLabel}>{task.label}</Text>
|
|
<View style={styles.pendingBadge}>
|
|
<Text style={styles.pendingBadgeText}>{task.count}人</Text>
|
|
</View>
|
|
</View>
|
|
{task.hint ? <Text style={styles.pendingHint}>{task.hint}</Text> : null}
|
|
</View>
|
|
<Ionicons name="chevron-forward" size={16} color={colors.textHint} />
|
|
</Pressable>
|
|
);
|
|
})}
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:聊天列表项 ===================== */
|
|
|
|
function ChatRow({ chat }: { chat: EnterpriseChatItem }) {
|
|
const router = useRouter();
|
|
return (
|
|
<Pressable style={styles.chatRow} onPress={() => router.push('/chat/' + chat.id)}>
|
|
<View style={styles.chatAvatar}>
|
|
<Text style={styles.chatAvatarText}>{chat.avatar}</Text>
|
|
</View>
|
|
<View style={styles.chatBody}>
|
|
<View style={styles.chatHeader}>
|
|
<View style={styles.chatNameWrap}>
|
|
<Text style={styles.chatName}>{chat.name}</Text>
|
|
{chat.labels.length > 0 ? (
|
|
<View style={styles.chatLabelTag}>
|
|
<Text style={styles.chatLabelTagText}>{chat.labels[0]}</Text>
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
<Text style={styles.chatTime}>{chat.time}</Text>
|
|
</View>
|
|
<Text style={styles.chatTitle}>{chat.title}</Text>
|
|
<View style={styles.chatFooter}>
|
|
<Text style={styles.chatLastMessage} numberOfLines={1}>
|
|
{chat.lastMessage}
|
|
</Text>
|
|
{chat.unreadCount > 0 ? (
|
|
<View style={styles.unreadBadge}>
|
|
<Text style={styles.unreadBadgeText}>{chat.unreadCount}</Text>
|
|
</View>
|
|
) : null}
|
|
</View>
|
|
</View>
|
|
</Pressable>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:搜索栏 ===================== */
|
|
|
|
function SearchBar({
|
|
value,
|
|
onChange,
|
|
onClear,
|
|
}: {
|
|
value: string;
|
|
onChange: (text: string) => void;
|
|
onClear: () => void;
|
|
}) {
|
|
return (
|
|
<View style={styles.searchBar}>
|
|
<Ionicons name="search-outline" size={18} color={colors.textHint} />
|
|
<TextInput
|
|
style={styles.searchInput}
|
|
value={value}
|
|
onChangeText={onChange}
|
|
placeholder="搜索候选人姓名 / 职位 / 消息"
|
|
placeholderTextColor={colors.textHint}
|
|
returnKeyType="search"
|
|
/>
|
|
{value !== '' && (
|
|
<Pressable onPress={onClear} hitSlop={8}>
|
|
<Ionicons name="close-circle" size={16} color={colors.textHint} />
|
|
</Pressable>
|
|
)}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:快捷操作栏 ===================== */
|
|
|
|
/** 单个快捷操作。`route` 必填 —— 每个入口都必须有落点,没有目标页的宁可不放 */
|
|
type QuickActionItem = { icon: string; label: string; route: string };
|
|
|
|
function QuickActions({
|
|
actions,
|
|
onPressAction,
|
|
}: {
|
|
actions: QuickActionItem[];
|
|
onPressAction: (action: QuickActionItem) => void;
|
|
}) {
|
|
return (
|
|
<View style={styles.quickActionsCard}>
|
|
{actions.map((action) => (
|
|
<Pressable key={action.label} style={styles.quickAction} onPress={() => onPressAction(action)}>
|
|
<Ionicons name={action.icon as keyof typeof Ionicons.glyphMap} size={20} color={colors.textSecondary} />
|
|
<Text style={styles.quickActionText}>{action.label}</Text>
|
|
</Pressable>
|
|
))}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:空状态 ===================== */
|
|
|
|
function EmptyState({
|
|
dataReference,
|
|
onDiscover,
|
|
}: {
|
|
dataReference: { label: string; value: string }[];
|
|
onDiscover: () => void;
|
|
}) {
|
|
return (
|
|
<View style={styles.emptyCard}>
|
|
<View style={styles.emptyIconWrap}>
|
|
<Ionicons name="chatbubbles-outline" size={48} color={colors.primary} />
|
|
</View>
|
|
<Text style={styles.emptyTitle}>还没有沟通记录</Text>
|
|
<Text style={styles.emptySubtitle}>从人才推荐中发现合适的候选人,主动发起沟通吧</Text>
|
|
<Pressable style={styles.emptyBtn} onPress={onDiscover} hitSlop={6}>
|
|
<Text style={styles.emptyBtnText}>去发现人才</Text>
|
|
</Pressable>
|
|
|
|
<View style={styles.dataCard}>
|
|
<Text style={styles.dataTitle}>数据参考</Text>
|
|
{dataReference.map((item, index) => (
|
|
<View key={index} style={styles.dataRow}>
|
|
<Ionicons name="trending-up-outline" size={16} color={colors.success} />
|
|
<Text style={styles.dataText}>
|
|
{item.label}
|
|
<Text style={styles.dataValue}> {item.value}</Text>
|
|
</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 页面 ===================== */
|
|
|
|
/*
|
|
* 「批量发Offer」「群发通知」原先在这里,但两者都没有对应页面,点了只能弹「功能开发中」。
|
|
* 按「不留假交互」的口径摘掉(与 talent-recommendation.tsx 的 POOL_ACTIONS 同一处理)。
|
|
*/
|
|
const QUICK_ACTIONS: QuickActionItem[] = [
|
|
{ icon: 'mail-outline', label: '批量发邀请', route: '/talent-recommendation' },
|
|
{ icon: 'calendar-outline', label: '面试评分', route: '/interview-score' },
|
|
];
|
|
|
|
export default function EnterpriseChatScreen() {
|
|
const router = useRouter();
|
|
const {
|
|
communication,
|
|
activeTab,
|
|
setActiveTab,
|
|
keyword,
|
|
setKeyword,
|
|
chats,
|
|
isEmptySearch,
|
|
loading,
|
|
error,
|
|
refresh,
|
|
} = useEnterpriseCommunication();
|
|
|
|
/** 快捷操作:每个入口都由数据保证有落点,页面不再需要「没页面就弹提示」的分支 */
|
|
const handleQuickAction = (action: QuickActionItem) => {
|
|
router.push(action.route);
|
|
};
|
|
|
|
// 待办卡片:跳页面或切 Tab,目标由接口层给,页面不写死映射。
|
|
// PendingTask 是联合类型,两者必居其一,故不需要「都没有」的兜底分支
|
|
const handlePressTask = (task: PendingTask) => {
|
|
if (task.tabKey) {
|
|
setActiveTab(task.tabKey);
|
|
setKeyword('');
|
|
return;
|
|
}
|
|
router.push(task.route as never);
|
|
};
|
|
|
|
if (loading) {
|
|
return (
|
|
<SafeAreaView style={styles.container} edges={['top']}>
|
|
<Header companyName={ENTERPRISE_DISPLAY_NAME} onBack={() => router.back()} />
|
|
<View style={styles.center}>
|
|
<ActivityIndicator size="large" color={colors.primary} />
|
|
</View>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
if (error || !communication) {
|
|
return (
|
|
<SafeAreaView style={styles.container} edges={['top']}>
|
|
<Header companyName={ENTERPRISE_DISPLAY_NAME} onBack={() => router.back()} />
|
|
<View style={styles.center}>
|
|
<Ionicons name="alert-circle-outline" size={40} color={colors.danger} />
|
|
<Text style={styles.tip}>加载失败</Text>
|
|
<Pressable style={styles.retryBtn} onPress={refresh}>
|
|
<Text style={styles.retryText}>重试</Text>
|
|
</Pressable>
|
|
</View>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<SafeAreaView style={styles.container} edges={['top', 'bottom']}>
|
|
<Header companyName={communication.companyName} onBack={() => router.back()} />
|
|
<TabBar tabs={communication.tabs} active={activeTab} onChange={setActiveTab} />
|
|
<ScrollView contentContainerStyle={styles.body} showsVerticalScrollIndicator={false}>
|
|
{communication.hasData ? (
|
|
<View>
|
|
<PendingTasks tasks={communication.pendingTasks} onPressTask={handlePressTask} />
|
|
<SearchBar value={keyword} onChange={setKeyword} onClear={() => setKeyword('')} />
|
|
{chats.length === 0 ? (
|
|
<View style={styles.emptyList}>
|
|
<Ionicons name="chatbubbles-outline" size={32} color={colors.textHint} />
|
|
<Text style={styles.emptyListText}>
|
|
{isEmptySearch ? `没有匹配「${keyword.trim()}」的会话` : '这个分类下暂时没有会话'}
|
|
</Text>
|
|
</View>
|
|
) : (
|
|
<View style={styles.chatListCard}>
|
|
{chats.map((chat, index) => {
|
|
const isLast = index === chats.length - 1;
|
|
return (
|
|
<View key={chat.id} style={isLast ? undefined : styles.chatBorder}>
|
|
<ChatRow chat={chat} />
|
|
</View>
|
|
);
|
|
})}
|
|
</View>
|
|
)}
|
|
<QuickActions actions={QUICK_ACTIONS} onPressAction={handleQuickAction} />
|
|
</View>
|
|
) : (
|
|
<EmptyState
|
|
dataReference={communication.dataReference}
|
|
onDiscover={() => router.navigate('/talent-recommendation')}
|
|
/>
|
|
)}
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: { flex: 1, backgroundColor: colors.pageBg },
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
paddingHorizontal: 12,
|
|
paddingVertical: 12,
|
|
backgroundColor: colors.white,
|
|
},
|
|
headerBtn: { width: 40, alignItems: 'center' },
|
|
headerCenter: { alignItems: 'center' },
|
|
headerCompany: { fontSize: 12, color: colors.textSecondary },
|
|
headerTitle: { fontSize: 17, fontWeight: '700', color: colors.textPrimary, marginTop: 2 },
|
|
startBtn: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: colors.primaryBtn,
|
|
paddingHorizontal: 10,
|
|
paddingVertical: 6,
|
|
borderRadius: 16,
|
|
},
|
|
startBtnText: {
|
|
color: colors.white,
|
|
fontSize: 12,
|
|
fontWeight: '600',
|
|
marginLeft: 2,
|
|
},
|
|
tabBar: {
|
|
flexDirection: 'row',
|
|
backgroundColor: colors.white,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: colors.borderLight,
|
|
},
|
|
tabItem: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
paddingTop: 8,
|
|
},
|
|
tabLabel: {
|
|
fontSize: 13,
|
|
color: colors.textSecondary,
|
|
paddingBottom: 8,
|
|
},
|
|
tabLabelActive: {
|
|
color: colors.textPrimary,
|
|
fontWeight: '600',
|
|
},
|
|
tabCount: {
|
|
fontSize: 12,
|
|
color: colors.textHint,
|
|
marginLeft: 2,
|
|
},
|
|
tabCountActive: {
|
|
color: colors.primary,
|
|
},
|
|
tabIndicator: {
|
|
height: 2,
|
|
width: 20,
|
|
borderRadius: 1,
|
|
backgroundColor: 'transparent',
|
|
marginBottom: -1,
|
|
},
|
|
tabIndicatorActive: {
|
|
backgroundColor: colors.primary,
|
|
},
|
|
body: {
|
|
padding: spacing.card,
|
|
paddingBottom: 24,
|
|
},
|
|
center: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
gap: 12,
|
|
},
|
|
tip: { fontSize: 14, color: colors.textSecondary },
|
|
retryBtn: {
|
|
marginTop: 8,
|
|
paddingHorizontal: 24,
|
|
paddingVertical: spacing.card,
|
|
borderRadius: 18,
|
|
backgroundColor: colors.primaryBtn,
|
|
},
|
|
retryText: { color: colors.white, fontSize: 13, fontWeight: '600' },
|
|
pendingCard: {
|
|
backgroundColor: colors.white,
|
|
borderRadius: spacing.card,
|
|
padding: spacing.card,
|
|
marginBottom: 8,
|
|
},
|
|
pendingTitle: {
|
|
fontSize: 15,
|
|
fontWeight: '700',
|
|
color: colors.textPrimary,
|
|
marginBottom: 12,
|
|
},
|
|
pendingGrid: {
|
|
gap: 8,
|
|
},
|
|
pendingItem: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: colors.pageBg,
|
|
borderRadius: spacing.card,
|
|
padding: spacing.card,
|
|
},
|
|
pendingIconWrap: {
|
|
width: 40,
|
|
height: 40,
|
|
borderRadius: 10,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginRight: 12,
|
|
},
|
|
pendingBody: {
|
|
flex: 1,
|
|
},
|
|
pendingLabelRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
pendingLabel: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: colors.textPrimary,
|
|
},
|
|
pendingBadge: {
|
|
backgroundColor: colors.actionLight,
|
|
borderRadius: 10,
|
|
paddingHorizontal: spacing.card,
|
|
paddingVertical: 2,
|
|
marginLeft: 8,
|
|
},
|
|
pendingBadgeText: {
|
|
fontSize: 12,
|
|
fontWeight: '700',
|
|
color: colors.actionText,
|
|
},
|
|
pendingHint: {
|
|
fontSize: 12,
|
|
color: colors.textSecondary,
|
|
marginTop: 2,
|
|
},
|
|
searchBar: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
backgroundColor: colors.white,
|
|
borderRadius: 10,
|
|
paddingHorizontal: 12,
|
|
paddingVertical: 10,
|
|
marginBottom: 12,
|
|
},
|
|
searchInput: {
|
|
flex: 1,
|
|
marginLeft: 8,
|
|
fontSize: 14,
|
|
color: colors.textPrimary,
|
|
padding: 0,
|
|
},
|
|
emptyList: {
|
|
alignItems: 'center',
|
|
gap: 10,
|
|
padding: spacing.card,
|
|
backgroundColor: colors.white,
|
|
borderRadius: spacing.card,
|
|
},
|
|
emptyListText: { fontSize: 13, color: colors.textSecondary },
|
|
chatListCard: {
|
|
backgroundColor: colors.white,
|
|
borderRadius: spacing.card,
|
|
overflow: 'hidden',
|
|
marginBottom: 8,
|
|
},
|
|
chatBorder: {
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: colors.borderLight,
|
|
},
|
|
chatRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
padding: 14,
|
|
},
|
|
chatAvatar: {
|
|
width: 48,
|
|
height: 48,
|
|
borderRadius: 24,
|
|
backgroundColor: colors.primaryLight,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginRight: 12,
|
|
},
|
|
chatAvatarText: {
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
color: colors.primary,
|
|
},
|
|
chatBody: {
|
|
flex: 1,
|
|
},
|
|
chatHeader: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
},
|
|
chatNameWrap: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
chatName: {
|
|
fontSize: 15,
|
|
fontWeight: '700',
|
|
color: colors.textPrimary,
|
|
},
|
|
chatLabelTag: {
|
|
backgroundColor: colors.compareOrange + '20',
|
|
borderRadius: spacing.card,
|
|
paddingHorizontal: 6,
|
|
paddingVertical: 2,
|
|
marginLeft: 8,
|
|
},
|
|
chatLabelTagText: {
|
|
fontSize: 11,
|
|
color: colors.compareOrange,
|
|
fontWeight: '600',
|
|
},
|
|
chatTime: {
|
|
fontSize: 12,
|
|
color: colors.textHint,
|
|
},
|
|
chatTitle: {
|
|
fontSize: 13,
|
|
color: colors.textSecondary,
|
|
marginTop: 2,
|
|
},
|
|
chatFooter: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginTop: 4,
|
|
},
|
|
chatLastMessage: {
|
|
flex: 1,
|
|
fontSize: 13,
|
|
color: colors.textHint,
|
|
},
|
|
unreadBadge: {
|
|
minWidth: 18,
|
|
height: 18,
|
|
borderRadius: 9,
|
|
backgroundColor: colors.danger,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginLeft: 8,
|
|
},
|
|
unreadBadgeText: {
|
|
fontSize: 11,
|
|
color: colors.white,
|
|
fontWeight: '700',
|
|
},
|
|
quickActionsCard: {
|
|
flexDirection: 'row',
|
|
backgroundColor: colors.white,
|
|
borderRadius: spacing.card,
|
|
paddingVertical: spacing.card,
|
|
},
|
|
quickAction: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
},
|
|
quickActionText: {
|
|
fontSize: 11,
|
|
color: colors.textSecondary,
|
|
marginTop: 4,
|
|
},
|
|
emptyCard: {
|
|
backgroundColor: colors.white,
|
|
borderRadius: spacing.card,
|
|
padding: spacing.card,
|
|
alignItems: 'center',
|
|
},
|
|
emptyIconWrap: {
|
|
width: 88,
|
|
height: 88,
|
|
borderRadius: 44,
|
|
backgroundColor: colors.primaryLight,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginBottom: 16,
|
|
},
|
|
emptyTitle: {
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
color: colors.textPrimary,
|
|
marginBottom: 8,
|
|
},
|
|
emptySubtitle: {
|
|
fontSize: 13,
|
|
color: colors.textSecondary,
|
|
textAlign: 'center',
|
|
marginBottom: 20,
|
|
},
|
|
emptyBtn: {
|
|
backgroundColor: colors.primaryBtn,
|
|
paddingHorizontal: 32,
|
|
paddingVertical: 12,
|
|
borderRadius: 24,
|
|
marginBottom: 24,
|
|
},
|
|
emptyBtnText: {
|
|
color: colors.white,
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
},
|
|
dataCard: {
|
|
width: '100%',
|
|
backgroundColor: colors.primaryLight,
|
|
borderRadius: spacing.card,
|
|
padding: spacing.card,
|
|
alignItems: 'flex-start',
|
|
},
|
|
dataTitle: {
|
|
fontSize: 14,
|
|
fontWeight: '700',
|
|
color: colors.primaryText,
|
|
marginBottom: 12,
|
|
},
|
|
dataRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'flex-start',
|
|
marginBottom: 10,
|
|
},
|
|
dataText: {
|
|
flex: 1,
|
|
fontSize: 13,
|
|
color: colors.textPrimary,
|
|
marginLeft: 10,
|
|
lineHeight: 18,
|
|
},
|
|
dataValue: {
|
|
color: colors.success,
|
|
fontWeight: '700',
|
|
},
|
|
});
|
|
|