Skip to content

Instantly share code, notes, and snippets.

@adhoch
Created May 9, 2018 22:05
Show Gist options
  • Save adhoch/d74d00f20f312526716ec2203b30956a to your computer and use it in GitHub Desktop.
Save adhoch/d74d00f20f312526716ec2203b30956a to your computer and use it in GitHub Desktop.
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import _ from 'lodash';
import withStyles from 'isomorphic-style-loader/lib/withStyles';
import ApplyCard from '../../components/ApplyCard';
import Loader from '../../components/Loader';
/* eslint-disable import/no-named-as-default */
import style from './ApplicationDragContainer.scss';
import { headerProps } from '../../dummyData/dummyData';
import { TransitionMotion, presets, Motion, spring } from 'react-motion';
function reinsert(arr, from, to) {
const _arr = arr.slice(0);
const val = _arr[from];
_arr.splice(from, 1);
_arr.splice(to, 0, val);
return _arr;
}
function clamp(n, min, max) {
return Math.max(Math.min(n, max), min);
}
const springConfig = { stiffness: 300, damping: 50 };
class ApplicationDragContainer extends Component {
static defaultProps = {
normalSchools: null,
};
static propTypes = {
addParameterAndSearch: PropTypes.func.isRequired,
currentSchool: PropTypes.func.isRequired,
filters: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.string.isRequired,
}),
).isRequired,
filtersLoaded: PropTypes.bool.isRequired,
filtersLoading: PropTypes.bool.isRequired,
getSchoolsPrograms: PropTypes.func.isRequired,
getSchoolsApplications: PropTypes.func.isRequired,
getStudent: PropTypes.func.isRequired,
getStudentApplications: PropTypes.func.isRequired,
getFilters: PropTypes.func.isRequired,
optionsDict: PropTypes.shape({}).isRequired,
parameters: PropTypes.arrayOf(PropTypes.shape).isRequired,
loaded: PropTypes.bool.isRequired,
loading: PropTypes.bool.isRequired,
schools: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string.isRequired,
url: PropTypes.string.isRequired,
}),
).isRequired,
normalSchools: PropTypes.shape(),
saveApplication: PropTypes.func.isRequired,
setPage: PropTypes.func.isRequired,
user: PropTypes.shape({
applicationId: PropTypes.string,
address: PropTypes.string,
studentApplications: PropTypes.shape({
entities: PropTypes.shape({
application: PropTypes.shape({}),
}),
}),
}).isRequired,
updateApplicationRank: PropTypes.func.isRequired,
intl: PropTypes.shape({
locale: PropTypes.string,
}).isRequired,
};
constructor(props) {
super(props);
this.state = {
topDeltaY: 0,
mouseY: 0,
isPressed: false,
originalPosOfLastPressed: 0,
order: _.range(4),
order1: this.props.user.studentApplications.results,
};
}
componentDidMount() {
window.addEventListener('touchmove', this.handleTouchMove);
window.addEventListener('touchend', this.handleMouseUp);
window.addEventListener('mousemove', this.handleMouseMove);
window.addEventListener('mouseup', this.handleMouseUp);
}
handleTouchStart = (key, pressLocation, e) => {
this.handleMouseDown2(key, pressLocation, e.touches[0]);
};
handleTouchMove = e => {
e.preventDefault();
this.handleMouseMove2(e.touches[0]);
};
handleMouseDown = (pos, pressY, { pageY }) => {
this.setState({
topDeltaY: pageY - pressY - (100 * pressY),
mouseY: pressY,
isPressed: true,
originalPosOfLastPressed: pos,
});
};
handleMouseMove = ({ pageY }) => {
const { isPressed, topDeltaY, order, originalPosOfLastPressed } = this.state;
const { results } = this.props.user.studentApplications;
let rowPosition = 0;
if (isPressed) {
event.preventDefault();
const mouseY = pageY - topDeltaY;
let currentRow = results[clamp(Math.round(mouseY / 146), 0, results.length - 1)];
currentRow = results.indexOf(currentRow);
const newOrder = reinsert(results, results.indexOf(originalPosOfLastPressed), currentRow);
if (currentRow !== results.indexOf(originalPosOfLastPressed)) {
this.props.exportnewApplicationDragDrop(newOrder);
}
rowPosition = currentRow * 146;
this.setState({ mouseY: mouseY - rowPosition });
}
};
handleMouseUp = () => {
const { results } = this.props.user.studentApplications;
const { application } = this.props.user.studentApplications.entities;
if (this.state.isPressed){
const x = results.map( (id, index) => {
return ({
programId: id,
applicationProgramId: application[id].id,
rank: index + 1,
})
});
const y = results.map( (id, index) => {
return ({
"id": application[id].id,
"rank": index + 1,
})
});
this.props.test(y,x);
}
this.setState({ isPressed: false, topDeltaY: 0 });
};
saveApplicationFunc = (id, schoolId, savedApplication, savedApplicationId) => {
this.props.saveApplication(id, schoolId, savedApplication, savedApplicationId);
return true;
};
willEnter() {
return {
width: 0,
maxHeight: 0,
opacity: 0,
};
}
willLeave() {
return {
width: spring(0),
maxHeight: spring(0),
opacity: spring(0),
};
}
// schoolListItem = (rank, id, programId, className );
renderApplicationMotion = (programId, id, rank) => {
const { normalSchools, updateApplicationRank, currentSchool } = this.props;
const { mouseY, isPressed, originalPosOfLastPressed } = this.state;
const style =
originalPosOfLastPressed === programId && isPressed
? {
scale: spring(1.1, springConfig),
shadow: spring(16, springConfig),
y: mouseY,
}
: {
scale: spring(1, springConfig),
shadow: spring(1, springConfig),
y: spring(this.props.user.studentApplications.results.indexOf(programId) * 1.46, springConfig),
};
return (
<Motion style={style}>
{({ scale, shadow, y }) => (
<div
onMouseDown={this.handleMouseDown.bind(null, programId, y)}
onTouchStart={this.handleTouchStart.bind(null, programId, y)}
style={{
boxShadow: `rgba(0, 0, 0, 0.2) 0px ${shadow}px ${2 * shadow}px 0px`,
transform: `translate3d(0, ${y}px, 0) scale(${scale})`,
WebkitTransform: `translate3d(0, ${y}px, 0) scale(${scale})`,
zIndex: programId === originalPosOfLastPressed ? 99 : 1,
}}
>
<div rank={rank} key={`${id}-${programId}`} className={style.applicationListItem}>
{/* * Keydown is a placeholder for functional keydown * */}
<div>
<ApplyCard
onClick={() => currentSchool(id)}
rank={rank}
{...normalSchools.entities.school[id]}
{...headerProps}
singleProgramId={programId}
updateApplicationRank={updateApplicationRank}
removeProgram={this.saveApplicationFunc}
/>
</div>
</div>
</div>
)}
</Motion>
);
};
renderApplications = () => {
const { normalSchools, loading } = this.props;
let load = null;
if (loading) {
load = (
<li className={style.listItem}>
<Loader />
</li>
);
return load;
}
let programList = _.orderBy(
_.without(
_.flatten(
normalSchools.result.map(id =>
normalSchools.entities.school[id].getSavedApplications().map(programId => ({
id,
programId: programId.id,
rank: this.props.user.studentApplications.results.indexOf(programId.id),
})),
),
),
undefined,
),
'rank',
);
if (programList.length === 0 ) {
return (
<div>
<ul className={style.applicationList}>
<li key="emptyApplicationList" className={style.emptyApplicationList}>
<p>CMSABLE NOTE FOR EMPTY PROGRAM LIST</p>
</li>
</ul>
</div>
);
} else if (programList.length !== 0) {
programList =
<TransitionMotion
willLeave={this.willLeave}
willEnter={this.willEnter}
styles={programList.map(item => {
return {
key: `${item.id}-${item.programId}`,
style: {
width: spring(660, presets.gentle),
opacity: spring(1, presets.gentle),
maxHeight: spring(446, presets.gentle),
},
data: {
rank: item.rank,
id: item.id,
programId: item.programId,
},
};
})}
>
{interpolatedStyles => (
<ol className={style.applicationList}>
{interpolatedStyles.map(config => {
const { id, programId, rank } = config.data;
return <li key={programId}
style={{ ...config.style }}>
{this.renderApplicationMotion(programId, id, rank)}
</li>
})}
</ol>
)}
</TransitionMotion>
}
return (
<div>
{programList}
{load}
</div>
);
};
render() {
return <div className={style.applications}>{this.renderApplications()}</div>;
}
}
// We use the injectIntl Higher Order Component (HOC) to make sure the component updates
// Read more about that here https://github.com/yahoo/react-intl/issues/371 and
// https://github.com/yahoo/react-intl/wiki/API#injectintl
export default withStyles(style)(ApplicationDragContainer);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment