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.
705 lines
19 KiB
705 lines
19 KiB
import { Ionicons } from '@expo/vector-icons';
|
|
import { useLocalSearchParams, useRouter } from 'expo-router';
|
|
import {
|
|
Pressable,
|
|
ScrollView,
|
|
StyleSheet,
|
|
Text,
|
|
View,
|
|
} from 'react-native';
|
|
import { SafeAreaView } from 'react-native-safe-area-context';
|
|
import Svg, { Line, Path, Polygon, Text as SvgText } from 'react-native-svg';
|
|
import { useCandidateDetail } from '../src/hooks';
|
|
import { LoadingState, ErrorState } from '../src/components/StateView';
|
|
import { colors } from '../src/theme';
|
|
import type { CandidateAbility, CandidateReview } from '../src/types';
|
|
|
|
/* ===================== 子组件:顶部导航 ===================== */
|
|
|
|
function Header({ onBack }: { onBack: () => void }) {
|
|
return (
|
|
<View style={styles.header}>
|
|
<Pressable style={styles.headerBtn} onPress={onBack} hitSlop={8}>
|
|
<Ionicons name="chevron-back" size={24} color={colors.textPrimary} />
|
|
</Pressable>
|
|
<Text style={styles.headerTitle}>候选人详情</Text>
|
|
{/* 原先这里是「更多」图标:没有下拉菜单,先摘掉 */}
|
|
<View style={styles.headerBtn} />
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:基本信息卡 ===================== */
|
|
|
|
function BasicInfoCard({
|
|
name,
|
|
matchPercent,
|
|
info,
|
|
}: {
|
|
name: string;
|
|
matchPercent: number;
|
|
info: {
|
|
age: number;
|
|
gender: string;
|
|
experience: string;
|
|
education: string;
|
|
city: string;
|
|
phone: string;
|
|
email: string;
|
|
jobStatus: string;
|
|
};
|
|
}) {
|
|
return (
|
|
<View style={styles.infoCard}>
|
|
<View style={styles.infoHeader}>
|
|
<View style={styles.avatarBox}>
|
|
<Text style={styles.avatarText}>{name[0]}</Text>
|
|
</View>
|
|
<View style={styles.infoMain}>
|
|
<Text style={styles.infoName}>{name}</Text>
|
|
<Text style={styles.infoSub}>
|
|
{info.age}岁 · {info.gender} · {info.experience} · {info.education} · {info.city}
|
|
</Text>
|
|
</View>
|
|
<View style={styles.matchBox}>
|
|
<Text style={styles.matchValue}>{matchPercent}%</Text>
|
|
<Text style={styles.matchLabel}>匹配度</Text>
|
|
</View>
|
|
</View>
|
|
<View style={styles.contactRow}>
|
|
<View style={styles.contactItem}>
|
|
<Ionicons name="call-outline" size={14} color={colors.textHint} />
|
|
<Text style={styles.contactText}>{info.phone}</Text>
|
|
</View>
|
|
<View style={styles.contactItem}>
|
|
<Ionicons name="mail-outline" size={14} color={colors.textHint} />
|
|
<Text style={styles.contactText}>{info.email}</Text>
|
|
</View>
|
|
</View>
|
|
<View style={styles.statusTag}>
|
|
<Text style={styles.statusText}>{info.jobStatus}</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:综合评分卡 ===================== */
|
|
|
|
function OverallScoreCard({ score, percentile }: { score: number; percentile: number }) {
|
|
return (
|
|
<View style={styles.scoreCard}>
|
|
<View>
|
|
<Text style={styles.scoreValue}>{score}</Text>
|
|
<Text style={styles.scoreLabel}>综合评分</Text>
|
|
<Text style={styles.scoreMeta}>超过 {percentile}% 同岗位候选人</Text>
|
|
</View>
|
|
<View style={styles.scoreIcon}>
|
|
<Ionicons name="trophy-outline" size={44} color={colors.primary} />
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:趋势图 ===================== */
|
|
|
|
function TrendChart({ trend }: { trend: { month: string; score: number }[] }) {
|
|
const width = 320;
|
|
const height = 120;
|
|
const padding = { top: 16, right: 24, bottom: 24, left: 32 };
|
|
const chartW = width - padding.left - padding.right;
|
|
const chartH = height - padding.top - padding.bottom;
|
|
const minScore = 70;
|
|
const maxScore = 100;
|
|
|
|
const points = trend.map((t, i) => {
|
|
const x = padding.left + (i / (trend.length - 1)) * chartW;
|
|
const y = padding.top + chartH - ((t.score - minScore) / (maxScore - minScore)) * chartH;
|
|
return { x, y, month: t.month };
|
|
});
|
|
|
|
const pathD = points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x} ${p.y}`).join(' ');
|
|
|
|
return (
|
|
<View style={styles.card}>
|
|
<Text style={styles.cardTitle}>评分趋势</Text>
|
|
<Svg width={width} height={height}>
|
|
{[75, 80, 85, 90, 95].map((s) => {
|
|
const y = padding.top + chartH - ((s - minScore) / (maxScore - minScore)) * chartH;
|
|
return <Line key={s} x1={padding.left} y1={y} x2={width - padding.right} y2={y} stroke={colors.borderLight} strokeWidth={1} />;
|
|
})}
|
|
<Path d={pathD} stroke={colors.primary} strokeWidth={2} fill="none" />
|
|
{points.map((p, i) => (
|
|
<Polygon key={i} points={`${p.x - 4},${p.y - 4} ${p.x + 4},${p.y - 4} ${p.x},${p.y + 4}`} fill={colors.primary} />
|
|
))}
|
|
{points.map((p, i) => (
|
|
<SvgText key={i} x={p.x} y={height - 6} fill={colors.textSecondary} fontSize={10} textAnchor="middle">
|
|
{p.month}
|
|
</SvgText>
|
|
))}
|
|
</Svg>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:八维能力雷达图 ===================== */
|
|
|
|
function AbilityRadar({ abilities }: { abilities: CandidateAbility[] }) {
|
|
const size = 220;
|
|
const center = size / 2;
|
|
const radius = 80;
|
|
const angleStep = (Math.PI * 2) / abilities.length;
|
|
|
|
const axisPoints = abilities.map((_, i) => {
|
|
const angle = i * angleStep - Math.PI / 2;
|
|
return {
|
|
x: center + radius * Math.cos(angle),
|
|
y: center + radius * Math.sin(angle),
|
|
label: abilities[i].name,
|
|
};
|
|
});
|
|
|
|
const dataPoints = abilities.map((d, i) => {
|
|
const angle = i * angleStep - Math.PI / 2;
|
|
const r = (d.score / d.maxScore) * radius;
|
|
return {
|
|
x: center + r * Math.cos(angle),
|
|
y: center + r * Math.sin(angle),
|
|
};
|
|
});
|
|
|
|
const polygonPoints = dataPoints.map((p) => `${p.x},${p.y}`).join(' ');
|
|
|
|
return (
|
|
<View style={styles.card}>
|
|
<Text style={styles.cardTitle}>八维能力评分</Text>
|
|
<View style={styles.radarWrap}>
|
|
<Svg width={size} height={size}>
|
|
{[0.2, 0.4, 0.6, 0.8, 1].map((scale) => (
|
|
<Polygon
|
|
key={scale}
|
|
points={axisPoints.map((a) => {
|
|
const px = center + (a.x - center) * scale;
|
|
const py = center + (a.y - center) * scale;
|
|
return `${px},${py}`;
|
|
}).join(' ')}
|
|
fill="none"
|
|
stroke={colors.borderLight}
|
|
strokeWidth={1}
|
|
/>
|
|
))}
|
|
{axisPoints.map((a, i) => (
|
|
<Line key={i} x1={center} y1={center} x2={a.x} y2={a.y} stroke={colors.borderLight} strokeWidth={1} />
|
|
))}
|
|
<Polygon points={polygonPoints} fill={colors.primary + '25'} stroke={colors.primary} strokeWidth={2} />
|
|
{axisPoints.map((a, i) => {
|
|
const labelX = center + (a.x - center) * 1.18;
|
|
const labelY = center + (a.y - center) * 1.18;
|
|
return (
|
|
<SvgText key={i} x={labelX} y={labelY} fill={colors.textSecondary} fontSize={10} textAnchor="middle" alignmentBaseline="middle">
|
|
{a.label}
|
|
</SvgText>
|
|
);
|
|
})}
|
|
</Svg>
|
|
</View>
|
|
<View style={styles.abilityList}>
|
|
{abilities.map((a) => (
|
|
<View key={a.id} style={styles.abilityItem}>
|
|
<Text style={styles.abilityName}>{a.name}</Text>
|
|
<View style={styles.abilityTrack}>
|
|
<View style={[styles.abilityFill, { width: `${a.score}%` }]} />
|
|
</View>
|
|
<Text style={styles.abilityScore}>{a.score}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:面试评价 ===================== */
|
|
|
|
function ReviewList({ reviews }: { reviews: CandidateReview[] }) {
|
|
return (
|
|
<View style={styles.card}>
|
|
<Text style={styles.cardTitle}>面试评价</Text>
|
|
{reviews.map((review) => (
|
|
<View key={review.id} style={styles.reviewItem}>
|
|
<View style={styles.reviewHeader}>
|
|
<View style={styles.reviewUser}>
|
|
<Text style={styles.reviewName}>{review.interviewer}</Text>
|
|
<Text style={styles.reviewRole}>{review.position}</Text>
|
|
</View>
|
|
<View style={styles.reviewRating}>
|
|
<Text style={styles.reviewScore}>{review.rating}.0</Text>
|
|
<Ionicons name="star" size={12} color={colors.compareOrange} />
|
|
</View>
|
|
</View>
|
|
<Text style={styles.reviewContent}>{review.content}</Text>
|
|
<View style={styles.tagRow}>
|
|
{review.tags.map((tag) => (
|
|
<View key={tag} style={styles.reviewTag}>
|
|
<Text style={styles.reviewTagText}>{tag}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
<Text style={styles.reviewDate}>{review.date}</Text>
|
|
</View>
|
|
))}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 子组件:录用建议 ===================== */
|
|
|
|
function HireSuggestionCard({
|
|
suggestions,
|
|
salary,
|
|
}: {
|
|
suggestions: { type: string; title: string; desc: string; selected?: boolean }[];
|
|
salary: { range: string; level: string; note: string };
|
|
}) {
|
|
const typeColor: Record<string, string> = {
|
|
strong: colors.success,
|
|
consider: colors.compareOrange,
|
|
reject: colors.danger,
|
|
};
|
|
return (
|
|
<View style={styles.card}>
|
|
<Text style={styles.cardTitle}>录用建议</Text>
|
|
{suggestions.map((s) => (
|
|
<View
|
|
key={s.type}
|
|
style={[
|
|
styles.suggestionRow,
|
|
s.selected && { backgroundColor: typeColor[s.type] + '10', borderColor: typeColor[s.type] },
|
|
]}
|
|
>
|
|
<View style={[styles.suggestionDot, { backgroundColor: typeColor[s.type] }]} />
|
|
<View style={styles.suggestionBody}>
|
|
<Text style={styles.suggestionTitle}>{s.title}</Text>
|
|
<Text style={styles.suggestionDesc}>{s.desc}</Text>
|
|
</View>
|
|
{s.selected && <Ionicons name="checkmark-circle" size={20} color={typeColor[s.type]} />}
|
|
</View>
|
|
))}
|
|
<View style={styles.salaryBox}>
|
|
<Text style={styles.salaryLabel}>薪资建议</Text>
|
|
<Text style={styles.salaryRange}>{salary.range}</Text>
|
|
<Text style={styles.salaryLevel}>{salary.level}</Text>
|
|
<Text style={styles.salaryNote}>{salary.note}</Text>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 页面主组件 ===================== */
|
|
|
|
export default function CandidateDetailScreen() {
|
|
const router = useRouter();
|
|
const { id } = useLocalSearchParams<{ id: string }>();
|
|
const candidateId = (id && id.length > 0) ? id : 'candidate-1';
|
|
const { candidate, loading, error, refresh, invite, inviting, invited } = useCandidateDetail(candidateId);
|
|
|
|
if (loading) {
|
|
return (
|
|
<SafeAreaView style={styles.loadingContainer} edges={['top']}>
|
|
<LoadingState text="加载中…" />
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
if (error || !candidate) {
|
|
return (
|
|
<SafeAreaView style={styles.loadingContainer} edges={['top']}>
|
|
<ErrorState onRetry={refresh} />
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<View style={styles.container}>
|
|
<SafeAreaView edges={['top']}>
|
|
<Header onBack={() => router.back()} />
|
|
</SafeAreaView>
|
|
<ScrollView style={styles.scroll} contentContainerStyle={styles.scrollContent}>
|
|
<BasicInfoCard name={candidate.basicInfo.name} matchPercent={candidate.matchPercent} info={candidate.basicInfo} />
|
|
<OverallScoreCard score={candidate.overallScore} percentile={candidate.percentile} />
|
|
<TrendChart trend={candidate.trend} />
|
|
<AbilityRadar abilities={candidate.abilities} />
|
|
<ReviewList reviews={candidate.reviews} />
|
|
<HireSuggestionCard suggestions={candidate.hireSuggestions} salary={candidate.salarySuggestion} />
|
|
</ScrollView>
|
|
<View style={styles.footer}>
|
|
{/* 发起沟通:进该候选人的会话页(此前是空 Pressable,点了没反应) */}
|
|
<Pressable style={styles.chatBtn} onPress={() => router.push(`/chat/${candidate.id}`)}>
|
|
<Text style={styles.chatText}>发起沟通</Text>
|
|
</Pressable>
|
|
<Pressable
|
|
style={[styles.inviteBtn, (inviting || invited) && styles.inviteBtnDisabled]}
|
|
onPress={invite}
|
|
disabled={inviting || invited}
|
|
>
|
|
<Text style={styles.inviteText}>{invited ? '已邀请' : inviting ? '邀请中...' : '邀请面试'}</Text>
|
|
</Pressable>
|
|
</View>
|
|
</View>
|
|
);
|
|
}
|
|
|
|
/* ===================== 样式 ===================== */
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
backgroundColor: colors.pageBg,
|
|
},
|
|
loadingContainer: {
|
|
flex: 1,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
backgroundColor: colors.pageBg,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
justifyContent: 'space-between',
|
|
paddingHorizontal: 16,
|
|
paddingVertical: 12,
|
|
backgroundColor: colors.white,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: colors.borderLight,
|
|
},
|
|
headerBtn: {
|
|
width: 36,
|
|
height: 36,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
headerTitle: {
|
|
fontSize: 17,
|
|
fontWeight: '600',
|
|
color: colors.textPrimary,
|
|
},
|
|
scroll: {
|
|
flex: 1,
|
|
},
|
|
scrollContent: {
|
|
padding: 16,
|
|
paddingBottom: 100,
|
|
},
|
|
infoCard: {
|
|
backgroundColor: colors.white,
|
|
borderRadius: 8,
|
|
padding: 16,
|
|
marginBottom: 16,
|
|
},
|
|
infoHeader: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginBottom: 14,
|
|
},
|
|
avatarBox: {
|
|
width: 56,
|
|
height: 56,
|
|
borderRadius: 28,
|
|
backgroundColor: colors.primaryLight,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
marginRight: 12,
|
|
},
|
|
avatarText: {
|
|
fontSize: 22,
|
|
fontWeight: '700',
|
|
color: colors.primary,
|
|
},
|
|
infoMain: {
|
|
flex: 1,
|
|
},
|
|
infoName: {
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
color: colors.textPrimary,
|
|
marginBottom: 4,
|
|
},
|
|
infoSub: {
|
|
fontSize: 13,
|
|
color: colors.textSecondary,
|
|
},
|
|
matchBox: {
|
|
alignItems: 'center',
|
|
backgroundColor: colors.successLight,
|
|
borderRadius: 8,
|
|
paddingHorizontal: 12,
|
|
paddingVertical: 8,
|
|
},
|
|
matchValue: {
|
|
fontSize: 20,
|
|
fontWeight: '700',
|
|
color: colors.success,
|
|
},
|
|
matchLabel: {
|
|
fontSize: 11,
|
|
color: colors.successText,
|
|
},
|
|
contactRow: {
|
|
flexDirection: 'row',
|
|
marginBottom: 12,
|
|
},
|
|
contactItem: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginRight: 16,
|
|
},
|
|
contactText: {
|
|
fontSize: 13,
|
|
color: colors.textSecondary,
|
|
marginLeft: 4,
|
|
},
|
|
statusTag: {
|
|
alignSelf: 'flex-start',
|
|
backgroundColor: colors.infoLight,
|
|
paddingHorizontal: 10,
|
|
paddingVertical: 4,
|
|
borderRadius: 12,
|
|
},
|
|
statusText: {
|
|
fontSize: 12,
|
|
color: colors.infoText,
|
|
fontWeight: '500',
|
|
},
|
|
scoreCard: {
|
|
backgroundColor: colors.white,
|
|
borderRadius: 8,
|
|
padding: 20,
|
|
marginBottom: 16,
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
},
|
|
scoreValue: {
|
|
fontSize: 38,
|
|
fontWeight: '700',
|
|
color: colors.primary,
|
|
},
|
|
scoreLabel: {
|
|
fontSize: 14,
|
|
color: colors.textSecondary,
|
|
marginTop: 2,
|
|
},
|
|
scoreMeta: {
|
|
fontSize: 13,
|
|
color: colors.textHint,
|
|
marginTop: 6,
|
|
},
|
|
scoreIcon: {
|
|
width: 64,
|
|
height: 64,
|
|
borderRadius: 32,
|
|
backgroundColor: colors.primaryLight,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
card: {
|
|
backgroundColor: colors.white,
|
|
borderRadius: 8,
|
|
padding: 16,
|
|
marginBottom: 16,
|
|
},
|
|
cardTitle: {
|
|
fontSize: 16,
|
|
fontWeight: '700',
|
|
color: colors.textPrimary,
|
|
marginBottom: 12,
|
|
},
|
|
radarWrap: {
|
|
alignItems: 'center',
|
|
},
|
|
abilityList: {
|
|
marginTop: 16,
|
|
},
|
|
abilityItem: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
marginBottom: 10,
|
|
},
|
|
abilityName: {
|
|
width: 70,
|
|
fontSize: 13,
|
|
color: colors.textSecondary,
|
|
},
|
|
abilityTrack: {
|
|
flex: 1,
|
|
height: 8,
|
|
borderRadius: 4,
|
|
backgroundColor: colors.borderLight,
|
|
marginHorizontal: 10,
|
|
},
|
|
abilityFill: {
|
|
height: 8,
|
|
borderRadius: 4,
|
|
backgroundColor: colors.primary,
|
|
},
|
|
abilityScore: {
|
|
width: 28,
|
|
fontSize: 13,
|
|
fontWeight: '600',
|
|
color: colors.textPrimary,
|
|
textAlign: 'right',
|
|
},
|
|
reviewItem: {
|
|
paddingVertical: 14,
|
|
borderBottomWidth: 1,
|
|
borderBottomColor: colors.borderLight,
|
|
},
|
|
reviewHeader: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
marginBottom: 8,
|
|
},
|
|
reviewUser: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
reviewName: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: colors.textPrimary,
|
|
marginRight: 8,
|
|
},
|
|
reviewRole: {
|
|
fontSize: 12,
|
|
color: colors.textSecondary,
|
|
},
|
|
reviewRating: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
reviewScore: {
|
|
fontSize: 14,
|
|
fontWeight: '700',
|
|
color: colors.compareOrange,
|
|
marginRight: 4,
|
|
},
|
|
reviewContent: {
|
|
fontSize: 14,
|
|
color: colors.textPrimary,
|
|
lineHeight: 20,
|
|
marginBottom: 10,
|
|
},
|
|
tagRow: {
|
|
flexDirection: 'row',
|
|
flexWrap: 'wrap',
|
|
marginBottom: 8,
|
|
},
|
|
reviewTag: {
|
|
paddingHorizontal: 8,
|
|
paddingVertical: 4,
|
|
borderRadius: 12,
|
|
backgroundColor: colors.primaryLight,
|
|
marginRight: 8,
|
|
marginBottom: 6,
|
|
},
|
|
reviewTagText: {
|
|
fontSize: 11,
|
|
color: colors.primaryText,
|
|
},
|
|
reviewDate: {
|
|
fontSize: 12,
|
|
color: colors.textHint,
|
|
},
|
|
suggestionRow: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
padding: 12,
|
|
borderRadius: 12,
|
|
borderWidth: 1,
|
|
borderColor: colors.borderLight,
|
|
marginBottom: 10,
|
|
},
|
|
suggestionDot: {
|
|
width: 10,
|
|
height: 10,
|
|
borderRadius: 5,
|
|
marginRight: 10,
|
|
},
|
|
suggestionBody: {
|
|
flex: 1,
|
|
},
|
|
suggestionTitle: {
|
|
fontSize: 14,
|
|
fontWeight: '600',
|
|
color: colors.textPrimary,
|
|
marginBottom: 2,
|
|
},
|
|
suggestionDesc: {
|
|
fontSize: 12,
|
|
color: colors.textSecondary,
|
|
},
|
|
salaryBox: {
|
|
marginTop: 12,
|
|
padding: 14,
|
|
borderRadius: 8,
|
|
backgroundColor: colors.infoLight,
|
|
},
|
|
salaryLabel: {
|
|
fontSize: 13,
|
|
color: colors.infoText,
|
|
marginBottom: 6,
|
|
},
|
|
salaryRange: {
|
|
fontSize: 24,
|
|
fontWeight: '700',
|
|
color: colors.info,
|
|
},
|
|
salaryLevel: {
|
|
fontSize: 13,
|
|
color: colors.infoText,
|
|
marginTop: 2,
|
|
},
|
|
salaryNote: {
|
|
fontSize: 12,
|
|
color: colors.textSecondary,
|
|
marginTop: 6,
|
|
},
|
|
footer: {
|
|
flexDirection: 'row',
|
|
padding: 16,
|
|
paddingBottom: 24,
|
|
backgroundColor: colors.white,
|
|
borderTopWidth: 1,
|
|
borderTopColor: colors.borderLight,
|
|
},
|
|
chatBtn: {
|
|
flex: 1,
|
|
height: 46,
|
|
borderRadius: 24,
|
|
borderWidth: 1,
|
|
borderColor: colors.border,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
marginRight: 12,
|
|
},
|
|
chatText: {
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
color: colors.textPrimary,
|
|
},
|
|
inviteBtn: {
|
|
flex: 2,
|
|
height: 46,
|
|
borderRadius: 24,
|
|
backgroundColor: colors.primaryBtn,
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
inviteBtnDisabled: {
|
|
opacity: 0.6,
|
|
},
|
|
inviteText: {
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
color: colors.white,
|
|
},
|
|
});
|
|
|