noirtempest's avatar

ERROR Failed to submit verification: [Error: Failed to submit verification: Request failed with status code 400]

hooks:

import AsyncStorage from "@react-native-async-storage/async-storage";
import axiosInstance, { getJWTHeader } from "../../../../../../utils/axiosConfig";
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { useNavigation } from "@react-navigation/native";

async function verifyUser(userToVerify) {
    try {
        console.log('Verify Data:', userToVerify);
        const userStr = await AsyncStorage.getItem("upcare_user");
        if (!userStr) {
            throw new Error("User not found");
        }
        const user = JSON.parse(userStr);

        const headers = getJWTHeader(user);
        const { data } = await axiosInstance.post("/user/profile/submit-verification", userToVerify, { headers });

        const updatedUser = { ...user, ...data.verificationData };
        await AsyncStorage.setItem('upcare_user', JSON.stringify(updatedUser));

        console.log('Stored User Data:', updatedUser); // Log the updated user data

        return data.user;
    } catch (error) {
        throw new Error("Failed to submit verification: " + error.message);
    }
}


export const useVerifyUser = () => {
    const queryClient = useQueryClient();
    const navigation = useNavigation();

    return useMutation(
        verifyUser,
        {
            onSuccess: (updatedUser) => {
                queryClient.setQueryData(['user'], updatedUser);
                navigation.goBack();
            },
            onError: (error) => {
                console.error("Failed to submit verification:", error);
            },
            onSettled: () => {
                queryClient.invalidateQueries(['user']);
            },
        }
    );
};

the handling of submission:

import * as React from 'react';
import { View, StyleSheet, Text, ScrollView, Image, TouchableOpacity, Alert } from 'react-native';
import { Button, Title, Appbar, TouchableRipple } from 'react-native-paper';
import * as ImagePicker from 'expo-image-picker';
import { useForm, Controller } from 'react-hook-form';
import { useNavigation } from '@react-navigation/native';
import { useVerifyUser } from './hooks/useVerifyUser';

const VerificationScreen = () => {
    const navigation = useNavigation();
    const { control, handleSubmit, setValue } = useForm({
        defaultValues: {
            verification: {
                id1FrontImage: '',
                id1BackImage: '',
                id2FrontImage: '',
                id2BackImage: '',
                id3FrontImage: '',
                id3BackImage: '',
            }
        }
    });
    const verifyUserMutation = useVerifyUser();

    const pickImage = async (imageType, idNumber) => {
        try {
            const result = await ImagePicker.launchImageLibraryAsync({
                mediaTypes: ImagePicker.MediaTypeOptions.Images,
                allowsEditing: true,
                aspect: [4, 3],
                quality: 1,
            });

            if (result && !result.canceled && result.assets && result.assets.length > 0) {
                const selectedImageUri = result.assets[0].uri;

                setValue(`verification.id${idNumber}${imageType.charAt(0).toUpperCase() + imageType.slice(1)}Image`, selectedImageUri);
            }
        } catch (error) {
            console.error('Image picker error:', error);
            Alert.alert('Error', 'Failed to pick image. Please try again.');
        }
    };


    const onSubmit = async (data) => {
        try {
            await verifyUserMutation.mutateAsync(data);
        } catch (error) {
            console.error('Failed to submit verification:', error);
            Alert.alert('Error', 'Failed to submit verification. Please try again.');
        }
    };

    return (
        <View style={{ flex: 1 }}>
            <Appbar.Header>
                <Appbar.BackAction onPress={() => navigation.goBack()} />
            </Appbar.Header>
            <ScrollView contentContainerStyle={styles.container}>
                {/* ID 1 */}
                <View>
                    <Title>ID 1</Title>
                    {/* ID 1 Front */}
                    <Controller
                        control={control}
                        render={({ field: { value } }) => (
                            <View style={styles.imageContainer}>
                                <TouchableRipple style={styles.imagePicker} onPress={() => pickImage('front', 1)}>
                                    {value ? (
                                        <Image source={{ uri: value }} style={styles.image} />
                                    ) : (
                                        <Text style={styles.text}>Tap to upload front image</Text>
                                    )}
                                </TouchableRipple>
                            </View>
                        )}
                        name="verification.id1FrontImage"
                    />
                    {/* ID 1 Back */}
                    <Controller
                        control={control}
                        render={({ field: { value } }) => (
                            <View style={styles.imageContainer}>
                                <TouchableRipple style={styles.imagePicker} onPress={() => pickImage('back', 1)}>
                                    {value ? (
                                        <Image source={{ uri: value }} style={styles.image} />
                                    ) : (
                                        <Text style={styles.text}>Tap to upload back image</Text>
                                    )}
                                </TouchableRipple>
                            </View>
                        )}
                        name="verification.id1BackImage"
                    />
                </View>

                {/* ID 2 */}
                <View>
                    <Title>ID 2</Title>
                    {/* ID 2 Front */}
                    <Controller
                        control={control}
                        render={({ field: { value } }) => (
                            <View style={styles.imageContainer}>
                                <TouchableRipple style={styles.imagePicker} onPress={() => pickImage('front', 2)}>
                                    {value ? (
                                        <Image source={{ uri: value }} style={styles.image} />
                                    ) : (
                                        <Text style={styles.text}>Tap to upload front image</Text>
                                    )}
                                </TouchableRipple>
                            </View>
                        )}
                        name="verification.id2FrontImage"
                    />
                    {/* ID 2 Back */}
                    <Controller
                        control={control}
                        render={({ field: { value } }) => (
                            <View style={styles.imageContainer}>
                                <TouchableRipple style={styles.imagePicker} onPress={() => pickImage('back', 2)}>
                                    {value ? (
                                        <Image source={{ uri: value }} style={styles.image} />
                                    ) : (
                                        <Text style={styles.text}>Tap to upload back image</Text>
                                    )}
                                </TouchableRipple>
                            </View>
                        )}
                        name="verification.id2BackImage"
                    />
                </View>

                {/* ID 3 */}
                <View>
                    <Title>ID 3</Title>
                    {/* ID 3 Front */}
                    <Controller
                        control={control}
                        render={({ field: { value } }) => (
                            <View style={styles.imageContainer}>
                                <TouchableRipple style={styles.imagePicker} onPress={() => pickImage('front', 3)}>
                                    {value ? (
                                        <Image source={{ uri: value }} style={styles.image} />
                                    ) : (
                                        <Text style={styles.text}>Tap to upload front image</Text>
                                    )}
                                </TouchableRipple>
                            </View>
                        )}
                        name="verification.id3FrontImage"
                    />
                    {/* ID 3 Back */}
                    <Controller
                        control={control}
                        render={({ field: { value } }) => (
                            <View style={styles.imageContainer}>
                                <TouchableRipple style={styles.imagePicker} onPress={() => pickImage('back', 3)}>
                                    {value ? (
                                        <Image source={{ uri: value }} style={styles.image} />
                                    ) : (
                                        <Text style={styles.text}>Tap to upload back image</Text>
                                    )}
                                </TouchableRipple>
                            </View>
                        )}
                        name="verification.id3BackImage"
                    />
                </View>

                <Button mode="outlined" onPress={handleSubmit(onSubmit)}>Submit</Button>
            </ScrollView>
        </View>
    );
};

const styles = StyleSheet.create({
    container: {
        padding: 16,
        backgroundColor: "#F4F7FB",
    },
    imageContainer: {
        marginVertical: 8,
    },
    imagePicker: {
        backgroundColor: "#0A3480",
        alignItems: 'center',
        justifyContent: 'center',
        height: 150,
        borderRadius: 14,
    },
    image: {
        width: '100%',
        height: '100%',
        resizeMode: 'cover',
        borderRadius: 14,
    },
    text: { color: 'white' }
});

export default VerificationScreen;

backend:

    public function submitVerification(Request $request)
    {
        $user = auth()->user();

        $validate = $this->validateRequest($request, $user->role);

        if ($validate->fails()) {
            return response()->json(['error' => $validate->errors()], 400);
        }

        $verificationData = $this->getOrCreateVerificationData($user, $request);

        if ($request->has('verification') && !empty($request->verification)) {
            $this->handleFileAttachments($verificationData, $request->verification, $user->id);
        }

        $verificationData->status = $request->has('checkStatus') ? 'pending' : 'to be reviewed';
        $verificationData->save();

        // Get attached images
        $attachedImages = $verificationData->getMedia('verification_' . $user->id)->map(function ($media) {
            return $media->file_name;
        });

        $responseData = [
            'message' => 'Verification submitted successfully.',
            'type' => 'success',
            'verificationData' => $verificationData,
            'attachedImages' => $attachedImages,
        ];

        return response()->json($responseData, 200);
    }

    private function validateRequest(Request $request, $role)
    {
        $rules = ['verification.*' => ['required', 'image']];
        if ($role === 'user') {
            $rules = array_merge($rules, [
                'verification' => ['array', 'min:2', 'required'],
                'checkStatus' => 'nullable',
                'verificationID' => 'nullable',
            ]);
        } else {
            $rules = array_merge($rules, [
                'link' => 'nullable',
                'checkStatus' => 'nullable',
                'verificationID' => 'nullable',
            ]);
        }

        return Validator::make($request->all(), $rules);
    }

    private function getOrCreateVerificationData($user, Request $request)
    {
        if ($request->filled('verificationID')) {
            $verificationData = UserVerification::find($request->verificationID);
            $verificationData->clearMediaCollection('verification_' . $user->id);
        } else {
            $verificationData = new UserVerification(['user_id' => $user->id]);
            if ($user->role !== 'user') {
                $verificationData->link = $request->link;
            }
            $verificationData->save();
        }
        return $verificationData;
    }

    private function handleFileAttachments($verificationData, $files, $userId)
    {
        foreach ($files as $index => $data) {
            $verificationData->attachUserID($data, $index, $userId);
        }
    }

tho the back end is functioning well Im having problem in sending data to the serve from client to server side what might be the problem help please

0 likes
0 replies

Please or to participate in this conversation.