How can I specify the name of pdf print for react native project for iOS - react-native

I'm using both expo-print and expo-sharing to save file.
const { uri } = await Print.printToFileAsync({html});
await shareAsync(uri, { UTI: ".pdf", mimeType: "application/pdf" });
by default it is using UUID, I want to specify the file eg, abc.pdf, but I don't see the doc has any option to setup the file name.

I found the answer here
import * as Print from 'expo-print'
import * as Sharing from 'expo-sharing'
import * as FileSystem from 'expo-file-system'
const printToPdf = async () => {
const response = await Print.printToFileAsync({
html: createHtmlStringForPdf(),
})
// this changes the bit after the last slash of the uri (the document's name) to "invoice_<date of transaction"
const pdfName = `${response.uri.slice(
0,
response.uri.lastIndexOf('/') + 1
)}invoice_${readableDate.getTime()}.pdf`
await FileSystem.moveAsync({
from: response.uri,
to: pdfName,
})
sharePdf(pdfName)
}
const sharePdf = (url) => {
Sharing.shareAsync(url)
}

Related

Nuxt 3 file upload and store in locally in the project

I want to create a simple Nuxt 3 file upload implementation that stores the file in the locally in a folder in the Nuxt project. In PHP the server side code is very easy and straight forward but I am finding it difficult doing the same thing in Nuxt 3 server side.
First:
npm install formidable
second:
define formidable in Nuxt config file inside modules list.
export default defineNuxtConfig({
modules: ["formidable"],
});
then in your handler for example upload.post.js :
import formidable from "formidable";
import fs from "fs";
import path from "path";
export default defineEventHandler(async (event) => {
let imageUrl = "";
let oldPath = "";
let newPath = "";
const form = formidable({ multiples: true });
const data = await new Promise((resolve, reject) => {
form.parse(event.req, (err, fields, files) => {
if (err) {
reject(err);
}
if (!files.photo) {
resolve({
status: "error",
message: "Please upload a photo with name photo in the form",
});
}
if (files.photo.mimetype.startsWith("image/")) {
let imageName =
Date.now() +
Math.round(Math.random() * 100000) +
files.photo.originalFilename;
oldPath = files.photo.filepath;
newPath = `${path.join("public", "uploads", imageName)}`;
imageUrl = "./public/upload/" + imageName;
fs.copyFileSync(oldPath, newPath);
resolve({
status: "ok",
url: imageUrl,
});
} else {
resolve({
status: "error",
message: "Please upload nothing but images.",
});
}
});
});
return data;
});
don't forget to name the input field "photo" in the client side or change it here in every "files.photo".
ALso the path of uploaded photos will be in public/uploads directory you can change it too if you like in "path.join" method.
Good luck

I am converting Images to pdf using a npm library in react native why it is giving error of null object?

I am using react-native-image-to-pdf library to convert images to pdf in my react native app. from https://www.npmjs.com/package/react-native-image-to-pdf
var photoPath = ['https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&h=350','https://images.pexels.com/photos/20787/pexels-photo.jpg?auto=compress&cs=tinysrgb&h=350'];
const myAsyncPDFFunction = async () => {
try {
const options = {
imagePaths: photoPath,
name: 'PDFName',
};
const pdf = await RNImageToPdf.createPDFbyImages(options);
console.log(pdf.filePath);
} catch(e) {
console.log(e);
}
}
but this is giving error Error: Attempt to invoke virtual method 'int android.graphics.Bitmap.getWidth()' on a null object reference
I have also tried giving path as ['./assets/a.png', './assets/b.png']
but still getting same error
Based on the usage example, your photoPath needs to be a local file path and not a remote path.
My recommendation is to first use rn-fetch-blob to download the remote image to the device, and then pass your new local image path to react-native-image-to-pdf. Something like:
RNFetchBlob
.config({
// add this option that makes response data to be stored as a file,
// this is much more performant.
fileCache : true,
})
.fetch('GET', 'http://www.example.com/file/example.png', {
//some headers ..
})
.then(async (res) => {
// the temp file path
console.log('The file saved to ', res.path())
const options = {
imagePaths: [res.path()],
name: 'PDFName',
};
const pdf = await RNImageToPdf.createPDFbyImages(options);
})
from file path remove the text 'file://; with empty string('').
const options = {
imagePaths: [uri.replace('file://', '')],
name: 'FileName',
quality: .9, // optional compression paramter
};
replace('file://', '') it's work for me

How to create csv file in expo react native

I'm still new to React Native may I know how can I create csv file in react native using expo? I've seen people suggesting expo-file-system as they said it is not recommended to use react-native-fs if using expo but I not sure how to use it. is it using FileSystem.writeAsStringAsync(fileUri, contents, options)?
Here is an example of a function that creates a simple .csv file
I'm using react-native-csv to generate the .csv.
expo-media-library is used to move the file from a folder accessible from the app to a publicly accessible folder.
import { jsonToCSV, readRemoteFile } from 'react-native-csv';
import * as FileSystem from 'expo-file-system';
import * as Permissions from 'expo-permissions';
import * as MediaLibrary from 'expo-media-library';
export async function makeCSV() {
const jsonData = `[
{
"Column 1": "Name",
"Column 2": "Surname",
"Column 3": "Email",
"Column 4": "Info"
}
]`;
const CSV = jsonToCSV(jsonData);
// Name the File
const directoryUri = FileSystem.documentDirectory;
const fileUri = directoryUri + `formData.csv`;
// Ask permission (if not granted)
const perm = await Permissions.askAsync(Permissions.MEDIA_LIBRARY);
if (perm.status != 'granted') {
console.log("Permission not Granted!")
return;
}
// Write the file to system
FileSystem.writeAsStringAsync(fileUri, CSV)
try {
const asset = await MediaLibrary.createAssetAsync(fileUri);
const album = await MediaLibrary.getAlbumAsync('forms');
console.log(album)
if (album == null) {
await MediaLibrary.createAlbumAsync('forms', asset, true);
} else {
await MediaLibrary.addAssetsToAlbumAsync([asset], album, true);
}
} catch (error) {
console.log(error);
}
}

Write files to directory error - Expo FileSystem

I am really struggling to find where I am going wrong with this. I am trying to move the picked (ImagePicker) image from cache to app scope directory folder named images/. I created a directory images/ using FileSystem.makeDirectoryAsync but while trying to move the picked image to this directory I am getting an error. Please can someone help me I am really struggling
Expected Result
The image successfully moves to the images/ directory
Actual Result
[Unhandled promise rejection: Error: File 'file:///var/mobile/Containers/Data/Application/318CFCE4-16DF-44DD-92B3-39DECA61EA14/Library/Caches/ExponentExperienceData/%2540user%252FtestApp/ImagePicker/ECD218AE-3DD3-429F-B1F5-469DA1AC661C.jpg' could not be moved to
'file:///var/mobile/Containers/Data/Application/318CFCE4-16DF-44DD-92B3-39DECA61EA14/Documents/ExponentExperienceData/%2540user%252FtestApp/images/ECD218AE-3DD3-429F-B1F5-469DA1AC661C.jpg/'.]
This is my code:
import React, { useEffect, useState } from "react";
import {Text,View,TouchableOpacity,Alert,} from "react-native";
import * as ImagePicker from "expo-image-picker";
import * as Permissions from "expo-permissions";
import * as FileSystem from "expo-file-system";
const ImageCard = (props) => {
const { handlePickedImage } = props;
const [image, setImage] = useState("");
// Create any app folders that don't already exist
export const checkAndCreateFolder = async folder_path => {
const folder_info = await FileSystem.getInfoAsync(folder_path);
if (!Boolean(folder_info.exists)) {
// Create folder
console.log("checkAndCreateFolder: Making " + folder_path);
try {
await FileSystem.makeDirectoryAsync(folder_path, {
intermediates: true
});
} catch (error) {
// Report folder creation error, include the folder existence before and now
const new_folder_info = await FileSystem.getInfoAsync(folder_path);
const debug = `checkAndCreateFolder: ${
error.message
} old:${JSON.stringify(folder_info)} new:${JSON.stringify(
new_folder_info
)}`;
console.log(debug);
}
}
};
const veryfiyPermissons = async () => {
const result = await Permissions.askAsync(Permissions.CAMERA_ROLL);
if (result.status !== "granted") {
Alert.alert(
"Insufficient permissions",
"You need to grant permissions to access Camera Roll",
[{ text: "Okay" }]
);
return false;
}
return true;
};
const selectImageHandler = async () => {
const hasPermisson = await veryfiyPermissons();
if (!hasPermisson) {
return;
}
const image = await ImagePicker.launchImageLibraryAsync({
quality: 0.5,
});
if (image.cancelled) {
randomImage;
} else {
let localUri = image.uri;
let localUriNamePart = localUri.split("/");
const fileName = localUriNamePart[localUriNamePart.length - 1];
const images_folder = `${FileSystem.documentDirectory + 'images/'}`
checkAndCreateFolder(images_folder);
const setTheFile = `${images_folder + `${fileName}/`}`
await FileSystem.moveAsync({
from: localUri,
to: newLocation
}).then((i) => {
setImage(setTheFile);
handlePickedImage(setTheFile);
})
}
};
return (
<View>
<TouchableOpacity onPress={selectImageHandler}>
<Text>Add Photo</Text>
</TouchableOpacity>
</View>
);
};
export default ImageCard;

Extract zip file from react native project folder on initial running

We want to include zip file on react native project, for example in project/src/assets/zip folder, include it in the build and extract it to local phone storage on initial App run.
What we want to achieve is, suppose we have a web page that we want to show on react native app. We can decrease the loading time by including the asset for the web page on the project, then told the web page to search for the assets file locally.
We have successfully showing web page with local assets downloaded from internet, in zip format. But We haven’t found on how to achieve the same using zip file on local project.
We have try to import the asset file, then unzip it directly like below with no luck
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
unzip(zipFile, destination)
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
We have try to use react-native-local-resource to get the file with several combinations without luck too
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
import loadLocalResource from 'react-native-local-resource'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
loadLocalResource(assetsZip)
.then((fileContent) => unzip(fileContent, destination))
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
import loadLocalResource from 'react-native-local-resource'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
const fileName = 'file.zip'
loadLocalResource(assetsZip)
.then((fileContent) => RNFS.writeFile(destination + fileName, fileContent))
.then(() => unzip(destination + fileName, destination))
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
How can We extract zip file on project folder into Phone Storage?
EDIT:
while the previous answer was working on debug version of the app, it seems to break on production, because on production resource.uri return file:// uri instead of http:// as in debug version.
to fix the problem we need to check whether it was file uri or http url. then use copy function on react-native-fs instead of download function, if it was file uri.
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
const filename = 'file.zip'
const resource = resolveAssetSource(zipFile)
const fileUri = resource.uri
this.loadZipFile(fileUri, destination + filename)
.then((result) => unzip(destination + filename, destination))
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
}
loadZipFile = (fileUri, destinationFile) = {
if (fileUri.startWith('file://')) {
return RNFS.copyFile(fileUri, destinationFile)
} else {
const downloadOptions = {
fromUrl: fileUri,
toFile: destinationFile
}
return RNFS.downloadFile(downloadOptions).promise
}
}
this should work on both production and debug version, even sending zip file using code push was working fine on our case.
OLD ANSWER:
After looking on react-native-local-resource source code, We come up with some Idea.
The problem with react-native-local-resource in our case is, that the final result was text, but zip file is not a text. So we try to intercept the code in the middle to get zip file as we want.
After some experiment, we follow react-native-local-resource code until we got the uri of the file, then use react-native-fs to download the file into local storage folder, then unzip those file.
Here is sample of working code on our case
import zipFile from './assets/zip/file.zip'
import * as RNFS from 'react-native-fs'
import { unzip } from 'react-native-zip-archive'
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource'
...
componentDidMount() {
const destination = RNFS.DocumentDirectoryPath + '/'
const filename = 'file.zip'
const resource = resolveAssetSource(zipFile)
const fileUri = resource.uri
const downloadOptions = {
fromUrl: fileUri,
toFile: destination + filename
}
RNFS.downloadFile(downloadOptions).promise
.then((result) => unzip(destination + filename, destination))
.then((result) => {
console.log(result)
})
.catch((error) => {
console.log(error)
})
}
Hope it can help anyone who have meet the same problem