Source: app/actions/resources/notificationActions.js

import debugLib from 'debug';
import createAction from 'redux-actions/lib/createAction';
import { createSelector } from 'reselect';
import { apiPatch } from './apiActions/apiRequest';
import { getEntitiesFromCollection } from '../../selectors/collectionSelector';
import apiGetCollection from './apiActions/apiGetCollection';
import { NOTIFICATIONS } from '../../data/collectionIds';
import { setEntity, updateEntities } from '../entities/entityActions';
import { GATEWAY_MESSAGE_AUTH } from '../../data/Injectables';
import { NOTIFICATION } from '../../data/entityTypes';

const debug = debugLib('SlimmingWorld:notificationActions');

export const UPDATE_NOTIFICATION_COUNT = 'notificationActions/UPDATE_NOTIFICATION_COUNT';

const updateNotificationCount = createAction(UPDATE_NOTIFICATION_COUNT);

export const GET_NOTIFICATIONS = 'notificationActions/GET_NOTIFICATIONS';

/**
 * Retrieves notifications
 * @param loadMore
 * @param limit
 */
export const getNotifications = (loadMore = false, limit = 10) =>
  apiGetCollection(
    GET_NOTIFICATIONS,
    GATEWAY_MESSAGE_AUTH,
    '/notifications',
    NOTIFICATIONS,
    {
      limit,
      ...(loadMore
        ? {
            from: {
              param: 'sinceId',
              key: 'id',
            },
          }
        : {}),
    },
    {
      requestData: {
        userId: 'me',
      },
      transformResponse: response => ({
        pagination: response.pagination,
        data: response.data.notifications,
      }),
      entityType: NOTIFICATION,
    },
  );

export const MARK_NOTIFICATION_READ = 'notificationActions/MARK_NOTIFICATION_READ';

/**
 *
 * Mark notifcation(s) as read
 * @param ids
 */
export const markNotificationsRead = ids => (dispatch, getState) => {
  const state = getState();
  const idsArray = Array.isArray(ids) ? ids.find() : [ids];
  const { totalRead, totalUnread } = state.notifications;
  const { entities } = getEntitiesFromCollection(state, { collectionId: NOTIFICATIONS });
  const entitiesToUpdate = entities.filter(entity => idsArray.indexOf(entity.id) > -1);

  entitiesToUpdate.forEach(entity =>
    dispatch(setEntity(NOTIFICATION, entity.id, { ...entity, isRead: true }, true)),
  );

  dispatch(
    updateNotificationCount({
      totalUnread: totalUnread - idsArray.length,
      totalRead: totalRead + idsArray.length,
    }),
  );

  dispatch(
    apiPatch(MARK_NOTIFICATION_READ, GATEWAY_MESSAGE_AUTH, `/notifications/${idsArray.join(',')}`, {
      isRead: true,
      userId: 'me',
    }),
  ).catch(error => {
    debug(error);

    dispatch(
      updateNotificationCount({
        totalUnread,
        totalRead,
      }),
    );

    entitiesToUpdate.forEach(entity =>
      dispatch(setEntity(NOTIFICATION, entity.id, { ...entity, isRead: false }, true)),
    );
  });
};

export const MARK_ALL_NOTIFICATIONS_READ = 'notificationActions/MARK_ALL_NOTIFICATIONS_READ';

export const markAllNotificationsRead = () => (dispatch, getState) => {
  const { totalRead, totalUnread } = getState().notifications;

  return dispatch(
    apiPatch(
      MARK_ALL_NOTIFICATIONS_READ,
      GATEWAY_MESSAGE_AUTH,
      /**
       * The userId is added directly as a query-parameter in the request URL, because this is the
       * only PATCH-call where we have to do this. Normally, the userId would be passed in the body.
       * However, this one is created in a different way because backend needs to support the old
       * API-call (for the App) and proxy it to this one, resulting in adding the userId as a
       * query-parameter.
       */
      '/notifications/mark-all-as-read?userId=me',
    ),
  ).then(() => {
    dispatch(updateEntities(NOTIFICATION, { isRead: true }, { isRead: false }));
    dispatch(
      updateNotificationCount({
        totalRead: totalRead + totalUnread,
        totalUnread: 0,
      }),
    );
  });
};

const EMPTY_ARRAY = [];

export const createNotificationAwardFullSelector = createSelector(
  state => state.entities.notification,
  state => state.entities.award,
  (notification, award) => {
    const notifications = notification ? [...Object.values(notification)] : EMPTY_ARRAY;
    const awards = award ? [...Object.values(award)] : EMPTY_ARRAY;
    if (notifications.length > 0 && awards.length > 0) {
      notifications.forEach((itemNoti, i) => {
        awards.forEach(itemAward => {
          if (itemNoti.award && itemNoti.award.id === itemAward.id) {
            notifications[i] = {
              ...itemNoti,
              award: {
                ...itemAward,
              },
            };
          }
        });
      });
    }

    return notifications;
  },
);