import { createSelector } from 'reselect';
import { addressFields } from 'common/src/app/data/enum/FieldNames/AccountFieldNames';
import returnOnlyPresentValues from 'common/src/app/util/form/returnOnlyPresentValues';
import AccountState from '../data/enum/AccountState';
import { hasFlag } from '../util/bitwiseUtils';
import { JWT_CLAUSE_MAP, JWT_CLAUSE_MAP_ID_TOKEN } from '../reducers/authenticationReducer';
import { ACCOUNT } from '../data/entityTypes';
const EMPTY_ARRAY = [];
const EMPTY_OBJECT = {};
/**
* Selector that receives the root redux state and returns an object
* with user information. If the user is not logged in, this selector returns
* null. If the user is logged in but the account entity is not loaded from
* the API, this object will contain a limited amount of properties which are
* available on the access token.
*/
export const userAccountSelector = createSelector(
state => (state.authentication && state.authentication.userInfo) || EMPTY_OBJECT,
state => state.entities[ACCOUNT] || {},
(userInfo = {}, accountEntities) => {
const result = {};
result.initialUserState = userInfo.initialUserState;
Object.keys(JWT_CLAUSE_MAP).forEach(
clause => (result[JWT_CLAUSE_MAP[clause]] = userInfo[clause]),
);
Object.keys(JWT_CLAUSE_MAP_ID_TOKEN).forEach(
clause => (result[JWT_CLAUSE_MAP_ID_TOKEN[clause]] = userInfo[clause]),
);
// Always return groupId as an array
if (result[JWT_CLAUSE_MAP.group_id]) {
result[JWT_CLAUSE_MAP.group_id] = [].concat(result[JWT_CLAUSE_MAP.group_id]);
}
if (accountEntities[result.id]) {
return {
...result,
...accountEntities[result.id],
};
}
return result;
},
);
/**
* Selector that extracts the user id from the userAccountSelector.
* Returns null if no account data is available
*/
export const userIdSelector = createSelector(
[userAccountSelector, (state, props) => props && props.id],
(userAccount, userId) => userId || (userAccount && userAccount.id),
);
/**
* Selector that extracts the user groupIds from the userAccountSelector.
* Returns empty array if no account data is available
*/
export const userGroupIdsSelector = createSelector(
userAccountSelector,
(state, props) => props && props.groups,
(userAccount, groupId) => groupId || (userAccount && userAccount.groupId) || EMPTY_ARRAY,
);
/**
* Retrieve a user account by id
*/
export const userAccountByIdSelector = userId =>
createSelector(
state => state.entities[ACCOUNT][userId],
accountEntities => {
if (accountEntities) {
return {
account: accountEntities,
};
}
return {
account: {},
};
},
);
export const isSubscriptionValidSelector = createSelector(userAccountSelector, account => {
if (account) {
const onlineSubscriptionValid = hasFlag(
account.accountState,
AccountState.ONLINE_SUBSCRIPTION_VALID,
);
const groupSubscriptionvalid = hasFlag(
account.accountState,
AccountState.GROUP_MEMBERSHIP_VALID,
);
// return if we have a valid group or online subscription
return onlineSubscriptionValid || groupSubscriptionvalid;
}
return false;
});
export const isUserLoggedInSelector = createSelector(
state => state.identity,
identity => identity && !!identity.user,
);
export const userIdentitySelector = createSelector(
state => state.identity,
identity => (identity && identity.user) || EMPTY_OBJECT,
);
export const isOnlineSubscriptionValidSelector = createSelector(userAccountSelector, account => {
if (!account) return false;
return hasFlag(account.accountState, AccountState.ONLINE_SUBSCRIPTION_VALID);
});
export const isGroupMembershipValidSelector = createSelector(userAccountSelector, account => {
if (!account) return false;
return hasFlag(account.accountState, AccountState.GROUP_MEMBERSHIP_VALID);
});
export const userAndEntityIdSelector = createSelector(
(state, userId) => {
const ownUserId = userIdSelector(state);
const selectedId = !userId || userId.toString() === ownUserId ? 'me' : userId;
const entityId = selectedId === 'me' ? ownUserId : selectedId;
return {
selectedId,
entityId,
};
},
user => ({
...user,
}),
);
export const memberTypeSelector = createSelector(userAccountSelector, account =>
!account ? false : account.memberType,
);
// Map values a user has to each possible field
export const userAddressFieldsSelector = createSelector(userAccountSelector, account =>
returnOnlyPresentValues(addressFields, account),
);
export const userAccountAvatarSelector = createSelector(
userAccountSelector,
account => account?.avatar,
);
export const userAccountWeightUnitSelector = createSelector(
userAccountSelector,
account => account?.weightUnit,
);
export const authUserInfoSelector = createSelector(
state => state.authentication.userInfo,
userInfo => userInfo,
);
export const userAccountFirstNameSelector = createSelector(
userAccountSelector,
account => account?.firstName,
);