|
| 1 | +import { createSelector, createStructuredSelector } from 'reselect'; |
| 2 | +import isEmpty from 'lodash/isEmpty'; |
| 3 | +import findIndex from 'lodash/findIndex'; |
| 4 | +import { formatNumber } from 'utils/format'; |
| 5 | +import { sortByKey } from 'utils/data'; |
| 6 | + |
| 7 | +// get list data |
| 8 | +const getData = state => state.data && state.data; |
| 9 | +const getLocationName = state => state.locationName || null; |
| 10 | +const getLocation = state => state.allLocation || null; |
| 11 | +const getLocationDict = state => state.locationDict || null; |
| 12 | +const getLocationObject = state => state.locationObject || null; |
| 13 | +const getSentences = state => state.config && state.config.sentences; |
| 14 | +const getColors = state => state.colors || null; |
| 15 | +const getSettings = state => state.settings || null; |
| 16 | + |
| 17 | +const getSortedData = createSelector( |
| 18 | + [getData, getSettings], |
| 19 | + (data, settings) => { |
| 20 | + if (isEmpty(data)) return null; |
| 21 | + return sortByKey(data, settings.variable).reverse(); |
| 22 | + } |
| 23 | +); |
| 24 | + |
| 25 | +export const parseData = createSelector( |
| 26 | + [ |
| 27 | + getSortedData, |
| 28 | + getColors, |
| 29 | + getLocation, |
| 30 | + getLocationDict, |
| 31 | + getLocationObject, |
| 32 | + getSettings |
| 33 | + ], |
| 34 | + (data, colors, location, locationsDict, locationObj, settings) => { |
| 35 | + if (isEmpty(data)) return null; |
| 36 | + |
| 37 | + let dataTrimmed = data.map((d, i) => ({ |
| 38 | + ...d, |
| 39 | + rank: i + 1 |
| 40 | + })); |
| 41 | + |
| 42 | + let key; |
| 43 | + if (data[0].admin_2) key = 'admin_2'; |
| 44 | + else if (data[0].admin_1) key = 'admin_1'; |
| 45 | + else key = 'iso'; |
| 46 | + |
| 47 | + if (location.payload.adm0) { |
| 48 | + const locationIndex = locationObj |
| 49 | + ? findIndex(data, d => d[key] === locationObj.value) |
| 50 | + : -1; |
| 51 | + if (locationIndex === -1) return null; |
| 52 | + |
| 53 | + let trimStart = locationIndex - 2; |
| 54 | + let trimEnd = locationIndex + 3; |
| 55 | + if (locationIndex < 2) { |
| 56 | + trimStart = 0; |
| 57 | + trimEnd = 5; |
| 58 | + } |
| 59 | + if (locationIndex > data.length - 3) { |
| 60 | + trimStart = data.length - 5; |
| 61 | + trimEnd = data.length; |
| 62 | + } |
| 63 | + dataTrimmed = dataTrimmed.slice(trimStart, trimEnd); |
| 64 | + } |
| 65 | + const { query, type } = location; |
| 66 | + |
| 67 | + return dataTrimmed.map((d, i) => ({ |
| 68 | + ...d, |
| 69 | + label: locationsDict[d[key]], |
| 70 | + color: colors.density, |
| 71 | + key: `${d.iso}-${i}`, |
| 72 | + path: { |
| 73 | + type, |
| 74 | + payload: { type: 'country', adm0: d.iso }, |
| 75 | + query |
| 76 | + }, |
| 77 | + value: d[settings.variable], |
| 78 | + unit: settings.variable === 'totalbiomass' ? 't' : 't/ha' |
| 79 | + })); |
| 80 | + } |
| 81 | +); |
| 82 | + |
| 83 | +export const parseSentence = createSelector( |
| 84 | + [getData, getLocationName, getSentences, getLocationDict, getSettings], |
| 85 | + (data, location, sentences, locationsDict, settings) => { |
| 86 | + if (!sentences || isEmpty(data)) return null; |
| 87 | + |
| 88 | + if (location === 'global') { |
| 89 | + const sorted = sortByKey(data, [settings.variable]).reverse(); |
| 90 | + |
| 91 | + let biomTop5 = 0; |
| 92 | + let densTop5 = 0; |
| 93 | + const biomTotal = sorted.reduce((acc, next, i) => { |
| 94 | + if (i < 5) { |
| 95 | + biomTop5 += next.totalbiomass; |
| 96 | + densTop5 += next.biomassdensity; |
| 97 | + } |
| 98 | + return acc + next.totalbiomass; |
| 99 | + }, 0); |
| 100 | + |
| 101 | + const percent = biomTop5 / biomTotal * 100; |
| 102 | + const avgBiomDensity = densTop5 / 5; |
| 103 | + |
| 104 | + const value = |
| 105 | + settings.variable === 'totalbiomass' |
| 106 | + ? formatNumber({ num: percent, unit: '%' }) |
| 107 | + : formatNumber({ num: avgBiomDensity, unit: 't/ha' }); |
| 108 | + |
| 109 | + const labels = { |
| 110 | + biomassdensity: 'biomass density', |
| 111 | + totalbiomass: 'total biomass' |
| 112 | + }; |
| 113 | + |
| 114 | + return { |
| 115 | + sentence: sentences[settings.variable], |
| 116 | + params: { |
| 117 | + label: labels[settings.variable], |
| 118 | + value |
| 119 | + } |
| 120 | + }; |
| 121 | + } |
| 122 | + const iso = Object.keys(locationsDict).find( |
| 123 | + key => locationsDict[key] === location |
| 124 | + ); |
| 125 | + const region = data.find(item => { |
| 126 | + if (item.admin_2) return String(item.admin_2) === iso; |
| 127 | + else if (item.admin_1) return String(item.admin_1) === iso; |
| 128 | + return item.iso === iso; |
| 129 | + }); |
| 130 | + if (!region) return null; |
| 131 | + |
| 132 | + const { biomassdensity, totalbiomass } = region; |
| 133 | + return { |
| 134 | + sentence: sentences.initial, |
| 135 | + params: { |
| 136 | + location, |
| 137 | + biomassDensity: formatNumber({ num: biomassdensity, unit: 't/ha' }), |
| 138 | + totalBiomass: formatNumber({ num: totalbiomass, unit: 't' }) |
| 139 | + } |
| 140 | + }; |
| 141 | + } |
| 142 | +); |
| 143 | + |
| 144 | +export default createStructuredSelector({ |
| 145 | + data: parseData, |
| 146 | + sentence: parseSentence |
| 147 | +}); |
0 commit comments