0

The problem

I've been struggling with this problem for a few weeks now and have no idea how to solve it. I am originally a Python coder, but I am learning TypeScript and React-Native through this project with Supabase as the backend. One of my tabs allows users to upload multiple images as part of a tutorial builder page. These images are then uploaded one at a time to the storage bucket.

There is no issue with uploads on the Android emulator version. Each image is subsequently uploaded along with the other information in the form to their different relational tables and correct storage bucket.

However, the iOS version always fails on the first submission attempt due to a TypeError: Network request failed. usually due to the final image in the tutorial section. Resubmission attempts with the same data and images succeed but once a successful submission occurs the cycle repeats itself. Additionally, using the built-in iOS gallery images always results in an error regardless of resubmission.

I have a feeling the error is due to issues with the size of the images being uploaded, but, I don't understand why this would be happening given the limit on the bucket is 50MB and the images are only 1-2MB at a time but most are only 10s kB. This paired with the fact the submission works on resubmit and always works on android has me really stumped.

Fixes I've tried

  1. Setting delays to delay image uploads using setTimeout(resolve, 1000).
  2. Converted the upload to use arrayBuffer from the base64 file data.
  3. Tried uploading blob objects instead.
  4. Tested every combination of image sizes and number of images.
  5. Checked if there's a rate limit set on the bucket.
  6. Changed all of the permissions on the bucket to allow any access type.

The error

Here's the error I receive when the submission fails.

 ERROR  Upload failed: Network request failed TypeError: Network request failed
    at anonymous (http://localhost:8081/index.bundle//&platform=ios&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=org.reactjs.native.example.CosmiCosDev:5044:33)
    at apply (native)
    at anonymous (http://localhost:8081/index.bundle//&platform=ios&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=org.reactjs.native.example.CosmiCosDev:37722:26)
    at _callTimer (http://localhost:8081/index.bundle//&platform=ios&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=org.reactjs.native.example.CosmiCosDev:37661:17)
    at callTimers (http://localhost:8081/index.bundle//&platform=ios&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=org.reactjs.native.example.CosmiCosDev:37817:19)
    at apply (native)
    at __callFunction (http://localhost:8081/index.bundle//&platform=ios&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=org.reactjs.native.example.CosmiCosDev:2688:38)
    at anonymous (http://localhost:8081/index.bundle//&platform=ios&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=org.reactjs.native.example.CosmiCosDev:2444:31)
    at __guard (http://localhost:8081/index.bundle//&platform=ios&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=org.reactjs.native.example.CosmiCosDev:2634:15)
    at callFunctionReturnFlushedQueue (http://localhost:8081/index.bundle//&platform=ios&dev=true&lazy=true&minify=false&inlineSourceMap=false&modulesOnly=false&runModule=true&app=org.reactjs.native.example.CosmiCosDev:2443:21)
 ERROR  Error creating post:  [TypeError: Network request failed]

Code

Imports

import React, {useState, useEffect} from 'react';
import {View, Text, Button, StyleSheet, Image, Modal, Alert, SafeAreaView, Pressable, TouchableWithoutFeedback, Keyboard, TouchableOpacity, ScrollView,
} from 'react-native';
import {launchImageLibrary} from 'react-native-image-picker';
import {supabase} from '../config/supabase';
import uuid from 'react-native-uuid';
import { decode } from "base64-arraybuffer";

Image picker

const handleImagePicker = () => {
    const options = {
      mediaType: 'photo',
      includeBase64: true,
      quality: 1,
    };

    launchImageLibrary(options, (response) => {
      if (response.didCancel) {
        console.log('User cancelled image picker');
      } else if (response.error) {
        console.log('ImagePicker Error: ', response.error);
      } else if (response.assets) {
        const selectedImage = response.assets[0];
        setCoverImage({
          uri: selectedImage.uri,
          fileName: selectedImage.fileName,
          type: selectedImage.type,
          base64: selectedImage.base64,
        });
        setImageUri(selectedImage.uri);
      }
    });
  };

Image upload function (called by submission function)

const uploadToBucket = async (bucket: string, userID: string, contentID: string, image: any, order_position: number) => {
  try {
    const imagePath = `${userID}/${contentID}/${order_position}`;
    
    console.log('Uploading to:', imagePath);
    console.log('The image', image.uri)

    const { data, error } = await supabase.storage
      .from(bucket)
      .upload(imagePath, decode(image.base64), {
        upsert: true,
        contentType: "image/*",
    }
    );

    if (error) {
      console.error('Upload error:', error);
      throw error;
    }

    console.log('File uploaded successfully:', data);
    return data;
  } catch (err) {
    console.error('Upload failed:', err.message, err.stack);
    throw err;
  }
};

Submission function

useEffect(() => {
    const fetchUser = async () => {
      const { data: { user }, error } = await supabase.auth.getUser();
      if (error || !user) {
        console.error('Error fetching user:', error);
        Alert.alert('Error', 'User not authenticated.');
        return;
      }
      setUser(user);
    };

    fetchUser();
  }, []);

const submitPostData = async () => {
    if (!user) {
      Alert.alert("Error", "User not authenticated.");
      return;
    }
    if (!coverImage) {
      Alert.alert("Error", "Please select a cover image.");
      return;
    }
  
    try {
      const buildId = uuid.v4();
      const userUid = user.id;
      await uploadToBucket("build_content", userUid, buildId, coverImage, 0);
      // Prepare build data
      const buildData = {
        uid: buildId,
        user_uid: userUid,
        title: "Test name",
        est_price: 500,
        difficulty: 4,
        time: 25,
      };
  
      // Save post metadata to Supabase
      const { error: buildInsertError } = await supabase
        .from("builds")
        .insert(buildData);
  
      if (buildInsertError) {
        throw buildInsertError;
      }
  
      let guideSections = [];
  
      for (const tutorial of tutorials) {
        let newSection = {
          build_uid: buildId,
          content_type: 2,
          order_pos: tutorial.order_pos, // Incrementally increases for each tutorial section
          mainContent: "",
          secondaryContent: "",
        };
  
        switch (tutorial.tutType) {
          case 2:
            newSection.mainContent = tutorial.tutImgText
            await uploadToBucket(
              "build_content",
              userUid,
              buildId,
              tutorial.tutImage,
              tutorial.order_pos
            );
            break;
        }
  
        guideSections.push(newSection);
      }
  
      const { error: tutInsertError } = await supabase
        .from("guide_section")
        .insert(guideSections);
      if (tutInsertError) {
        throw tutInsertError;
      }
  
      Alert.alert("Success", "Post created successfully!");
      navigation.navigate("Builder");
    } catch (error) {
      console.error("Error creating post: ", error);
      Alert.alert("Error", "There was a problem creating your post.");
    }
  };

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.