react-native-document-picker not listing some files - javascript

I'm giving a try to react-native-document-picker. In my use case, what I want is listing some .db files so that the user is able to select one of them to import to my app. Turns out that, while using react-native-document-picker, when I navigate to the folder where the db file is, neither the .db file is shown nor the other files are.
As it's possible to see bellow, while I'm accessing the folder using Google Files, I can see the files, but I can't when I'm using react-native-document-picker:
Google files result (files being listed)
React-native-document-picker result (no files being listed)
My code is very very simple and the version I'm using is react-native-document-picker:4.0.6:
import DocumentPicker, {
DirectoryPickerResponse,
DocumentPickerResponse,
isInProgress,
types,
} from 'react-native-document-picker';
const getImportFile = async (translate) => {
try {
const file = await DocumentPicker.pick();
console.log(file);
return { success: true, error: null, payload: file };
} catch (ex) {
return { success: false, error: ex }
}
}
I'd appreciate if someone could help me with it.

Related

getting an error while trying to pick a directory using expo document picker in react-native

hay guys, i am making a react native app with expo and i am using "expo document picker" module to access the folder in the device by clicking on the button in my app , i am getting this error in my terminal --
LOG [Error: Encountered an exception while calling native method: Exception occurred while executing exported method getDocumentAsync on module ExpoDocumentPicker: No Activity found to handle Intent { act=android.intent.action.OPEN_DOCUMENT cat=[android.intent.category.OPENABLE] typ=directory }]
this is my code---
const pickDirectory = async () => {
console.log("hi!!!!!");
try {
const permission =
await FileSystem.StorageAccessFramework.requestDirectoryPermissionsAsync();
if (permission.granted) {
const dir = await DocumentPicker.getDocumentAsync({
copyToCacheDirectory:true,
type: "directory",
});
// setSyncDirectory();
console.log(dir);
}
} catch (error) {
console.log(error);
}
};
The error you are seeing is because the DocumentPicker.getDocumentAsync() method can't find an app on your device that can open a folder.
The DocumentPicker module is meant for selecting and opening documents, not folders. If you want to let users choose a folder, you can use FileSystem.StorageAccessFramework instead. This allows you to request access to a directory and perform file operations like reading and writing files.
import * as FileSystem from 'expo-file-system';
const pickDirectory = async () => {
console.log("hi!!!!!");
try {
const permission = await FileSystem.requestDirectoryPermissionsAsync();
if (permission.granted) {
const dir = await FileSystem.StorageAccessFramework.browseForFolderAsync();
console.log(dir);
}
} catch (error) {
console.log(error);
}
};
Note that the browseForFolderAsync() method is currently only available on Android, so if you need to support iOS as well, you will need to use a different method or library to allow the user to select a folder.

Uploading images to AWS S3 bucket - specifying file path for randomly generated file names

I'm working on an automated testing project using PuppeteerJS in headless Chrome and trying to integrate existing screenshot functionality with AWS-SDK to upload images to an AWS S3 bucket on test failure.
The problem i'm having is the sub directories in a screenshots folder and the image file names are generated randomly in another file based on the current date and test environment, and run every time a test runs. The format of the generated directories/files is "screenshots/year/month/day/randomname.png".
The next step in the test is after the screenshots are generated, the folder containing the newly created images should be uploaded to AWS, and I've tried to achieve this using a glob to get every subdirectory and file with a png extension, like "screenshots/**/**/**/*.png", but i get a "no such file or directory" error". The folders/file names will be different everytime the tests run.
I've just started using AWS and I haven't been able to find a specific answer to my problem while researching.
import { PutObjectCommand } from "#aws-sdk/client-s3";
import { s3Client } from "../libs/s3Client.js";
import path from "path";
import fs from "fs";
const file = "../../screenshots/**/**/**/*.png";
const fileStream = fs.createReadStream(file);
// Set the parameters
export const uploadParams = {
Bucket: "bucket-name",
Key: path.basename(file),
// Add the required 'Body' parameter
Body: fileStream,
};
// Upload file to specified bucket.
export const run = async () => {
try {
const data = await s3Client.send(new PutObjectCommand(uploadParams));
console.log("Success", data);
return data; // For unit tests.
} catch (err) {
console.log("Error", err);
}
};
run();
Worked this out with the help of Jarmod. I needed to use the nodeJS:fs module to get the file paths recursively and returns a string which can be passed into the AWS fileStream variable for it to be uploaded to AWS. Jarmod shared the webmound article and i found the coder rocket fuel article hepful also.
https://www.webmound.com/nodejs-get-files-in-directories-recursively/
https://coderrocketfuel.com/article/recursively-list-all-the-files-in-a-directory-using-node-js

Can't get .env variables to work in React using Contentful

I am trying to connect to Contentful's API in my react project. If I hardcode the space and access tokens it works fine, but if I try to use a .env file it's not getting the token.
Here's my code:
import {createClient} from "contentful";
export const client = () => {
//console.log(process.env)
let whatever = createClient({
space: process.env.REACT_APP_SPACE_ID ,
accessToken: process.env.REACT_APP_ACCESS_TOKEN,
});
return whatever;
};
export const getRecipes = async () => {
try{
const entries = await client().getEntries({
content_type: "recipe",
select: "fields"
});
return entries;
} catch(error){
console.log(`error fetch: ${error}`);
return;
}
}
I've tried various patches but nothing has worked. I have react-scripts installed as well.
I console logged the process.env and it doesn't have the token or space id.
I tried importing dotenv but that created some weird polyfill error that I've never seen before.
It could be that: your env file is not in the project folder but instead in the src/ folder...just check it once to make sure, it's a very easy mistake that a lot of people make.
Or if you have the client folder inside the server folder which is sometimes needed for deployment it might not be working because of that folder structure as well

File not found in script

I've installed several libraries using NPM.
You have to load the file to use it there.All installed libraries are under the node_modules
The designation is like this.
<script src="../node_modules/vue/dist/vue.js"></script>
I'm sure it's on the server, I'm sure the URL of the script tag is correct
And I get the following error in the script, even though it is specified like this
login.html:45 GET https://***/node_modules/vue/dist/vue.js net::ERR_ABORTED 404
The JS file I prepared separately is loaded, but the original vue.js is not, so an error is coming back.
That's what we're trying to do with VUE.
I'm going to use Ajax to create an SPA
/* eslint-disable no-console */
const vue = require("vue"); //I added it, but it's still not working.
const axios = require("axios"); //I added it, but it's still not working.
var app = new Vue({
el: "#app",
data: {
url: "https://*****",
user: "",
password: "",
res: ""
},
methods: {
login: function () {
axios.post(this.url, {
user: this.user,
password: this.password
})
.then(function (response) {
this.res = response.data.d;
if (this.res === true) {
//true
} else {
//failed
}
})
.catch(function (error) {
alert('System error');
});
}
}
})
This is how usually use it from node_module
import Vue from 'vue'; // this will check inside node_modules for the file and include
Instead of loading the files through a script tag, use require() in your javascript. For example:
const express = require("express");
const vue = require("vue");
This will work on both the client and on the server.
Why not use a CDN?
This way, the browser will not have to download the Vue file from your server if it has already been cached. Also, you may be able to use the vue.min.js file which will load even faster than the normal Vue dist file...
For example, here is a script from cdnjs.com you could try:
<script
src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.11/vue.min.js"
integrity="sha256-ngFW3UnAN0Tnm76mDuu7uUtYEcG3G5H1+zioJw3t+68="
crossorigin="anonymous"></script>
Try replacing your script tag with this.

expo sqlite use existing database

According to the expo sqlite documentation for react-native I can initialize a db like so:
const db = SQLite.openDatabase('db.db');
This works and I can update the db like so:
update() {
db.transaction(tx => {
tx.executeSql(
`select * from items where done = ?;`,
[this.props.done ? 1 : 0],
(_, { rows: { _array } }) => this.setState({ items: _array })
);
});
}
From my limited understanding this creates a database in the device. And then it's manipulated keeping all the db local.
I have a database with all the necessary tables already setup. How can I have it use the current database I already have setup?
For example: (not correct syntax)
const db = SQLite.openDatabaseIShipWithApp('mypath/mydb.db');
I couldn't find any documentation to help me with this.
The only reason I mention the above is because I already have the db with the tables and data.
Any help would be appreciated!
I was able to achieve this by using expo's FileSystem.downloadAsync:
first I import it since I'm using expo managed app:
import { FileSystem } from 'expo';
Then I download it from a server like so:
// load DB for expo
FileSystem.downloadAsync(
'http://example.com/downloads/data.sqlite',
FileSystem.documentDirectory + 'data.sqlite'
)
.then(({ uri }) => {
console.log('Finished downloading to ', uri)
})
.catch(error => {
console.error(error);
})
The first parameter is the uri for the location, the second one is where I'd like to place it. Here I am using documentDirectory.
If using local prepopulated database in assets:
import * as FileSystem from "expo-file-system";
import {Asset} from "expo-asset";
async function openDatabaseIShipWithApp() {
const internalDbName = "dbInStorage.sqlite"; // Call whatever you want
const sqlDir = FileSystem.documentDirectory + "SQLite/";
if (!(await FileSystem.getInfoAsync(sqlDir + internalDbName)).exists) {
await FileSystem.makeDirectoryAsync(sqlDir, {intermediates: true});
const asset = Asset.fromModule(require("../assets/database/mydb.sqlite"));
await FileSystem.downloadAsync(asset.uri, sqlDir + internalDbName);
}
this.database = SQLite.openDatabase(internalDbName);
}
This creates the SQLite directory and database if not exists. Otherwise FileSystem.downloadAsync() will throw an error on fresh installed app.
Some remarks:
You cannot use variable in require() (only string). See e.g. this.
You have to explicitly allow file extension .db or .sqlite to be loadable in Expo, see this. You have to create a file metro.config.js in root:
const defaultAssetExts = require("metro-config/src/defaults/defaults").assetExts;
module.exports = {
resolver: {
assetExts: [
...defaultAssetExts,
"db", "sqlite"
]
}
};
And may add following to app.json
"expo": {
"assetBundlePatterns": [
"**/*"
]
}
If want to delete loaded database (e.g. for testing) you have to clear whole Expo App data in Phone settings (deleting cache not sufficient). Or write a method like this:
async function removeDatabase() {
const sqlDir = FileSystem.documentDirectory + "SQLite/";
await FileSystem.deleteAsync(sqlDir + "dbInStorage.sqlite", {idempotent: true});
}
It's pretty straight forward
If you bundle your app, you have to move the Database from the asset folder to the document directory first. In order to do that, check if a folder named SQLite exists. If not, create it. Why do you need a folder called SQLite? That is because SQLite.openDatabase(databaseName) looks per default in FileSystem.documentDirectory + 'SQLite'. Then, when the folder is created, you can download the database from the asset folder. Make sure you have your database in a folder called asset. Locate the foler asset under src/asset of your app document tree. Also, make sure to configure your app.json and metro.config.js.
import * as SQLite from 'expo-sqlite';
import * as FileSystem from 'expo-file-system';
import { Asset } from 'expo-asset';
const FOO = 'foo.db'
if (!(await FileSystem.getInfoAsync(FileSystem.documentDirectory + 'SQLite')).exists) {
await FileSystem.makeDirectoryAsync(FileSystem.documentDirectory + 'SQLite');
};
await FileSystem.downloadAsync(
// the name 'foo.db' is hardcoded because it is used with require()
Asset.fromModule(require('../../asset/foo.db')).uri,
// use constant FOO constant to access 'foo.db' whereever possible
FileSystem.documentDirectory + `SQLite/${FOO}`
);
// Then you can use the database like this
SQLite.openDatabase(FOO).transaction(...);
// app.json
{
"name": "Your App name",
"displayName": "Your App name",
"assetBundlePatterns": [
"assets/**"
],
"packagerOpts": {
"assetExts": ["db"]
}
}
// metro config
const { getDefaultConfig } = require('#expo/metro-config');
const defaultConfig = getDefaultConfig(__dirname);
module.exports = {
resolver: {
assetExts: [...defaultConfig.resolver.assetExts, 'db', 'json'],
},
transformer: {
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
};
This is all extracted from the documentation of expo.
I don't believe this is possible in expo. There is a way to use an existing database if you are using a bare android project which involves writing some native code to copy the database from the project assets to the standard location on the phone (/data/ etc) for your application.
https://medium.com/#johann.pardanaud/ship-an-android-app-with-a-pre-populated-database-cd2b3aa3311f
I have always personally created the database myself with CREATE TABLE IF NOT EXISTS since sqlite requires you to define the schema before you query it. If you need to seed the database, this step would then be followed by additional steps to insert the required data.
In most cases, you will need to also check your reference data and update it from the server at regular intervals (it might even change from publishing your apk to someone downloading the app) and this code would also work when there is no reference data in the database.
There are a couple of services which try and take his hassle away from you (e.g. parse) but you will need to decide if you are happy with them hosting your data.) I haven't used them so not sure how this works exactly but I'm told it tries to solve the offline first type problems.
Remember that in future iterations you may need to modify the structure for future versions (to add fields etc) so you will probably need to define some code that loads when the application is first started, checks the database version and applies any changes that are required to bring the database up to the appropriate level.

Categories