teamdigitale/italia-app

View on GitHub
ts/utils/internalLink.ts

Summary

Maintainability
A
0 mins
Test Coverage
/**
 * An handler for application internal links
 */
import * as A from "fp-ts/lib/Array";
import * as O from "fp-ts/lib/Option";
import { pipe } from "fp-ts/lib/function";
import { fciEnabled } from "../config";
import CGN_ROUTES from "../features/bonus/cgn/navigation/routes";
import { FCI_ROUTES } from "../features/fci/navigation/routes";
import ROUTES from "../navigation/routes";
import { MESSAGES_ROUTES } from "../features/messages/navigation/routes";
import { SERVICES_ROUTES } from "../features/services/common/navigation/routes";
import { isTestEnv } from "./environment";
import {
  IO_FIMS_LINK_PREFIX,
  IO_INTERNAL_LINK_PREFIX,
  IO_INTERNAL_LINK_PROTOCOL,
  IO_UNIVERSAL_LINK_PREFIX
} from "./navigation";
import { extractPathFromURL } from "./url";

/**
 * This handling is used to convert old CTAs and links to current internal linking config
 * of react-navigation ≥ v5.
 *
 * This object should not be edited anymore.
 * To add new routes consider to add a new path only on AppStackNavigator linking config.
 */
// TODO: string should be replaced with a strong type that express all the allowed routes
const routesToNavigationLink: Record<string, string> = {
  [MESSAGES_ROUTES.MESSAGES_HOME]: "/main/messages",
  [ROUTES.PROFILE_PREFERENCES_HOME]: "/profile/preferences",
  [ROUTES.WALLET_HOME]: "/main/wallet",
  [SERVICES_ROUTES.SERVICES_HOME]: "/main/services",
  [ROUTES.PROFILE_MAIN]: "/main/profile",
  [ROUTES.PROFILE_PRIVACY]: "/profile/privacy",
  [ROUTES.PROFILE_PRIVACY_MAIN]: "/profile/privacy-main",
  [ROUTES.PAYMENTS_HISTORY_SCREEN]: "/wallet/payments-history",
  [ROUTES.CREDIT_CARD_ONBOARDING_ATTEMPTS_SCREEN]:
    "/wallet/card-onboarding-attempts"
};

const legacyRoutesToNavigationLink: Record<string, string> = {
  PREFERENCES_SERVICES: "/main/services",
  PREFERENCES_HOME: "/profile/preferences"
};

const cgnRoutesToNavigationLink: Record<string, string> = {
  [CGN_ROUTES.ACTIVATION.CTA_START_CGN]: "/cgn-activation/start",
  [CGN_ROUTES.DETAILS.DETAILS]: "/cgn-details/detail"
};

const fciRoutesToNavigationLink: Record<string, string> = {
  [FCI_ROUTES.MAIN]: "/fci/main"
};

const allowedRoutes = {
  ...routesToNavigationLink,
  ...cgnRoutesToNavigationLink,
  ...legacyRoutesToNavigationLink,
  ...(fciEnabled ? fciRoutesToNavigationLink : {})
};

export const isServiceDetailNavigationLink = (
  internalOrUniversalLink: string
) =>
  pipe(internalOrUniversalLink.toUpperCase(), upperInternalOrUniversalLink =>
    pipe(
      [
        `${IO_INTERNAL_LINK_PROTOCOL}//services/service-detail`,
        `${IO_UNIVERSAL_LINK_PREFIX}/services/service-detail`
      ],
      A.map((allowedInternalOrUniversalLink: string) =>
        allowedInternalOrUniversalLink.toUpperCase()
      ),
      A.some(
        upperAllowedInternalOrUniversalLink =>
          upperInternalOrUniversalLink.indexOf(
            upperAllowedInternalOrUniversalLink
          ) === 0
      )
    )
  );

export const testableALLOWED_ROUTE_NAMES = isTestEnv
  ? allowedRoutes
  : undefined;

/**
 * Extracts the internal route from href. If it is defined and allowed (white listed)
 * returns the internal route, otherwise returns the href
 * @param href
 * @returns
 */
export function getInternalRoute(href: string): string {
  return pipe(
    extractPathFromURL(
      [IO_INTERNAL_LINK_PREFIX, IO_UNIVERSAL_LINK_PREFIX, IO_FIMS_LINK_PREFIX],
      href
    ),
    O.fromNullable,
    O.map(extractedPath => {
      const [path, params] = extractedPath.split("?");

      return pipe(
        allowedRoutes[path.toUpperCase()],
        O.fromNullable,
        O.map(innerPath => innerPath + (params ? "?" + params : "")),
        O.getOrElse(() =>
          extractedPath.startsWith("/") ? extractedPath : "/" + extractedPath
        )
      );
    }),
    O.getOrElse(() => href)
  );
}

/**
 * try to extract the internal route from href. If it is defined and allowed (white listed)
 * dispatch the navigation params (to store into the store) and dispatch the navigation action
 * @param linkTo
 * @param href
 */
export function handleInternalLink(
  linkTo: (path: string) => void,
  href: string
) {
  linkTo(getInternalRoute(href));
}