Source: app/actions/resources/plannerManageActivityActions.js

import moment from 'moment';
import createAction from 'redux-actions/lib/createAction';
import { GATEWAY_ACTIVITY_AUTH } from '../../data/Injectables';
import { apiGet, apiPost, apiDelete } from './apiActions/apiRequest';
import { debug } from '../../util/plannerActionUtils';
import { getPlannerDayActivity } from './plannerActivitySummaryActions';
import {
  PLANNER_ACTIVITY,
  PLANNER_ACTIVITY_TYPE,
  PLANNER_ACTIVITY_GOAL,
} from '../../data/entityTypes';
import ActivityStatus, { IS_BLOCKING_ERROR } from '../../data/enum/ActivityStatus';
import { activeAwardSelector } from '../../selectors/plannerSelectors';
import { setSummaryLoading } from './plannerFoodSummaryActions';
import { retriggerAnimation } from '../components/lottieActions';
import { userIdSelector } from '../../selectors/userAccountSelectors';
import { removeEntities, setEntity } from '../entities/entityActions';

export const POST_ACTIVITY_TYPE = 'plannerManageActivityActions/POST_ACTIVITY_TYPE';
export const createActivity = values => dispatch =>
  dispatch(
    apiPost(POST_ACTIVITY_TYPE, GATEWAY_ACTIVITY_AUTH, `/activity-types`, {
      description: values.activityDescription,
      categories: values.muscleStrengthening ? 1 : 0,
      title: values.activityName,
    }),
  )
    .then(response => {
      dispatch(setEntity(PLANNER_ACTIVITY_TYPE, response.data.id, response.data));
      return response;
    })
    .catch(err => debug(err));

export const POST_ACTIVITY = 'plannerManageActivityActions/POST_ACTIVITY';
export const postActivity = (values, activityTypeId) => (dispatch, getState) => {
  const state = getState();
  const date = state.planner.activePlannedDay || moment().format('YYYY-MM-DD');
  const userId = userIdSelector(getState());

  return dispatch(
    apiPost(POST_ACTIVITY, GATEWAY_ACTIVITY_AUTH, '/activities', {
      activityTypeId,
      duration: values.duration,
      status: values.activityComplete ? 1 : 0,
      plannedDateUTC: date,
      profileId: userId,
    }),
  )
    .catch(err => {
      Promise.all([
        dispatch(validateDuration(JSON.parse(err.response.text).error.fields[0].message)),
        dispatch(setSummaryLoading(false)),
        dispatch(retriggerAnimation(false)),
      ]);
      return JSON.parse(err.response.text);
    })
    .then(response => dispatch(checkComplete(response)))
    .then(hasCompleted => {
      dispatch(getPlannerDayActivity(date, true));
      return hasCompleted;
    });
};

export const DELETE_ACTIVITY = 'plannerManageActivityActions/DELETE_ACTIVITY';
export const deleteActivity = (activity, date) => dispatch =>
  dispatch(apiDelete(DELETE_ACTIVITY, GATEWAY_ACTIVITY_AUTH, `/activities/${activity.id}`))
    .then(() => dispatch(removeEntities([activity.id], PLANNER_ACTIVITY)))
    .then(() => dispatch(getPlannerDayActivity(date, true)))
    .catch(err => debug(err));

export const DELETE_ACTIVITY_TYPE = 'plannerManageActivityActions/DELETE_ACTIVITY';
export const deleteActivityType = activity => async (dispatch, getState) => {
  const state = getState();
  const recentActivities = state.entities?.[PLANNER_ACTIVITY];
  const recentActivity = Object.values(recentActivities).find(
    item => item.activityTypeId === activity.activityTypeId || item.activityTypeId === activity.id,
  );

  await dispatch(
    apiDelete(
      DELETE_ACTIVITY_TYPE,
      GATEWAY_ACTIVITY_AUTH,
      `/activity-types/${activity.activityTypeId || activity.id}`,
    ),
  ).catch(err => debug(err));

  if (recentActivity) {
    await dispatch(removeEntities([recentActivity.id], PLANNER_ACTIVITY));
  }

  if (activity.activityTypeId) {
    return dispatch(removeEntities([activity.activityTypeId], PLANNER_ACTIVITY_TYPE));
  }

  return dispatch(removeEntities([activity.id], PLANNER_ACTIVITY_TYPE));
};

/**
 * TODO: this should not be here! SWO-6268
 *
 * this should be a backend task - whenever passing something into the api - we should have a response for
 * the current status of the award! Current we send activity data to the api, then ask the api what the status is after that data.
 */
export const CHECK_COMPLETE = 'plannerManageActivityActions/CHECK_COMPLETE';
const checkComplete = response => (dispatch, getState) => {
  const activeAwardInState = activeAwardSelector(getState());

  // If the user has not got an award active then abort check
  if (typeof activeAwardInState !== 'object' || Object.keys(activeAwardInState).length === 0) {
    return response.error ? IS_BLOCKING_ERROR : false;
  }

  return dispatch(
    apiGet(CHECK_COMPLETE, GATEWAY_ACTIVITY_AUTH, `/activity-goals/${activeAwardInState.id}`),
  ).then(({ data }) => {
    //  Check to see if the api has changed the status of the active award
    if (data.status === ActivityStatus.ACHIEVED && data.status !== activeAwardInState.status) {
      // Store the id of the award this is used to get information about the
      // award in the modal
      dispatch(setLatestAchievedAward(data.id));
      // Change the active award status in state to achieved
      dispatch(setEntity(PLANNER_ACTIVITY_GOAL, data.id, { ...data }, true));

      return true; // Mark the award has completed this will fire off a modal
    }

    // The award was not completed
    return response.error ? IS_BLOCKING_ERROR : false;
  });
};

// Store id of last completed award
export const SET_LATEST_ACHIEVED_AWARD = 'plannerManageActivityActions/SET_LATEST_ACHIEVED_AWARD';
const setLatestAchievedAward = createAction(SET_LATEST_ACHIEVED_AWARD);

export const VALIDATE_DURATION = 'plannerManageActivityActions/VALIDATE_DURATION';
export const validateDuration = createAction(VALIDATE_DURATION);