instantjob-recruiter-client
Version:
a set of tools for creating an instantjob recruiter react client
221 lines (206 loc) • 6.55 kB
JSX
import React, {Component} from 'react'
import {connect} from 'react-redux'
import classNames from 'classnames/bind'
import Calendar from 'components/generic_calendar'
import Tabbar from 'components/tabbar'
import Button from 'components/utils/button'
import TimePickers, {
chunks_count_in_hour, chunk_length_in_minutes, chunks_count_in_day, get_periods, get_start_end,
get_days_chunks, day_id,
} from 'components/input_calendar/time_pickers'
import moment from 'common/moment'
import {
for_all, array_from_hash, range, array_from_set, group_consecutive, set_from_array, exist,
empty_set, map_hash, create_hash,
} from 'common/utilities'
import {color} from 'common/constants'
import auto_bind from 'common/auto_bind'
import store from 'common/store'
import {dismiss_popover} from 'actions/display'
import {remove_item, create_item, toggle_item_id} from 'reducers/base'
import {tolerant_equal} from 'selectors/base'
const cx = classNames.bind(require('styles/mission_period_picker.scss'))
class MissionPeriodPicker extends Component {
constructor(props) {
super(props)
auto_bind(this)
this.update_initial_days(props.initial_events)
let mode = "all"
let identical_days = (day1, day2) => tolerant_equal(array_from_set(day1).sort(), array_from_set(day2).sort())
if (empty_set(this.initial_days) || group_consecutive(array_from_hash(this.initial_days), identical_days).length == 1) {
mode = "day"
}
this.state = {
active_days: map_hash(this.initial_days, () => true),
day_active: set_from_array(range(chunks_count_in_day).filter(
(chunk) => exist(array_from_hash(this.initial_days), (day) => day[chunk])
)),
chunks: this.initial_days,
mode,
}
this.all_time_pickers = {}
}
on_day_click(date) {
this.setState(toggle_item_id(this.state, "active_days", day_id(date)))
}
on_create_period(start, end, paint) {
let day_ids = [], current = moment(start)
while (current.isBefore(end)) {
day_ids.push(day_id(current))
current.add(1, 'day')
}
this.setState({active_days: {
...this.state.active_days,
...map_hash(set_from_array(day_ids), () => paint)
}})
}
flip(date, chunks, paint) {
let chunks_range = create_hash(chunks, () => paint)
switch (this.state.mode) {
case "day":
this.setState(({day_active}) => ({
day_active: {
...day_active,
...chunks_range,
},
}))
break
case "all":
let id = day_id(date)
this.setState(({chunks, day_active}) => ({
chunks: {
...chunks,
[id]: {
...(chunks[id] || day_active),
...chunks_range,
},
},
}))
break
}
}
update_initial_days(events) {
this.initial_days = get_days_chunks(events)
}
get_day_events() {
return array_from_set(this.state.active_days).map((day) => ({
start: moment(day),
end: moment(day).endOf('day'),
full_days: true,
}))
}
get_events() {
let days = array_from_set(this.state.active_days)
let events = []
let add_events = (day, active_chunks) => {
get_periods(active_chunks).forEach(({start, end}) => {
events.push({
...get_start_end(day, start, end),
full_days: false,
})
})
}
switch (this.state.mode) {
case 'day':
days.forEach((day) => add_events(day, this.state.day_active))
break
case 'all':
days.forEach((day) => add_events(
day,
this.state.chunks[day] || this.state.day_active,
))
break
}
if (events.length == 0) {
events = days.map((day) => ({
start: moment(day),
end: moment(day).endOf('day'),
full_days: true,
}))
}
return events
}
on_save() {
this.props.on_save(this.get_events())
}
render_time_picker() {
let common_props = {
drag_color: color('primary', 'light'),
flip: this.flip,
}
switch (this.state.mode) {
case "day":
return (
<TimePickers
day_label={false}
days={[{date: moment(), chunks: this.state.day_active}]}
{...common_props}
/>
)
case "all":
return (
<TimePickers
days={array_from_set(this.state.active_days).map((day) => moment(day)).sort((a, b) => a.isAfter(b) ? 1 : (a.isSame(b) ? 0 : -1)).map((day) => ({
date: day,
chunks: this.state.chunks[day_id(day)] || this.state.day_active,
}))}
{...common_props}
/>
)
}
}
set_mode(mode) {
this.setState({mode})
}
render() {
return (
<div style={{display: 'flex', alignItems: 'stretch'}}>
<div className={cx('mission-period-picker')}>
<div className={cx('mission-period-picker__calendar')}>
<Calendar
hide_navigation
events={{[color('primary')]: this.get_day_events()}}
on_click={this.on_day_click}
drag_color={color('primary')}
on_drag_and_drop={this.on_create_period}
/>
</div>
<div className={cx('mission-period-picker__time')}>
<Tabbar
tabs={[
{
label: "Horaires uniques pour toute la mission",
onClick: () => this.set_mode("day"),
is_active: () => this.state.mode == "day",
},
{
label: "Jour par jour",
onClick: () => this.set_mode("all"),
is_active: () => this.state.mode == "all",
},
]}
/>
<div className={cx('mission-period-picker__time-pickers')}>
{this.render_time_picker()}
</div>
<div className={cx('mission-period-picker__time-button')}>
<Button onClick={this.on_save}>
Enregistrer les dates de la mission
</Button>
</div>
</div>
</div>
</div>
)
}
}
MissionPeriodPicker.defaultProps = {
initial_events: [],
update_events: () => {},
}
export default connect(
(state, {mission_id}) => ({
initial_events: array_from_hash(state.missions.events)
.filter(({calenderable_id, deleted_at}) => calenderable_id == mission_id && !deleted_at)
}),
)(MissionPeriodPicker)