@selfcommunity/react-core
Version:
React Core Components useful for integrating UI Community components (react-ui).
272 lines (269 loc) • 11.5 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const react_1 = require("react");
const api_services_1 = require("@selfcommunity/api-services");
const types_1 = require("@selfcommunity/types");
const utils_1 = require("@selfcommunity/utils");
const Errors_1 = require("../constants/Errors");
const SCPreferencesProvider_1 = require("../components/provider/SCPreferencesProvider");
const Preferences_1 = require("../constants/Preferences");
const useSCCachingManager_1 = tslib_1.__importDefault(require("./useSCCachingManager"));
const pubsub_js_1 = tslib_1.__importDefault(require("pubsub-js"));
const Notification_1 = require("../constants/Notification");
const types_2 = require("@selfcommunity/types");
const use_deep_compare_effect_1 = require("use-deep-compare-effect");
/**
:::info
This custom hook is used to manage to manage friends.
:::
:::tip How to use it:
Follow these steps:
```jsx
1. const scUserContext: SCUserContextType = useSCUser();
2. const scConnectionsManager: SCConnectionsManagerType = scUserContext.manager.connections;
3. scConnectionsManager.status(user)
```
:::
*/
function useSCConnectionsManager(user) {
const { cache, updateCache, emptyCache, data, setData, loading, setLoading, setUnLoading, isLoading } = (0, useSCCachingManager_1.default)();
const scPreferencesContext = (0, SCPreferencesProvider_1.useSCPreferences)();
const authUserId = user ? user.id : null;
const connectionsDisabled = Preferences_1.CONFIGURATIONS_FOLLOW_ENABLED in scPreferencesContext.preferences && scPreferencesContext.preferences[Preferences_1.CONFIGURATIONS_FOLLOW_ENABLED].value;
const notificationConnAcceptSubscription = (0, react_1.useRef)(null);
const notificationConnRequestSubscription = (0, react_1.useRef)(null);
const notificationConnRemoveSubscription = (0, react_1.useRef)(null);
const notificationConnRequestCancelSubscription = (0, react_1.useRef)(null);
/**
* Notification subscriber handler
* @param msg
* @param data
*/
const notificationSubscriber = (msg, dataMsg) => {
if (dataMsg.data.connection !== undefined) {
let _upd;
switch (Notification_1.SCNotificationMapping[dataMsg.data.activity_type]) {
case types_1.SCNotificationTypologyType.CONNECTION_REQUEST:
_upd = { user: 'request_user', state: types_2.SCConnectionStatus.CONNECTION_REQUEST_RECEIVED };
break;
case types_1.SCNotificationTypologyType.CONNECTION_CANCEL_REQUEST:
_upd = { user: 'cancel_request_user', state: null };
break;
case types_1.SCNotificationTypologyType.CONNECTION_ACCEPT:
_upd = { user: 'accept_user', state: types_2.SCConnectionStatus.CONNECTED };
break;
case types_1.SCNotificationTypologyType.CONNECTION_REMOVE:
_upd = { user: 'remove_user', state: null };
break;
}
updateCache([dataMsg.data[_upd.user].id]);
setData((prev) => getDataUpdated(prev, dataMsg.data[_upd.user].id, _upd.state));
}
};
/**
* Subscribe to notification types user_follow, user_unfollow
*/
(0, use_deep_compare_effect_1.useDeepCompareEffectNoCheck)(() => {
notificationConnAcceptSubscription.current = pubsub_js_1.default.subscribe(`${types_1.SCNotificationTopicType.INTERACTION}.${types_1.SCNotificationTypologyType.CONNECTION_ACCEPT}`, notificationSubscriber);
notificationConnRequestSubscription.current = pubsub_js_1.default.subscribe(`${types_1.SCNotificationTopicType.INTERACTION}.${types_1.SCNotificationTypologyType.CONNECTION_REQUEST}`, notificationSubscriber);
notificationConnRequestCancelSubscription.current = pubsub_js_1.default.subscribe(`${types_1.SCNotificationTopicType.INTERACTION}.${types_1.SCNotificationTypologyType.CONNECTION_CANCEL_REQUEST}`, notificationSubscriber);
notificationConnRemoveSubscription.current = pubsub_js_1.default.subscribe(`${types_1.SCNotificationTopicType.INTERACTION}.${types_1.SCNotificationTypologyType.CONNECTION_REMOVE}`, notificationSubscriber);
return () => {
pubsub_js_1.default.unsubscribe(notificationConnAcceptSubscription.current);
pubsub_js_1.default.unsubscribe(notificationConnRequestSubscription.current);
pubsub_js_1.default.unsubscribe(notificationConnRequestCancelSubscription.current);
pubsub_js_1.default.unsubscribe(notificationConnRemoveSubscription.current);
};
}, [data]);
/**
* Memoized refresh all connections
* It makes a single request to the server and retrieves
* all the users connected by the authenticated user in a single solution
* It might be useful for multi-tab sync
*/
const refresh = (0, react_1.useMemo)(() => () => {
emptyCache();
if (authUserId && cache.length > 0) {
// Only if user is authenticated
api_services_1.http
.request({
url: api_services_1.Endpoints.UserConnectionStatuses.url({}),
method: api_services_1.Endpoints.UserConnectionStatuses.method,
data: { users: cache },
})
.then((res) => {
if (res.status >= 300) {
return Promise.reject(res);
}
updateCache(Object.keys(res.data.connection_statuses).map((id) => parseInt(id)));
setData(Object.keys(res.data.connection_statuses).map((k) => ({ [k]: res.data.connection_statuses[k] })));
return Promise.resolve(res.data);
})
.catch((e) => {
utils_1.Logger.error(Errors_1.SCOPE_SC_CORE, 'Unable to refresh users Connections by the authenticated user.');
utils_1.Logger.error(Errors_1.SCOPE_SC_CORE, e);
});
}
}, [data, authUserId, cache]);
/**
* Memoized Request connection
*/
const handleRequest = (0, react_1.useMemo)(() => (user, endpoint) => {
setLoading(user.id);
return api_services_1.http
.request({
url: endpoint.url({ id: user.id }),
method: endpoint.method,
})
.then((res) => {
if (res.status >= 300) {
return Promise.reject(res);
}
updateCache([user.id]);
setData((prev) => getDataUpdated(prev, user.id, res.data.connection_status));
setUnLoading(user.id);
return Promise.resolve(res.data);
})
.catch((e) => {
utils_1.Logger.error(Errors_1.SCOPE_SC_CORE, e);
if (e && e.response && e.response && e.response.status && e.response.status === 403) {
setUnLoading(user.id);
return Promise.reject(e);
}
return checkUserConnectionStatus(user);
});
}, [data, loading, cache]);
/**
* Memoized Request connection
*/
const requestConnection = (0, react_1.useMemo)(() => (user) => {
return handleRequest(user, api_services_1.Endpoints.UserRequestConnection);
}, [handleRequest]);
/**
* Memoized cancel request connection
*/
const cancelRequestConnection = (0, react_1.useMemo)(() => (user) => {
return handleRequest(user, api_services_1.Endpoints.UserCancelRequestConnection);
}, [handleRequest]);
/**
* Memoized Remove connection
*/
const removeConnection = (0, react_1.useMemo)(() => (user) => {
return handleRequest(user, api_services_1.Endpoints.UserRemoveConnection);
}, [handleRequest]);
/**
* Memoized Accept Request connection
*/
const acceptConnection = (0, react_1.useMemo)(() => (user) => {
return handleRequest(user, api_services_1.Endpoints.UserAcceptRequestConnection);
}, [handleRequest]);
/**
* Return current user status if exists,
* otherwise return null
*/
const getCurrentUserCacheStatus = (0, react_1.useMemo)(() => (user) => {
const d = data.filter((k) => parseInt(Object.keys(k)[0]) === user.id);
return d.length ? d[0][user.id] : null;
}, [data]);
/**
* Check if the authenticated user is connected with the user
* Update the users cached
* Update user statuses
* @param user
*/
const checkUserConnectionStatus = (user) => {
setLoading(user.id);
return api_services_1.http
.request({
url: api_services_1.Endpoints.UserCheckConnectionStatus.url({ id: user.id }),
method: api_services_1.Endpoints.UserCheckConnectionStatus.method,
})
.then((res) => {
if (res.status >= 300) {
return Promise.reject(res);
}
setData((prev) => getDataUpdated(prev, user.id, res.data.connection_status));
updateCache([user.id]);
setUnLoading(user.id);
return Promise.resolve(res.data);
})
.catch((e) => {
setUnLoading(user.id);
return Promise.reject(e);
});
};
/**
* Get updated data
* @param data
* @param userId
* @param connectionStatus
*/
const getDataUpdated = (data, userId, connectionStatus) => {
const _index = data.findIndex((k) => parseInt(Object.keys(k)[0]) === userId);
let _data;
if (_index < 0) {
_data = [...data, ...[{ [userId]: connectionStatus }]];
}
else {
_data = data.map((k, i) => {
if (parseInt(Object.keys(k)[0]) === userId) {
return { [Object.keys(k)[0]]: connectionStatus };
}
return { [Object.keys(k)[0]]: data[i][Object.keys(k)[0]] };
});
}
return _data;
};
/**
* Bypass remote check if the user is followed
*/
const getConnectionStatus = (0, react_1.useMemo)(() => (user) => {
updateCache([user.id]);
setData((prev) => getDataUpdated(prev, user.id, user.connection_status));
return user.connection_status;
}, [data, cache]);
/**
* Memoized status
* If user is already in cache -> check data user statuses,
* otherwise, check if auth user is connected with user
*/
const status = (user) => {
if (cache.includes(user.id)) {
return getCurrentUserCacheStatus(user);
}
if (authUserId) {
if ('connection_status' in user) {
return getConnectionStatus(user);
}
if (!isLoading(user)) {
checkUserConnectionStatus(user);
}
}
return null;
};
/**
* Empty cache on logout
*/
(0, react_1.useEffect)(() => {
if (!authUserId) {
emptyCache();
}
}, [authUserId]);
if (connectionsDisabled || !user) {
return { connections: data, loading, isLoading };
}
return {
connections: data,
loading,
isLoading,
status,
requestConnection,
cancelRequestConnection,
acceptConnection,
removeConnection,
refresh,
emptyCache,
};
}
exports.default = useSCConnectionsManager;
;