PriceSummary
Итоговая цена для checkout и конфигураторов: заголовок с периодом (ButtonDropdown), базовая сумма, скидки, аккордеон деталей заказа, состояния loading / dataError и ссылка на расчёт.
Демо
Когда использовать
- Страница заказа или боковая панель с полной детализацией цены.
- Нужен выбор периода биллинга (
period+periodOptions) и callbackonPeriodChanged. - Требуется раскрываемый список позиций заказа (
invoice) со скидками по строкам.
Когда не нужен PriceSummary:
- Достаточно одной строки «Итого» без аккордеона и периода —
PriceSummarySmall. - Только выпадающий список периода без блока цены —
ButtonDropdown.
Анатомия
Корневой контейнер с acrylic-фоном (@cloud-ru/ds-materials) и внутренними секциями:
HeaderBlock
Строка «Итого» + период. При нескольких periodOptions рендерится ButtonDropdown (desktop — Droplist, mobile — modal). При одном периоде — статический текст.
ContentBlock
Обёртка контента с состояниями:
loading— спиннер вместо контента.dataError— сообщение и кнопка retry (onRetry).- иначе — дочерние блоки ниже.
DiscountBlock
Опционально при discount: базовая цена и строки скидок с процентами.
TotalValueBlock
Крупная сумма (value), префикс totalSumType='from', подсказки (hint, hintTooltipText), дельта (valueDelta).
InvoiceBlock
Опционально при invoice: аккордеон «Детали заказа» с секциями и позициями.
docsLink
Function-ссылка внизу блока (по умолчанию текст из locale).
Установка
pnpm add @cloud-ru/ds-uikit-product-price-summary
import { PRICE_PERIOD, PriceSummary } from '@cloud-ru/ds-uikit-product-price-summary'
Базовый пример
<PriceSummary
value={9_999_999.99}
period={PRICE_PERIOD.Month}
periodOptions={[PRICE_PERIOD.Month, PRICE_PERIOD.Year]}
onPeriodChanged={setPeriod}
promoBadge={{ text: '−9%' }}
discount={{
price: 9_999_999.99,
discounts: [
{ value: 1000, percent: 9 },
{ value: 1000, percent: 9 },
],
}}
hint='Дополнительная информация'
invoice={/* …секции детализации… */}
docsLink={{ href: 'https://example.com', text: 'Подробнее о тарифах и ценах' }}
/>
Примеры использования
Со скидкой
import { PRICE_PERIOD, PriceSummary } from '@cloud-ru/ds-uikit-product-price-summary';
import styles from '../demoSurface.module.scss';
export function WithDiscount() {
return (
<div className={styles.surface}>
<PriceSummary
value={10800}
period={PRICE_PERIOD.Month}
periodOptions={[PRICE_PERIOD.Month]}
discount={{
price: 12000,
discounts: [{ value: 1200, percent: 10 }],
}}
/>
</div>
);
}С детализацией заказа
import { PRICE_PERIOD } from '@cloud-ru/ds-uikit-product-price-summary';
import styles from '../demoSurface.module.scss';
import { PriceSummaryControlled } from '../PriceSummaryControlled';
export function WithInvoice() {
return (
<div className={styles.surface}>
<PriceSummaryControlled
value={10800}
period={PRICE_PERIOD.Month}
periodOptions={[PRICE_PERIOD.Month, PRICE_PERIOD.Year]}
invoice={[
{
title: 'Compute',
items: [{ label: 'vCPU', price: 8000, primary: true }],
},
]}
/>
</div>
);
}Props
Types
PriceSummaryProps| Prop | Type | Default | Required | Description |
|---|---|---|---|---|
className | string | — | no | Дополнительный класс корневого контейнера. |
data-test-id | string | — | no | |
dataError | boolean | — | no | |
discount | DiscountDetails | — | no | Блок базовой цены и скидок. |
docsLink | { href?: string; label?: string; } | undefined | — | no | Ссылка «Подробнее о расчёте». |
hint | string | — | no | |
hintAppearance | "default" | "systemError" | "userError" | "warning" | — | no | |
hintLink | { href?: string; label: string; } | — | no | |
hintTooltipText | ReactNode | — | no | |
invoice | InvoiceDetails[] | — | no | Секции детализации заказа в аккордеоне. |
invoiceExpandedDefault | boolean | true | no | Начальное состояние раскрытия аккордеона invoice. |
loading | boolean | — | no | |
onPeriodChanged | ((period: PricePeriod) => void) | — | no | |
onRetry | (() => void) | — | no | |
period | "day" | "hour" | "minute" | "month" | "year" | — | yes | |
periodOptions | PricePeriod[] | — | yes | |
promoBadge | string | Pick<PromoTagProps, "label" | "appearance"> | — | no | |
showHintLink | boolean | — | no | |
showHintTooltip | boolean | false | no | |
totalSumType | "equal" | "from" | — | no | |
value | number | — | no | |
valueDelta | PriceDeltaDetails | — | no | |
vatType | "excluding" | "including" | — | no |
Unions
Types
PriceSummaryProps
DiscountDetails
InvoiceDetails
PriceDeltaDetails
Unions
AppearanceState
PricePeriod
TotalSumType
VatType
Related props
LinkProps
PromoTagOwnProps
PromoTagProps
Адаптивность
PriceSummary — адаптивный компонент: вёрстка перестраивается под mobile, а вложенные адаптивные блоки сами переключают поверхность. Раскладку он берёт из AdaptiveProvider (контекст @cloud-ru/ds-adaptive); публичный API единый для обеих платформ:
- desktop (по умолчанию) — выбор периода открывается в
Droplist, подсказкиQuestionTooltipвсплывают по наведению. - mobile — выбор периода открывается в modal, а подсказки
QuestionTooltipраскрываются по нажатию вBottomSheet.
Верстайте под desktop и поставьте один <AdaptiveProvider> в корне приложения — mobile-перестроение включается автоматически (desktop-first). Пропа layoutType у компонента нет: источник раскладки — только контекст.
Как форсировать платформу
Форс — только контекстом, не пропом:
- Поддерево — вложенный провайдер:
import { AdaptiveProvider } from '@cloud-ru/ds-adaptive' <AdaptiveProvider layoutType='mobile'> <PriceSummary value={value} period={period} periodOptions={periodOptions} /> </AdaptiveProvider> - Отдельный компонент —
withLayoutType(module-scope, сахар над провайдером):import { withLayoutType } from '@cloud-ru/ds-adaptive' import { PriceSummary } from '@cloud-ru/ds-uikit-product-price-summary' const MobilePriceSummary = withLayoutType(PriceSummary, 'mobile')
Mobile
Total
VAT included
Discount -10%
10 800,00 ₽
Дополнительная информация
import { AdaptiveProvider, LAYOUT_TYPE } from '@cloud-ru/ds-adaptive';
import { PRICE_PERIOD, PriceSummary } from '@cloud-ru/ds-uikit-product-price-summary';
export function MobileLayout() {
return (
<div style={{ maxWidth: 360 }}>
<AdaptiveProvider layoutType={LAYOUT_TYPE.Mobile}>
<PriceSummary
value={10800}
period={PRICE_PERIOD.Month}
periodOptions={[PRICE_PERIOD.Month, PRICE_PERIOD.Year]}
discount={{
price: 12000,
discounts: [{ value: 1200, percent: 10 }],
}}
hint='Дополнительная информация'
hintTooltipText='Итоговая сумма с учётом скидки за выбранный период.'
/>
</AdaptiveProvider>
</div>
);
}Подробнее о модели адаптивности — Адаптивность — паттерн.