Convert Dynamic JSON to PDF and XML in React - reactjs

In my project, I'm using ReactJS as a frontend and Flask for Backend.
Here's a code I wrote to Get a case's details in the from of JSON and also convert it to Pretty JSON.
I now require a download button with which I can take the JSON input and download it as JSON, PDF and XML.
Here's the code-
CaseTree.js
<Grid item xs={12} md={10} className={classes.rightUpperPart}>
{/* Render CaseTree in Pretty Json format */}
{
(caseReducer.isLoading || !caseReducer.caseTree ||fileReducer.isLoading || !fileReducer.file || !fileReducer.fileType) ? (
<JsonPretty data={caseReducer.caseTree}/>
) : (fileReducer.fileType === 'report' || fileReducer.fileType === 'txt') ? (
<ShowTXT data={fileReducer.file} className={classes.rightPart}/>
) : (fileReducer.fileType === 'tsv') ? (
<ShowTSV data={fileReducer.file} className={classes.rightPart}/>) : (
<pre className={classes.preStyle}>{fileReducer.file}</pre>
)
}
</Grid>
**ADD DOWNLOAD BUTTON HERE**
JSON Pretty File
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import {
Box,
Typography
} from '#material-ui/core';
import { useSelector } from 'react-redux';
// custom styles
const useStyles = makeStyles((theme) =>({
root: {
backgroundColor: '#1f4662',
color: '#fff',
fontSize: '12px',
overflow: 'auto',
padding: theme.spacing(4),
height: theme.spacing(55),
},
headerStyle: {
backgroundColor: '193549',
fontFamily: 'monospace',
color: '#ffc600',
},
preStyle: {
display: 'block',
padding: '10px 3px',
margin: '0',
color: '#fff'
}
}))
function JsonPretty({data}) {
// invoke custom styles
const classes = useStyles()
// get case Reducer
const caseReducer = useSelector(state => state.case)
// default json data
const defaultData = {
"processing": ( caseReducer.isLoading ) ? "Wait Processing..." : "Done",
"success": false,
"message": ( caseReducer.error ) ? caseReducer.error : "Please Provide a Case Name.",
}
return (
<Box component="div" className={classes.root}>
<Typography className={classes.headerStyle}>
Pretty Json Format
</Typography>
{
(data) ? (
<pre className={classes.preStyle}>
{JSON.stringify(data, null, 4)}
</pre>
) : (
<pre className={classes.preStyle}>
{JSON.stringify(defaultData, null, 4)}
</pre>
)
}
</Box>
)
}
export default JsonPretty
LoadCaseTree def
export const loadCaseTree = (case_name) => (dispatch) => {
//// dispatch laod case
dispatch({
type: LOAD_CASE_TREE
})
//// Create request data body
const data = {
case_name: case_name
}
//// Get token from localstorage
const token = localStorage.getItem('openmf_token')
//// add headers
const config = {
headers: {
'Content-Type': 'application/json'
}
}
//// If token available add to headers
if (token) {
config.headers.Authorization = `Bearer ${token}`
} else {
dispatch({ type: LOAD_CASE_TREE_FAILED })
dispatch(setAlert('Please Log In.'))
return
}
//// Send request to server
axios.post('/case/case-tree', data, config)
.then((res) => {
const case_tree_json = JSON.parse(res.data.tree)
dispatch({
type: LOAD_CASE_TREE_SUCCESSFULL,
payload: {
tree: case_tree_json,
case: res.data.case
}
})
dispatch(setAlert(res.data.message, 'success'))
})
.catch((err) => {
const res = err.response
//// check err status code
if(res && (res.status === 404 || res.status === 422 || res.status === 500)){
dispatch({
type: LOAD_CASE_TREE_FAILED,
payload: {
error: res.data.message
}
})
dispatch(setAlert(res.data.message))
return
}
//// FOr unknown reason
dispatch({
type: LOAD_CASE_TREE_FAILED,
payload: {
error: 'Something went wrong.'
}
})
//// dispatch alert
dispatch(setAlert('Something went wrong.'))
})
}
Please let me know if I've missed out on any code snippet or information.

Related

React native, axios put request

The first problem: when opening a modal with editing an avatar, 2 requests are sent to the server.
The second problem: the avatar is not updated. The answer comes that the email should be specified, but I just pass the string. The full text of the error is shown in the screenshot.
Sending an avatar change request
import { BottomSheet } from '#rneui/themed'
import { FC, useState } from 'react'
import { useForm } from 'react-hook-form'
import { Pressable, ScrollView, View } from 'react-native'
import GestureRecognizer from 'react-native-swipe-gestures'
import { IUser } from '#/types/user.inteerface'
import { IAvatarEdit } from '#/components/screens/profile/avatarEdit/avatarEdit.interface'
import { useAvatar } from '#/components/screens/profile/avatarEdit/useAvatar'
import { Avatars, Button, Heading, Layout } from '#/components/ui'
import { getModalStyle, modalStyle } from '#/components/ui/style'
type AvatarData = {
image_url: string
}
const dataList: AvatarData[] = [
{
image_url:
'https://cdn.pixabay.com/photo/2017/03/01/22/18/avatar-2109804_1280.png'
},
{
image_url: 'https://randomuser.me/api/portraits/men/36.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2014/09/17/20/03/profile-449912__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2020/09/18/05/58/lights-5580916__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2016/11/21/12/42/beard-1845166_1280.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2012/04/18/18/07/user-37448_1280.png'
},
{
image_url: 'https://randomuser.me/api/portraits/men/36.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2019/11/03/20/11/portrait-4599553__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2014/09/17/20/03/profile-449912__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2020/09/18/05/58/lights-5580916__340.jpg'
},
{
image_url:
'https://cdn.pixabay.com/photo/2016/11/21/12/42/beard-1845166_1280.jpg'
}
]
const AvatarEdit: FC<IAvatarEdit> = ({ onClose, isVisible, ...props }) => {
const { setValue } = useForm<IUser>()
const { onSubmit, user } = useAvatar(setValue)
const [selected, setSelected] = useState<string>(user?.avatar || '')
const onAvatarSubmit = () => {
onSubmit({ avatar: selected } as IUser)
onClose()
}
return (
<GestureRecognizer
onSwipeDown={onClose}
config={{
velocityThreshold: 0.3,
directionalOffsetThreshold: 80
}}
style={{
flex: 1
}}
>
<BottomSheet
backdropStyle={{
backgroundColor: 'rgba(0, 0, 0, 0.5)'
}}
onBackdropPress={onClose}
isVisible={isVisible}
{...props}
>
<Layout
style={{
...getModalStyle(modalStyle)
}}
>
<View
style={{
flex: 1,
paddingHorizontal: 20,
paddingVertical: 20
}}
>
<Heading className='pb-3' title='Edit' />
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'flex-start'
}}
>
<Avatars
rounded={true}
size={100}
source={selected ? { uri: selected } : { uri: user?.avatar }}
/>
<View
style={{
marginTop: 15,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-end'
}}
>
<Button style={{ marginRight: 10 }} onPress={onAvatarSubmit}>
Save
</Button>
</View>
</View>
</View>
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
style={{ flex: 1 }}
>
{dataList.map((item, index) => (
<Pressable key={index}>
<Avatars
onPress={() => setSelected(item.image_url)}
rounded={true}
key={index}
size={60}
source={{ uri: item.image_url }}
/>
</Pressable>
))}
</ScrollView>
</Layout>
</BottomSheet>
</GestureRecognizer>
)
}
export default AvatarEdit
import { IAuthFormData } from '#/types/auth.interface'
import { IUser } from '#/types/user.inteerface'
import { getUserUrl } from '#/config/api.config'
import { request } from '#/services/api/request.api'
export const UserService = {
async getAll(searchTerm?: string) {
return request<IUser[]>({
url: getUserUrl(''),
method: 'GET',
params: searchTerm ? { searchTerm } : {}
})
},
async getProfile() {
return request<IUser>({
url: getUserUrl('profile'),
method: 'GET'
})
},
async getById(_id: string) {
return request<IUser>({
url: getUserUrl(`${_id}`),
method: 'GET'
})
},
async updateProfile(data: IAuthFormData) {
return request<IUser>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async updateUser(data: IAuthFormData, _id: string) {
return request<string>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async updateAvatar(data: IUser) {
return request<string>({
url: getUserUrl('profile'),
method: 'PUT',
data
})
},
async deleteUser(_id: string) {
return request<string>({
url: getUserUrl(`${_id}`),
method: 'DELETE'
})
}
// async getFavorites() {
// return request<IUser>({
// url: getUserUrl('profile/favorites'),
// method: 'GET'
// })
// },
}
import { useMutation, useQuery } from '#tanstack/react-query'
import { SubmitHandler, UseFormSetValue } from 'react-hook-form'
import Toast from 'react-native-toast-message'
import { IUser } from '#/types/user.inteerface'
import { UserService } from '#/services/user/user.service'
export const useAvatar = (setValue: UseFormSetValue<IUser>) => {
const { isLoading, data: user } = useQuery(
['avatar'],
() => UserService.getProfile(),
{
onSuccess: ({ avatar }) => {
setValue('avatar', avatar)
}
}
)
const { mutateAsync } = useMutation(
['update avatar'],
(data: IUser) => UserService.updateAvatar(data),
{
onSuccess: ({}) => {
Toast.show({
type: 'success',
text1: 'avatar update',
text2: 'avatar update was successful'
})
}
}
)
const onSubmit: SubmitHandler<IUser> = async data => {
await mutateAsync(data)
}
return { onSubmit, isLoading, user }
}

Unexpected go back on react-navigation

I have a nested stack in my project. Everything works fine but when I click a button that takes you to a page where at first it has to load the user list with useEffect, the page does a navigation.goBack (). If I take useEffect off the page, when I click the button it goes to the right page.
listaUtenti: async () => {
setLoad(true);
getAuth().currentUser.getIdToken(true).then(function(idToken) {
fetch('http://ipipip/users', {
method: 'GET',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + idToken,
}
}).then((response) => {
return (response.json())
}).
then((response) => {
console.log(response);
if(response.status === 403){
throw new Error(response.message);
}
setLoad(false);
})
.catch(function(error) {
setLoad(false);
console.log(error);
showMessage({
message: "Attenzione",
description: String(error),
type: "danger",
backgroundColor: '#FF3D71',
color: '#FFFFFF',
statusBarHeight: 0,
style: { borderRadius: 10, marginTop: Constants.statusBarHeight + 10, width: '90%', alignSelf: 'center' }
});
})
}).catch(function(error) {
setLoad(false);
console.log(error);
showMessage({
message: "Attenzione",
description: error.message,
type: "danger",
backgroundColor: '#FF3D71',
color: '#FFFFFF',
statusBarHeight: 0,
style: { borderRadius: 10, marginTop: Constants.statusBarHeight + 10, width: '90%', alignSelf: 'center' }
});
})
},
In my HomePage i have a button that on press navigate to ListaUtentiScreen
<Button style={{marginVertical:10}} onPress={() => {navigation.navigate('ListaUtenti')}}>Lista utenti</Button>
I call "listaUtenti()" in useEffect
const BackIcon = (props) => (
<Icon {...props} name='arrow-back' />
);
export default function ListaUtentiScreen({navigation}) {
const { tema, listaUtenti } = useContext(AuthContext);
const [utenti, setUtenti] = useState({});
const ref = useRef(null);
useScrollToTop(ref);
const navigateBack = () => {
navigation.goBack();
};
const BackAction = () => (
<TopNavigationAction icon={BackIcon} onPress={navigateBack}/>
);
useEffect(() => {
const lista = async () => {
const users = await listaUtenti();
setUtenti(users);
};
lista();
return () => {
setUtenti({});
};
});
return (
<>
<TopNavigation title='Lista utenti' alignment='center' accessoryLeft={BackAction}/>
<Divider/>
<KeyboardAwareScrollView ref={ref} extraHeight={100} enableOnAndroid={true} scrollEnabled={true} contentContainerStyle={{flexGrow:1}} style={{backgroundColor: tema ? '#151A30' : '#EDF1F7'}}>
<Layout style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: tema ? '#151A30' : '#EDF1F7' }}>
<Text>Hello</Text>
</Layout>
</KeyboardAwareScrollView>
</>
);
}
if I remove useEffect, it navigates to listaUtenti but if I use useeffect it goes back. If I try to use console.log () to see if the function is used, on the terminal it prints the user list but it goes back anyway
This is a video that show the error
Without a code snippet its pretty hard to answer, however my intuition tells me you're doing something like this
<Button onPress={navigation.goBack()}> {Back arrow in the top left corner} </Button>
When you should be doing something like this:
<Button onPress={(e)=>navigation.goBack()}> {Back arrow in the top left corner} </Button>
The difference here is the (e) => inside the onPress/onClick (depending on what framework you're using) without the (e) => the function is called immediately when the button is rendered. Again, not 100% sure without the code snippet

Expo app keeps returning TypeError: undefined is not an object (evaluating 'function')

I am creating a mobile app that takes a picture and then returns the objects it detected. the way it works is that i have heroku running the ml model api. the weird thing about this error is that it happened after my code worked and sent an api request which then returned a json of what it detected. and when i ran it again it gave me [TypeError: undefined is not an object (evaluating '_expo.ImageManipulator.manipulateAsync')]. i looked at the value of image and asset to see if they are undefined and the console printed false. i even tried
console.log(typeof image==='undefined')
console.log(typeof asset==='undefined')
console.log(typeof image=='undefined')
console.log(typeof asset=='undefined')
just to make sure that the value of the variables aren't undefined. i then commented out the function to see what would happen and i got [TypeError: undefined is not an object (evaluating '_this.toServer')]. i then restarted the expo server and did everything i did above again but it keeps giving me [TypeError: undefined is not an object (evaluating '_expo.ImageManipulator.manipulateAsync')]. the code below is the code for the function that saves the image and makes a post request.
const takePicture = async () => {
if (cameraRef) {
try {
const data = await cameraRef.current.takePictureAsync();
console.log(data);
setImage(data.uri);
} catch (error) {
console.log(error);
}
}
};
uriToBase64 = async (uri) => {
let base64 = await FS.readAsStringAsync(uri, {
encoding: FS.EncodingType.Base64,
});
return base64;
};
const savePicture = async () => {
if (image) {
try {
const asset = await MediaLibrary.createAssetAsync(image);
console.log(image===undefined)
console.log(asset===undefined)
console.log(image==undefined)
console.log(asset===undefined)
let manipResult = await ImageManipulator.manipulateAsync(
asset,[{ resize: { width: 800, height: 800 } }],{ format: 'jpg' });
let assetResized = await MediaLibrary.createAssetAsync(manipResult);
await this.toServer({
type:"image",
base64: uriToBase64(assetResized),
uri: assetResized,
});
setImage(null);
console.log('saved successfully');
} catch (error) {
console.log(error);
}
}
};
also if i do:
if(!(image==undefined))
to make it so that if the image is undefined it won't do anything i get
LOG [Error: Argument of an incompatible class: class java.util.HashMap cannot be passed as an argument to parameter expecting class java.lang.String.]
WARN Possible Unhandled Promise Rejection (id: 0):
Error: Argument of an incompatible class: class java.util.HashMap cannot be passed as an argument to parameter expecting class java.lang.String.
promiseMethodWrapper#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:22934:45
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:114097:40
readAsStringAsync$#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:118249:92
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24590:34
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24648:30
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24672:19
tryCallTwo#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30323:9
doResolve#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30487:25
Promise#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30346:14
callInvokeWithMethodAndArg#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24671:33
_invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24676:157
async#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24762:69
readAsStringAsync#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:118236:38
_callee3$#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:120465:69
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24590:34
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24648:30
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24672:19
tryCallTwo#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30323:9
doResolve#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30487:25
Promise#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30346:14
callInvokeWithMethodAndArg#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24671:33
_invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24676:157
async#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24762:69
_callee3#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:120460:40
_callee5$#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:120529:36
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24590:34
tryCatch#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24610:23
invoke#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24648:30
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:24654:19
tryCallOne#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30314:16
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:30415:27
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:31506:26
_callTimer#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:31406:17
_callReactNativeMicrotasksPass#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:31441:17
callReactNativeMicrotasks#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:31648:44
__callReactNativeMicrotasks#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:23414:46
http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:23193:45
__guard#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:23397:15
flushedQueue#http://192.168.1.4:19000/node_modules%5Cexpo%5CAppEntry.bundle?platform=android&dev=true&hot=false:23192:21
flushedQueue#[native code]
invokeCallbackAndReturnFlushedQueue#[native code]
here is the entire code:
import React, { useState, useEffect, useRef } from 'react';
import { Text, View, StyleSheet, TouchableOpacity, Image } from 'react-native';
import Constants from 'expo-constants';
import { Camera, CameraType } from 'expo-camera';
import * as MediaLibrary from 'expo-media-library';
import { MaterialIcons } from '#expo/vector-icons';
import Button from './src/components/Button';
import axios from 'axios'
import { Buffer } from "buffer";
import * as FS from "expo-file-system";
import { ImageManipulator } from 'expo';
export default function App() {
const [hasCameraPermission, setHasCameraPermission] = useState(null);
const [image, setImage] = useState(null);
const [type, setType] = useState(Camera.Constants.Type.back);
const [flash, setFlash] = useState(Camera.Constants.FlashMode.off);
const cameraRef = useRef(null);
useEffect(() => {
(async () => {
MediaLibrary.requestPermissionsAsync();
const cameraStatus = await Camera.requestCameraPermissionsAsync();
setHasCameraPermission(cameraStatus.status === 'granted');
})();
}, []);
const takePicture = async () => {
if (cameraRef) {
try {
const data = await cameraRef.current.takePictureAsync();
console.log(data);
setImage(data.uri);
} catch (error) {
console.log(error);
}
}
};
uriToBase64 = async (uri) => {
let base64 = await FS.readAsStringAsync(uri, {
encoding: FS.EncodingType.Base64,
});
return base64;
};
toServer = async (mediaFile) => {
url = "censored url so that trolls wont use it ";
let response = await FS.uploadAsync(url, mediaFile.uri, {
headers: {
"content-type": "image/jpeg",
},
httpMethod: "POST",
uploadType: FS.FileSystemUploadType.BINARY_CONTENT,
});
console.log(response);
};
const savePicture = async () => {
if (image) {
try {
const asset = await MediaLibrary.createAssetAsync(image);
console.log(typeof image==='undefined')
console.log(typeof asset==='undefined')
console.log(typeof image=='undefined')
console.log(typeof asset=='undefined')
await this.toServer({
type:"image",
base64: uriToBase64(asset),
uri: asset,
});
setImage(null);
console.log('saved successfully');
} catch (error) {
console.log(error);
}
}
};
if (hasCameraPermission === false) {
return <Text>No access to camera</Text>;
}
return (
<View style={styles.container}>
{!image ? (
<Camera
style={styles.camera}
type={type}
ref={cameraRef}
flashMode={flash}
>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 30,
}}
>
<Button
title=""
icon="retweet"
onPress={() => {
setType(
type === CameraType.back ? CameraType.front : CameraType.back
);
}}
/>
<Button
onPress={() =>
setFlash(
flash === Camera.Constants.FlashMode.off
? Camera.Constants.FlashMode.on
: Camera.Constants.FlashMode.off
)
}
icon="flash"
color={flash === Camera.Constants.FlashMode.off ? 'gray' : '#fff'}
/>
</View>
</Camera>
) : (
<Image source={{ uri: image }} style={styles.camera} />
)}
<View style={styles.controls}>
{image ? (
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
paddingHorizontal: 50,
}}
>
<Button
title="Re-take"
onPress={() => setImage(null)}
icon="retweet"
/>
<Button title="Save" onPress={savePicture} icon="check" />
</View>
) : (
<Button title="Take a picture" onPress={takePicture} icon="camera" />
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#000',
padding: 8,
},
controls: {
flex: 0.5,
},
button: {
height: 40,
borderRadius: 6,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
},
text: {
fontWeight: 'bold',
fontSize: 16,
color: '#E9730F',
marginLeft: 10,
},
camera: {
flex: 5,
borderRadius: 20,
},
topControls: {
flex: 1,
},
});

Trying to generate alerts for invalid fetches for cities with OpenWeatherMaps API

So I'm trying to generate alerts for users that attempt to access weather data for invalid cities via the OpenWeatherMaps API.
I'm mostly there. However, when I test this out, two things happen:
Browser generates the proper alert.
However, once you click on the confirmation button for the alert...
"Unhandled Rejection (TypeError): Cannot destructure property 'data' of '(intermediate value)' as it is undefined."
Here is the code that I'm currently using:
const fetchWeather = async (query) => {
const { data } = await axios.get(
URL,
{
params: {
q: query,
units: "metric",
APPID: API_KEY,
},
}).catch (function (error) {
alert(error.response.data.message)
})
};
Full code:
Search.jsx component:
import React, { useState } from "react";
import fetchWeather from "../api/fetchWeather";
import { makeStyles } from "#material-ui/core/styles";
import TextField from "#material-ui/core/TextField";
import InputAdornment from '#material-ui/core/InputAdornment';
import SearchIcon from '#material-ui/icons/Search';
const Search = () => {
let [displayResults, setDisplayResults] = useState(false);
let [query, setQuery] = useState("");
let [feelsLike, setFeelsLike] = useState(0);
let [mainTemp, setMainTemp] = useState(0);
let [description, setDescription] = useState("");
let [main, setMain] = useState("");
let [iconID, setIconID] = useState("");
let [windSpeed, setWindSpeed] = useState("");
let [windGust, setWindGust] = useState("");
let [windDirection, setWindDirection] = useState("");
let [name, setName] = useState("");
let [country, setCountry] = useState("");
const useStyles = makeStyles((theme) => ({
button: {
backgroundColor: "#FDB124",
color: "black",
fontFamily: "Mortal Kombat",
"&:hover": {
background: "#B57602",
},
},
root: {
"& > *": {
display: 'flex',
margin: theme.spacing(1),
// width: "25ch",
},
input: {
color: "white",
},
primary: {
backgroundColor: "#FDB124",
},
"& label.Mui-focused": {
color: "#FDB124",
},
"& label": {
color: "#FDB124",
fontFamily: "Mortal Kombat",
},
"& input": {
color: "#FDB124",
fontFamily: "Mortal Kombat",
},
"& .MuiInput-underline:after": {
borderBottomColor: "#FDB124",
},
"& .MuiOutlinedInput-root": {
"& fieldset": {
borderColor: "#FDB124",
},
"&:hover fieldset": {
borderColor: "#FDB124",
},
"&.Mui-focused fieldset": {
borderColor: "#FDB124",
},
},
},
}));
const weatherSearch = async (e) => {
if (e.key === "Enter") {
const data = await fetchWeather(query);
setDisplayResults(true);
setFeelsLike(data.main.feels_like);
setMainTemp(data.main.temp);
setDescription(data.weather[0].description);
setMain(data.weather[0].main);
setIconID(data.weather[0].icon);
setWindSpeed(data.wind.speed);
setWindGust(data.wind.gust);
setWindDirection(data.wind.deg);
setName(data.name);
setCountry(data.sys.country);
setQuery("");
}
};
const classes = useStyles();
return (
<div>
<h1 className="cityChoose">CHOOSE YOUR CITY:</h1>
<TextField
id="outlined-basic"
label="Enter City"
variant="outlined"
color="secondary"
size="small"
spellCheck="false"
className={classes.root}
value={query}
onChange={(e) => setQuery(e.target.value)}
onKeyPress={weatherSearch}
InputProps={{
startAdornment: (
<InputAdornment position="start" style={{color: "#FDB124"}}>
<SearchIcon />
</InputAdornment>
),
}}
/>
{displayResults ? null : <h4>Example: Chicago, IL, US</h4>}
{displayResults ? (
<>
<h1>The current weather in {name}, {country} is:</h1>
<span>
<div>
{description}
<br />
<img
src={"http://openweathermap.org/img/wn/" + iconID + "#2x.png"}
/>
</div>
<h2>Temperature:</h2>
<br />
<div>
{(mainTemp * 1.8 + 32).toFixed(1)} °F / {mainTemp.toFixed(1)}{" "}
°C
</div>
<br />
<br />
<h2>Winds:</h2>
<div>Wind Direction: {windDirection}</div>
<div>Wind Speed: {windSpeed} MPH</div>
<div>Wind Gusts: {windGust} MPH</div>
</span>
</>
) : null}
</div>
);
};
export default Search;
fetchWeather.jsx:
import React from "react";
import axios from "axios";
const URL = "https://api.openweathermap.org/data/2.5/weather";
const API_KEY = "*key is here*";
const fetchWeather = async (query) => {
const { data } = await axios.get(
URL,
{
params: {
q: query,
units: "metric",
APPID: API_KEY,
},
}).catch (function (error) {
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log("Error: ", error.message);
}
});
console.log(data);
return data;
};
export default fetchWeather;
Ok, so the problem you're having has to do with the fact that axios throws an error and does not return an object with key data back to const { data } = await axios.get(. Fixing this is quite straightforward.
The reason it cannot destructure data from your bad axios call is because you're not accommodating it inside the catch block
.catch (function (error) {
alert(error.response.data.message)
})
Your catch block should instead look like this:
.catch (error => {
return {data: error.response.data ? error.response.data : 'No data'}
}
)
So the final (and working) version of your fetchWeather function is...
const fetchWeather = async (query) => {
const { data } = await axios.get(
'https://httpstat.us/400',
{
params: {
q: query,
units: "metric",
APPID: 'XXXXXXXX',
},
})
.catch (error => {
return {data: error.response.data ? error.response.data : 'No data'}
}
)
console.log(data)
};
You can try it with these two test URLs:
https://httpstat.us/200 returns 200 OK
https://httpstat.us/400 returns 400 Bad Request
The latter will trigger the catch.
Please keep in mind that my code, as written, will throw an error if you're calling a domain that does not resolve to an ip (e.g. http://hskjfhshgsg.com/api/sss/sss or something like that.)
Try to check for the error like this:
if (error.response) {
console.log(error.response.data);
console.log(error.response.status);
console.log(error.response.headers);
} else if (error.request) {
console.log(error.request);
} else {
console.log("Error", error.message);
}
Working sample: https://codesandbox.io/s/openweathermap-test-forked-35781?file=/src/index.js:434-749

React Native Mathematical operation not working properly

I am diving to this question from my previous question here: React Native mathematical actions not working
However, I got the problem from the answer there and updated my code (I know that I did not solve the illegal state modifying, the main system is not working properly).
App.js
import React, { Component } from 'react';
import {
ActivityIndicator,
Text,
View,
StyleSheet,
FlatList,
Alert,
TouchableOpacity,
ScrollView,
TextInput
} from 'react-native';
import {
Avatar,
Card,
Button,
Divider,
ListItem,
Image
} from 'react-native-elements';
import Icon from 'react-native-vector-icons/FontAwesome';
import HTML from 'react-native-render-html';
import UserAvatar from 'react-native-user-avatar';
import { StackNavigator } from 'react-navigation';
import { createAppContainer } from 'react-navigation';
import { createStackNavigator } from 'react-navigation-stack';
import Cookies from 'universal-cookie';
import Heart from './components/heart';
const cookies = new Cookies();
class HomeScreen extends React.Component {
static navigationOptions = {
title: '',
};
constructor(props) {
super(props);
this.state = {
Loading: true,
data: [],
imageUrls: [],
isPress: false,
loveAction: '',
};
}
fetchLeash(user) {
return fetch('https://lishup.com/app/', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ user }),
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({ data: responseJson });
Promise.all(
responseJson.map(({ images }) => this.fetchImage(images))
).then((imageUrls) => this.setState({ imageUrls }));
})
.catch((error) => {
Alert.alert('error!');
})
.finally(() => {
this.setState({ Loading: false });
});
}
fetchImage(image) {
return fetch('https://lishup.com/app/fetch-image.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({ image }),
})
.then((response) => response.json())
.then((responseJson) =>
// Filter elements with empty string URLs, then app just the URL
responseJson.filter(({ url }) => url).map(({ url }) => url)
);
}
componentDidMount() {
this.fetchLeash(cookies.get('user'));
}
heartOnPress = (id, writer) => {
this.setState((state) => {
const data = state.data.map((el) => {
if(el.id === id) {
if(el.isLiked == true){
el.loves = el.loves - 1;
} else {
el.loves = el.loves + 1;
}
el.isliked = !el.isliked;
}
return el;
});
const isPress = !state.isPress
return { data, isPress };
});
fetch('https://lishup.com/app/love.php', {
method: 'POST',
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
id: id,
user: cookies.get('user'),
author: writer
}),
})
.then((response) => response.json())
.then((responseJson) => {
});
};
renderLeash = ({ item, index }) => (
<View>
<Card
style={{
height: 100,
justifyContent: 'center',
alignItems: 'center',
}}>
<ListItem
leftAvatar={{
title: item.user,
source: { uri: item.userpic },
}}
title={item.user}
subtitle={item.time}
chevron
/>
<Divider style={{ margin: 5, backgroundColor: 'white' }} />
<HTML html={item.text} />
<ScrollView
horizontal={true}
>
<View style={{flex:1, flexDirection:'row'}}>
{this.state.imageUrls[index] && this.state.imageUrls[index].length
? this.state.imageUrls[index].map((uri) => (
<Image
source={{ uri }}
style={{ flex:1, width: 500, height: 500, resizeMode: 'contain'}}
PlaceholderContent={<ActivityIndicator />}
/>
))
: null}
</View>
</ScrollView>
<Text>{item.loves}</Text>
<Text>{this.state.loveAction}</Text>
<Heart isLiked={item.isliked} main={item.user} id={item.id} onPress={this.heartOnPress} />
</Card>
</View>
);
render() {
if (this.state.Loading == true) {
cookies.set('user', 'LishUp', { path: '/' });
return (
<ActivityIndicator
size="large"
style={{ marginTop: 100 }}
color="#0000ff"
/>
);
} else {
return (
<View>
<FlatList
style={{ width: 400 }}
data={this.state.data}
keyExtractor={(item, idx) => idx}
renderItem={this.renderLeash}
/>
</View>
);
}
}
}
const styles = StyleSheet.create({});
const RootStack = createStackNavigator(
{
Home: { screen: HomeScreen },
},
{
initialRouteName: 'Home',
}
);
export default createAppContainer(RootStack);
heart.js
import React from 'react';
import { View, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
const Heart = ({ isLiked, onPress, main, id }) => {
return (
<View>
{isLiked ? (
<TouchableOpacity onPress={() => onPress(id, main)}>
<Icon name="heart" size={30} color="red" />
</TouchableOpacity>
) : (
<TouchableOpacity onPress={() => onPress(id, main)}>
<Icon name="heart" size={30} color="grey" />
</TouchableOpacity>
)}
</View>
);
};
export default Heart;
The problem right is: Suppose, there is 2 loves in a post. I pressed love. It just adds 1 beside the number 2 instead of doing an addition. Like- it becomes 21 instead of being 3
I can't understand where is the mistake, does react native avoid this kind of mathematical operation?
My snack: https://snack.expo.io/#nothingtosay/privileged-toffee
First of call you can change you Heart component
import React from 'react';
import { View, TouchableOpacity } from 'react-native';
import Icon from 'react-native-vector-icons/FontAwesome';
const Heart = ({ isLiked, onPress, main, id }) => {
return (
<View>
<TouchableOpacity onPress={() => onPress(id, main)}>
<Icon name="heart" size={30} color={isLiked?"red":"grey"} />
</TouchableOpacity>
</View>
);
};
export default Heart;
and you can parse the el.loves value before adding and subtracting Like this
el.loves = parseInt(el.loves) - 1;
el.loves = parseInt(el.loves) + 1;
It is just treating your “loves” as a string. Convert to number first with parseInt:
if(el.isLiked == true){
el.loves = parseInt(el.loves) - 1;
} else {
el.loves = parseInt(el.loves) + 1;
}

Resources