itzpradip / react-native-firebase-social-app

393 stars 253 forks source link

Returning null when using iPhone device #6

Open nonoumasy opened 3 years ago

nonoumasy commented 3 years ago

I used the code in the AddPostScreen.js. Everything works in the simulator. An image gets uploaded successfully in Firebase storage. However, when I use my iPhone 8 device, it will work up to the part where I select the photo, it will display the photo selected, it will submit, show the success alert but after that it's returning null and it does NOT upload to Firebase Storage.

My Firebase security rules is not strict and allows writes if request.auth.uid != null;

import {
  ActivityIndicator,
  Alert,
  Image,
  KeyboardAvoidingView,
  Platform,
  SafeAreaView,
  StyleSheet,
  Text,
  View,
} from 'react-native';
import { Controller, useForm } from 'react-hook-form';
import React, { useState } from 'react';

import { Button } from 'react-native-elements';
import FormButton from '../components/FormButton';
import FormInput from '../components/FormInput';
import ImagePicker from 'react-native-image-crop-picker';
// import ImagePicker from 'react-native-image-picker';
import { ScrollView } from 'react-native-gesture-handler';
import { addEntry } from '../lib/api';
import storage from '@react-native-firebase/storage';

export default function AddEntryScreen({ navigation, route }) {
  const { control, handleSubmit, errors, reset } = useForm();
  const [image, setImage] = useState(null);
  const [uploading, setUploading] = useState(false);
  const [transferred, setTransferred] = useState(0);

  const { id } = route.params;

  const onSubmit = async (data) => {
    try {
      const imageUrl = await uploadImage();
      console.log('Image Url: ', imageUrl);
      await addEntry({ id, data, imageUrl });
      Alert.alert(
        'Post published!',
        'Your post has been published Successfully!',
      );
      setImage(null);
    } catch (error) {
      console.warn(error);
    }
    reset();
    navigation.goBack();
  };

  const onPress = () => {
    reset();
    navigation.goBack();
  };

  const choosePhotoFromLibrary = () => {
    ImagePicker.openPicker({
      width: 1200,
      height: 780,
      cropping: true,
    }).then((image) => {
      console.log(image);
      const imageUri = Platform.OS === 'ios' ? image.sourceURL : image.path;
      setImage(imageUri);
    });
  };

  const uploadImage = async () => {
    if (image == null) {
      return null;
    }
    const uploadUri = image;
    let filename = uploadUri.substring(uploadUri.lastIndexOf('/') + 1);

    // Add timestamp to File Name
    const extension = filename.split('.').pop();
    const name = filename.split('.').slice(0, -1).join('.');
    filename = name + Date.now() + '.' + extension;

    setUploading(true);
    setTransferred(0);

    const storageRef = storage().ref(`photos/${filename}`);
    const task = storageRef.putFile(uploadUri);

    // Set transferred state
    task.on('state_changed', (taskSnapshot) => {
      console.log(
        `${taskSnapshot.bytesTransferred} transferred out of ${taskSnapshot.totalBytes}`,
      );

      setTransferred(
        Math.round(taskSnapshot.bytesTransferred / taskSnapshot.totalBytes) *
          100,
      );
    });

    try {
      await task;

      const url = await storageRef.getDownloadURL();

      setUploading(false);
      setImage(null);

      Alert.alert(
        'Image uploaded!',
        'Your image has been uploaded to the Firebase Cloud Storage Successfully!',
      );
      return url;
    } catch (e) {
      console.log(e);
      return null;
    }
  };

  return (
    <SafeAreaView>
      <KeyboardAvoidingView
        behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
        style={styles.container}>
        <ScrollView
          showsVerticalScrollIndicator={false}
          contentContainerStyle={{ width: '90%' }}>
          <Text>Add New Entry</Text>
          {image != null ? (
            <View>
              <Image
                source={{ uri: image }}
                resizeMode="cover"
                style={styles.image}
              />
            </View>
          ) : null}

          <Controller
            name="title"
            defaultValue={''}
            control={control}
            rules={{
              required: {
                value: true,
                message: 'Title is required',
              },
            }}
            render={({ onChange, value }) => (
              <>
                <FormInput
                  error={errors.title}
                  errorText={errors?.title?.message}
                  numberOfLines={1}
                  autoCapitalize={'sentences'}
                  placeholderText="Title"
                  onChangeText={(value) => onChange(value)}
                  value={value}
                />
                <Text style={{ color: '#ED5D5D' }}>
                  {errors.title && errors.title.message}
                </Text>
              </>
            )}
          />

          <Controller
            name="description"
            defaultValue={''}
            control={control}
            rules={{
              required: {
                value: true,
                message: 'description is required',
              },
              minLength: {
                value: 5,
                message:
                  'The minimum length for the description is 5 characters.',
              },
            }}
            render={({ onChange, value }) => (
              <>
                <FormInput
                  error={errors.description}
                  errorText={errors?.description?.message}
                  autoCapitalize={'sentences'}
                  multiline
                  numberOfLines={4}
                  style={styles.textArea}
                  placeholderText="Description"
                  onChangeText={(value) => onChange(value)}
                  value={value}
                />
                <Text style={{ color: '#ED5D5D' }}>
                  {errors.description && errors.description.message}
                </Text>
              </>
            )}
          />

          <Controller
            name="location"
            defaultValue={''}
            control={control}
            rules={{
              required: {
                value: true,
                message: 'Location is required',
              },
            }}
            render={({ onChange, value }) => (
              <>
                <FormInput
                  error={errors.location}
                  errorText={errors?.location?.message}
                  autoCapitalize={'words'}
                  placeholderText="Location"
                  onChangeText={(value) => onChange(value)}
                  value={value}
                />
                <Text style={{ color: '#ED5D5D' }}>
                  {errors.location && errors.location.message}
                </Text>
              </>
            )}
          />

          <FormButton
            onPress={choosePhotoFromLibrary}
            buttonTitle="Add Photo"
          />
          {uploading ? (
            <View style={{ justifyContent: 'center', alignItems: 'center' }}>
              <Text>{transferred} % Completed!</Text>
              <ActivityIndicator size="large" color="#333" />
            </View>
          ) : (
            <FormButton onPress={handleSubmit(onSubmit)} buttonTitle="Submit" />
          )}

          <View style={{ marginVertical: 10 }}>
            <Button
              title="Cancel"
              onPress={onPress}
              type="clear"
              titleStyle={{ color: '#26978A' }}
            />
          </View>
        </ScrollView>
      </KeyboardAvoidingView>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    justifyContent: 'center',
    alignItems: 'center',
  },
  header: {
    // flex: 1,
    flexDirection: 'row',
    marginTop: 20,
  },
  textArea: {
    height: 160,
    padding: 10,
    fontSize: 16,
    color: '#333',
    width: '100%',
  },
  image: {
    width: '100%',
    height: 240,
    borderRadius: 10,
    marginVertical: 10,
  },
});
nonoumasy commented 3 years ago

ok I figured out a solution. I used

const imageUri = Platform.OS === 'ios' ? image.path : image.path;

for both iOS as well and it worked. Hope it helps.