233 lines
6.8 KiB
TypeScript
233 lines
6.8 KiB
TypeScript
import { useTheme } from '@/components/ThemeContext';
|
||
import { useMutation, useQueryClient } from '@tanstack/react-query';
|
||
import { useRouter } from 'expo-router';
|
||
import { ArrowLeft } from 'lucide-react-native';
|
||
import React, { useState } from 'react';
|
||
import { useTranslation } from 'react-i18next';
|
||
import {
|
||
ActivityIndicator,
|
||
Pressable,
|
||
ScrollView,
|
||
StyleSheet,
|
||
Switch,
|
||
Text,
|
||
TextInput,
|
||
ToastAndroid,
|
||
View,
|
||
} from 'react-native';
|
||
import { user_api } from '../lib/api';
|
||
|
||
type FormType = {
|
||
code: string;
|
||
referral_share: string;
|
||
description: string;
|
||
is_agent: boolean;
|
||
};
|
||
|
||
export default function CreateReferrals() {
|
||
const { isDark } = useTheme();
|
||
const { t } = useTranslation();
|
||
const router = useRouter();
|
||
const queryClient = useQueryClient();
|
||
const [form, setForm] = useState<FormType>({
|
||
code: '',
|
||
referral_share: '',
|
||
description: '',
|
||
is_agent: false,
|
||
});
|
||
|
||
const { mutate, isPending } = useMutation({
|
||
mutationFn: (body: {
|
||
code: string;
|
||
referral_share: number;
|
||
description: string;
|
||
is_agent: boolean;
|
||
}) => user_api.create_referral(body),
|
||
onSuccess: () => {
|
||
ToastAndroid.show(t('Referral yaratildi'), ToastAndroid.SHORT);
|
||
queryClient.refetchQueries({ queryKey: ['my_referrals'] });
|
||
router.back();
|
||
},
|
||
onError: () => {
|
||
ToastAndroid.show(t('Xatolik yuz berdi'), ToastAndroid.SHORT);
|
||
},
|
||
});
|
||
|
||
const [errors, setErrors] = useState<any>({});
|
||
|
||
const update = (key: keyof FormType, value: any) => setForm((p) => ({ ...p, [key]: value }));
|
||
|
||
const validate = () => {
|
||
const e: any = {};
|
||
|
||
if (!form.code || form.code.length !== 9)
|
||
e.code = 'Kod aynan 9 ta belgidan iborat bo‘lishi kerak';
|
||
if (!form.description || form.description.length < 5)
|
||
e.description = 'Tavsif kamida 5 ta belgidan iborat bo‘lishi kerak';
|
||
|
||
if (form.is_agent) {
|
||
if (!form.referral_share || Number(form.referral_share) <= 0)
|
||
e.referral_share = 'Agent uchun foiz majburiy';
|
||
}
|
||
|
||
setErrors(e);
|
||
return Object.keys(e).length === 0;
|
||
};
|
||
|
||
const handleSave = () => {
|
||
if (!validate()) return;
|
||
|
||
const payload = {
|
||
code: form.code,
|
||
referral_share: form.is_agent ? Number(form.referral_share) : 0,
|
||
description: form.description,
|
||
is_agent: form.is_agent,
|
||
};
|
||
|
||
mutate(payload);
|
||
};
|
||
|
||
return (
|
||
<View style={{ flex: 1, backgroundColor: isDark ? '#0f172a' : '#f8fafc' }}>
|
||
{/* HEADER */}
|
||
<View style={[styles.header, { backgroundColor: isDark ? '#0f172a' : '#fff' }]}>
|
||
<Pressable onPress={() => router.back()}>
|
||
<ArrowLeft color={isDark ? '#fff' : '#0f172a'} />
|
||
</Pressable>
|
||
|
||
<Text style={[styles.headerTitle, { color: isDark ? '#fff' : '#0f172a' }]}>
|
||
{t('Referral yaratish')}
|
||
</Text>
|
||
|
||
<Pressable onPress={handleSave}>
|
||
{isPending ? (
|
||
<ActivityIndicator size={'small'} />
|
||
) : (
|
||
<Text style={styles.save}>{t('Saqlash')}</Text>
|
||
)}
|
||
</Pressable>
|
||
</View>
|
||
|
||
<ScrollView contentContainerStyle={styles.container}>
|
||
{/* NOM */}
|
||
<Text style={[styles.label, { color: isDark ? '#fff' : '#0f172a' }]}>
|
||
{t('Referral nomi')}
|
||
</Text>
|
||
<View style={[styles.inputBox, theme(isDark)]}>
|
||
<TextInput
|
||
maxLength={9}
|
||
style={[styles.input, { color: isDark ? '#fff' : '#0f172a' }]}
|
||
placeholder="ABC123"
|
||
placeholderTextColor="#94a3b8"
|
||
value={form.code}
|
||
onChangeText={(v) => update('code', v)}
|
||
/>
|
||
</View>
|
||
{errors.code && <Text style={styles.error}>{t(errors.code)}</Text>}
|
||
|
||
{/* TAVSIF */}
|
||
<Text style={[styles.label, { color: isDark ? '#fff' : '#0f172a' }]}>{t('Tavsif')}</Text>
|
||
<View style={[styles.inputBox, styles.textArea, theme(isDark)]}>
|
||
<TextInput
|
||
multiline
|
||
textAlignVertical="top"
|
||
style={[styles.input, { color: isDark ? '#fff' : '#0f172a' }]}
|
||
placeholder={t('Batafsil yozing...')}
|
||
placeholderTextColor="#94a3b8"
|
||
value={form.description}
|
||
onChangeText={(v) => update('description', v)}
|
||
/>
|
||
</View>
|
||
{errors.description && <Text style={styles.error}>{t(errors.description)}</Text>}
|
||
|
||
{/* AGENT SWITCH */}
|
||
<View style={styles.switchRow}>
|
||
<Text style={[styles.label, { color: isDark ? '#fff' : '#0f172a' }]}>
|
||
{t('Agentmi?')}
|
||
</Text>
|
||
<Switch
|
||
value={form.is_agent}
|
||
onValueChange={(v) => {
|
||
update('is_agent', v);
|
||
if (!v) update('referral_share', '');
|
||
}}
|
||
/>
|
||
</View>
|
||
|
||
{/* 👉 FOIZ FAQAT AGENT YOQILGANDA */}
|
||
{form.is_agent && (
|
||
<>
|
||
<Text style={[styles.label, { color: isDark ? '#fff' : '#0f172a' }]}>
|
||
{t('Referral foizi (%)')}
|
||
</Text>
|
||
<View style={[styles.inputBox, theme(isDark)]}>
|
||
<TextInput
|
||
maxLength={1}
|
||
keyboardType="numeric"
|
||
style={[styles.input, { color: isDark ? '#fff' : '#0f172a' }]}
|
||
placeholder="5"
|
||
placeholderTextColor="#94a3b8"
|
||
value={form.referral_share}
|
||
onChangeText={(v) => {
|
||
// faqat 1–5 oralig‘ini qabul qiladi
|
||
if (v === '') {
|
||
update('referral_share', '');
|
||
return;
|
||
}
|
||
|
||
const num = Number(v);
|
||
if (num >= 1 && num <= 5) {
|
||
update('referral_share', v);
|
||
}
|
||
}}
|
||
/>
|
||
</View>
|
||
{errors.referral_share && <Text style={styles.error}>{t(errors.referral_share)}</Text>}
|
||
</>
|
||
)}
|
||
</ScrollView>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
const theme = (isDark: boolean) => ({
|
||
backgroundColor: isDark ? '#1e293b' : '#fff',
|
||
borderColor: isDark ? '#334155' : '#e2e8f0',
|
||
});
|
||
|
||
const styles = StyleSheet.create({
|
||
header: {
|
||
padding: 16,
|
||
flexDirection: 'row',
|
||
alignItems: 'center',
|
||
justifyContent: 'space-between',
|
||
elevation: 3,
|
||
},
|
||
headerTitle: { fontSize: 18, fontWeight: '700' },
|
||
save: { color: '#3b82f6', fontSize: 16, fontWeight: '600' },
|
||
|
||
container: { padding: 16, gap: 10 },
|
||
label: { fontSize: 15, fontWeight: '700' },
|
||
error: { color: '#ef4444', fontSize: 13, marginLeft: 6 },
|
||
|
||
inputBox: {
|
||
flexDirection: 'row',
|
||
borderRadius: 16,
|
||
borderWidth: 1,
|
||
paddingHorizontal: 6,
|
||
height: 56,
|
||
},
|
||
textArea: { height: 120, alignItems: 'flex-start' },
|
||
input: {
|
||
flex: 1,
|
||
fontSize: 16,
|
||
},
|
||
|
||
switchRow: {
|
||
flexDirection: 'row',
|
||
justifyContent: 'space-between',
|
||
alignItems: 'center',
|
||
marginTop: 10,
|
||
},
|
||
});
|