Files
info-target-mobile/screens/profile/ui/AddService.tsx
Samandar Turgunboyev d747c72c8d complated
2026-02-17 10:46:57 +05:00

197 lines
5.4 KiB
TypeScript

import { useTheme } from '@/components/ThemeContext';
import StepTwo from '@/screens/create-ads/ui/StepTwo';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { useRouter } from 'expo-router';
import { ArrowLeft } from 'lucide-react-native';
import { useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';
import {
ActivityIndicator,
Alert,
Pressable,
ScrollView,
StyleSheet,
Text,
View,
} from 'react-native';
import { user_api } from '../lib/api';
import StepOneServices from './StepOneService';
type MediaFile = {
uri: string;
type: string;
name: string;
};
interface formDataType {
title: string;
description: string;
media: MediaFile[];
category: any[];
}
const getMimeType = (uri: string) => {
const ext = uri.split('.').pop()?.toLowerCase();
switch (ext) {
case 'jpg':
case 'jpeg':
return 'image/jpeg';
case 'png':
return 'image/png';
case 'webp':
return 'image/webp';
case 'heic':
return 'image/heic';
default:
return 'application/octet-stream';
}
};
export default function AddService() {
const router = useRouter();
const queryClient = useQueryClient();
const { isDark } = useTheme();
const { t } = useTranslation();
const [step, setStep] = useState(1);
const stepOneRef = useRef<any>(null);
const stepTwoRef = useRef<any>(null);
const [formData, setFormData] = useState<formDataType>({
title: '',
description: '',
media: [],
category: [],
});
const { mutate, isPending } = useMutation({
mutationFn: (body: FormData) => user_api.add_service(body),
onSuccess: () => {
queryClient.refetchQueries({ queryKey: ['my_services'] });
router.back();
},
onError: (err: any) => {
if (err?.response?.data?.data?.description[0]) {
Alert.alert(t('Xatolik yuz berdi'), err?.response?.data?.data?.description[0]);
} else if (err?.response?.data?.data?.files[0]) {
Alert.alert(t('Xatolik yuz berdi'), err?.response?.data?.data?.title[0]);
} else if (err?.response?.data?.data?.title[0]) {
Alert.alert(t('Xatolik yuz berdi'), err?.response?.data?.data?.title[0]);
} else {
Alert.alert(t('Xatolik yuz berdi'), err?.message);
}
},
});
const updateForm = (key: string, value: any) =>
setFormData((prev: any) => ({ ...prev, [key]: value }));
const handleNext = () => {
if (step === 1) {
const valid = stepOneRef.current?.validate();
if (!valid) return;
setStep(2);
}
};
const handleBack = () => {
if (step === 2) setStep(1);
else router.back();
};
const handleSave = () => {
const valid = stepTwoRef.current?.validate();
if (!valid) return;
const form = new FormData();
form.append('title', formData.title);
form.append('description', formData.description);
formData.media.forEach((file) => {
form.append(`files`, {
uri: file.uri,
type: getMimeType(file.uri),
name: file.uri.split('/').pop(),
} as any);
});
formData.category.forEach((e) => {
form.append(`category`, e.id);
});
mutate(form);
};
const removeMedia = (i: number) =>
updateForm(
'media',
formData.media.filter((_: any, idx: number) => idx !== i)
);
return (
<View style={{ flex: 1, backgroundColor: isDark ? '#0f172a' : '#f8fafc' }}>
<View style={[styles.header, { backgroundColor: isDark ? '#0f172a' : '#ffffff' }]}>
<View
style={{ flexDirection: 'row', gap: 10, alignContent: 'center', alignItems: 'center' }}
>
<Pressable onPress={handleBack}>
<ArrowLeft color={isDark ? '#fff' : '#0f172a'} />
</Pressable>
<Text style={[styles.headerTitle, { color: isDark ? '#fff' : '#0f172a' }]}>
{step === 1 ? t('Yangi xizmat (1/2)') : t('Yangi xizmat (2/2)')}
</Text>
</View>
{step === 2 ? (
<Pressable
onPress={handleSave}
style={({ pressed }) => [
{
opacity: pressed || isPending ? 0.6 : 1,
flexDirection: 'row',
alignItems: 'center',
gap: 8,
},
]}
disabled={isPending}
>
{isPending ? (
<ActivityIndicator size={'small'} />
) : (
<Text style={styles.saveButton}>{t('Saqlash')}</Text>
)}
</Pressable>
) : (
<Pressable onPress={handleNext}>
<Text style={styles.saveButton}>{t('Keyingi')}</Text>
</Pressable>
)}
</View>
<ScrollView contentContainerStyle={styles.container}>
{step === 1 && (
<StepOneServices
ref={stepOneRef}
formData={formData}
updateForm={updateForm}
removeMedia={removeMedia}
/>
)}
{step === 2 && <StepTwo ref={stepTwoRef} formData={formData} updateForm={updateForm} />}
</ScrollView>
</View>
);
}
const styles = StyleSheet.create({
header: {
flexDirection: 'row',
justifyContent: 'space-between',
padding: 16,
alignItems: 'center',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
elevation: 3,
},
headerTitle: { fontSize: 18, fontWeight: '700' },
saveButton: { color: '#3b82f6', fontSize: 16, fontWeight: '600' },
container: { padding: 16, paddingBottom: 10 },
});