UNPKG

instantjob-recruiter-client

Version:

a set of tools for creating an instantjob recruiter react client

360 lines (338 loc) 11.3 kB
import React from 'react' import moment from 'common/moment' import {browserHistory} from 'react-router' import {MdEdit, MdDone, MdDoneAll, MdSend, MdClose} from 'react-icons/lib/md' import request from './request' import store from './store' import { set_from_array, set_intersection, human_plural, set_count, download_file, array_from_set, empty_set, make_memoized, } from 'common/utilities' import {color} from 'common/styles' import {cancelable_timeout} from 'common/cancelable' import { store_deals, store_missions, update_mission, update_deal, store_available_users, remove_mission, remove_deal, send_mission, assign_mission, unassign_mission, replace_mission_events, remove_deals, } from '../actions/missions' import {dismiss_popover, show_popover, alert_success} from 'actions/display' import CancelMission from 'components/popovers/cancel_mission' import SendMission from 'components/popovers/send_mission' import AssignMission from 'components/popovers/assign_mission' import UnassignMission from 'components/popovers/unassign_mission' import ConfirmMissionUpdate from 'components/popovers/confirm_mission_update' import CustomizeDealFields from 'components/popovers/customize_deal_fields' import {get_missions, get_deals, get_mission_proposals} from 'selectors/missions' export function mission_period(mission) { if (mission.start) { let day_format = `D MMM${moment().isSame(mission.start, 'year') ? '' : ' YYYY'}` let hour_format = 'HH:mm' let day_with_hour_format = `${day_format} ${mission.full_days ? '' : hour_format}`.trim() if (moment(mission.start).isSame(mission.end, 'day')) { return `${moment(mission.start).format(day_format)}${mission.full_days ? '' : ` : ${moment(mission.start).format(hour_format)}${moment(mission.end).format(hour_format)}`}` } else { return `${moment(mission.start).format(day_with_hour_format)}${moment(mission.end).format(day_with_hour_format)}` } } else { return "" } } export function action_create_deal() { request.post(`recruiters/${store.getState().profile.id}/deals`) .then((deal) => { store.dispatch(store_deals([deal])) browserHistory.push(`/deals/${deal.id}`) }) } export function action_update_mission({users_count, grouped_users_status: {assigned, accepted}, status}, mission) { const action = () => { store.dispatch(update_mission(mission)) request.delayed_put(`missions/${mission.id}`, {mission}) } if ( status != 'assigned' && mission.users_count && assigned.length >= mission.users_count && accepted.length ) { store.dispatch(show_popover( ConfirmMissionUpdate, {on_confirm: action}, "Attention" )) } else { action() } } export function action_cancel_mission({id, status}) { function action() { store.dispatch(remove_mission(id)) request.delete(`missions/${id}`) } if (status == 'draft') { action() } else { store.dispatch(show_popover( CancelMission, { on_click: () => { action() store.dispatch(dismiss_popover()) }, mission_status: status, }, 'Annuler la prestation', )) } } export function action_cancel_deal({id, status, missions}) { function action() { store.dispatch(remove_deal(id)) request.delete(`deals/${id}`) browserHistory.push("/deals") } store.dispatch(show_popover( CancelMission, { on_click: () => { action() store.dispatch(dismiss_popover()) }, mission_status: status, }, 'Annuler la mission', )) } export function action_update_mission_events(mission_id, events) { return request.post(`missions/${mission_id}/events`, {events}) .then((events) => store.dispatch(replace_mission_events(mission_id, events))) } export function place_from_workplace({latitude, longitude, name, address}) { return { location: { lat: latitude, lng: longitude, }, label: name, address, } } export function action_send_mission(mission, user_ids) { return new Promise((resolve, reject) => { store.dispatch(show_popover( SendMission, { mission_id: mission.id, on_confirm() { request.put(`missions/${mission.id}/send`, {user_ids}) .then(() => store.dispatch(alert_success("La proposition de mission a bien été envoyée aux candidats que vous aviez sélectionnés."))) store.dispatch(send_mission(mission.id, user_ids)) store.dispatch(dismiss_popover()) resolve() } }, store.getState().profile.agency.name )) }) } export function action_assign_mission(mission, user_ids, status = 'accepted') { return new Promise((resolve, reject) => { store.dispatch(show_popover( AssignMission, { status, mission, on_confirm() { request.put(`missions/${mission.id}/assign`, {user_ids}) .then(() => { const {grouped_users_status: {accepted}, status} = get_missions(store.getState())[mission.id] const has_users_with_status_not_retained = status == "assigned" && set_count(set_intersection(set_from_array(mission.grouped_users_status.accepted), accepted)) store.dispatch(alert_success(`La mission a bien été validée auprès ${human_plural( user_ids.length, "du candidat que vous aviez sélectionné, et il a été prévenu par mail", "des candidats que vous aviez sélectionnés, et ils ont été prévenus par mail" )}.${ has_users_with_status_not_retained ? " Les candidats qui s'étaient déclarés intéressés et que vous n'avez pas sélectionés ont reçu un message pour les prévenir." : "" }`)) }) store.dispatch(assign_mission(mission.id, user_ids)) store.dispatch(dismiss_popover()) resolve() } }, 'Valider la mission pour ce candidat' )) }) } export function action_unassign_mission(mission, user_ids) { return new Promise((resolve, reject) => { store.dispatch(show_popover( UnassignMission, {on_confirm() { request.put(`missions/${mission.id}/unassign`, {user_ids}) .then(() => store.dispatch(alert_success(`Nous avons envoyé un mail ${human_plural(user_ids.length, 'au candidat que vous aviez sélectionné pour lui dire que sa', 'aux candidats que vous aviez sélectionnés pour leur dire que leur')} mission est annulée.`))) store.dispatch(unassign_mission(mission.id, user_ids)) store.dispatch(dismiss_popover()) resolve() }}, 'Annuler la mission pour ce candidat' )) }) } export function action_duplicate_deal({id}) { browserHistory.push('/deals') request.post(`deals/${id}/duplicate`) .then((deal) => { browserHistory.push(`/deals/${deal.id}`) store.dispatch(store_deals([deal])) }) } export function deal_has_custom_fields({has_custom_events, has_custom_workplace, custom_field_ids}) { return has_custom_events || has_custom_workplace || !empty_set(custom_field_ids) } export function action_add_mission(deal) { function action() { request.post(`deals/${deal.id}/missions`) .then((mission) => store.dispatch(store_missions([mission]))) } if (!deal_has_custom_fields(deal)) { action_customize_deal_fields(deal) .then(action) } else { action() } } export function action_customize_deal_fields({id}) { return new Promise((resolve, reject) => { store.dispatch(show_popover( CustomizeDealFields, { deal_id: id, update(deal) { store.dispatch(update_deal({...deal, id})) const {has_custom_events, has_custom_workplace, custom_field_ids} = deal request.put(`deals/${id}`, {deal: {has_custom_events, has_custom_workplace, custom_field_ids: array_from_set(custom_field_ids)}}) store.dispatch(dismiss_popover()) resolve() } }, "Sélectionner les champs spécifiques à chaque prestation" )) }) } export function action_export_users({id}) { return request.asynchronous(`deals/${id}/export_users`) .then((response) => { download_file(response.url, "mission") }) } export const get_mission_status_elements = make_memoized((status) => { switch (status) { case 'draft': return { priority: 1, name: 'non proposée', color: color('black', 'pale'), icon: <MdEdit />, } case 'sent': return { priority: 4, name: 'en attente de réponse', color: color('primary', 'light'), icon: "?", } case 'pending_assignement': return { priority: 3, name: 'en attente de validation', color: color('attention'), icon: <MdDone />, } case 'assigned': return { priority: 5, name: 'validée', color: color('primary'), icon: <MdDoneAll />, } case 'pending_selection': return { priority: 2, name: 'à proposer à nouveau', color: color('important'), icon: <MdSend />, } } }) export function get_mission_proposal_status_elements(status) { switch (status) { case 'new': return { icon: "?", color: color('primary', 'light'), } case 'accepted': return { icon: <MdDone />, color: color('attention'), } case 'rejected': return { icon: <MdClose />, color: color('black', 'pale'), } case 'assigned': return { icon: <MdDoneAll />, color: color('primary'), } default: return {} } } export function action_cancel_drafts(deal_ids) { const deals = get_deals(store.getState()) deal_ids = deal_ids.filter((id) => (deals[id] || {}).status == 'draft') request.put(`deals/cancel`, {deal_ids}) store.dispatch(remove_deals(deal_ids)) } export function action_toggle_publish_mission({id, published}) { store.dispatch(update_mission({id, published: !published})) if (published) { return request.put(`missions/${id}/unpublish`) } else { return request.put(`missions/${id}/publish`) } } export function action_notify_updated_mission(mission_id) { const {id, notification_timeout, sent} = get_mission_proposals(store.getState())[mission_id] if (!sent) { return } if (notification_timeout) { notification_timeout.cancel() } const will_send_notification_at = moment().add(1, 'minute') store.dispatch(update_mission({ id, notification_timeout: cancelable_timeout(() => { request.put(`missions/${id}/notify_of_update`) store.dispatch(update_mission({ id, notification_timeout: cancelable_timeout(() => { store.dispatch(update_mission({id, will_send_notification_at: false})) }, 2 * 1000) })) }, -moment().diff(will_send_notification_at)), will_send_notification_at, })) } export function action_cancel_notify_updated_mission({id, notification_timeout}) { if (notification_timeout) { notification_timeout.cancel() } store.dispatch(update_mission({id, will_send_notification_at: false})) }