UNPKG

instantjob-recruiter-client

Version:

a set of tools for creating an instantjob recruiter react client

307 lines (289 loc) 9.59 kB
import React, {Component} from 'react' import classNames from 'classnames/bind' import {connect} from 'react-redux' import {browserHistory} from 'react-router' import styled from 'styled-components' import {MdFlag, MdAddCircle, MdFileDownload, MdEdit, MdDone, MdDoneAll, MdSend} from 'react-icons/lib/md' import FilterableList from 'components/filterable_list/filterable_list' import {get_filter_on_click} from 'components/filterable_list/make_filter_maker_from_field' import Button from 'components/utils/button' import Tag from 'components/utils/tag' import MissionStatus from 'components/mission_status/mission_status' import persistent_state from 'common/persistent_state' import {set_from_array, property_getter, set_count, set_intersection} from 'common/utilities' import auto_bind from 'common/auto_bind' import request from 'common/request' import store from 'common/store' import moment from 'common/moment' import { get_mission_status_elements, mission_period, action_create_deal, action_cancel_drafts, } from 'common/missions' import {action_export_field} from 'common/fields' import {link} from 'common/styles' import {dismiss_popover, show_popover} from 'actions/display' import {get_missions_filter_fields, get_exports_fields} from 'selectors/fields' import {get_initially_selected_recruiters} from 'selectors/missions' import {get_recruiters} from 'selectors/recruiters' const cx = classNames.bind(require('styles/filterable_table.scss')) export const get_initial_state = (props) => ({ exclusive_filters: { status: set_from_array(['draft', 'sent', 'pending_assignement', 'pending_selection', 'assigned']), recruiter: set_from_array(props.initially_selected_recruiters), }, order_by({status}) { return get_mission_status_elements(status).priority }, loading_export_missions: {}, ascending: true, }) export function get_filters_and_deals({deals, fields, workplaces, recruiters, state, setState}) { const status_filter_maker = FilterableList.make_filter_maker_from_field({ id: 'status', name: 'Statut', category: 'exclusive', value_ids: ['draft', 'pending_selection', 'pending_assignement', 'sent', 'assigned'], get_value_props(status, selected = false) { const {name, icon} = get_mission_status_elements(status) || {} return { id: status, name: ( <Tag icon={icon}> {name} </Tag> ), } }, get_item_values({status}) { return [status] }, }) const initial_make_status_filter_props = status_filter_maker.make_filter_props status_filter_maker.make_filter_props = (args) => ({ ...initial_make_status_filter_props(args), onClick: get_filter_on_click('status', args.setState, ({status}) => { return get_mission_status_elements(status).priority }) }) const workplace_filter_maker = FilterableList.make_filter_maker_from_field({ id: 'workplace', category: 'exclusive', name: 'Lieu de travail', value_ids: Object.keys(workplaces), tolerant: true, get_value_props(id) { return workplaces[id] }, get_item_values({workplace_ids}) { return workplace_ids || [] }, }) const recruiter_filter_maker = FilterableList.make_filter_maker_from_field({ id: 'recruiter', category: 'exclusive', name: 'Recruteur', value_ids: Object.keys(recruiters), get_value_props(id) { const recruiter = recruiters[id] || {} return {...recruiter, name: recruiter.full_name} }, get_item_values({recruiter}) { return [recruiter.id] }, }) const filter_makers = [ status_filter_maker, workplace_filter_maker, recruiter_filter_maker, ...[ {id: 'created_at', category: 'date', name: 'Date de création', get_item_value: property_getter('created_at')}, {id: 'start', category: 'date', name: 'Date de début', get_item_value: property_getter('start')}, {id: 'end', category: 'date', name: 'Date de fin', get_item_value: property_getter('end')}, ].map(FilterableList.make_filter_maker_from_field), ...fields.map(FilterableList.make_filter_maker_from_field).filter(Boolean) ] return { filters: FilterableList.get_filters(filter_makers, deals, state, setState), deals: FilterableList.get_filtered_items( filter_makers, deals, state, ), } } class DealsList extends Component { constructor(props) { super(props) this.state = persistent_state.get(props.persistent_state_key, { ...FilterableList.initial_state, ...get_initial_state(props), }) auto_bind(this) } componentWillUnmount() { persistent_state.store(this.props.persistent_state_key, this.state) } set_state(arg) { this.setState(arg) } get_filters_and_deals() { const {deals, fields, workplaces, recruiters} = this.props return get_filters_and_deals({deals, fields, workplaces, recruiters, state: this.state, setState: this.set_state}) } get_statistics({users_count, waiting_count, accepted_count, assigned_count, empty_count, status}) { const assigned = {count: assigned_count, icon: <MdDoneAll />} switch (status) { case 'draft': return [{count: users_count, icon: <MdEdit />}] case 'pending_assignement': case 'sent': return [ {count: accepted_count, icon: <MdDone />}, {count: waiting_count, icon: "?"}, assigned, ] case 'pending_selection': return [ {count: empty_count, icon: <MdSend />}, assigned, ] case 'assigned': return [assigned] default: } } get_selected_count(selected_deal_ids) { return set_count(set_intersection(selected_deal_ids, set_from_array(this.props.deals.map(property_getter('id'))))) } render_deal({id, workplace, recruiter, created_at, ...deal}) { workplace = workplace || {} return ( <Deal onClick={() => browserHistory.push(`/deals/${id}`)}> <MissionStatus simple {...deal} /> <Information> <Top> <Workplace> <WorkplaceName> {workplace.name} </WorkplaceName> <WorkplaceAddress> {workplace.address} </WorkplaceAddress> </Workplace> <Statistics> {this.get_statistics(deal).filter(property_getter('count')).map(({count, icon}, index) => ( <Statistic key={index}> {count} <StatisticIcon> {icon} </StatisticIcon> </Statistic> ))} </Statistics> </Top> <Bottom> <Period> {mission_period(deal)} </Period> <Creation> Créée {moment(created_at).calendar().toLowerCase()} par {recruiter.full_name} </Creation> </Bottom> </Information> </Deal> ) } make_export_action({name, id}) { return ({length}) => ({ onClick: (deal_ids, unselect_deals) => { unselect_deals() this.setState({loading_export_missions: {[id]: true}}) action_export_field(id, deal_ids) .then(() => this.setState({loading_export_missions: {[id]: false}})) }, label: `Exporter ${name} pour les missions sélectionnées`, loading: this.state.loading_export_missions[id], disabled: !length, }) } render() { const {export_fields} = this.props const {filters, deals} = this.get_filters_and_deals() return ( <FilterableList icon={MdFlag} empty_text={"Aucune mission"} filters={filters} secondary_actions={[ ({length}) => ({onClick: action_cancel_drafts, label: 'Supprimer les brouillons sélectionnés', disabled: !length}), ...export_fields.map(this.make_export_action), ]} main_action={{icon: MdAddCircle, onClick: action_create_deal, label: 'Nouvelle Mission', action: true}} render_item={this.render_deal} selectable get_selected_count={this.get_selected_count} > {deals} </FilterableList> ) } } export default connect( (state) => ({ workplaces: state.missions.workplaces, recruiters: get_recruiters(state), fields: get_missions_filter_fields(state), export_fields: get_exports_fields(state), agency_id: state.profile.agency.id, initially_selected_recruiters: get_initially_selected_recruiters(state) }) )(DealsList) const Workplace = styled.div` display: flex; align-items: baseline; ` const WorkplaceName = styled.div` font-size: 18px; margin-right: 6px; ` const WorkplaceAddress = styled.div`` const Period = styled.div`` const Creation = styled.div`` const Deal = styled.div` flex: 1; ${({onClick}) => onClick ? link : ''} display: flex; align-items: center; padding-right: 5px; ` const Information = styled.div` flex: 1; display: flex; align-items: stretch; justify-content: space-between; flex-direction: column; margin-left: 10px; height: 50px; ` const Top = styled.div` display: flex; align-items: center; justify-content: space-between; ` const Statistics = styled.div` display: flex; align-items: center; ` const Statistic = styled.div` display: flex; align-items: center; margin-left: 10px; ` const StatisticIcon = styled.div` margin-left: 3px; font-size: 16px; ` const Bottom = styled.div` display: flex; align-items: center; justify-content: space-between; `