export default function addonsReducer()

in src/amo/reducers/addons.js [368:573]


export default function addonsReducer(
  // eslint-disable-next-line default-param-last
  state: AddonsState = initialState,
  action: Action,
): AddonsState {
  switch (action.type) {
    case SET_LANG:
      return {
        ...state,
        lang: action.payload.lang,
      };

    case FETCH_ADDON: {
      const { slug } = action.payload;

      return {
        ...state,
        loadingByIdInURL: {
          ...state.loadingByIdInURL,
          [slug]: true,
        },
      };
    }

    case LOAD_ADDON: {
      const { addon: loadedAddon, slug } = action.payload;

      const byID = { ...state.byID };
      const byGUID = { ...state.byGUID };
      const bySlug = { ...state.bySlug };
      const byIdInURL = { ...state.byIdInURL };
      const loadingByIdInURL = { ...state.loadingByIdInURL };

      const addon = createInternalAddon(loadedAddon, state.lang);
      // Flow wants hash maps with string keys.
      // See: https://zhenyong.github.io/flowtype/docs/objects.html#objects-as-maps
      byID[`${addon.id}`] = addon;

      byIdInURL[slug] = addon.id;
      loadingByIdInURL[slug] = false;

      if (addon.slug) {
        bySlug[addon.slug.toLowerCase()] = addon.id;
      }

      if (addon.guid) {
        byGUID[addon.guid] = addon.id;
      }

      return {
        ...state,
        byID,
        byGUID,
        bySlug,
        byIdInURL,
        loadingByIdInURL,
      };
    }

    case UNLOAD_ADDON_REVIEWS: {
      const { addonId } = action.payload;
      const addon = getAddonByID(state, addonId);

      if (addon) {
        return {
          ...state,
          byID: {
            ...state.byID,
            [`${addonId}`]: undefined,
          },
          byGUID: {
            ...state.byGUID,
            [addon.guid]: undefined,
          },
          bySlug: {
            ...state.bySlug,
            [addon.slug.toLowerCase()]: undefined,
          },
          loadingByIdInURL: {
            ...state.loadingByIdInURL,
            [addon.slug]: undefined,
          },
        };
      }
      return state;
    }

    case UPDATE_RATING_COUNTS: {
      const { addonId, oldReview, newReview } = action.payload;

      const addon = getAddonByID(state, addonId);
      if (!addon) {
        return state;
      }

      const { ratings } = addon;
      let average = ratings ? ratings.average : 0;
      let ratingCount = ratings ? ratings.count : 0;
      let reviewCount = ratings ? ratings.text_count : 0;

      const newGroupedRatings = ratings
        ? { ...ratings.grouped_counts }
        : createGroupedRatings();

      if (
        oldReview &&
        oldReview.score &&
        newGroupedRatings[oldReview.score] > 0
      ) {
        newGroupedRatings[oldReview.score] -= 1;
      }
      if (newReview && newReview.score) {
        newGroupedRatings[newReview.score] += 1;
      }

      let countForAverage = ratingCount;
      if (average && countForAverage && oldReview && oldReview.score) {
        // If average and countForAverage are defined and greater than 0,
        // begin by subtracting the old rating to reset the baseline.
        const countAfterRemoval = countForAverage - 1;

        if (countAfterRemoval === 0) {
          // There are no ratings left.
          average = 0;
        } else {
          // Expand all existing rating scores, take away the old score,
          // and recalculate the average.
          average =
            (average * countForAverage - oldReview.score) / countAfterRemoval;
        }
        countForAverage = countAfterRemoval;
      }

      // Expand all existing rating scores, add in the new score,
      // and recalculate the average.
      average =
        (average * countForAverage + Number(newReview.score)) /
        (countForAverage + 1);

      // Adjust rating / review counts.
      if (!oldReview) {
        // A new rating / review was added.
        ratingCount += 1;
        if (newReview.body) {
          reviewCount += 1;
        }
      } else if (!oldReview.body && newReview.body) {
        // A rating was converted into a review.
        reviewCount += 1;
      }

      return {
        ...state,
        byID: {
          ...state.byID,
          [addonId]: {
            ...addon,
            ratings: {
              ...ratings,
              average,
              // It's impossible to recalculate the bayesian_average
              // (i.e. median) so we set it to the average as an
              // approximation.
              bayesian_average: average,
              count: ratingCount,
              grouped_counts: newGroupedRatings,
              text_count: reviewCount,
            },
          },
        },
      };
    }

    case FETCH_ADDON_INFO: {
      const { slug } = action.payload;
      return {
        ...state,
        infoBySlug: {
          ...state.infoBySlug,
          [slug]: {
            info: undefined,
            loading: true,
          },
        },
      };
    }

    case LOAD_ADDON_INFO: {
      const { slug, info } = action.payload;

      return {
        ...state,
        infoBySlug: {
          ...state.infoBySlug,
          [slug]: {
            info: createInternalAddonInfo(info, state.lang),
            loading: false,
          },
        },
      };
    }

    default:
      return state;
  }
}