452 lines
12 KiB
TypeScript
452 lines
12 KiB
TypeScript
import { formatPhone, normalizeDigits } from '@/constants/formatPhone';
|
||
import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
|
||
import { Edit2, Plus } from 'lucide-react-native';
|
||
import { useEffect, useState } from 'react';
|
||
import { Alert, Modal, Pressable, StyleSheet, Text, TextInput, View } from 'react-native';
|
||
import { user_api } from '../lib/api';
|
||
import { UserInfoResponseData } from '../lib/type';
|
||
|
||
export function PersonalInfoTab() {
|
||
const [editModalVisible, setEditModalVisible] = useState(false);
|
||
const [addFieldModalVisible, setAddFieldModalVisible] = useState(false);
|
||
const [newField, setNewField] = useState('');
|
||
const [focused, setFocused] = useState(false);
|
||
const [editData, setEditData] = useState<UserInfoResponseData | undefined>(undefined);
|
||
const [phone, setPhone] = useState('');
|
||
|
||
const queryClient = useQueryClient();
|
||
|
||
// GET ME
|
||
const {
|
||
data: me,
|
||
isLoading,
|
||
isError,
|
||
} = useQuery({
|
||
queryKey: ['get_me'],
|
||
queryFn: () => user_api.getMe(),
|
||
select: (res) => {
|
||
setPhone(res.data.data.phone || '');
|
||
return res;
|
||
},
|
||
});
|
||
|
||
// UPDATE ME mutation
|
||
const updateMutation = useMutation({
|
||
mutationFn: (body: {
|
||
first_name: string;
|
||
industries: {
|
||
id: number;
|
||
name: string;
|
||
code: string;
|
||
external_id: null | number;
|
||
level: number;
|
||
is_leaf: boolean;
|
||
icon_name: null | string;
|
||
parent: {
|
||
id: number;
|
||
name: string;
|
||
code: string;
|
||
};
|
||
}[];
|
||
person_type: 'employee' | 'legal_entity' | 'ytt' | 'band';
|
||
phone: string;
|
||
activate_types: number[];
|
||
age: number;
|
||
gender: 'male' | 'female';
|
||
}) => user_api.updateMe(body),
|
||
onSuccess: (res) => {
|
||
queryClient.invalidateQueries({ queryKey: ['get_me'] });
|
||
setEditModalVisible(false);
|
||
Alert.alert('Muvaffaqiyat', 'Ma’lumotlar yangilandi');
|
||
},
|
||
onError: () => {
|
||
Alert.alert('Xatolik', 'Ma’lumotlarni yangilashda xatolik yuz berdi');
|
||
},
|
||
});
|
||
|
||
// const handleSave = () => {
|
||
// if (!editData) return;
|
||
|
||
// // Backendga yuboriladigan data
|
||
// const payload: {
|
||
// first_name: string;
|
||
// industries: {
|
||
// id: number;
|
||
// name: string;
|
||
// code: string;
|
||
// external_id: null | number;
|
||
// level: number;
|
||
// is_leaf: boolean;
|
||
// icon_name: null | string;
|
||
// parent: {
|
||
// id: number;
|
||
// name: string;
|
||
// code: string;
|
||
// };
|
||
// }[];
|
||
// person_type: 'employee' | 'legal_entity' | 'ytt' | 'band';
|
||
// phone: string;
|
||
// } = {
|
||
// first_name: editData.director_full_name,
|
||
// phone: normalizeDigits(phone),
|
||
// industries:
|
||
// };
|
||
|
||
// updateMutation.mutate();
|
||
// };
|
||
|
||
const handlePhone = (text: string) => {
|
||
const n = normalizeDigits(text);
|
||
setPhone(n);
|
||
};
|
||
|
||
const handleAddField = () => {
|
||
if (newField.trim()) {
|
||
setNewField('');
|
||
setAddFieldModalVisible(false);
|
||
}
|
||
};
|
||
|
||
const handleRemoveField = (field: string) => {
|
||
Alert.alert('Soha olib tashlash', `"${field}" sohasini olib tashlashni xohlaysizmi?`, [
|
||
{ text: 'Bekor qilish', style: 'cancel' },
|
||
{
|
||
text: 'Olib tashlash',
|
||
style: 'destructive',
|
||
},
|
||
]);
|
||
};
|
||
|
||
useEffect(() => {
|
||
if (me?.data.data) {
|
||
setPhone(me.data.data.phone || '');
|
||
}
|
||
}, [me]);
|
||
|
||
return (
|
||
<View style={styles.container}>
|
||
{/* Personal Info Card */}
|
||
<View style={styles.card}>
|
||
<View style={styles.cardHeader}>
|
||
<Text style={styles.cardTitle}>Shaxsiy ma'lumotlar</Text>
|
||
<Pressable onPress={() => setEditModalVisible(true)} style={styles.editButton}>
|
||
<Edit2 size={18} color="#3b82f6" />
|
||
<Text style={styles.editButtonText}>Tahrirlash</Text>
|
||
</Pressable>
|
||
</View>
|
||
|
||
<View style={styles.infoRow}>
|
||
<Text style={styles.label}>Ism</Text>
|
||
<Text style={styles.value}>{me?.data.data.director_full_name}</Text>
|
||
</View>
|
||
|
||
<View style={styles.infoRow}>
|
||
<Text style={styles.label}>Telefon raqam</Text>
|
||
<Text style={styles.value}>+{me?.data.data.phone}</Text>
|
||
</View>
|
||
|
||
<View style={styles.infoRow}>
|
||
<Text style={styles.label}>Foydalanuvchi turi</Text>
|
||
<Text style={styles.value}>
|
||
{me?.data.data.person_type === 'employee'
|
||
? 'Xodim'
|
||
: me?.data.data.person_type === 'legal_entity'
|
||
? 'Yuridik shaxs'
|
||
: me?.data.data.person_type === 'ytt'
|
||
? 'Yakka tartibdagi tadbirkor'
|
||
: "O'zini o'zi band qilgan shaxs"}
|
||
</Text>
|
||
</View>
|
||
</View>
|
||
|
||
{/* Activity Fields Card */}
|
||
<View style={styles.card}>
|
||
<View style={styles.cardHeader}>
|
||
<Text style={styles.cardTitle}>Faoliyat sohalari</Text>
|
||
<Pressable onPress={() => setAddFieldModalVisible(true)} style={styles.addButton}>
|
||
<Plus size={18} color="#10b981" />
|
||
<Text style={styles.addButtonText}>Qo'shish</Text>
|
||
</Pressable>
|
||
</View>
|
||
|
||
<View style={styles.fieldsContainer}>
|
||
{me?.data.data.activate_types.map((field) => (
|
||
<View key={field.id} style={styles.fieldChip}>
|
||
<Text style={styles.fieldText}>{field.name}</Text>
|
||
</View>
|
||
))}
|
||
</View>
|
||
</View>
|
||
|
||
{/* Edit Modal */}
|
||
<Modal
|
||
visible={editModalVisible}
|
||
transparent
|
||
animationType="slide"
|
||
onRequestClose={() => setEditModalVisible(false)}
|
||
>
|
||
<View style={styles.modalOverlay}>
|
||
<View style={styles.modalContent}>
|
||
<Text style={styles.modalTitle}>Ma'lumotlarni tahrirlash</Text>
|
||
|
||
<Text style={styles.inputLabel}>Ism</Text>
|
||
<TextInput
|
||
style={styles.input}
|
||
value={editData?.data.first_name}
|
||
onChangeText={(text) =>
|
||
setEditData((prev) => prev && { ...prev, director_full_name: text })
|
||
}
|
||
placeholderTextColor="#64748b"
|
||
/>
|
||
|
||
<Text style={styles.label}>Telefon</Text>
|
||
<View style={styles.inputBox}>
|
||
<View style={styles.prefixContainer}>
|
||
<Text style={[styles.prefix, focused && styles.prefixFocused]}>+998</Text>
|
||
<View style={styles.divider} />
|
||
</View>
|
||
<TextInput
|
||
style={{ ...styles.input, borderWidth: 0 }}
|
||
value={formatPhone(phone)}
|
||
onChangeText={handlePhone}
|
||
onFocus={() => setFocused(true)}
|
||
onBlur={() => setFocused(false)}
|
||
keyboardType="phone-pad"
|
||
placeholder="90 123 45 67"
|
||
maxLength={12}
|
||
placeholderTextColor="#94a3b8"
|
||
/>
|
||
</View>
|
||
|
||
<View style={styles.modalButtons}>
|
||
<Pressable
|
||
onPress={() => setEditModalVisible(false)}
|
||
style={[styles.modalButton, styles.cancelButton]}
|
||
>
|
||
<Text style={styles.cancelButtonText}>Bekor qilish</Text>
|
||
</Pressable>
|
||
<Pressable style={[styles.modalButton, styles.saveButton]}>
|
||
<Text style={styles.saveButtonText}>Saqlash</Text>
|
||
</Pressable>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</Modal>
|
||
|
||
{/* Add Field Modal */}
|
||
<Modal
|
||
visible={addFieldModalVisible}
|
||
transparent
|
||
animationType="slide"
|
||
onRequestClose={() => setAddFieldModalVisible(false)}
|
||
>
|
||
<View style={styles.modalOverlay}>
|
||
<View style={styles.modalContent}>
|
||
<Text style={styles.modalTitle}>Faoliyat sohasini qo'shish</Text>
|
||
|
||
<Text style={styles.inputLabel}>Soha nomi</Text>
|
||
<TextInput
|
||
style={styles.input}
|
||
value={newField}
|
||
onChangeText={setNewField}
|
||
placeholder="Masalan: IT"
|
||
placeholderTextColor="#64748b"
|
||
/>
|
||
|
||
<View style={styles.modalButtons}>
|
||
<Pressable
|
||
onPress={() => {
|
||
setNewField('');
|
||
setAddFieldModalVisible(false);
|
||
}}
|
||
style={[styles.modalButton, styles.cancelButton]}
|
||
>
|
||
<Text style={styles.cancelButtonText}>Bekor qilish</Text>
|
||
</Pressable>
|
||
<Pressable onPress={handleAddField} style={[styles.modalButton, styles.saveButton]}>
|
||
<Text style={styles.saveButtonText}>Qo'shish</Text>
|
||
</Pressable>
|
||
</View>
|
||
</View>
|
||
</View>
|
||
</Modal>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
container: {
|
||
padding: 16,
|
||
gap: 16,
|
||
paddingBottom: 100,
|
||
},
|
||
divider: {
|
||
width: 1.5,
|
||
height: 24,
|
||
backgroundColor: '#fff',
|
||
marginLeft: 12,
|
||
},
|
||
prefix: {
|
||
fontSize: 16,
|
||
fontWeight: '600',
|
||
color: '#fff',
|
||
letterSpacing: 0.3,
|
||
},
|
||
prefixFocused: {
|
||
color: '#fff',
|
||
},
|
||
prefixContainer: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
marginRight: 12,
|
||
},
|
||
inputBox: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
backgroundColor: '#1e293b',
|
||
borderRadius: 16,
|
||
borderWidth: 1,
|
||
borderColor: '#334155',
|
||
paddingHorizontal: 16,
|
||
height: 56,
|
||
},
|
||
card: {
|
||
backgroundColor: '#1e293b',
|
||
borderRadius: 16,
|
||
padding: 20,
|
||
gap: 16,
|
||
},
|
||
cardHeader: {
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
},
|
||
cardTitle: {
|
||
fontSize: 18,
|
||
fontWeight: '700' as const,
|
||
color: '#f8fafc',
|
||
},
|
||
editButton: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
gap: 6,
|
||
paddingHorizontal: 12,
|
||
paddingVertical: 8,
|
||
borderRadius: 8,
|
||
backgroundColor: '#1e40af20',
|
||
},
|
||
editButtonText: {
|
||
fontSize: 14,
|
||
fontWeight: '600' as const,
|
||
color: '#3b82f6',
|
||
},
|
||
addButton: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
gap: 6,
|
||
paddingHorizontal: 12,
|
||
paddingVertical: 8,
|
||
borderRadius: 8,
|
||
backgroundColor: '#10b98120',
|
||
},
|
||
addButtonText: {
|
||
fontSize: 14,
|
||
fontWeight: '600' as const,
|
||
color: '#10b981',
|
||
},
|
||
infoRow: {
|
||
gap: 6,
|
||
},
|
||
label: {
|
||
fontSize: 13,
|
||
color: '#94a3b8',
|
||
fontWeight: '500' as const,
|
||
},
|
||
value: {
|
||
fontSize: 16,
|
||
color: '#f8fafc',
|
||
fontWeight: '600' as const,
|
||
},
|
||
fieldsContainer: {
|
||
flexDirection: 'row',
|
||
flexWrap: 'wrap',
|
||
gap: 8,
|
||
},
|
||
fieldChip: {
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
gap: 8,
|
||
paddingHorizontal: 12,
|
||
paddingVertical: 8,
|
||
borderRadius: 20,
|
||
backgroundColor: '#334155',
|
||
},
|
||
fieldText: {
|
||
fontSize: 14,
|
||
color: '#f8fafc',
|
||
fontWeight: '600' as const,
|
||
},
|
||
modalOverlay: {
|
||
flex: 1,
|
||
backgroundColor: '#00000090',
|
||
justifyContent: 'center',
|
||
alignItems: 'center',
|
||
padding: 20,
|
||
},
|
||
modalContent: {
|
||
width: '100%',
|
||
maxWidth: 400,
|
||
backgroundColor: '#1e293b',
|
||
borderRadius: 20,
|
||
padding: 24,
|
||
gap: 16,
|
||
},
|
||
modalTitle: {
|
||
fontSize: 20,
|
||
fontWeight: '700' as const,
|
||
color: '#f8fafc',
|
||
marginBottom: 8,
|
||
},
|
||
inputLabel: {
|
||
fontSize: 14,
|
||
fontWeight: '600' as const,
|
||
color: '#94a3b8',
|
||
marginBottom: -8,
|
||
},
|
||
input: {
|
||
borderRadius: 12,
|
||
padding: 14,
|
||
fontSize: 16,
|
||
color: '#f8fafc',
|
||
borderWidth: 1,
|
||
borderColor: '#334155',
|
||
},
|
||
modalButtons: {
|
||
flexDirection: 'row',
|
||
gap: 12,
|
||
marginTop: 8,
|
||
},
|
||
modalButton: {
|
||
flex: 1,
|
||
paddingVertical: 14,
|
||
borderRadius: 12,
|
||
alignItems: 'center',
|
||
},
|
||
cancelButton: {
|
||
backgroundColor: '#334155',
|
||
},
|
||
saveButton: {
|
||
backgroundColor: '#3b82f6',
|
||
},
|
||
cancelButtonText: {
|
||
fontSize: 16,
|
||
fontWeight: '600' as const,
|
||
color: '#f8fafc',
|
||
},
|
||
saveButtonText: {
|
||
fontSize: 16,
|
||
fontWeight: '600' as const,
|
||
color: '#ffffff',
|
||
},
|
||
});
|