Convert uri to file react native js - reactjs

Above is the request that I am trying to make in react native.
But I have URI
How shall I convert this to a file while sending to backend(PHP) server
This's my data to be sent in body:
const profileImageToBeSentToUpdate = {
data: {
id: authContext.user.id,
token: authContext.user.oauth_token.access_token,
profile_image: source.uri //Need help here, need to convert uri to file in order to send to php
},
type: 'POST',
url: 'update_profile_image',
success: profileImageUpdateSuccess,
error: profileImageUpdateError
};
authContext.setLoader();
console.log('***********profile data binded: ', profileImageToBeSentToUpdate);
NetworkAdaptation.postData(profileImageToBeSentToUpdate);
Now, backend (PHP) wants file format, I have URI format in react

React and React Native have no idea about what file system is. So they cannot make a file.
A workaround could be download a new file by using this code:
downloadprofileImageFile = () => {
const element = document.createElement("a");
const file = new Blob([source.uri], {type: 'text/plain'});
element.href = URL.createObjectURL(file);
element.download = "profile_image.txt";
document.body.appendChild(element);
element.click();
}
Then, pass the file to your profileImageToBeSentToUpdate function.

use rn-fetch-blob
import { Platform } from 'react-native';
const postImage = (localImageUri, remoteUrl) =>
RNFetchBlob.fetch(
'POST',
remoteUrl,
{ 'Content-Type': 'multipart/form-data' },
[
{
name: 'myimage',
filename: 'myimage',
type: 'image/jpeg',
data: RNFetchBlob.wrap(Platform.OS === 'ios' ? localImageUri.replace('file://', '') : localImageUri),
},
],
).then(response => {
// do something
}).catch(error => {
// do something
});

I used image picker and from imageResponse during showImagePicker method got the following details and used it in data to send
profile_image: { uri: imageResponse.uri, name: imageResponse.fileName, type: imageResponse.type }

Related

React-native - Upload image from Camera to Apollo-Server using Apollo-client

I am capturing image from my camera and I am saving it in variable:
const [image,setImage] = useState(null)
.................
let photo = await cameraRef.takePictureAsync();
setImage(photo);
This sets image file like and it looks-like:
file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540borislavvr%252Fnative-voe/Camera/78b65450-378e-4e8f-85f5-3bfe38e9f8bd.jpg
As this is stored in my image constant I am trying now to send this image to my Apollo Server.
I have my fileType.ts:
const { gql } = require("apollo-server-express");
const otherType = gql`
scalar Upload
type File {
url: String
}
`;
export default otherType;
So this image which I am going to upload is part of type called Case.
When I am creating case it looks-like:
extend type Mutation {
createCase(input: CreateCase!, attachments: Upload): Case
}
In my React-Native App I perform this mutation like this:
const SEND_CASE = gql`
mutation CreateCase($input: CreateCase!, $attachments: Upload) {
createCase(input: $input, attachments: $attachments) {
_id
}
}
`;
..............
const [
createCase,
{ data: caseData, loading: caseLoading, error: caseError },
] = useMutation(SEND_CASE);
..........
const data = new FormData();
data.append("file", {
name: "problem.jpg",
uri: image,
type: "image.jpg",
});
createCase({
variables: {
input: {
description: description,
date: new Date().toDateString(),
priority: isChecked,
userId: userData.getSingleUserByUsername[0]._id,
categoryId: categories,
},
attachments: data,
},
});
}}
I know I am passing probably the file wrong but what I console log in my back-end is:
Mutation: {
createCase: async (
parentValue: any,
{ input, attachments }: { input: CaseInterface; attachments: any },
context: any
) => {
console.log(attachments);
},
},
which is giving me:
{ _parts: [ [ 'file', [Object] ] ] }
and if I console.log(attachments._parts):
[
[
'file',
{
name: 'problem.jpg',
uri: 'file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540borislavvr%252Fnative-voe/Camera/2c87803d-ba3f-43cc-b674-22dfafe04d58.jpg',
type: 'image.jpg'
}
]
]
So my question is "Is it possible to upload this data and visualize image"? When I do the same with React and use input button to upload file I am able to have:
const { createReadStream, filename, mimetype, endcoding } = await args
.file
from file so I have this createReadStream. How can I do the same for picture taken from react-native camera?

Pass data from React to Sails and return value

In my React app I have three fields:
firstNumber = accept any number >0
secondNumber = accept any number >0
operator = accept +,-,*,% as a string
I want to send it as a POST request to Sails so it can make the calculation. For example: 2+3 returns 5. Then I would show the return value in React.
I have written the React part and I believe it is right.
handleClick = (event) => {
event.preventDefault()
const inputField = {
firstNumber: this.state.firstNumber,
operator: this.state.operator,
secondNumber: this.state.secondNumber}
const request = {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ inputField })
};
fetch('http://localhost:1337/teste', request)
.then(response => response.json())
.then(data => this.setState({ total: data.valor}));
}
In Sails I have created a controller to handle this. But I can't find a way to import the inputField and use the data of fistNumber, secondNumber, and operator in a function.
What are the necessary steps to do in Sails.js?
In Sails, you might use Action2 controllers in your api/controllers folder.
module.exports = {
friendlyName: 'Welcome user',
description: 'Look up the specified user and welcome them, or redirect to a signup page if no user was found.',
inputs: {
userId: {
description: 'The ID of the user to look up.',
// By declaring a numeric example, Sails will automatically respond with `res.badRequest`
// if the `userId` parameter is not a number.
type: 'number',
// By making the `userId` parameter required, Sails will automatically respond with
// `res.badRequest` if it's left out.
required: true
}
},
exits: {
success: {
responseType: 'view',
viewTemplatePath: 'pages/welcome'
},
notFound: {
description: 'No user with the specified ID was found in the database.',
responseType: 'notFound'
}
},
fn: async function ({userId}) {
// Look up the user whose ID was specified in the request.
// Note that we don't have to validate that `userId` is a number;
// the machine runner does this for us and returns `badRequest`
// if validation fails.
var user = await User.findOne({ id: userId });
// If no user was found, respond "notFound" (like calling `res.notFound()`)
if (!user) { throw 'notFound'; }
// Display a personalized welcome view.
return {
name: user.name
};
}
};
So, you define your inputs and process them in fn: function(inputs) where you have access to inputs.firstNumber and the rest of fields.
Source: https://sailsjs.com/documentation/concepts/actions-and-controllers

How to push multiple images in an array?

I'm creating a React Native application. I want to create an image array because I need to upload them to the server. But when I upload multiple images they are not storing like an array. every time the imagesQueue array has only one image.
my code as follows.
const [filePath, setFilePath] = useState({
imagesQueue: []
});
const chooseFile = () => {
const options = {
title: 'Select an option',
storageOptions: {
skipBackup: true,
path: 'images',
},
};
ImagePicker.showImagePicker(options, (response) => {
// console.log('Response = ', response);
if (response.didCancel) {
console.log('User cancelled image picker');
} else if (response.error) {
console.log('ImagePicker Error: ', response.error);
} else {
// let source = response;
// You can also display the image using data:
let source = {
uri: 'data:image/jpeg;base64,' + response.data
};
setFilePath({
...filePath,
imagesQueue: [source],
});
console.log("stored item : " + filePath.imagesQueue);
}
});
};
How to store multiple images in the same state. Thanks in advance.
the data probably will store in formData - it's easy format for later passing it to BE.
firstly You need store somewhere those data:
const [selectedFiles, setSelectedFiles] = useState([]);
Later there is possibility to use .concat() - that function connects 2 arrays:
setSelectedFiles(((prevState) => prevState.concat(fileData)));
And in the last step, You need to pass those data to Your form:
const formData = new FormData();
for (let i = 0; i < selectedFiles.length; i++) {
formData.append('Files', selectedFiles[i].File);
}

MERN+ Cloudinary: Unsupported source URL

I'm trying to upload file to cloudinary. Here is part of my react component
...
addItem() {
...
let file = this.fileInput.value;
keywords !== "" && this.props.onAddItem(keywords, place, image);
...
}
render() {
return (
....
<Input
type="file"
innerRef={(input) => {this.fileInput = input}}
name="image"
id="image"
placeholder=""/>
)
}
Here is action file:
export function onAddItem(keywords, place, file, id, isChangebale = false) {
return (dispatch) => {
axios.all([
axios.post('https://api.cloudinary.com/v1_1/myservername/image/upload',
{upload_preset: "mypresetname", file: file}),
axios.post('http://localhost:3001/api/items/', { keywords, place, id, isChangebale })
])
.then(axios.spread((cloudinaryRes, localRes) => {
console.log(cloudinaryRes, localRes);
}))
I receive error xhr.js:178 POST https://api.cloudinary.com/v1_1/testovich/image/upload 400 (Bad Request) and in response headers "X-Cld-Error: Unsupported source URL: C:\fakepath\2017-12-07_19-06-445.png"
When I test using postman I have correct response.
So it looks like I do something wrong when pass file from rect component to action file. How to pass correct path/file to cloudinary?
There were two mistakes:
1. in react component there should be
let file = this.fileInput.files[0];//I upload only one file
instead of
let file = this.fileInput.value;
in action file
export function onAddItem(keywords, place, image, id, isChangebale = false) {
const formData = new FormData();
formData.append("file", image);
formData.append("upload_preset", "mypresetname");
return (dispatch) => {
axios.all([
// AJAX upload request using Axios )
axios.post('https://api.cloudinary.com/v1_1/myservername/image/upload',
formData,
instead of:
export function onAddItem(keywords, place, file, id, isChangebale = false) {
return (dispatch) => {
axios.all([
axios.post('https://api.cloudinary.com/v1_1/myservername/image/upload',
{upload_preset: "mypresetname", file: file}),
Convert the image to a base64 like const base64Img = data:image/jpg;base64,${file.data};
The file.data represents the data property from response from image picker.
Then I passed the base64Img to data like
return RNFetchBlob.fetch('POST', apiUrl, headerProps, [ { name: 'file', fileName: file.fileName, type: file.type, data: base64Img } ]);
Hope it helps.

Ask User to choose photo from photo library or camera with react native button

I am using expo and cannot use https://github.com/react-community/react-native-image-picker , and would like to know how to implement the same functionality . I have the following code for each option separately (One button for gallery and the other one for camera)
_pickImage = async () => {
let pickerResult = await Expo.ImagePicker.launchImageLibraryAsync({
exif: true,
allowsEditing: false,
quality: 0.7,
base64: true,
})
if (pickerResult.cancelled) {
return
}
console.log(pickerResult)
}
And the other one is
uploadImage = async() =>{
// Display the camera to the user and wait for them to take a photo or to cancel
// the action
let result = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [4, 3],
});
if (result.cancelled) {
return;
}
// ImagePicker saves the taken photo to disk and returns a local URI to it
let localUri = result.uri;
let filename = localUri.split('/').pop();
// Infer the type of the image
let match = /\.(\w+)$/.exec(filename);
let type = match ? `image/${match[1]}` : `image`;
// Upload the image using the fetch and FormData APIs
let formData = new FormData();
// Assume "photo" is the name of the form field the server expects
formData.append('photo', { uri: localUri, name: filename, type });
return await fetch(YOUR_SERVER_URL, {
method: 'POST',
body: formData,
header: {
'content-type': 'multipart/form-data',
},
});
}
}
And the both functions was called as
<Button title="Pick image" onPress={this._pickImage} />
<Button title="Upload image" onPress={this._uploadImage} />
But how do I make i work as shown below:
Expo has released the ActionSheet library which provides exact functionality you need.

Resources