Skip to content

Commit

Permalink
feat(ips): order ipv4 vrack
Browse files Browse the repository at this point in the history
ref: MANAGER-15838

Signed-off-by: Nicolas Pierre-charles <[email protected]>
  • Loading branch information
Nicolas Pierre-charles committed Jan 8, 2025
1 parent 8ed1c18 commit bd661ab
Show file tree
Hide file tree
Showing 29 changed files with 630 additions and 27 deletions.
1 change: 0 additions & 1 deletion packages/manager-react-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
"@ovhcloud/ods-themes": "^18.3.0",
"@ovh-ux/manager-core-api": "^0.9.0",
"@ovh-ux/manager-react-shell-client": "^0.8.1",
"@ovh-ux/manager-tailwind-config": "^0.2.0",
"@ovh-ux/manager-vite-config": "^0.8.1",
"@storybook/addon-docs": "^7.5.3",
"@storybook/addon-essentials": "7.5.3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export function Price({
ovhSubsidiary,
locale,
isConvertIntervalUnit,
isStartingPrice,
suffix = '',
}: Readonly<PriceProps>) {
const { t } = useTranslation('price');
const isAsiaFormat = ['ASIA', 'AU', 'IN', 'SG'].includes(ovhSubsidiary);
Expand Down Expand Up @@ -81,6 +83,11 @@ export function Price({
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{intervalUnitText}
</span>
{suffix && (
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{suffix}
</span>
)}
<TextPriceContent>
<span className="text-[--ods-color-neutral-500] text-[14px] leading-[18px] font-semibold">
({priceWithTax}
Expand All @@ -105,6 +112,11 @@ export function Price({
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{intervalUnitText}
</span>
{suffix && (
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{suffix}
</span>
)}
</>
),
},
Expand All @@ -118,6 +130,11 @@ export function Price({
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{intervalUnitText}
</span>
{suffix && (
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{suffix}
</span>
)}
</>
),
},
Expand All @@ -134,6 +151,11 @@ export function Price({
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{intervalUnitText}
</span>
{suffix && (
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{suffix}
</span>
)}
</>
),
},
Expand All @@ -150,6 +172,11 @@ export function Price({
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{intervalUnitText}
</span>
{suffix && (
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{suffix}
</span>
)}
<TextPriceContent>
<span className="text-[--ods-color-neutral-500] text-[14px] leading-[18px] font-semibold">
({priceWithTax}
Expand All @@ -171,6 +198,11 @@ export function Price({
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{intervalUnitText}
</span>
{suffix && (
<span className="ml-1 text-[--ods-color-text] text-[16px] leading-[20px] font-semibold">
{suffix}
</span>
)}
</>
),
},
Expand All @@ -181,7 +213,12 @@ export function Price({
return <></>;
}

return <OdsText>{matchingComponent.component}</OdsText>;
return (
<OdsText>
{isStartingPrice && value > 0 ? t('price_from_label') : ''}
{matchingComponent.component}
</OdsText>
);
}

export default Price;
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ export interface PriceProps {
ovhSubsidiary: OvhSubsidiary;
isConvertIntervalUnit?: boolean;
locale: string;
suffix?: string;
isStartingPrice?: boolean;
}

export const getPrice = (value: number, tax?: number): number => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"price_ht_label": "HT",
"price_ttc_label": "TTC",
"price_from_label": "à partir de ",
"price_free": "Inclus",
"price_gst_excl_label": "ex. GST",
"price_gst_incl_label": "incl. GST",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@ export const Links: React.FC<LinksProps> = ({
iconAlignment: ODS_LINK_ICON_ALIGNMENT[iconAlignment],
})}
{...props}
{...(type === LinkType.back && { icon: ODS_ICON_NAME.arrowLeft })}
{...(type === LinkType.back && {
icon: ODS_ICON_NAME.arrowLeft,
iconAlignment: IconLinkAlignmentType.left,
})}
{...(type === LinkType.next && { icon: ODS_ICON_NAME.arrowRight })}
{...(type === LinkType.external && { icon: ODS_ICON_NAME.externalLink })}
label={label}
Expand Down
4 changes: 2 additions & 2 deletions packages/manager/apps/ips/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@
"@ovh-ux/manager-react-core-application": "*",
"@ovh-ux/manager-react-shell-client": "^0.8.1",
"@ovh-ux/request-tagger": "^0.4.0",
"@ovhcloud/ods-components": "18.4.0",
"@ovhcloud/ods-themes": "^18.4.0",
"@ovhcloud/ods-components": "18.4.1",
"@ovhcloud/ods-themes": "^18.4.1",
"flag-icons": "^7.2.3",
"i18next": "^23.8.2",
"i18next-http-backend": "^2.4.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"title": "Bienvenue uapp",
"crumb": "ips",
"tabs_2": "Tabs 2",
"onboarding": "Onboarding"
"onboarding": "Onboarding",
"per_ip": "/IP"
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"title": "Listing page",
"listing_resultats": "résultats"
"listing_resultats": "résultats",
"orderIps": "Commander des IPs"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"title": "Commander des Additional IP",
"back_link": "Retour à la page précédente",
"ip_version_title": "Sélectionner la version de l'adresse IP",
"ip_version_description": "Pour un certain nombre de cas, vous aurez peut-être besoin d'une IPv4 standard, la plus utilisée, ou d'une nouvelle version du protocole - l'IPv6. Veuillez noter que la liste des produits compatibles peut varier.",
"ipv4_card_title": "IPv4",
"ipv4_card_description": "Standard Internet (à partir d'aujourd'hui). Protocole d'adressage le plus couramment utilisé sur Internet, donc le plus couramment pris en charge.",
"ipv6_card_title": "IPv6",
"ipv6_card_badge_label": "beta",
"ipv6_card_description": "Lorsque de grands blocs IP sont nécessaires et qu'un schéma d'adressage hiérarchique est défini, l'IPv6 est le meilleur choix. Assurez-vous que tous vos clients sont en mesure d'utiliser le nouveau protocole ainsi que vos services",
"service_selection_title": "Sélectionnez le service pour lequel vous désirez acheter des Additional IP",
"service_selection_select_label": "Service",
"service_selection_select_placeholder": "Sélectionnez...",
"service_selection_select_vrack_option_group_label": "Réseau Privé vRack",
"region_selection_title": "Sélectionnez une région pour votre nouvelle Additional IP",
"error_message": "Une erreur est survenue: {{error}}"
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import {
useBreadcrumb,
BreadcrumbItem,
} from '@/hooks/breadcrumb/useBreadcrumb';
} from '@/components/Breadcrumb/useBreadcrumb';
import appConfig from '@/ips.config';

export interface BreadcrumbProps {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import {
IntervalUnitType,
OvhSubsidiary,
Price,
} from '@ovh-ux/manager-react-components';
import { ShellContext } from '@ovh-ux/manager-react-shell-client';
import {
ODS_CARD_COLOR,
ODS_SPINNER_SIZE,
ODS_TEXT_PRESET,
} from '@ovhcloud/ods-components';
import {
OdsCard,
OdsDivider,
OdsSpinner,
OdsText,
} from '@ovhcloud/ods-components/react';
import { useTranslation } from 'react-i18next';

export const selectedBorderColor = '#0050D7';

export type OptionCardProps = {
className?: string;
isDisabled?: boolean;
isSelected?: boolean;
onClick?: () => void;
title: React.ReactNode;
description: string;
price: number;
};

export const OptionCard: React.FC<OptionCardProps> = ({
className,
isDisabled,
isSelected,
onClick,
title,
description,
price,
}) => {
const { environment } = React.useContext(ShellContext);
const { t, i18n } = useTranslation();
const stateStyle = isDisabled
? 'cursor-not-allowed bg-neutral-100'
: 'cursor-pointer';
const color = isSelected ? ODS_CARD_COLOR.primary : ODS_CARD_COLOR.neutral;
const borderStyle = isSelected
? `border-[2px] border-[${selectedBorderColor}]`
: 'm-[1px]';
return (
<OdsCard
className={`flex flex-col p-3 ${stateStyle} ${borderStyle} ${className}`}
onClick={() => !isDisabled && onClick?.()}
color={color}
>
<OdsText
className="flex justify-center mb-2"
preset={ODS_TEXT_PRESET.heading4}
>
{title}
</OdsText>
<OdsText preset={ODS_TEXT_PRESET.paragraph}>{description}</OdsText>
<OdsDivider className="block -ml-3 -mr-3 mt-auto mb-2" />
<OdsText
preset={ODS_TEXT_PRESET.paragraph}
className="flex justify-center"
>
{price === null ? (
<OdsSpinner size={ODS_SPINNER_SIZE.xs} />
) : (
<Price
isStartingPrice
suffix={t('per_ip')}
value={price}
tax={0}
intervalUnit={IntervalUnitType.month}
ovhSubsidiary={environment.user.ovhSubsidiary as OvhSubsidiary}
locale={i18n.language}
/>
)}
</OdsText>
</OdsCard>
);
};
65 changes: 65 additions & 0 deletions packages/manager/apps/ips/src/data/api/catalog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { ApiResponse, apiClient } from '@ovh-ux/manager-core-api';
import { CurrencyCode, OvhSubsidiary } from '@ovh-ux/manager-react-components';

export type CatalogIpPlan = {
addonsFamily: unknown[];
consumptionBillingStrategy: string | null;
details: {
metadatas: { key: string; value: 'true' | 'false' }[];
pricings: {
default: [
{
capacities: ('installation' | 'renew')[];
commitment: number;
description: string;
interval: number;
intervalUnit: string;
maximumQuantity: number;
maximumRepeat: number;
minimumQuantity: number;
minimumRepeat: number;
mustBeCompleted: boolean;
price: { currencyCode: CurrencyCode; text: string; value: number };
priceCapInUcents: number | null;
priceInUcents: number;
pricingStrategy: string;
},
];
};
product: {
configurations: {
defaultValue: string | null;
isCustom: boolean;
isMandatory: boolean;
name: string;
values: string[];
}[];
description: string;
internalType:
| 'cloud_service'
| 'delivery'
| 'deposit'
| 'domain'
| 'implementation_services'
| 'saas_license'
| 'shipping'
| 'storage';
name: string;
};
};
familyName?: string | null;
invoiceName: string;
planCode: string;
pricingType: 'rental' | 'consumption';
};

export type CatalogIpsResponse = {
catalogId: number;
merchantCode: OvhSubsidiary;
plans: CatalogIpPlan[];
};

export const getCatalogIps = (
sub: OvhSubsidiary = OvhSubsidiary.FR,
): Promise<ApiResponse<CatalogIpsResponse>> =>
apiClient.v6.get(`/order/catalog/formatted/ip?ovhSubsidiary=${sub}`);
4 changes: 4 additions & 0 deletions packages/manager/apps/ips/src/data/api/vrack.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { ApiResponse, apiClient } from '@ovh-ux/manager-core-api';

export const getVrackList = (): Promise<ApiResponse<string[]>> =>
apiClient.v6.get('/vrack');
25 changes: 25 additions & 0 deletions packages/manager/apps/ips/src/data/hooks/catalog.constant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
export const IP_FAILOVER_PLANCODE = {
EU: 'ip-failover-ripe',
CA: 'ip-failover-arin',
US: 'ip-failover-arin',
};

export const DATACENTER_TO_REGION: { [datacenter: string]: string } = {
RBX: 'eu-west-rbx',
GRA: 'eu-west-gra',
SBG: 'eu-west-sbg',
PAR: 'eu-west-par',
CR2: 'labeu-west-1-preprod',
LIM: 'eu-west-lim',
WAW: 'eu-central-waw',
ERI: 'eu-west-eri',
BHS: 'ca-east-bhs',
YYZ: 'ca-east-tor',
SGP: 'ap-southeast-sgp',
SYD: 'ap-southeast-syd',
YNM: 'ap-south-mum',
VIN: 'us-east-vin',
HIL: 'us-west-hil',
};

export const getCatalogIpsQueryKey = (sub: string) => ['getCatalogIps', sub];
Loading

0 comments on commit bd661ab

Please sign in to comment.