UNPKG

chayns-components

Version:

A set of beautiful React components for developing chayns® applications.

336 lines (331 loc) 12 kB
/* eslint-disable no-console */ import React, { createContext, useEffect, useReducer, useCallback, useContext, useRef, useState } from 'react'; import PropTypes from 'prop-types'; import debounce from 'lodash.debounce'; import { reducer as PersonsReducer, initialState } from './PersonsReducer'; import { fetchPersons, fetchUacPersons, fetchSites, fetchKnownPersons } from './PersonsApi'; import { fetchGroups } from '../uacGroups/UacGroupApi'; import { convertKnownPerson, convertPerson, convertPersons, convertSites, convertUacPersons } from './PersonsConverter'; import FriendsHelper from './FriendsHelper'; import simplifyString from '../../../../utils/simplifyString'; const ObjectMapping = { groups: [{ key: 'friends', lang: { de: 'Freunde', en: 'friends' }, roundIcons: true, filter: inputValue => e => inputValue ? e.name && ` ${simplifyString(e.name)}`.includes(` ${simplifyString(inputValue)}`) || e.personId && e.personId === inputValue : true }, { key: 'personsRelated', lang: { de: 'Personen', en: 'persons' }, roundIcons: true, show: value => value && value.length >= 3 }, { key: 'sites', lang: { de: 'Sites', en: 'friends' }, roundIcons: false, show: value => value && value.length >= 3 }, { key: 'personsUnrelated', lang: { de: 'Weitere Personen', en: 'further friends' }, roundIcons: true, show: value => value && value.length >= 3 }, { key: 'groups', lang: { de: 'Gruppen', en: 'groups' }, filter: inputValue => e => e.name && e.name.toLowerCase().startsWith((inputValue || '').toLowerCase()) }, { key: 'knownPersons', lang: { de: 'Bekannte Personen', en: 'known persons' }, roundIcons: true, show: value => value && value.length >= 3 }, { key: 'uacPersons', lang: { de: 'Personen', en: 'persons' }, roundIcons: true, show: value => value && value.length >= 3 }, { key: 'addEntry', lang: { de: 'Hinzufügen', en: 'Add' } }], showName: 'name', identifier: 'id', search: ['fullName', 'firstName', 'lastName', 'personId'], relations: 'relations', imageUrl: 'imageUrl', verified: 'verificationState' }; const PersonFinderContext = /*#__PURE__*/createContext({ ...initialState, dispatch: () => console.warn('[chayns components] PersonsContext: dispatch: no context provided'), onChange: () => console.warn('[chayns components] PersonsContext: onChange: no context provided'), onLoadMore: () => console.warn('[chayns components] PersonsContext: onLoadMore: no context provided'), setFriend: () => console.warn('[chayns components] PersonsContext: setFriend: no context provided'), isFriend: () => console.warn('[chayns components] PersonsContext: isFriend: no context provided') }); const PersonFinderStateProvider = _ref => { let { children, take = 20, enablePersons = true, enableSites = false, enableFriends = true, enableUacGroups = false, enableKnownPersons, includeOwn = false, uacId, reducerFunction, inputValue = '', addInputToList = false } = _ref; const [state, dispatch] = useReducer(PersonsReducer, initialState); const skipPersons = state.data.personsUnrelated.length + state.data.personsRelated.length; const skipSites = state.data.sites.length; const skipKnownPersons = state.data.knownPersons.length; const skipUacPersons = state.data.uacPersons.length; const knownPersonsInitialized = useRef(false); const uacGroupsInitialized = useRef(false); const [lastValue, setLastValue] = useState(''); useEffect(() => { if (!enableFriends) return undefined; FriendsHelper.init(); // Use event listener to update all contexts if friends change const friendsListener = () => dispatch({ type: 'RECEIVE_FRIENDS', data: [] }); friendsListener(FriendsHelper.getFriendsList()); FriendsHelper.addUpdateListener(friendsListener); return () => FriendsHelper.removeUpdateListener(friendsListener); }, [enableFriends]); useEffect(() => { (async () => { if (!enableUacGroups || uacGroupsInitialized.current) return; let groups = await fetchGroups(); groups = groups.map(_ref2 => { let { id, showName } = _ref2; return { type: 'GROUP', id, name: showName, imageUrl: `https://sub60.tobit.com/l/${chayns.env.site.id}?size=100` }; }); dispatch({ type: 'RECEIVE_GROUPS', data: groups }); uacGroupsInitialized.current = true; })(); }, [enableUacGroups]); const loadPersons = useCallback(async function (inputValue, clear) { if (clear === void 0) { clear = false; } const value = inputValue.trim(); if (value.length < 3 || !enablePersons || uacId) return; dispatch({ type: 'REQUEST_PERSONS', showWaitCursor: { personsRelated: state.hasMore.personsRelated, personsUnrelated: !state.hasMore.personsRelated }, clear }); const persons = await fetchPersons(value, clear ? 0 : skipPersons, take); const convertedPersons = convertPersons(persons); const hasMore = { personsRelated: convertedPersons.personsRelated.length === take, personsUnrelated: persons.length === take }; // not optimal performance-wise but reduces redundant code const [ownUser] = convertPersons([{ type: 'PERSON', name: chayns.env.user.fullName, id: chayns.env.user.personId, fullName: chayns.env.user.fullName, firstName: chayns.env.user.firstName, lastName: chayns.env.user.lastName, personId: chayns.env.user.personId }]).personsRelated; // prepend own user when prop is used, user is logged in and name matches if (includeOwn && clear && chayns.env.user.isAuthenticated && ownUser.fullName && ownUser.fullName.toLowerCase().startsWith(value.toLowerCase())) { convertedPersons.personsRelated.unshift(ownUser); } else if (!includeOwn && convertedPersons.personsRelated.some(user => user.personId === ownUser.personId)) { convertedPersons.personsRelated.splice(convertedPersons.personsRelated.findIndex(user => user.personId === ownUser.personId), 1); } dispatch({ type: 'RECEIVE_PERSONS', data: convertedPersons, hasMore }); }, [enablePersons, uacId, state.hasMore.personsRelated, skipPersons, take, includeOwn]); const loadUacPersons = useCallback(async function (value, clear) { if (clear === void 0) { clear = false; } if (value.length < 3 || !uacId) return; dispatch({ type: 'REQUEST_UAC_PERSONS', showWaitCursor: true, clear }); const persons = await fetchUacPersons(uacId)(value, clear ? 0 : skipUacPersons, take); const convertedPersons = convertUacPersons(persons); const hasMore = convertedPersons.length === take; dispatch({ type: 'RECEIVE_UAC_PERSONS', data: convertedPersons, hasMore }); }, [uacId, skipUacPersons, take]); const loadSites = useCallback(async function (value, clear) { if (clear === void 0) { clear = false; } if (value.length < 3 || !enableSites) return; dispatch({ type: 'REQUEST_SITES', showWaitCursor: true, clear }); const sites = await fetchSites(value, clear ? 0 : skipSites, take); dispatch({ type: 'RECEIVE_SITES', data: convertSites(sites), hasMore: sites.length === take }); }, [skipSites, take, enableSites]); const loadKnownPersons = useCallback(async function (value, clear) { if (clear === void 0) { clear = false; } if (value.length < 3 || !enableKnownPersons) return; dispatch({ type: 'REQUEST_KNOWN_PERSONS', showWaitCursor: true, clear }); const persons = await fetchKnownPersons(value, clear ? 0 : skipKnownPersons, take); dispatch({ type: 'RECEIVE_KNOWN_PERSONS', data: convertKnownPerson(persons), hasMore: persons.length === take }); }, [skipKnownPersons, take, enableKnownPersons]); useEffect(() => { if (knownPersonsInitialized.current) return; loadKnownPersons(''); knownPersonsInitialized.current = true; }, [loadKnownPersons]); // eslint-disable-next-line react-hooks/exhaustive-deps const onChange = useCallback(debounce(async value => { try { setLastValue(value); await Promise.all([loadPersons(value, true), loadUacPersons(value, true), loadSites(value, true), loadKnownPersons(value, true)]); } catch (err) { console.error(err); } }, 500), [take, enableKnownPersons, enableFriends, enablePersons, enableSites, enableUacGroups, enableKnownPersons, uacId]); useEffect(() => { // only trigger when enablePersons, enableSite, enableKnownPersons or uacId props change if (lastValue) { onChange(lastValue); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [enablePersons, enableSites, enableKnownPersons, uacId]); const onLoadMore = useCallback(async (type, value) => { const promises = []; if (!type || type !== 'sites' && type !== 'knownPersons' && type !== 'uacPersons') { promises.push(loadPersons(value)); } if (!type || type === 'uacPersons') { promises.push(loadUacPersons(value)); } if (!type || type === 'sites') { promises.push(loadSites(value)); } if (!type || type === 'knownPersons' || !enablePersons && type === 'default') { promises.push(loadKnownPersons(value)); } await Promise.all(promises); }, [loadPersons, loadSites, loadKnownPersons, loadUacPersons, enablePersons]); const unreducedData = { personsRelated: enablePersons ? state.data.personsRelated : [], personsUnrelated: enablePersons ? state.data.personsUnrelated : [], sites: enableSites ? state.data.sites : [], groups: enableUacGroups ? state.data.groups : [], knownPersons: enableKnownPersons ? state.data.knownPersons : [], uacPersons: uacId ? state.data.uacPersons : [], friends: enableFriends ? FriendsHelper.getFriendsList() : [], addEntry: addInputToList ? [{ type: 'ADD_ENTRY', id: -1, name: inputValue || 'Hinzufügen', imageUrl: 'https://tsimg.cloud/77896-21884/0ef639efc1322459faf298467f6111383ea72c1a.svg' }] : [] }; unreducedData.personsRelated = unreducedData.personsRelated.filter(person => !unreducedData.friends.find(friend => friend.personId === person.personId)); unreducedData.personsUnrelated = unreducedData.personsUnrelated.filter(person => !unreducedData.friends.find(friend => friend.personId === person.personId)); const data = typeof reducerFunction === 'function' ? reducerFunction(unreducedData) : unreducedData; return /*#__PURE__*/React.createElement(PersonFinderContext.Provider, { value: { ...state, data, autoLoading: !enableUacGroups && !enableSites && (enablePersons && !enableKnownPersons || !enablePersons && enableKnownPersons), dispatch, onLoadMore, onChange, setFriend: FriendsHelper.setFriend, isFriend: FriendsHelper.isFriend } }, children); }; PersonFinderStateProvider.propTypes = { children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]), take: PropTypes.number, enablePersons: PropTypes.bool, enableSites: PropTypes.bool, enableFriends: PropTypes.bool, enableUacGroups: PropTypes.bool, enableKnownPersons: PropTypes.bool, includeOwn: PropTypes.bool, uacId: PropTypes.number, reducerFunction: PropTypes.func, addInputToList: PropTypes.bool, inputValue: PropTypes.string }; export default { Consumer: PersonFinderContext.Consumer, Provider: PersonFinderStateProvider, ObjectMapping, ValueConverter: convertPerson }; export const useStateValue = () => useContext(PersonFinderContext); //# sourceMappingURL=PersonsContext.js.map