im using uppy library in reactjs, when i tried to upload many files nothing happened until the files uploaded (when selecting files in the window dialog and before getting files). How can i catch the event when i choosed the files in the window dialog and before getting them?
Sample code is stated as follows;
import { useState } from 'react'
import Uppy from '#uppy/core'
import thumbnailGenerator from '#uppy/thumbnail-generator'
import { DragDrop } from '#uppy/react'
import { Card, CardHeader, CardTitle, CardBody } from 'reactstrap'
const FileUploaderMulti = () => {
const [previewArr, setPreviewArr] = useState([])
const uppy = new Uppy({
meta: { type: 'avatar' },
autoProceed: true
})
uppy.use(thumbnailGenerator)
uppy.on('thumbnail:generated', (file, preview) => {
const arr = previewArr
arr.push(preview)
setPreviewArr([...arr])
})
const renderPreview = () => {
if (previewArr.length) {
return previewArr.map((src, index) => <img key={index} className='rounded mt-2 mr-1' src={src} alt='avatar' />)
} else {
return null
}
}
return (
<Card>
<CardHeader>
<CardTitle tag='h4'> Multiple Files Upload</CardTitle>
</CardHeader>
<CardBody>
<DragDrop uppy={uppy} />
{renderPreview()}
</CardBody>
</Card>
)
}
export default FileUploaderMulti
Related
I'm trying to create a playwright test (in javascript) that uses the page object model of classes, but where the test and page object model aren't in the same directory path.
The problem I'm having is it can't find my page-object-model class file. The error is Error: Cannot find module './pom/home-page'. What am I missing or doing wrong?
My file setup and path structure are as follows:
/package.config.js
...
const config = {
testDir: './test/playwright',
...
/test/playwright/pom/home-page.js
const { expect } = require ('#playwright/test');
exports.HomePage = class HomePage {
constructor(page) {
this.page = page;
this.searchInput = page.locator('#searchInput');
this.searchButton = page.locator('#searchButton');
}
}
/test/playwright/scripts/home/search.spec.js
const {test, expect} = require('#playwright/test');
const {HomePage} = require('./pom/home-page');
test.beforeAll( async ({ page }) => { ... });
test.beforeEach( async ({ page }) => { ... });
test.afterAll( async ({ page }) => { ... });
test.describe( 'As a user I want to search', () => {
test('"mySearchTerm1" and return {the expected result}', async ({ page }) => {
const homePage = new HomePage(page);
...
});
test('"mySearchTerm2" and return {the expected result}', async ({ page }) => {
const homePage = new HomePage(page);
...
});
});
Those using TypeScript can simplify this using tsconfig.json
https://playwright.dev/docs/test-typescript#manually-compile-tests-with-typescript
in tsconfig add:
"baseUrl": ".",
"paths":{
"#pages/*":[
"/test/playwright/pom/*"
]
}
Then you can import it in your fixture or test file like this:
import { HomePage } from "#pages/home-page"
This can be used to shorten fixtures or other files.
So, apparently the file reference is relative to the directory the test is located, not the testDir directory defined in the config file. I need to change line 2 in search.spec.js
const {HomePage} = require('../../pom/home-page');
I am trying to create a delete functionality in my application which seems to be deleting the object from the backend just fine, but not in the frontend.
Here is how I structured my project:
in actions/deleteJournal.js
export const deleteJournal = (journal) => {
return dispatch => {
fetch(`http://localhost:3001/journals/${journal.id}` , {
method: "DELETE" })
.then(resp => resp.json())
.then(journal => { dispatch({ type: "DELETE_JOURNAL", journal })
})
}
}
in reducers/journalsReducer.js
const initialState = {
journals: [],
loading: true
}
const journalsReducer = (state=initialState, action) => {
switch(action.type) {
case "LOADING":
return {
...state,
loading: true
}
case "SET_JOURNALS":
return {
...state,
loading: false,
journals: action.journals
}
case "ADD_JOURNAL":
return {
...state,
journals: [...state.journals, action.journal],
}
case 'DELETE_JOURNAL':
return {
journals: state.journals.filter(todo => todo.id !== action.id),
...state
}
default:
return state;
}
}
export default journalsReducer
in components/List.js
import React, { Component } from 'react'
import { connect } from 'react-redux'
import Journal from './Journal'
import { deleteJournal } from '../actions/getJournals'
class ListFiltered extends Component {
render() {
const journals = this.props.journals.map( journal => journal.locationId === this.props.locationId && <Journal key={journal.id} title={journal.title} content={journal.content} id={journal.id} deleteJournal={this.props.deleteJournal} />)
return (
<div>
{journals}
<p></p>
</div>
)
}
}
const mapStateToProps = state => {
return {
journals: state.journals
}
}
export default connect(mapStateToProps, {deleteJournal})(ListFiltered)
in components/Journal.js
class Journal extends Component {
render() {
const { id, title, content } = this.props;
return (
<div>
<ul>
<li>
<h3>{ title } </h3>
<p> { content }</p> <button onClick={() => this.props.deleteJournal(this.props) }>Delete</button>
</li>
</ul>
</div>
)
}
}
export default Journal
So this seems to be giving me an error " Uncaught (in promise) SyntaxError: Unexpected end of JSON input
at deleteJournal.js:48"
I checked my server and it seems to be deleting it from there but nothing in the frontend and when I refresh the item is deleted.
What can I do so it automatically deletes the item from the frontend?
I suspect the issue may be with your line
.then(resp => resp.json())
What is the body of the response when you issue the DELETE request? If it's not a valid JSON object, then JavaScript would throw the error you're seeing.
As you're not using the parsed JSON at all, you could conceivably remove that line:
export const deleteJournal = (journal) => {
return dispatch => {
fetch(`http://localhost:3001/journals/${journal.id}` , {
method: "DELETE" })
.then(journal => { dispatch({ type: "DELETE_JOURNAL", journal })
})
}
}
...but you might want to have some of checking that the DELETE method was executed successfully.
How you do that's up to you and your Rails API, but I'd typically expect to see the response have an HTTP status in the 2xx range when something is successfully deleted, and in the 4xx range if something couldn't be deleted (e.g., if the ID wasn't recognised, or there were dependency issues which meant the deletion request was rejected). That feels outside the scope of this question though.
I am having an extremely weird issue where I don't even know where to begin to debug since it only happens when I get the app into test flight. Basically I am trying to load channels based on geolocation. Some automatically load and then some are loaded if less than 100 miles from a mountain (lets call these PUBLIC and PRIVATE channels- both of which are in the same list). I have these 2 firebase calls in my action creator and push them into an array and then call dispatch after. I have an issue with the FlatList where it loads the PUBLIC channels and only when I scroll do the PRIVATE channels. There are a bunch of things I have tried including the most common from that specific github issue (flatlist updating) 'removeClippedSubviews={false}', extra data, pure components, etc, but none have worked.
Instead I found a way to get around this (I know it isn't the best, but I just want a solution that works for now) by just setting a timeout and waiting for the channels before dispatching the action:
setTimeout(function(){ dispatch(loadPublicChannelsSuccess(data)); }, 10);
Unfortunately, now is when the crazy issue comes in. Basically, this works for debug, release/ everything I have tried with XCode, but when it gets to my device the render method basically sits at a loading indicator until I switch tabs with react navigation. This makes no sense to me since it doesn't happen always (maybe 80%) of the time, and only in test flight so far. I had never seen this before setting the timeout either so not really sure where to begin:
render() {
const {loadPublicChannels, loading, publicChannels, checkedInMountain, selectedMountain} = this.props;
return !loadPublicChannels && publicChannels && !loading
? (
<MessagePanelPublic publicChannels={publicChannels} selectedMountain={selectedMountain}/>
) : (
<LoadingAnimation />
);
}
actions
export const getUserPublicChannels = () => {
return (dispatch, state) => {
dispatch(loadPublicChannels());
// get all mountains within distance specified
let mountainsInRange = state().session.mountainsInRange;
// get the user selected mountain
let selectedMountain = state().session.selectedMountain;
// see if the selected mountain is in range to add on additional channels
let currentMountain;
mountainsInRange
? (currentMountain =
mountainsInRange.filter(mountain => mountain.id === selectedMountain)
.length === 1
? true
: false)
: (currentMountain = false);
// mountain public channels (don't need to be within distance)
let currentMountainPublicChannelsRef = FIREBASE_REF_CHANNEL_INFO.child(
"Public"
)
.child(`${selectedMountain}`)
.child("Public");
// mountain private channels- only can see if within range (geolocation)
let currentMountainPrivateChannelsRef = FIREBASE_REF_CHANNEL_INFO.child(
"Public"
)
.child(`${selectedMountain}`)
.child("Private");
// get public channels
return currentMountainPublicChannelsRef
.orderByChild("key")
.once("value")
.then(snapshot => {
let publicChannelsToDownload = [];
snapshot.forEach(channelSnapshot => {
let channelId = channelSnapshot.key;
let channelInfo = channelSnapshot.val();
// add the channel ID to the download list
publicChannelsToDownload.push({ id: channelId, info: channelInfo });
});
// if mountain exists then get private channels/ if in range
if (currentMountain) {
currentMountainPrivateChannelsRef
.orderByChild("key")
.once("value")
.then(snapshot => {
snapshot.forEach(channelSnapshot => {
let channelId = channelSnapshot.key;
let channelInfo = channelSnapshot.val();
publicChannelsToDownload.push({
id: channelId,
info: channelInfo
});
});
});
}
return publicChannelsToDownload;
})
.then(data => {
setTimeout(function(){ dispatch(loadPublicChannelsSuccess(data)); }, 10);
});
};
};
reducer related to public channels
case types.LOAD_PUBLIC_CHANNELS:
return {
...state,
loadPublicChannels: true
};
case types.LOAD_PUBLIC_CHANNELS_SUCCESS:
console.log("PUBLIC");
console.log(action.publicChannels);
console.log(action);
return {
...state,
publicChannels: action.publicChannels,
loadPublicChannels: false,
messages: {}
};
case types.LOAD_PUBLIC_CHANNELS_ERROR:
return {
...state,
channelsPublicError: action.error,
loadPublicChannels: false
};
container which calls mapStateToProps and mapDispatchToProps
class MessagePanelPublicContainer extends Component {
constructor(props) {
super(props);
}
// get public and private channels from redux
async componentDidMount() {
this.props.getUserPrivateChannels();
this.props.loadCurrentUser();
// this.props.getUserPublicChannels();
}
componentDidUpdate(prevProps) {
if (this.props.mountainsInRange && prevProps.mountainsInRange !== this.props.mountainsInRange || prevProps.selectedMountain !== this.props.selectedMountain) {
this.props.getUserPublicChannels();
}
}
lessThan12HourAgo = (date) => {
return moment(date).isAfter(moment().subtract(12, 'hours'));
}
render() {
const {loadPublicChannels, loading, publicChannels, checkedInMountain, selectedMountain} = this.props;
return !loadPublicChannels && publicChannels && !loading
? (
<MessagePanelPublic publicChannels={publicChannels} selectedMountain={selectedMountain}/>
) : (
<LoadingAnimation />
);
}
}
const mapStateToProps = state => {
return {
publicChannels: state.chat.publicChannels,
loadPublicChannels: state.chat.loadPublicChannels,
currentUser: state.chat.currentUser,
loading: state.chat.loadCurrentUser,
mountainsInRange: state.session.mountainsInRange,
selectedMountain: state.session.selectedMountain,
};
}
const mapDispatchToProps = {
loadCurrentUser,
getUserPublicChannels,
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(MessagePanelPublicContainer);
component
import React, { Component } from "react";
import { View, Text, FlatList, ImageComponent } from "react-native";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { ListItem, Icon, Button } from "react-native-elements";
import { withNavigation } from "react-navigation";
import LinearGradient from "react-native-linear-gradient";
import styles from "./Styles";
import moment from 'moment';
import FastImage from 'react-native-fast-image';
class MessagePanelPublicComponent extends Component {
render() {
// rendering all public channels
const renderPublicChannels = ({ item }) => {
return (
<ListItem
leftAvatar={{
source: { uri: item.info.ChannelPicture },
rounded: false,
overlayContainerStyle: { backgroundColor: "white" },
ImageComponent: FastImage
}}
title={item.info.Name}
titleStyle={styles.title}
chevron={true}
bottomDivider={true}
id={item.Name}
containerStyle={styles.listItemStyle}
/>
);
};
const renderText = () => {
return (
<View style={styles.extraTextContainer}>
<Text style={styles.extraText}>
Get within 100 miles from resort or select a closer resort to see more channels...
</Text>
<Icon
name="map-marker"
type="font-awesome"
size={40}
iconStyle={styles.extraIcon}
/>
</View>
);
};
return (
<View style={styles.container}>
<View style={styles.channelList}>
<FlatList
data={this.props.publicChannels}
renderItem={renderPublicChannels}
// keyExtractor={item => item.Name}
keyExtractor={(item, index) => index.toString()}
extraData={this.props.publicChannels}
removeClippedSubviews={false}
/>
{this.props.publicChannels.length < 3 ? renderText() : null}
</View>
</View>
);
}
}
We are using firebase deeplinks in a react native application built for both iOS and Android.
Example deeplink: https://monedacacao.page.link/RifKomEk3bhNM9CW9?d=1
Expected behavior:
User scans a QR Code that contains a deeplink in QRScannerScreen
onSuccess (e) is triggered and the link is opened using Linking.openUr()
In ReduxNavigation Firebase.links().onLink() is triggered and redirects the user to SendDestinataryScreen
Actual behavior
In Android this works as intended, but on iOS Linking.openURL(e.data) opens a browser with the Firebase fallback link instead of triggering the Firebase.links.onLin() action.
If the link is clicked from outside the application it behaves as intended. So this problem only occurs when opening the link from inside the application.
QRScannerScreen.js
...
onSuccess (e) {
Linking
.openURL(e.data)
.catch(err => console.error('An error occured', err))
}
...
ReduxNavigation.js
import React from 'react'
import { BackHandler, Platform } from 'react-native'
import { addNavigationHelpers, NavigationActions } from 'react-navigation'
import { createReduxBoundAddListener } from 'react-navigation-redux-helpers'
import { connect } from 'react-redux'
import firebase from 'react-native-firebase'
import AppNavigation from './AppNavigation'
class ReduxNavigation extends React.Component {
constructor (props) {
super(props)
// handle deeplinking
firebase.links().onLink((url) => {
console.log('URL', url)
if (this.props.token) {
this.props.dispatch(NavigationActions.push({
routeName: 'SendDestinataryScreen',
params: { link: url }
}))
} else {
this.props.dispatch(NavigationActions.push({
routeName: 'LoginScreen'
}))
}
})
}
componentDidMount () {
if (Platform.OS === 'ios') return
BackHandler.addEventListener('hardwareBackPress', () => {
const { dispatch, nav } = this.props
// change to whatever is your first screen, otherwise unpredictable results may occur
if (nav.routes.length === 1 && (nav.routes[0].routeName === 'LaunchScreen')) {
return false
}
// if (shouldCloseApp(nav)) return false
dispatch({ type: 'Navigation/BACK' })
return true
})
}
componentWillUnmount () {
if (Platform.OS === 'ios') return
BackHandler.removeEventListener('hardwareBackPress')
}
render () {
return <AppNavigation navigation={addNavigationHelpers({ dispatch: this.props.dispatch, state: this.props.nav, addListener: createReduxBoundAddListener('root') })} />
}
}
const mapStateToProps = state => ({ nav: state.nav, token: state.authentication.token })
export default connect(mapStateToProps)(ReduxNavigation)
I created a test using shallow that work fine locally, but when it's running in circleci in the bitbucket pull request didn't worked. When I changed the test to use mount it work fine locally and in the circleci. Any one have any idea of the reason of this?
Original test:
import React from 'react'
import { shallow } from 'enzyme'
import { Dashboard } from './../Dashboard'
describe('Dashboard', () => {
const wrapper = shallow(<Dashboard />)
it('has a header', () => {
const currentHeader = wrapper.find('Header')
expect(currentHeader.length).toEqual(1)
})
it('has a subHeader', () => {
const currentSubHeader = wrapper.find('SubHeader')
expect(currentSubHeader.length).toEqual(1)
})
it('has a content', () => {
const currentContent = wrapper.find('.sn-layout__content')
expect(currentContent.length).toEqual(1)
})
})
Modified test:
import React from 'react'
import { mount } from 'enzyme'
import { Dashboard } from './../Dashboard'
describe('Dashboard', () => {
const wrapper = mount(<Dashboard />)
it('has a header', () => {
const currentHeader = wrapper.find('.sn-layout__header')
expect(currentHeader.length).toEqual(1)
})
it('has a subHeader', () => {
const currentSubHeader = wrapper.find('.sn-layout__subheader')
expect(currentSubHeader.length).toEqual(1)
})
it('has a content', () => {
const currentContent = wrapper.find('.sn-layout__content')
expect(currentContent.length).toEqual(1)
})
})