Source: app/actions/resources/groupSearchActions.js

import createAction from 'redux-actions/lib/createAction';
import orderBy from 'lodash/orderBy';
import { push as historyPush } from 'react-router-redux';
import Pages from 'common/src/app/data/enum/Pages';

import { apiGet, apiPost } from './apiActions/apiRequest';
import { getValue } from '../../util/injector';
import { GATEWAY_GROUP_SEARCH } from '../../data/Injectables';
import dedupeAsyncThunk from '../../util/dedupeAsyncThunk';

/**
 * Public Group
 */
export const GET_GROUP_DETAIL_CALL = 'publicActions/GET_GROUP_DETAIL_CALL';
export const GET_GROUP_DETAIL = 'publicActions/GET_GROUP_DETAIL';
export const getGroupDetailSave = createAction(GET_GROUP_DETAIL);
export const getGroupDetail = dedupeAsyncThunk(
  id => dispatch =>
    dispatch(apiGet(GET_GROUP_DETAIL_CALL, GATEWAY_GROUP_SEARCH, `/groups/${id}`)).then(result => {
      result && result.data && dispatch(getGroupDetailSave(result.data));
      return result.data;
    }),
  true,
);

/**
 * AFT for group account api calls
 * @return {object}
 * Use the returned result.data in the head of subsequent calls:
 * {
 *   headers: {
 *    'X-XSRF-Token': result.data,
 *   },
 *   credentials: 'include',
 * }
 *
 */
export const getAntiForgeryToken = () => () =>
  getValue(GATEWAY_GROUP_SEARCH).get('/antiforgery', null, {
    credentials: 'include',
  });

export const GET_GROUP_SEARCH_RESULTS_CALL = 'publicActions/GET_GROUP_SEARCH_RESULTS_CALL';
export const GET_GROUP_SEARCH_RESULTS = 'publicActions/GET_GROUP_SEARCH_RESULTS';
export const getGroupSearchResults = createAction(GET_GROUP_SEARCH_RESULTS);

export const geocodeLocationGroupSearch = ({ day, time, lat, lng, rawPostcode }) => (
  dispatch,
  getState,
) => {
  const state = getState();
  return dispatch(
    apiPost(GET_GROUP_SEARCH_RESULTS_CALL, GATEWAY_GROUP_SEARCH, `/groups/search/location`, {
      rawPostcode,
      region: state.config.environmentConfig.geocoding.region,
      filters: { day, time },
      lat,
      lng,
    }),
  ).then(apiResult => dispatch(getGroupSearchResults(apiResult.data.groups)));
};

export const FETCH_GROUP_SEARCH_RESULTS = 'publicActions/FETCH_GROUP_SEARCH_RESULTS';
export const SET_GROUP_SEARCH_RESULTS = 'publicActions/SET_GROUP_SEARCH_RESULTS';
export const setGroupSearchResults = createAction(SET_GROUP_SEARCH_RESULTS);

export const countyBasedGroupSearch = (
  query,
  region,
  day,
  time,
  searchType = 'county',
) => dispatch =>
  dispatch(getAntiForgeryToken()).then(result =>
    dispatch(
      apiPost(
        FETCH_GROUP_SEARCH_RESULTS,
        GATEWAY_GROUP_SEARCH,
        `/groups/search/field`,
        {
          region,
          [searchType]: query,
          filters: { day, time },
        },
        {
          headers: {
            'X-XSRF-Token': result.data,
          },
          credentials: 'include',
        },
      ),
    ).then(groups =>
      dispatch(
        setGroupSearchResults(orderBy(groups.data.groups, ['venue.town', 'venue.address1'])),
      ),
    ),
  );

export const SET_GROUP_SEARCH_COUNTIES = 'publicActions/SET_GROUP_SEARCH_COUNTIES';
export const setCounties = createAction(SET_GROUP_SEARCH_COUNTIES);

export const GET_GROUP_SEARCH_COUNTIES = 'publicActions/GET_GROUP_SEARCH_COUNTIES';

export const getCounties = region => dispatch =>
  dispatch(apiGet(GET_GROUP_SEARCH_COUNTIES, GATEWAY_GROUP_SEARCH, `/groups/counties/${region}`))
    .then(response => dispatch(setCounties(response.data.counties)))
    .catch(e => {
      console.error(e);
    });

// Towns specific to a search request
export const SET_GROUP_SEARCH_TOWNS = 'publicActions/SET_GROUP_SEARCH_TOWNS';
export const setTowns = createAction(SET_GROUP_SEARCH_TOWNS);

// Every town we have
export const SET_ALL_GROUP_SEARCH_TOWNS = 'publicActions/SET_ALL_GROUP_SEARCH_TOWNS';
export const setAllTowns = createAction(SET_ALL_GROUP_SEARCH_TOWNS);

export const SET_GROUP_SEARCH_LOADING = 'publicActions/SET_GROUP_SEARCH_LOADING';
export const setGroupSearchLoading = createAction(SET_GROUP_SEARCH_LOADING);

export const GET_GROUP_SEARCH_TOWNS = 'publicActions/GET_GROUP_SEARCH_TOWNS';
export const GET_GEOCODE_FOR_TOWN = 'publicActions/GET_GEOCODE_FOR_TOWN';

export const getTowns = (region, county = '') => dispatch =>
  dispatch(
    apiGet(
      GET_GROUP_SEARCH_TOWNS,
      GATEWAY_GROUP_SEARCH,
      `/groups/towns/${region}${county === '' ? '' : `/${county}`}`,
    ),
  ).then(response => {
    dispatch(setTowns(response.data.towns));
    return response;
  });

/**
 * Get all towns from the DB (this is not xpressweigh's list of towns)
 */
export const getFullTowns = () => dispatch =>
  dispatch(apiGet(GET_GROUP_SEARCH_TOWNS, GATEWAY_GROUP_SEARCH, '/towns')).then(response => {
    dispatch(setAllTowns(response.data));
    return response;
  });

export const getGeocodeByTown = town => dispatch =>
  dispatch(apiGet(GET_GEOCODE_FOR_TOWN, GATEWAY_GROUP_SEARCH, `/towns/find?townAndCounty=${town}`));

export const goToTowns = async (town, dispatch) => {
  let result = {};

  await dispatch(getGeocodeByTown(town)).then(response => {
    const data = response.data;
    return (result = { lat: data.lat, long: data.lon });
  });

  return dispatch(
    historyPush(
      `${Pages.UK_PUBLIC_NEAREST_GROUP_LANDING}?lat=${result.lat}&lng=${result.long}&query=${town}`,
    ),
  );
};