Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { getRirFromPlanCode } from './useGetCatalog';

describe('getRirFromPlanCode', () => {
it.each([
{ planCode: 'byoip-failover-v4-arin', expected: 'ARIN' },
{ planCode: 'byoip-failover-v4-ripe', expected: 'RIPE' },
{ planCode: 'byoip-failover-v4-apnic', expected: 'APNIC' },
{ planCode: 'byoip-failover-v4', expected: '' },
{ planCode: 'unrelated-plan-code', expected: '' },
{ planCode: '', expected: '' },
{ planCode: undefined as unknown as string, expected: '' },
])('$planCode => $expected', ({ planCode, expected }) => {
expect(getRirFromPlanCode(planCode)).toBe(expected);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ export type Campus = {
planCode: string;
};

// Extract the RIR from a byoip plan code, e.g. "byoip-failover-v4-arin" -> "ARIN".
// Returns an empty string when the plan code cannot be decoded.
export const getRirFromPlanCode = (planCode: string): string => {
if (!planCode?.startsWith(`${BYOIP_FAILOVER_V4}-`)) return '';
return planCode.slice(BYOIP_FAILOVER_V4.length + 1).toUpperCase();
};

export type ProductConfiguration = {
name: string;
values: string[] | Campus[];
Expand Down Expand Up @@ -131,6 +138,37 @@ export const useGetCatalog = () => {
if (index !== -1 && plan?.details?.product?.configurations?.[index]) {
plan.details.product.configurations[index].values = campusList;
}

// On some subsidiaries (e.g. US) the catalog does not expose an ipRir
// configuration. In that case we derive the available RIRs from the
// campus plan codes so the RIR selection step is still usable.
const ipRirIndex = plan.details.product.configurations.findIndex(
({ name }) => name === CONFIG_NAME.IPRIR,
);
const derivedIpRirValues = Array.from(
new Set(
campusList
.map(({ planCode }) => getRirFromPlanCode(planCode))
.filter(Boolean),
),
);

if (ipRirIndex === -1) {
if (derivedIpRirValues.length > 0) {
plan.details.product.configurations.push({
name: CONFIG_NAME.IPRIR,
values: derivedIpRirValues,
});
}
} else {
const existingValues =
(plan.details.product.configurations[ipRirIndex]
.values as string[]) || [];
if (existingValues.length === 0) {
plan.details.product.configurations[ipRirIndex].values =
derivedIpRirValues;
}
}
}

return plan as unknown as Plan;
Expand Down
7 changes: 5 additions & 2 deletions packages/manager/apps/ips/src/pages/byoip/Byoip.utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ export type ConfigItem = {
/**
* Returns the express order settings
*/
export const getByoipProductSettings = (config: ConfigItem[]) =>
export const getByoipProductSettings = (
config: ConfigItem[],
planCode: string = BYOIP_FAILOVER_V4,
) =>
JSURL.stringify({
planCode: BYOIP_FAILOVER_V4,
planCode,
configuration: [...config].filter(Boolean),
option: [],
quantity: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,20 @@ import {
useOvhTracking,
} from '@ovh-ux/manager-react-shell-client';

import { BYOIP_FAILOVER_V4, CONFIG_NAME } from '@/data/hooks/catalog';
import {
BYOIP_FAILOVER_V4,
Campus,
CONFIG_NAME,
useGetCatalog,
} from '@/data/hooks/catalog';
import { urls } from '@/routes/routes.constant';

import { ByoipContext } from '../Byoip.context';
import {
ByoipPayloadParams,
ConfigItem,
getByoipProductSettings,
getConfigValues,
} from '../Byoip.utils';

interface DeclarationItem {
Expand All @@ -47,6 +53,17 @@ export const ByoipOrderModal: React.FC = () => {
const { trackClick } = useOvhTracking();
const { ipRir, selectedRegion, ipRange, asOwnRirType, asOwnNumberType } =
React.useContext(ByoipContext);
const { data: catalog } = useGetCatalog();

const campusValues = getConfigValues(
catalog?.details?.product.configurations,
CONFIG_NAME.CAMPUS,
) as Campus[];

const selectedCampus = campusValues.find(
(campus) => campus.name === selectedRegion,
);
const selectedPlanCode = selectedCampus?.planCode ?? BYOIP_FAILOVER_V4;

const orderBaseUrl = useOrderURL('express_review_base');

Expand Down Expand Up @@ -165,7 +182,7 @@ export const ByoipOrderModal: React.FC = () => {
ipRir,
campus: {
name: selectedRegion,
planCode: BYOIP_FAILOVER_V4,
planCode: selectedPlanCode,
},
ip: ipRange,
...(asOwnRirType && { asRir: asOwnRirType }),
Expand Down Expand Up @@ -195,7 +212,10 @@ export const ByoipOrderModal: React.FC = () => {
if (campus && updateConfig[campusId]) {
updateConfig[campusId].values = [campus.name];
}
const settings = getByoipProductSettings(updateConfig);
const settings = getByoipProductSettings(
updateConfig,
selectedPlanCode,
);
window.open(
`${orderBaseUrl}?products=~(${settings})`,
'_blank',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,11 @@ import {
import { OrderSection } from '@/components/OrderSection/OrderSection.component';
import { RegionCard } from '@/components/RegionCard/RegionCard.component';
import { DATACENTER_TO_REGION } from '@/data/hooks/catalog';
import { CONFIG_NAME, useGetCatalog } from '@/data/hooks/catalog/useGetCatalog';
import {
CONFIG_NAME,
getRirFromPlanCode,
useGetCatalog,
} from '@/data/hooks/catalog/useGetCatalog';
import { TRANSLATION_NAMESPACES } from '@/utils';

import { ByoipContext } from '../Byoip.context';
Expand All @@ -27,14 +31,25 @@ type CampusType = {
export const RegionSelectionSection: React.FC = () => {
const { t } = useTranslation([TRANSLATION_NAMESPACES.byoip]);
const { data: catalog, isLoading } = useGetCatalog();
const { selectedRegion, setSelectedRegion } = React.useContext(ByoipContext);
const { ipRir, selectedRegion, setSelectedRegion } =
React.useContext(ByoipContext);
const { trackClick } = useOvhTracking();

const campusValues = getConfigValues(
const allCampusValues = getConfigValues(
catalog?.details?.product.configurations,
CONFIG_NAME.CAMPUS,
) as CampusType[];

// When the catalog exposes multiple RIR-specific plan codes, keep only the
// campuses attached to the selected RIR. Otherwise fall back to the full list.
const campusValues = ipRir
? allCampusValues.filter(
(campus) => getRirFromPlanCode(campus.planCode) === ipRir.toUpperCase(),
)
: allCampusValues;
const campusValuesToDisplay =
campusValues.length > 0 ? campusValues : allCampusValues;

return (
<OrderSection
title={t('region_selection_title')}
Expand All @@ -43,7 +58,7 @@ export const RegionSelectionSection: React.FC = () => {
>
<React.Suspense fallback={<OdsSpinner />}>
<div className="flex flex-wrap items-stretch gap-7">
{campusValues.map((value) => {
{campusValuesToDisplay.map((value) => {
const region = DATACENTER_TO_REGION[value.name];
return (
<RegionCard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ export const useGetEligibleServices = (serviceName: string = '', region: string)

return {
ipv4List: ipv4Results
.filter((result) => result.data?.regions.includes(region))
.filter((result) => result.data?.regions?.includes(region) ?? false)
.map(({ data }) => data ?? defaultIpDetailValue),
ipv6List: ipv6Results
.filter((result) => result.data?.regions.includes(region))
.filter((result) => result.data?.regions?.includes(region) ?? false)
.map(({ data }) => data ?? defaultIpDetailValue),
isComplete: data?.status !== 'pending',
isLoading:
Expand Down
Loading