import { createSelector } from 'reselect';
import orderBy from 'lodash/orderBy';
import { PROFILE, PRIVACY_SETTINGS, USER_WEIGH_IN_HISTORY } from '../data/entityTypes';
import { userIdSelector } from './userAccountSelectors';
import { userWeighInsCollectionId } from '../data/collectionIds';
import { makeCollectionSelector } from './collectionSelector';
/**
* Selector that receives the root redux state and returns an object with user profile.
* If the user is not logged in, or if the user is logged in but the profile entity is
* not loaded from the API, this selector returns null.
*/
export const userProfileSelector = createSelector(
userIdSelector,
state => state.entities[PROFILE] || {},
(userId, profileEntities) => {
if (userId && profileEntities[userId]) {
return profileEntities[userId];
}
return null;
},
);
/**
* TEMP helper function, remove this once we implement correct profile > weighins normalisation
* @param state
*/
export const makeWeighInsSelector = () => {
const collectionSelector = makeCollectionSelector();
return createSelector(
(state, props) => {
const userId = userIdSelector(state, props);
return collectionSelector(state, { collectionId: userWeighInsCollectionId({ userId }) })
.entities;
},
userProfileSelector,
(weighInEntities, profile) => {
if (weighInEntities) {
return weighInEntities;
}
if (profile) {
return profile.weighIns;
}
return [];
},
);
};
const weighInSelector = makeWeighInsSelector();
/**
* Instance of weighInSelector that does not pass props, and thus will always get the weighins
* for the current user.
* @param state
* @returns {*}
*/
export const userWeighInsSelector = state => weighInSelector(state);
export const getPrivacySelector = createSelector(
state => state.entities[PRIVACY_SETTINGS] || null,
userIdSelector,
(privacyEntity, userId) => (privacyEntity ? privacyEntity[userId] : null),
);
export const getJourneyStartWeightSelector = createSelector(
userProfileSelector,
profile => profile && profile.currentJourney && profile.currentJourney.startWeight,
);
export const getJourneyIdSelector = createSelector(
userProfileSelector,
profile => profile?.currentJourney?.id,
);
/**
* Selector that gets the current weight of the user. It first checks the most recent weighIn,
* and will fall back to the startWeight when there are no weighIns yet.
*/
export const currentWeightSelector = createSelector(
userProfileSelector,
profile => profile && profile.currentJourney && profile.currentJourney.currentWeight,
);
export const userProfileHeightSelector = createSelector(
userProfileSelector,
profile => profile?.height,
);
export const userProfileCurrentWeightSelector = createSelector(
userProfileSelector,
profile => profile?.currentWeight,
);
/**
* Selector for selected weigh-in by id
*/
const weighInByIdSelector = createSelector(
state => state.weighIn.weighInById,
weighInById => {
if (weighInById) {
return weighInById;
}
return null;
},
);
/**
* Selector for weigh-in to add
*/
export const weighInToAddSelector = createSelector(
state => state.weighIn.weighInToAdd,
weighInToAdd => {
if (weighInToAdd) {
return weighInToAdd;
}
return null;
},
);
/**
* Select weigh-in history
*/
export const weighInHistorySelector = createSelector(
state => state.entities[USER_WEIGH_IN_HISTORY],
weighInHistory => {
if (weighInHistory) {
return Object.values(weighInHistory);
}
return [];
},
);
/**
* Selector that gets the previous weight of the after having done a new weighin.
* It first checks the second most recent weighIn, and will fall back to the initialWeight when
* there are no weighIns yet.
*
*/
export const previousWeightSelector = createSelector(
userWeighInsSelector,
getJourneyStartWeightSelector,
weighInHistorySelector,
weighInByIdSelector,
weighInToAddSelector,
(weighIns, journeyStartWeight, weighInHistory, weighInById, weighInToAdd) => {
const weighInWeights = weighIns && weighIns.filter(weighIn => !weighIn.skippingReason);
// Do a correct filter to get the correct previous weight, based on the weight you are editing or adding
const weighInToCheck = weighInById || weighInToAdd;
if (weighInToCheck && weighInHistory && weighInHistory.length > 1) {
const filteredWeighInHistory = weighInHistory.filter(weighIn => !weighIn.skippingReason);
const orderByDateWeighIns = orderBy(
filteredWeighInHistory,
weighIn => weighIn.startOfUserWeekUtc,
['desc'],
);
// Find the weigh-in index from the orderByDateWeighIns
const index = orderByDateWeighIns.findIndex(fd => weighInToCheck.id === fd.id);
const previousWeighIn = orderByDateWeighIns
.slice(index)
.find(
validWeighIn => validWeighIn.weighingDateUTC && validWeighIn.id !== weighInToCheck.id,
);
if (previousWeighIn) {
return previousWeighIn.weight;
}
return journeyStartWeight;
} else if (weighInWeights && weighInWeights.length > 1) {
return weighInWeights[1].weight;
}
return journeyStartWeight;
},
);
/**
* This combined selector is used for showing the correct current week number and mood on
* the progress tile
*/
export const lastWeighInSelector = createSelector(
userWeighInsSelector,
weighIns => weighIns?.[0] || null,
);
/**
* This selector finds if a user has completed a first weigh in yet
*/
export const isFirstWeighInSelector = createSelector(
userWeighInsSelector,
weighIns => weighIns && weighIns.length === 0,
);
/**
* Selector that determines if a member is at target using their currentWeight
* and targetWeight out of their current journey, returns false by default if member
* doesn't have a target weight.
*/
export const isAtTargetSelector = createSelector(userProfileSelector, profile => {
if (profile?.currentJourney?.targetWeight) {
return profile.currentJourney.currentWeight <= profile.currentJourney.targetWeight;
}
return false;
});