monitor.getDropResult() returns null (I look it console.log). It should return object(dragged item) with its position. Why does it return null?
I signature my component with DragSource,DropTarget..but it still returns null
Here is my entire component code:
import React, { PropTypes } from 'react';
import { DragSource } from 'react-dnd';
import { getEmptyImage } from 'react-dnd-html5-backend';
import { StoneConstants, StoneTypes, ItemTypes } from 'constants/AppConstants';
import OkeyStoneBase from 'components/OkeyStoneBase/OkeyStoneBase';
import './_OkeyStone.scss';
function checkForDragAction(props) {
// TODO receive the action via prop
if (props.stoneType === StoneTypes.ON_WITHDRAW_MIDDLE) {
props.onWithdrawMiddle();
} else if (props.stoneType === StoneTypes.ON_DISCARD_WEST) {
props.onWithdrawLeft();
}
}
function applyDropResult(props, result) {
if (props.stoneType === StoneTypes.ON_WITHDRAW_MIDDLE || props.stoneType === StoneTypes.ON_DISCARD_WEST) {
if (result === null) { //taşı tahtaya koymadıysa
}
props.withdrawRequestAtPosition(result.top, result.left);
}
if (props.stoneType === StoneTypes.ON_RAKE) {
if (result && result.stackType === StoneTypes.ON_DISCARD_SOUTH) {
props.onDiscardStone({
id: props.id,
number: props.number,
color: props.color
});
}
}
}
const stoneSource = {
canDrag(props) {
return props.draggable;
},
beginDrag(props) {
if (props.onBeginDrag) {
props.onBeginDrag();
}
checkForDragAction(props);
return {
id: props.id,
stoneType: props.stoneType,
left: props.left,
top: props.top,
color: props.color,
number: props.number
};
},
endDrag(props, monitor) {
if (props.onEndDrag) {
props.onEndDrag();
}
console.log(props.onEndDrag);
console.log(monitor);
***var result = monitor.getDropResult();***
console.log('stoneSource'+result);
applyDropResult(props, result);
}
};
function collect(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(),
isDragging: monitor.isDragging()
};
}
function getStyles(props) {
const scale = StoneConstants.MINI_SCALE;
let { left, top, isDragging, isMini } = props;
const { zIndex } = props;
const { canTransition } = props;
let transform = `translate3d(${left}px, ${top}px, 0)`;
if (isMini) {
transform += ` scale(${scale}, ${scale})`;
}
let result = {
transformOrigin: 'top left',
transform: transform,
WebkitTransform: transform,
zIndex: zIndex,
opacity: isDragging ? 0 : 1,
height: isDragging ? 0 : ''
};
if (isDragging || !canTransition) {
result.transition = 'none';
}
return result;
}
class OkeyStone extends React.Component {
handleStoneClick (e) {
const { id, onClicked } = this.props;
if (onClicked) {
e.stopPropagation();
onClicked(id);
}
}
componentDidMount() {
this.props.connectDragPreview(getEmptyImage(), {
captureDraggingState: true
});
}
render() {
let { connectDragSource } = this.props;
let { number, color } = this.props;
let { isStable, isSelected } = this.props;
let stableStyle = isStable ? 'okey-stone-stable' : '';
return connectDragSource(
<div className={'okey-stone-parent ' + stableStyle}
onClick={this.handleStoneClick}
style={getStyles(this.props)}>
<OkeyStoneBase number={number} color={color} isSelected={isSelected}/>
</div>
);
}
}
OkeyStone.propTypes = {
connectDragSource: PropTypes.func,
connectDragPreview: PropTypes.func,
isDragging: PropTypes.bool,
id: PropTypes.number,
left: PropTypes.number,
top: PropTypes.number,
stoneType: PropTypes.string,
isStable: PropTypes.bool,
isMini: PropTypes.bool
};
export default DragSource(ItemTypes.STONE, stoneSource, collect)(OkeyStone);
You need to create a DropTarget and define a drop() function within its source, and whatever that returns will be what is returned by the monitor.getDropResult() function inside of the DragSource's endDrag() function (per http://gaearon.github.io/react-dnd/docs-drag-source-monitor.html). I'm not sure what you'd like the component itself to look like, but if you created a DropTarget with a drop function resembling:
const stoneDropSource = {
drop(props, monitor) {
return monitor.getItem();
},
}
Then that is what you would receive from calling getDropResult() in the endDrag() function.
Related
I have an issue with my React application (with Redux Saga), I'm getting the console error:
The service worker navigation preload request was cancelled before 'preloadResponse' settled. If you intend to use 'preloadResponse', use waitUntil() or respondWith() to wait for the promise to settle.
I see this error on the console only on Chrome, not in Firefox or Edge.
This error does not affect my application.
The following steps reproduce the error:
1. Main page upload.
2. Go to movie details page.
3. Go back to main page.
Main.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { mainActions } from '../../store/actions/actions';
import './Main.scss';
import { MoviesList, SearchPanel } from '../../components';
const propTypes = {};
const defaultProps = {};
class Main extends Component {
constructor(props) {
super(props);
this.handleSearchTextChange = this.handleSearchTextChange.bind(this);
this.handleLoadMoreButtonClick = this.handleLoadMoreButtonClick.bind(this);
this.handleMovieClick = this.handleMovieClick.bind(this);
this.handleFavoriteMovieClick = this.handleFavoriteMovieClick.bind(this);
}
componentDidMount() {
this.handleComponentDidMount();
}
handleComponentDidMount() {
const { moviesList } = this.props;
if (!moviesList || moviesList.length <= 0) {
this.getMovies(null, false);
}
}
handleLoadMoreButtonClick() {
this.getMovies(null, false);
}
handleMovieClick(e) {
if (e.target.className === 'movie') {
this.props.history.push(`/details/${e.currentTarget.dataset.id}`);
}
}
handleSearchTextChange(e) {
const { pageNumber, favoriteMoviesList } = this.props;
this.props.onSearchTextChange({
searchText: e.target.value,
pageNumber: pageNumber,
favoriteMoviesList: favoriteMoviesList
});
}
handleFavoriteMovieClick(e) {
const { id, name, posterId } = e.currentTarget.dataset;
const { moviesList, favoriteMoviesList } = this.props;
this.props.onUpdateFavoriteMovies({
updatedMovie: { id: id, name: name, posterId: posterId },
favoriteMoviesList: favoriteMoviesList,
moviesList: moviesList
});
}
getMovies(updatedSearchText, isSearchChange) {
const { searchText, pageNumber, favoriteMoviesList } = this.props;
this.props.onLoadMovies({
pageNumber: pageNumber,
favoriteMoviesList: favoriteMoviesList,
updatedSearchText: isSearchChange ? updatedSearchText : searchText,
isSearchChange: isSearchChange
});
}
render() {
const { searchText, isLoadingMoreMovies, isPager, moviesList } = this.props;
return (
<div className="main-area">
<SearchPanel
searchText={searchText}
onSearchTextChange={this.handleSearchTextChange}
/>
<MoviesList
pageName='movies'
moviesList={moviesList}
isLoadingMoreMovies={isLoadingMoreMovies}
isPager={isPager}
onLoadMoreClick={this.handleLoadMoreButtonClick}
onMovieClick={this.handleMovieClick}
onFavoriteMovieClick={this.handleFavoriteMovieClick}
/>
</div>
);
}
}
Main.propTypes = propTypes;
Main.defaultProps = defaultProps;
const mapStateToProps = (state) => {
return {
searchText: state.main.searchText,
pageNumber: state.main.pageNumber,
isLoadingMoreMovies: state.main.isLoadingMoreMovies,
isPager: state.main.isPager,
moviesList: state.main.moviesList,
favoriteMoviesList: state.main.favoriteMoviesList
};
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadMovies: (request) => dispatch(mainActions.loadMovies(request)),
onSearchTextChange: (request) => dispatch(mainActions.searchTextChange(request)),
onUpdateFavoriteMovies: (request) => dispatch(mainActions.updateFavoriteMovies(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Main);
Details.jsx
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { detailsActions, mainActions } from '../../store/actions/actions';
import './Details.scss';
import { ActorsList, ButtonClick, CrewsList, FeaturesList, PageTitle, ProductionsList, Rating, Trailer } from '../../components';
import movieUtils from '../../utils/movie.utils';
const propTypes = {};
const defaultProps = {};
class Details extends Component {
constructor(props) {
super(props);
this.handleBackClick = this.handleBackClick.bind(this);
this.handleFavoriteMovieClick = this.handleFavoriteMovieClick.bind(this);
this.isFavorite = false;
}
componentDidMount() {
this.handleComponentDidMount();
}
handleComponentDidMount() {
if (this.props.moviesList.length <= 0) {
this.handleBackClick();
return;
}
const movieId = this.props.match.params.id;
if (!movieId) {
this.handleBackClick();
return;
}
this.props.onLoadMovieDetails(movieId);
this.updateIsFavorite(movieId);
}
numberWithCommas(number) {
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
}
updateIsFavorite(movieId) {
this.isFavorite = this.props.favoriteMoviesList.findIndex(movie => parseInt(movie.id) === parseInt(movieId)) > -1;
}
handleBackClick() {
this.props.history.push(`/`);
}
handleFavoriteMovieClick() {
const { movie, moviesList, favoriteMoviesList } = this.props;
this.props.onUpdateFavoriteMovies({
updatedMovie: { id: movie.id, name: movie.title, posterId: movie.poster_path },
favoriteMoviesList: favoriteMoviesList,
moviesList: moviesList
});
this.updateIsFavorite(movie.id);
}
render() {
const { movie, youtubeKey, credits } = this.props;
if (!movie) {
return null;
}
const { adult, poster_path, budget, genres, homepage, imdb_id, original_language, original_title,
overview, popularity, production_companies, production_countries, release_date, revenue, runtime, spoken_languages,
status, tagline, title, video, vote_average, vote_count } = movie;
const genresText = genres.map(genre => genre.name).join(', ');
const countriesText = production_countries.map(country => country.name).join(', ');
const languagesText = spoken_languages.map(language => language.name).join(', ');
const featuresList = [
{ item: 'Release Date', value: release_date },
{ item: 'Budget', value: `$${this.numberWithCommas(budget)}` },
{ item: 'Revenue', value: `$${this.numberWithCommas(revenue)}` },
{ item: 'Length', value: `${runtime} minutes` },
{ item: 'Popularity', value: popularity },
{ item: 'Original Title', value: original_title },
{ item: 'For Adults', value: adult ? 'Yes' : 'No' },
{ item: 'Original Language', value: original_language },
{ item: 'Spoken Languages', value: languagesText },
{ item: 'Countries', value: countriesText },
{ item: 'Status', value: status },
{ item: 'Is Video', value: video ? 'Yes' : 'No' }
];
const linksList = [];
if (homepage) {
linksList.push({ id: 1, name: 'Homepage', url: homepage });
}
if (imdb_id) {
linksList.push({ id: 2, name: 'IMDB', url: `https://www.imdb.com/title/${imdb_id}` });
}
const actorsList = movieUtils.removeDuplicates(credits ? credits.cast ? credits.cast : null : null, 'name');
const crewsList = movieUtils.removeDuplicates(credits ? credits.crew ? credits.crew : null : null, 'name');
return (
<div>
<section className="details-area">
<PageTitle
pageName='details'
pageTitle='Details'
/>
<ul className="details-content">
<li className="details-left" style={{ backgroundImage: `url('https://image.tmdb.org/t/p/original${poster_path}')` }}></li>
<li className="details-right">
<h2>{title} ({release_date.substr(0, 4)})</h2>
<p className="genres">{genresText}</p>
<p className="description short">{tagline}</p>
<Rating
rating={vote_average}
votesCount={this.numberWithCommas(vote_count)}
/>
<p className="description full">{overview}</p>
<div className="extra">
<FeaturesList
featuresList={featuresList.slice(0, 5)}
linksList={null}
isFavorite={this.isFavorite}
onFavoriteMovieClick={this.handleFavoriteMovieClick}
/>
{youtubeKey && <Trailer
youtubeKey={youtubeKey}
/>}
</div>
</li>
<div className="extra-features">
<FeaturesList
featuresList={featuresList.slice(5, featuresList.length)}
linksList={linksList}
isFavorite={null}
onFavoriteMovieClick={null}
/>
<ProductionsList
productionsList={production_companies}
/>
</div>
</ul>
</section>
<section className="actors-area">
<PageTitle
pageName='actors'
pageTitle='Cast'
/>
<ActorsList
actorsList={actorsList}
/>
</section>
<section className="crew-area">
<PageTitle
pageName='crew'
pageTitle='Crew'
/>
<CrewsList
crewsList={crewsList}
/>
</section>
<ButtonClick
buttonText={'Back'}
buttonTitle={'Back'}
isLoading={false}
onClick={this.handleBackClick}
/>
</div>
);
}
}
Details.propTypes = propTypes;
Details.defaultProps = defaultProps;
const mapStateToProps = (state) => {
return {
movie: state.details.movie,
youtubeKey: state.details.youtubeKey,
credits: state.details.credits,
moviesList: state.main.moviesList,
favoriteMoviesList: state.main.favoriteMoviesList
};
};
const mapDispatchToProps = (dispatch) => {
return {
onLoadMovieDetails: (movieId) => dispatch(detailsActions.loadDetails(movieId)),
onUpdateFavoriteMovies: (request) => dispatch(mainActions.updateFavoriteMovies(request))
};
};
export default connect(mapStateToProps, mapDispatchToProps)(Details);
What I already looked in:
Getting The service worker navigation preload request was cancelled before 'preloadResponse' settled
https://learn.microsoft.com/en-us/answers/questions/108004/getting-the-service-worker-navigation-preload-requ.html
https://support.google.com/mail/thread/4055804?hl=en
https://love2dev.com/pwa/service-worker-preload/
I tried to put this on Details.jsx page, but it didn't work:
self.addEventListener('fetch', event => {
event.respondWith(async function () {
// Respond from the cache if we can
const cachedResponse = await caches.match(event.request);
if (cachedResponse) return cachedResponse; // Else, use the preloaded response, if it's there
const response = await event.preloadResponse;
if (response) return response; // Else try the network.
return fetch(event.request);
}());
});
self.addEventListener('activate', event => {
event.waitUntil(async function () {
// Feature-detect
if (self.registration.navigationPreload) { // Enable navigation preloads!
console.log('Enable navigation preloads!');
await self.registration.navigationPreload.enable();
} return;
})();
});
How can I solve this issue? Thanks.
Had same error, even my iframe wasn't loading..whatever video you are using from youtube use nocookie/embed in url. It's working for me.
Try changing https://www.youtube.com/watch?v=i8eBBG46H8A to
https://www.youtube-nocookie.com/embed/i8eBBG46H8A
Hope nocookie & embed helps..!!
I have a method to submit the edited form, but when I'm clicking submit button, nothing happens. Via the console I figured out, that eventIndex = -1. What should I fix in the code below?
editEvent(event) {
const { currentUser, editGoogleCalendarEvent, calendarEvents } = this.props;
const {
events } = this.state;
let onlyDate = false;
console.log('event', event);
console.log('calendarEvents', calendarEvents);
const idx = events.indexOf(event);
const eventIndex = _.findIndex(calendarEvents.details.items, { id: event.id });
const editedEvent = { ...event };
console.log('Event Index', eventIndex);
const nextEvents = [...events];
nextEvents.splice(idx, 1, editedEvent);
if (eventIndex !== -1) {
const item = calendarEvents.details.items[eventIndex];
if (item.start.date && item.end.date) {
editedEvent.start = moment(event.start).format('YYYY-MM-DD');
editedEvent.end = moment(event.end).format('YYYY-MM-DD');
onlyDate = true;
}
}
this.setState({
events: nextEvents,
}, () => {
console.log('Object', { id: event.event.id, title: event.formValues.title, userId: currentUser.id, timezone: currentUser.timezone, onlyDate });
editGoogleCalendarEvent({
id: event.event.id,
start: moment(event.event.start).hours(event.formValues.period === 'AM' ? event.formValues.hour % 12 : (event.formValues.hour % 12) + 12).minutes(event.formValues.minute).toISOString(),
end: moment(event.event.end).hours(event.formValues.period === 'AM' ? event.formValues.hour % 12 : (event.formValues.hour % 12) + 12).minutes(event.formValues.minute).toISOString(),
title: event.formValues.title,
userId: currentUser.id,
timezone: currentUser.timezone,
onlyDate,
});
});
}
Form:
<EditCalendarEventForm
show={this.state.editShow}
isSubmitting={editEventProcess.isSubmitting}
calendarEvent={this.state.calendarEvent}
onSubmit={this.editEvent}
onHide={this.hideEditEventModal}
/>
Here is the whole page, maybe you will understand the situation better with it. Also I have an EditFormPage and api to work with the requests.
I was using moveEvent as an example to create editEvent method.
import React, { PropTypes } from 'react';
import moment from 'moment-timezone';
import Helmet from 'react-helmet';
import _ from 'lodash';
import { connect } from 'react-redux';
import { createStructuredSelector } from 'reselect';
import { GoogleLogin, GoogleLogout } from 'react-google-login';
import { reduxForm, reset } from 'redux-form';
import BigCalendar from 'react-big-calendar';
import withDragAndDrop from 'react-big-calendar/lib/addons/dragAndDrop';
import 'react-big-calendar/lib/less/styles.less';
import 'react-big-calendar/lib/addons/dragAndDrop/styles.less';
import AddCalendarEventForm from '../../../app/components/AddCalendarEventForm';
import EditCalendarEventForm from '../../../app/components/EditCalendarEventForm';
import { translate } from '../../../common/utilities/localization';
import {
selectCurrentUser,
selectCurrentGoogleUser,
} from '../../containers/App/selectors';
import {
submitGoogleAuth,
fetchGoogleCalendarEvents,
editGoogleCalendarEvent,
addGoogleCalendarEvent,
} from './actions';
import {
selectGoogleAuth,
selectCalendarEvents,
selectAddEventProcess,
selectEditEventProcess,
} from './selectors';
const formName = 'addCalendarEvent';
const formNameEdit = 'editCalendarEvent';
const DragAndDropCalendar = withDragAndDrop(BigCalendar);
const localizer = BigCalendar.momentLocalizer(moment);
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser(),
currentGoogleUser: selectCurrentGoogleUser(),
googleAuth: selectGoogleAuth(),
calendarEvents: selectCalendarEvents(),
addEventProcess: selectAddEventProcess(),
editEventProcess: selectEditEventProcess(),
});
const mapDispatchToProps = (dispatch) => ({
submitGoogleAuth: (externalUserId, googleToken) => dispatch(submitGoogleAuth(externalUserId, googleToken)),
fetchGoogleCalendarEvents: (data) => dispatch(fetchGoogleCalendarEvents(data)),
editGoogleCalendarEvent: (data) => dispatch(editGoogleCalendarEvent(data)),
addGoogleCalendarEvent: (data) => dispatch(addGoogleCalendarEvent(data)),
resetForm: () => dispatch(reset(formName)),
resetEditForm: () => dispatch(reset(formNameEdit)),
});
#reduxForm({
form: formName,
})
#connect(mapStateToProps, mapDispatchToProps)
export default class CalendarPage extends React.Component {
static propTypes = {
currentUser: PropTypes.any,
currentGoogleUser: PropTypes.any,
submitGoogleAuth: PropTypes.func.isRequired,
googleAuth: PropTypes.object,
fetchGoogleCalendarEvents: PropTypes.func,
calendarEvents: PropTypes.object,
editGoogleCalendarEvent: PropTypes.func,
addGoogleCalendarEvent: PropTypes.func,
addEventProcess: PropTypes.object,
editEventProcess: PropTypes.object,
resetForm: PropTypes.func,
resetEditForm: PropTypes.func,
};
constructor(props) {
super(props);
this.state = {
events: [],
show: null,
calendarEvent: null,
editShow: null,
};
this.onSuccess = this.onSuccess.bind(this);
this.onFailure = this.onFailure.bind(this);
this.moveEvent = this.moveEvent.bind(this);
this.editEvent = this.editEvent.bind(this);
this.newEvent = this.newEvent.bind(this);
this.showEventModal = this.showEventModal.bind(this);
this.showEditEventModal = this.showEditEventModal.bind(this);
this.hideEventModal = this.hideEventModal.bind(this);
this.hideEditEventModal = this.hideEditEventModal.bind(this);
}
componentDidMount() {
const { currentUser, currentGoogleUser } = this.props;
if (currentGoogleUser && currentGoogleUser.expires_at && moment(currentGoogleUser.expires_at).isAfter(moment())) {
this.props.fetchGoogleCalendarEvents({ ...currentGoogleUser, userId: currentUser.id });
}
}
componentWillReceiveProps(nextProps) {
if (nextProps.currentGoogleUser !== this.props.currentGoogleUser) {
this.props.fetchGoogleCalendarEvents({ ...nextProps.currentGoogleUser, userId: nextProps.currentUser.id });
}
if (nextProps.calendarEvents && nextProps.calendarEvents.details) {
const events = [];
for (const item of nextProps.calendarEvents.details.items) {
if (item.start && item.end) {
events.push({
id: item.id,
title: item.summary,
start: moment(item.start.dateTime || item.start.date),
end: moment(item.end.dateTime || item.end.date),
});
}
}
this.setState({ events });
}
if (!nextProps.addEventProcess.isSubmitting && this.props.addEventProcess.isSubmitting) {
this.hideEventModal();
}
if (!nextProps.editEventProcess.isSubmitting && this.props.editEventProcess.isSubmitting) {
this.hideEventModal();
}
}
onSuccess(ev) {
const { submitGoogleAuth, currentUser } = this.props;
submitGoogleAuth(currentUser.id, { ...ev.tokenObj, profileEmail: ev.profileObj.email });
}
onFailure(ev) {
console.log('onFailure', ev);
}
moveEvent({ event, start, end, isAllDay: droppedOnAllDaySlot }) {
const { currentUser, editGoogleCalendarEvent, calendarEvents } = this.props;
const { events } = this.state;
let onlyDate = false;
const idx = events.indexOf(event);
const eventIndex = _.findIndex(calendarEvents.details.items, { id: event.id });
let allDay = event.allDay;
if (!event.allDay && droppedOnAllDaySlot) {
allDay = true;
} else if (event.allDay && !droppedOnAllDaySlot) {
allDay = false;
}
const updatedEvent = { ...event, start, end, allDay };
const nextEvents = [...events];
nextEvents.splice(idx, 1, updatedEvent);
if (eventIndex !== -1) {
const item = calendarEvents.details.items[eventIndex];
if (item.start.date && item.end.date) {
updatedEvent.start = moment(start).format('YYYY-MM-DD');
updatedEvent.end = moment(end).format('YYYY-MM-DD');
onlyDate = true;
}
}
this.setState({
events: nextEvents,
}, () => {
editGoogleCalendarEvent({ ...updatedEvent, userId: currentUser.id, timezone: currentUser.timezone, onlyDate });
});
}
editEvent(event) {
const { currentUser, editGoogleCalendarEvent, calendarEvents } = this.props;
const { events } = this.state;
let onlyDate = false;
console.log('event', event);
console.log('calendarEvents', calendarEvents);
const idx = events.indexOf(event);
const eventIndex = _.findIndex(calendarEvents.details.items, { id: event.id });
const editedEvent = { ...event };
console.log('Event Index', eventIndex);
const nextEvents = [...events];
nextEvents.splice(idx, 1, editedEvent);
if (eventIndex !== -1) {
const item = calendarEvents.details.items[eventIndex];
if (item.start.date && item.end.date) {
editedEvent.start = moment(event.start).format('YYYY-MM-DD');
editedEvent.end = moment(event.end).format('YYYY-MM-DD');
onlyDate = true;
}
}
this.setState({
events: nextEvents,
}, () => {
console.log('Object', { id: event.event.id, title: event.formValues.title, userId: currentUser.id, timezone: currentUser.timezone, onlyDate });
editGoogleCalendarEvent({
id: event.event.id,
start: moment(event.event.start).hours(event.formValues.period === 'AM' ? event.formValues.hour % 12 : (event.formValues.hour % 12) + 12).minutes(event.formValues.minute).toISOString(),
end: moment(event.event.end).hours(event.formValues.period === 'AM' ? event.formValues.hour % 12 : (event.formValues.hour % 12) + 12).minutes(event.formValues.minute).toISOString(),
title: event.formValues.title,
userId: currentUser.id,
timezone: currentUser.timezone,
onlyDate,
});
});
}
resizeEvent = ({ event, start, end }) => {
const { events } = this.state;
const nextEvents = events.map(existingEvent => {
return existingEvent.id === event.id
? { ...existingEvent, start, end }
: existingEvent;
});
this.setState({
events: nextEvents,
});
// console.log(`${event.title} was resized to ${start}-${end}`);
}
newEvent(params) {
const { currentUser, addGoogleCalendarEvent } = this.props;
const { event, formValues } = params;
const newEvent = {
title: formValues.title,
description: formValues.description ? formValues.description : null,
allDay: event.slots.length === 1,
start: moment(event.start).hours(formValues.period === 'AM' ? formValues.hour % 12 : (formValues.hour % 12) + 12).minutes(formValues.minute).toISOString(),
end: moment(event.end).hours(formValues.period === 'AM' ? formValues.hour % 12 : (formValues.hour % 12) + 12).minutes(formValues.minute).toISOString(),
};
this.setState({
calendarEvent: null,
}, () => {
addGoogleCalendarEvent({ ...newEvent, userId: currentUser.id, timezone: currentUser.timezone });
});
}
showEventModal(event) {
this.setState({ calendarEvent: event, show: true });
}
showEditEventModal(event) {
const { calendarEvents } = this.props;
const eventIndex = _.findIndex(calendarEvents.details.items, { id: event.id });
const item = calendarEvents.details.items[eventIndex];
this.setState({ calendarEvent: item, editShow: true });
}
hideEventModal() {
const { resetForm } = this.props;
this.setState({ show: false, calendarEvent: null }, () => {
resetForm();
});
}
hideEditEventModal() {
const { resetEditForm } = this.props;
this.setState({ editShow: false, calendarEvent: null }, () => {
resetEditForm();
});
}
render() {
const { currentGoogleUser, addEventProcess, editEventProcess } = this.props;
let authorized = false;
if (currentGoogleUser && currentGoogleUser.expires_at) {
authorized = moment(currentGoogleUser.expires_at).isAfter(moment());
}
return (
<div>
<div className="container-fluid">
<Helmet title={translate('portals.page.calendarPage.helmetTitle')} />
<section className="calendar-section">
<h2 className="main-heading">{translate('portals.page.calendarPage.pageTitle')}</h2>
{!authorized &&
<GoogleLogin
clientId={GOOGLE_CLIENT_ID}
scope="https://www.googleapis.com/auth/calendar"
className="google-login"
onSuccess={this.onSuccess}
onFailure={this.onFailure}
>
<i className="google-image" />
<span> Sign in with Google</span>
</GoogleLogin>
}
{authorized &&
<DragAndDropCalendar
selectable
events={this.state.events}
localizer={localizer}
onEventDrop={this.moveEvent}
resizable
onEventResize={this.resizeEvent}
onSelectSlot={this.showEventModal}
onSelectEvent={this.showEditEventModal}
defaultView={BigCalendar.Views.MONTH}
defaultDate={new Date()}
views={{ month: true }}
/>
}
<AddCalendarEventForm
show={this.state.show}
isSubmitting={addEventProcess.isSubmitting}
calendarEvent={this.state.calendarEvent}
onSubmit={this.newEvent}
onHide={this.hideEventModal}
/>
<EditCalendarEventForm
show={this.state.editShow}
isSubmitting={editEventProcess.isSubmitting}
calendarEvent={this.state.calendarEvent}
onSubmit={this.editEvent}
onHide={this.hideEditEventModal}
/>
</section>
</div>
</div>
);
}
}
const eventIndex = _.findIndex(calendarEvents.details.items, { id: event.id });
Apparently, there is an array which is called _, I can't see it anywhere in your code, you should change the way your are doing the findIndex() method.
suchlike calendarEvents.details.items.findIndex({id: event.id})
although, I don't think there is a way to find a prop value inside an object this way.
you may want to loop on instead.
I am using the events calendar package, https://www.npmjs.com/package/react-native-events-calendar, I am trying to display the EventsCalendar component with events coming from redux.
events={fetchEvents[selected].dots} is an array but the component will not render, however if I copy the array directly into the component it renders.
Any ideas why my component won't render?
import React, { Component } from "react";
import { connect } from "react-redux";
import {
Text,
View,
StyleSheet,
Image,
Dimensions,
ActivityIndicator
} from "react-native";
import Icon from "react-native-vector-icons/FontAwesome";
import * as helpers from "../../helpers";
import {
fetchEvents,
changeMonth,
eventsForAgendaMonth
} from "../../actions/events";
import CustomHeader from "../../navigation/CustomHeader";
import XDate from "xdate";
import AgendaItem from "./AgendaItem";
import AgendaDay from "./AgendaDay";
import EventCalendar from "./DayView";
import propTypes from "prop-types";
class AgendaScreen extends Component {
static navigationOptions = {
title: "",
header: <CustomHeader />
};
constructor(props) {
super(props);
this._eventTapped = this._eventTapped.bind(this);
this.dateChanged = this.dateChanged.bind(this);
this.renderEvent = this.renderEvent.bind(this);
}
dateChanged(date) {
const { eventsForYear, eventsMonth } = this.props;
this.setState({ selectedDay: date });
this.props.dispatch(eventsForAgendaMonth(eventsForYear, date));
}
_eventTapped(event) {
alert(JSON.stringify(event));
}
loadItems(day) {
const { eventsForYear } = this.props;
this.props.dispatch(eventsForAgendaMonth(eventsForYear, day));
}
renderEvent(event) {
console.log("event", event);
return <AgendaItem {...event} />;
}
render() {
const {
fetchEvents,
navigation: {
state: {
params: {
day: { dateString: selected }
}
}
}
} = this.props;
const currentDate = helpers.currentDate;
let { width } = Dimensions.get("window");
return (
<View style={{ flex: 1 }}>
<EventCalendar
eventTapped={this._eventTapped.bind(this)}
events={fetchEvents[selected].dots}
width={width}
initDate={selected}
/>
</View>
);
}
}
const mapStateToProps = state => {
return {
fetchEvents: state.fetchEvents
};
};
export default connect(mapStateToProps)(AgendaScreen);
AgendaScreen.propTypes = {
eventsMonth: propTypes.object,
eventsForYear: propTypes.object
};
const styles = {
container: {
backgroundColor: "#00000000"
},
event: {
backgroundColor: "#00000000",
borderColor: "#DDE5FD",
borderWidth: 0,
borderRadius: 0,
paddingTop: 3,
paddingBottom: 2
},
header: {
height: 30,
paddingHorizontal: 30
},
headerText: {}
};
AFAIK I am not mutating state, I am createing a new object with my reducer:
case "EVENTS_SUCCESS":
const events = {};
const filteredEvents = action.data
.filter(event => {
if (
event.status === "cancelled" ||
!event.start.dateTime ||
helpers.checkDate(event.start.dateTime)
) {
return false;
}
return true;
})
.sort((a, b) => a.startTimeString - b.startTimeString);
filteredEvents.map(event => {
const {
start: { dateTime: startTime },
end: { dateTime: endTime },
summary,
id
} = event;
const sDate = new Date(startTime);
const eDate = new Date(endTime);
const startHour = sDate.getHours();
const startMinute = sDate.getMinutes();
const startDate =
sDate.getFullYear() +
"-" +
("0" + (sDate.getMonth() + 1)).slice(-2) +
"-" +
("0" + sDate.getDate()).slice(-2);
const endHour = eDate.getHours();
const endMinute = eDate.getMinutes();
const endDay = eDate.getDay();
const endMonth = eDate.getMonth();
const endYear = eDate.getFullYear();
const eventStartTime = `${startHour}-${startMinute}`;
const eventEndTime = `${endHour}-${endMinute}`;
let newEvent = {
title: summary,
summary,
id,
eventStartTime,
eventEndTime
};
events[startDate] = events[startDate] || { dots: [] };
const dotsEvents = [...events[startDate].dots, newEvent];
dotsEvents.sort(
(a, b) => a.startTimeString - b.startTimeString
);
events[startDate] = {
dots: dotsEvents,
disabled: false,
selected: true,
selectedColor: "#00CCCB",
customStyles: {
text: {
marginTop: 3
}
}
};
});
return {
...events
};
So I have a custom component (TextButton) and I have packaged it inside another component (ContainedButton). I'm currently attempting to style ContainedButton. However, I want to access the value of a prop of TextButton (theme) and use the value when styling ContainedButton.
ContainedButton:
import React, { Component } from 'react';
import TextButton from './TextButton';
class ContainedButton extends Component {
render() {
const { style } = this.props;
return (
<TextButton {...this.props} style={[styles.containedButtonStyle, style]} />
);
}
}
const styles = {
containedButtonStyle: {
backgroundColor: (TextButton prop theme)
padding: 2,
borderWidth: 1,
borderRadius: 5
}
};
export default ContainedButton;
In the parentheses next to 'backgroundColor', I want to insert the value of the theme prop located in TextButton. How would I achieve something like this?
TextButton (in case it's needed):
import React, { Component } from 'react';
import { Text, TouchableOpacity } from 'react-native';
import PropTypes from 'prop-types';
class TextButton extends Component {
constructor(props) {
super(props);
this.state = {};
}
componentWillMount() {}
componentWillReceiveProps(newProps) {
if (newProps.theme !== this.props.theme) {
this.determineTheme(newProps.theme);
}
if (newProps.size !== this.props.size) {
this.determineSize(newProps.size);
}
}
// set the theme
determineTheme = function (theme) {
if (theme === 'primary') {
return {
color: '#0098EE'
};
} else if (theme === 'secondary') {
return {
color: '#E70050'
};
} else if (theme === 'default') {
return {
color: '#E0E0E0'
};
}
return {
color: '#E0E0E0'
};
}
// set the size
determineSize = function (size) {
if (size === 'small') {
return {
fontSize: 16
};
} else if (size === 'medium') {
return {
fontSize: 22
};
} else if (size === 'large') {
return {
fontSize: 28
};
}
return {
fontSize: 22
};
}
render() {
const { onPress, children, theme, size, style } = this.props;
return (
<TouchableOpacity onPress={onPress} style={style}>
<Text style={[this.determineTheme(theme), this.determineSize(size)]}>{children}</Text>
</TouchableOpacity>
);
}
}
TextButton.propTypes = {
onPress: PropTypes.func,
title: PropTypes.string,
theme: PropTypes.string,
size: PropTypes.string
};
export default TextButton;
You can get the value of theme in the same way you get the value of style:
const { theme } = this.props;
Or combine them into a single statement:
const { style, theme } = this.props;
I've been trying to work off of the simple sortable example in the react-dnd examples but I am having trouble trying to convert the es7 code to es6. I've tried using babel but I don't really understand the code that it spits out.
Here is my code that I've tried to translate from es7 to es6:
import React, {PropTypes} from 'react';
import Router from 'react-router';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { DragSource, DropTarget } from 'react-dnd';
const style= {
border: '1px dashed gray',
padding: '0.5rem 1rem',
marginBottom: '.5rem',
backgroundColor: 'white',
cursor: 'move'
}
const ItemTypes = {
Coursepage: 'coursepage'
};
const coursePageSource = {
beginDrag(props) {
return {
id: props.id,
index: props.index
}
}
}
const coursePageTarget = {
hover(props, monitor, component){
const dragIndex = monitor.getItem().index;
const hoverIndex = props.index;
//don't replace items with themselves
if(dragIndex === hoverIndex){
return;
}
//Determine rectangle on screen
const hoverBoundingRect = findDOMNode(component).getBoundingClientRect();
//get vertical middle
const hoverMiddleY = (hoverBoundingRect.Bottom - hoverBoundingRect.Top) /2;
//get top pixels
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
//only perform the move when the mouse has crossed half of the items height
//when dragging downwards, only move when the cursor is below 50%
//when dragging upwards, only move when the cursor is above 50%
//dragging downwards
if(dragIndex < hoverIndex && hoverClientY < hoverMiddleY){
return;
}
//dragging upwards
if(dragIndex > hoverIndex && hoverClientY > hoverMiddleY){
return;
}
//time to actually perform the action
props.moveObject(dragIndex, hoverIndex);
}
}
// const propTypes = {
// connectDragSource: PropTypes.func.isRequired,
// connectDropTarget: PropTypes.func.isRequired,
// index: PropTypes.number.isRequired,
// isDragging: PropTypes.bool.isRequired,
// id: PropTypes.any.isRequired,
// text: PropTypes.string.isRequired,
// moveCard: PropTypes.func.isRequired
// };
function collectDropTarget(connect) {
return {
connectDropTarget: connect.dropTarget(),
};
}
/**
* Specifies which props to inject into your component.
*/
function collectDragSource(connect, monitor) {
return {
// Call this function inside render()
// to let React DnD handle the drag events:
connectDragSource: connect.dragSource(),
// You can ask the monitor about the current drag state:
isDragging: monitor.isDragging()
};
}
class Coursepage extends React.Component{
render(){
console.log(this.props);
const {text, isDragging, connectDragSource, connectDropTarget} = this.props;
const opacity = isDragging ? 0 : 1;
return connectDragSource(connectDropTarget(
<div style={{opacity}}>
{text}
</div>
));
}
}
// Coursepage.propTypes = propTypes;
export default DragSource(ItemTypes.Coursepage, coursePageSource, collectDragSource)(Coursepage);
export default DropTarget(ItemTypes.Coursepage, coursePageTarget, collectDropTarget)(Coursepage);
Now the error I'm getting from this is
"Uncaught TypeError: connectDropTarget is not a function."
I console logged this.props in render and I see that connectDragSource is showing up in the this.props object but not connectDropTarget.
Can anyone tell me what I'm missing?
By the way, this is the example code I was using:
https://github.com/gaearon/react-dnd/blob/master/examples/04%20Sortable/Simple/Card.js
I know this is a little old but I landed up here through google so I figured I would give it a go. First of all, you can't have two default exports as referenced here in section 3.2 http://www.2ality.com/2014/09/es6-modules-final.html
Instead you need to pass the result of one of your current default exports into the second function call - you'll see below.
This took me a couple of hours to get working as I'm also an Es6/7 newbie - so I invite any criticism!
// Container.js;
import React, { Component } from 'react';
import update from 'react/lib/update';
import Card from './Card';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
const style = {
width: 400
};
class Container extends Component {
constructor(props) {
super(props);
this.moveCard = this.moveCard.bind(this);
this.findCard = this.findCard.bind(this);
this.state = {
cards: [{
id: 1,
text: 'Write a cool JS library'
}, {
id: 2,
text: 'Make it generic enough'
}, {
id: 3,
text: 'Write README'
}, {
id: 4,
text: 'Create some examples'
}, {
id: 5,
text: 'Spam in Twitter and IRC to promote it (note that this element is taller than the others)'
}, {
id: 6,
text: '???'
}, {
id: 7,
text: 'PROFIT'
}]
};
}
findCard(id) {
const { cards } = this.state;
const card = cards.filter(c => c.id === id)[0];
return {
card,
index: cards.indexOf(card)
};
}
moveCard(id, atIndex) {
const { card, index } = this.findCard(id);
this.setState(update(this.state, {
cards: {
$splice: [
[index, 1],
[atIndex, 0, card]
]
}
}));
}
render() {
const { cards } = this.state;
return (
<div style={style}>
{cards.map((card, i) => {
return (
<Card key={card.id}
index={i}
id={card.id}
text={card.text}
moveCard={this.moveCard}
findCard={this.findCard} />
);
})}
</div>
);
}
}
export default DragDropContext(HTML5Backend)(Container)
Then Card.js
// Card.js
import React, { Component, PropTypes } from 'react';
import ItemTypes from './ItemTypes';
import { DragSource, DropTarget } from 'react-dnd';
const style = {
border: '1px dashed gray',
padding: '0.5rem 1rem',
marginBottom: '.5rem',
backgroundColor: 'white',
cursor: 'move'
};
const cardSource = {
beginDrag(props) {
return {
id: props.id,
originalIndex: props.findCard(props.id).index
};
},
endDrag(props, monitor) {
const { id: droppedId, originalIndex } = monitor.getItem();
const didDrop = monitor.didDrop();
if (!didDrop) {
props.moveCard(droppedId, originalIndex);
}
}
};
const cardTarget = {
canDrop() {
return false;
},
hover(props, monitor) {
const { id: draggedId } = monitor.getItem();
const { id: overId } = props;
if (draggedId !== overId) {
const { index: overIndex } = props.findCard(overId);
props.moveCard(draggedId, overIndex);
}
}
};
function collect(connect, monitor) {
console.log( "HERE2", connect );
return {
connectDropTarget: connect.dropTarget(),
isOver: monitor.isOver(),
canDrop: monitor.canDrop()
};
}
function collect2(connect, monitor) {
return {
connectDragSource: connect.dragSource(),
connectDragPreview: connect.dragPreview(),
isDragging: monitor.isDragging()
};
}
class Card extends Component {
render() {
const { text, isDragging, connectDragSource, connectDropTarget } = this.props;
const opacity = isDragging ? 0 : 1;
return connectDragSource(connectDropTarget(
<div >
{text}
</div>
));
}
}
Card.propTypes = {
connectDragSource: PropTypes.func.isRequired,
connectDropTarget: PropTypes.func.isRequired,
isDragging: PropTypes.bool.isRequired,
id: PropTypes.any.isRequired,
text: PropTypes.string.isRequired,
moveCard: PropTypes.func.isRequired,
findCard: PropTypes.func.isRequired
};
const x = DropTarget(ItemTypes.CARD, cardTarget, collect )(Card)
export default DragSource(ItemTypes.CARD, cardSource, collect2 )( x )
And then the types include
// ItemTypes.js
export default {
CARD: 'card'
};