fitst commit
This commit is contained in:
219
screens/profile/ui/AddEmployee.tsx
Normal file
219
screens/profile/ui/AddEmployee.tsx
Normal file
@@ -0,0 +1,219 @@
|
||||
import { useTheme } from '@/components/ThemeContext';
|
||||
import { formatPhone, normalizeDigits } from '@/constants/formatPhone';
|
||||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { AxiosError } from 'axios';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { ArrowLeft } from 'lucide-react-native';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
Alert,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TextInput,
|
||||
ToastAndroid,
|
||||
View,
|
||||
} from 'react-native';
|
||||
import { SafeAreaView } from 'react-native-safe-area-context';
|
||||
import { user_api } from '../lib/api';
|
||||
|
||||
export default function AddEmployee() {
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
const { isDark } = useTheme();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const theme = {
|
||||
background: isDark ? '#0f172a' : '#f8fafc',
|
||||
inputBg: isDark ? '#1e293b' : '#f1f5f9',
|
||||
inputBorder: isDark ? '#1e293b' : '#e2e8f0',
|
||||
text: isDark ? '#f8fafc' : '#0f172a',
|
||||
textSecondary: isDark ? '#64748b' : '#94a3b8',
|
||||
primary: '#3b82f6',
|
||||
placeholder: isDark ? '#94a3b8' : '#94a3b8',
|
||||
divider: isDark ? '#fff' : '#cbd5e1',
|
||||
};
|
||||
|
||||
const [firstName, setFirstName] = useState('');
|
||||
const [lastName, setLastName] = useState('');
|
||||
const [phoneNumber, setPhoneNumber] = useState('');
|
||||
const [focused, setFocused] = useState(false);
|
||||
|
||||
const { mutate, isPending } = useMutation({
|
||||
mutationFn: (body: { first_name: string; last_name: string; phone: string }) =>
|
||||
user_api.create_employee(body),
|
||||
onSuccess: () => {
|
||||
router.push('/profile/employees');
|
||||
queryClient.refetchQueries({ queryKey: ['employees-list'] });
|
||||
},
|
||||
onError: (err: AxiosError) => {
|
||||
const errMessage = (err.response?.data as { data: { phone: string[] } }).data.phone[0];
|
||||
Alert.alert(t('Xatolik yuz berdi'), errMessage || t('Xatolik yuz berdi'));
|
||||
},
|
||||
});
|
||||
|
||||
const handleChange = (text: string) => {
|
||||
setPhoneNumber(normalizeDigits(text));
|
||||
};
|
||||
|
||||
const handleSave = () => {
|
||||
if (!firstName.trim() || !lastName.trim() || !phoneNumber.trim()) {
|
||||
ToastAndroid.show(t("Barcha maydonlarni to'ldiring"), ToastAndroid.SHORT);
|
||||
return;
|
||||
}
|
||||
|
||||
mutate({
|
||||
first_name: firstName.trim(),
|
||||
last_name: lastName.trim(),
|
||||
phone: phoneNumber.trim(),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<SafeAreaView style={[styles.container, { backgroundColor: theme.background }]}>
|
||||
<View style={styles.topHeader}>
|
||||
<Pressable onPress={() => router.push('/profile/employees')}>
|
||||
<ArrowLeft color={theme.text} />
|
||||
</Pressable>
|
||||
<Text style={[styles.headerTitle, { color: theme.text }]}>{t("Yangi xodim qo'shish")}</Text>
|
||||
<Pressable onPress={handleSave} disabled={isPending}>
|
||||
{isPending ? (
|
||||
<ActivityIndicator size={'small'} />
|
||||
) : (
|
||||
<Text style={[styles.saveButton, { color: theme.primary }]}>{t('Saqlash')}</Text>
|
||||
)}
|
||||
</Pressable>
|
||||
</View>
|
||||
|
||||
<ScrollView style={styles.content} showsVerticalScrollIndicator={false}>
|
||||
<View style={styles.form}>
|
||||
<View style={styles.field}>
|
||||
<Text style={[styles.label, { color: theme.textSecondary }]}>{t('Ism')}</Text>
|
||||
<TextInput
|
||||
style={[styles.input, { backgroundColor: theme.inputBg, color: theme.text }]}
|
||||
value={firstName}
|
||||
onChangeText={setFirstName}
|
||||
placeholder={t('Ism kiriting')}
|
||||
placeholderTextColor={theme.placeholder}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View style={styles.field}>
|
||||
<Text style={[styles.label, { color: theme.textSecondary }]}>{t('Familiya')}</Text>
|
||||
<TextInput
|
||||
style={[styles.input, { backgroundColor: theme.inputBg, color: theme.text }]}
|
||||
value={lastName}
|
||||
onChangeText={setLastName}
|
||||
placeholder={t('Familiya kiriting')}
|
||||
placeholderTextColor={theme.placeholder}
|
||||
/>
|
||||
</View>
|
||||
|
||||
<View
|
||||
style={[
|
||||
styles.inputContainer,
|
||||
{ backgroundColor: theme.inputBg, borderColor: theme.inputBorder },
|
||||
focused && styles.inputFocused,
|
||||
]}
|
||||
>
|
||||
<View style={styles.prefixContainer}>
|
||||
<Text style={[styles.prefix, { color: theme.text }, focused && styles.prefixFocused]}>
|
||||
+998
|
||||
</Text>
|
||||
<View style={[styles.divider, { backgroundColor: theme.divider }]} />
|
||||
</View>
|
||||
|
||||
<TextInput
|
||||
value={formatPhone(phoneNumber)}
|
||||
onChangeText={handleChange}
|
||||
onFocus={() => setFocused(true)}
|
||||
onBlur={() => setFocused(false)}
|
||||
keyboardType="phone-pad"
|
||||
placeholder="90 123 45 67"
|
||||
placeholderTextColor={theme.placeholder}
|
||||
style={[styles.input, { color: theme.text }]}
|
||||
maxLength={12}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
},
|
||||
saveButton: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
paddingHorizontal: 8,
|
||||
},
|
||||
form: {
|
||||
padding: 16,
|
||||
gap: 20,
|
||||
},
|
||||
field: {
|
||||
gap: 12,
|
||||
},
|
||||
label: {
|
||||
fontSize: 13,
|
||||
fontWeight: '600',
|
||||
textTransform: 'uppercase',
|
||||
letterSpacing: 0.5,
|
||||
},
|
||||
input: {
|
||||
borderRadius: 16,
|
||||
padding: 16,
|
||||
fontSize: 17,
|
||||
fontWeight: '600',
|
||||
},
|
||||
inputContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
borderRadius: 14,
|
||||
borderWidth: 2,
|
||||
paddingHorizontal: 16,
|
||||
height: 56,
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 2 },
|
||||
shadowOpacity: 0.05,
|
||||
shadowRadius: 8,
|
||||
elevation: 2,
|
||||
},
|
||||
inputFocused: {
|
||||
shadowOpacity: 0.15,
|
||||
shadowRadius: 12,
|
||||
elevation: 4,
|
||||
},
|
||||
prefixContainer: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginRight: 12,
|
||||
},
|
||||
prefix: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
letterSpacing: 0.3,
|
||||
},
|
||||
prefixFocused: {},
|
||||
divider: {
|
||||
width: 1.5,
|
||||
height: 24,
|
||||
marginLeft: 12,
|
||||
},
|
||||
topHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
padding: 16,
|
||||
alignItems: 'center',
|
||||
},
|
||||
headerTitle: { fontSize: 18, fontWeight: '700' },
|
||||
});
|
||||
Reference in New Issue
Block a user