instantjob-recruiter-client
Version:
a set of tools for creating an instantjob recruiter react client
383 lines (364 loc) • 13.5 kB
JSX
import {tolerant_selector} from 'selectors/base'
import {
make_memoized, array_from_set, set_from_array, hash_with_key, filter_hash, property_getter, create_hash,
empty_array, map_hash, array_from_hash, flatten_array, split_hash,
} from 'common/utilities'
import {
missions_fields_options, users_fields_options, action_create_value, action_add_user_value,
action_update_field, action_remove_field, action_select_entity_value, action_remove_entity_value,
action_update_entity_comment, action_view_entity_template, action_upload_entity_file,
action_fetch_entity_computed_value, action_remove_value, action_update_value, action_create_value_field,
action_show_associated_values,
} from 'common/fields'
import {get_user_assigned_mission_ids} from './user_missions'
import store from 'common/store'
const get_raw_fields = (state) => state.fields.fields
const get_raw_values = (state) => state.fields.values
const get_raw_missions = (state) => state.missions.missions
const get_raw_deals = (state) => state.missions.deals
const get_raw_users = (state) => state.users.users
const get_raw_shifts = (state) => state.shifts.shifts
export const get_proposal_ids = tolerant_selector(
[get_raw_missions],
(missions) => flatten_array(
array_from_hash(missions).map(({assigned_proposals}) => (assigned_proposals || []).map(property_getter('id')))
)
)
export const get_values = tolerant_selector(
[get_raw_values],
(values) => map_hash(values, (value) => {
const {field_id, id} = value
return {
...value,
update(new_value) {
action_update_value({id, ...new_value})
},
remove() {
action_remove_value(id)
},
create_value_field() {
return action_create_value_field(field_id)
},
show_associated_values() {
action_show_associated_values(id)
},
}
})
)
export const get_values_by_field = tolerant_selector(
[get_values, get_raw_fields],
(values, fields) => split_hash(values, property_getter('field_id'), Object.keys(fields))
)
export const get_fields = tolerant_selector(
[get_raw_fields, get_values_by_field],
(fields, values_by_field) => array_from_hash(fields).map((field) => {
const values = values_by_field[field.id]
return {
...field,
value_ids: Object.keys(values),
values: array_from_hash(values),
tolerant: true,
get_value_props(value_id) {
return values[value_id]
},
get_item_values({id}) {
return [field.value_id_for[id]].filter(Boolean)
},
update(new_field) {
return action_update_field({id: field.id, ...new_field})
},
remove() {
return action_remove_field(field.id)
},
view_template(id) {
return action_view_entity_template(id, field)
},
create_value(value_name) {
return action_create_value(field.id, value_name)
},
select_value(entity_id, value_id, for_missions) {
return action_select_entity_value(entity_id, value_id, for_missions)
},
update_comment(entity_id, comment) {
return action_update_entity_comment(entity_id, field.id, comment)
},
fetch_value(entity_id) {
return action_fetch_entity_computed_value(entity_id, field.id)
},
}
})
)
function make_get_entity_ids(entity_type) {
switch (entity_type) {
case 'User':
return (state) => Object.keys(state.users.users)
case 'Mission':
return (state) => Object.keys(state.missions.missions)
case 'MissionProposal':
return get_proposal_ids
case 'Shift':
return (state) => Object.keys(state.shifts.shifts)
case 'Value':
return (state) => Object.keys(state.fields.values)
case 'Workplace':
return (state) => Object.keys(state.missions.workplaces)
case 'Deal':
return (state) => Object.keys(state.missions.deals)
default:
return (state) => []
}
}
const make_get_entity_values_by_entity = make_memoized((entity_type) => {
if (entity_type == 'Mission') {
return get_mission_values_by_mission
}
return tolerant_selector(
[get_raw_values, make_get_entity_ids(entity_type), get_raw_fields],
(values, entity_ids, fields) => create_hash(
entity_ids,
(entity_id) => Object.keys(values).filter((value_id) => {
const {field_id, entity_ids} = values[value_id] || {}
const {for_entity, category, value_id_for} = fields[field_id] || {}
if (for_entity == entity_type) {
switch (category) {
case 'non_exclusive':
return entity_ids[entity_id]
case 'exclusive':
return value_id == value_id_for[entity_id]
default:
return false
}
}
return false
})
)
)
})
export const get_mission_values_by_mission = tolerant_selector(
[get_raw_values, get_raw_missions, get_raw_deals, get_raw_fields],
(values, missions, deals, fields) => {
return create_hash(
Object.keys(missions),
(mission_id) => {
const {deal_id} = missions[mission_id]
const {custom_field_ids, template_mission_id} = deals[deal_id] || {custom_field_ids: {}}
const get_mission_id = make_memoized((field_id) => custom_field_ids[field_id] ? mission_id : template_mission_id)
return Object.keys(values).filter((value_id) => {
const {mission_ids, field_id} = values[value_id] || {mission_ids: {}}
const {for_entity, recycled, category, value_id_for} = fields[field_id] || {}
if (for_entity == 'Mission' || recycled) {
if (category == 'exclusive' && for_entity == 'Mission') {
return value_id == value_id_for[get_mission_id(field_id)]
} else {
return mission_ids[get_mission_id(field_id)]
}
}
return false
})
}
)
}
)
const make_fields_with_selected_values = (item_type, item_id, fields, values, selected_values) => {
let field_ids = fields.map(property_getter('id'))
let selected_values_by_field = create_hash(field_ids, () => [])
selected_values.forEach((id) => {
const value = values[id]
if (selected_values_by_field[value.field_id]) {
selected_values_by_field[value.field_id].push(value)
}
})
const for_missions = item_type == 'Mission'
return hash_with_key(fields.map((field) => {
const {
value_id_for, id, recycled, files, select_value, update_comment, view_template,
fetch_value, comments,
} = field
let {category} = field
if (recycled && for_missions) {
category = 'non_exclusive'
}
const selected_value_id = (value_id_for || {})[item_id]
function is_empty() {
switch (category) {
case "non_exclusive":
return empty_array(selected_values_by_field[id])
case "comment":
return !comments[item_id]
case "file":
return !files[item_id]
case "exclusive":
return !selected_value_id
}
}
return {
...field,
category,
selected_values: selected_values_by_field[field.id],
selected_value: values[selected_value_id],
empty: is_empty(),
comment: (comments || {})[item_id],
file: (files || {})[item_id],
selected: selected_value_id,
allow_creating_values: !for_missions || !field.recycled,
on_select_value(value_id) {
return select_value(item_id, value_id, for_missions)
},
on_deselect_value(value_id) {
return action_remove_entity_value(item_id, value_id, for_missions)
},
on_clear() {
return action_remove_entity_value(item_id, selected_value_id)
},
on_submit_comment(comment) {
return update_comment(item_id, comment)
},
view_template() {
return view_template(item_id)
},
upload_file(file) {
return action_upload_entity_file(item_id, id, file)
},
fetch_value() {
return fetch_value(item_id)
},
user_id: item_type == 'User' && item_id,
}
}))
}
const make_get_fields_by_entity = (entity_type) => {
function make_fields_filter(entity_id, values) {
if (entity_type == 'Mission') {
return ({for_entity, recycled}) => recycled || for_entity == 'Mission'
}
if (entity_type == 'Value') {
const value = values[entity_id] || {}
return ({for_entity, field_id}) => for_entity == 'Value' && value.field_id == field_id
}
return ({for_entity}) => for_entity == entity_type
}
return tolerant_selector(
[
get_fields, get_values, make_get_entity_ids(entity_type),
make_get_entity_values_by_entity(entity_type),
],
(fields, values, entity_ids, entity_values_by_entity) => create_hash(
entity_ids,
(entity_id) => make_fields_with_selected_values(
entity_type,
entity_id,
fields.filter(make_fields_filter(entity_id, values)),
values,
entity_values_by_entity[entity_id]
)
)
)
}
export const get_fields_by_proposal = make_get_fields_by_entity('MissionProposal')
export const get_fields_by_shift = make_get_fields_by_entity('Shift')
export const get_fields_by_user = make_get_fields_by_entity('User')
export const get_fields_by_mission = make_get_fields_by_entity('Mission')
export const get_fields_by_value = make_get_fields_by_entity('Value')
export const get_fields_by_workplace = make_get_fields_by_entity('Workplace')
export const get_fields_by_deal = make_get_fields_by_entity('Deal')
export const get_mission_fields = make_memoized((mission_id) => tolerant_selector(
[get_fields_by_mission],
(fields_by_mission) => fields_by_mission[mission_id]
))
export const get_user_fields = make_memoized((user_id) => tolerant_selector(
[get_fields_by_user],
(fields_by_user) => fields_by_user[user_id]
))
export const get_users_fields_with_locked_values = make_memoized((mission_id, status) => tolerant_selector(
[get_mission_values_by_mission, get_users_filter_fields],
(mission_values_by_mission, fields) => {
if (status == 'available') {
const locked_value_ids = set_from_array(mission_values_by_mission[mission_id] || [])
return fields.map(({values, ...field}) => ({
...field,
values: field.recycled ? values.map((value) => ({
...value,
locked: locked_value_ids[value.id],
})) : values,
}))
} else {
return fields
}
}
))
const make_get_specific_fields = (entity_type, for_missions = false) => tolerant_selector(
[get_fields],
(fields) => fields.filter(
({for_entity, recycled}) => for_entity == entity_type || (for_missions && recycled)
).map((field) => {
if (field.recycled && for_missions) {
return {
...field,
category: 'non_exclusive',
}
}
return field
})
)
export const get_users_fields = make_get_specific_fields('User')
export const get_missions_fields = make_get_specific_fields('Mission', true)
export const get_proposals_fields = make_get_specific_fields('MissionProposal')
export const get_shifts_fields = make_get_specific_fields('Shift')
export const get_workplaces_fields = make_get_specific_fields('Workplace')
export const get_exports_fields = make_get_specific_fields('Agency')
export const get_deals_fields = make_get_specific_fields('Deal')
export const get_missions_filter_fields = tolerant_selector(
[get_missions_fields],
(fields) => fields.map((field) => ({
...field,
get_item_values({template_mission, custom_field_ids, missions}) {
if (custom_field_ids[field.id]) {
return flatten_array(missions.map(field.get_item_values))
}
return field.get_item_values(template_mission)
},
}))
)
export const get_users_filter_fields = tolerant_selector(
[
get_users_fields, get_missions_fields, get_user_assigned_mission_ids, get_fields_by_mission,
get_raw_missions, get_raw_deals,
],
(users_fields, missions_fields, user_assigned_mission_ids, fields_by_mission, missions, deals) => {
return [
...users_fields,
...missions_fields.map((field) => {
const {category, recycled} = field
if (category == 'exclusive' && !recycled) {
return {
...field,
get_item_values({id}) {
const mission_ids = user_assigned_mission_ids[id] || []
return flatten_array(mission_ids.map((mission_id) => {
const mission = missions[mission_id] || {}
const {custom_field_ids, template_mission_id} = deals[mission.deal_id] || {}
if ((custom_field_ids || {})[field.id]) {
return field.get_item_values(mission)
} else {
return field.get_item_values(missions[template_mission_id] || {})
}
}))
},
}
}
return null
}).filter(Boolean),
]
}
)
export const get_missions_recyclable_fields = tolerant_selector(
[get_raw_fields],
(fields) => filter_hash(
fields,
({for_entity, recycled, category}) => for_entity == 'User' && !recycled && (category == 'non_exclusive' || category == 'exclusive')
)
)
export const get_mission_fields_by_deal = tolerant_selector(
[get_fields_by_mission, get_raw_deals],
(fields_by_mission, deals) => map_hash(deals, ({template_mission_id}) => array_from_hash(fields_by_mission[template_mission_id]))
)