5180 fichiers 38.5 Mo 0 téléchargements 304 vues mis à jour il y a 6 heures ui
nitro-v36-with-renderer-v36 / src / components / catalog / views / CatalogPurchaseConfirmView.tsx
CatalogPurchaseConfirmView.tsx 9.7 Ko Télécharger le fichier
import { FC, MutableRefObject, useEffect, useState } from 'react';
import { GetConfigurationValue, IPurchasableOffer, LocalizeText, ProductTypeEnum } from '../../../api';
import { localizeWithFallback } from '../../../api/utils/localizeWithFallback';
import { getCatalogBundlePrice, ICatalogBundleDiscountRuleset } from '../../../api/catalog/CatalogBundleDiscount';
import {
    LayoutChatStyleImageView,
    LayoutCurrencyIcon,
    LayoutFurniImageView,
    OctaneCardContentView,
    OctaneCardHeaderView,
    OctaneCardView
} from '../../../common';
import { Checkbox } from '../../../common/Checkbox';
import { InlineDialog } from '../../../common/InlineDialog';
import { BaseButton } from '../../../common/BaseButton';
import { NativeTextTree } from '../../../common/native-text/NativeTextTree';

interface CatalogPurchaseConfirmViewProps {
    offer: IPurchasableOffer;
    quantity: number;
    bundleDiscountRuleset?: ICatalogBundleDiscountRuleset;
    isGift?: boolean;
    isSubmitting?: boolean;
    /** AIR PurchaseConfirmationDialog.ltdRaffleEnded: the server put this LTD purchase into a raffle. */
    isRaffling?: boolean;
    onConfirm: () => void;
    onCancel: () => void;
}

const RAFFLE_DOT_INTERVAL = 150;
const RAFFLE_MAX_DOTS = 14;

export const nextRaffleDots = (dots: number): number => (dots >= RAFFLE_MAX_DOTS ? 1 : dots + 1);

// AIR updateDots: the raffling line with one to fourteen dots behind it, one more every 150 ms.
const CatalogPurchaseRaffleText: FC = () => {
    const [dots, setDots] = useState(1);

    useEffect(() => {
        const interval = setInterval(() => setDots((value) => nextRaffleDots(value)), RAFFLE_DOT_INTERVAL);

        return () => clearInterval(interval);
    }, []);

    return (
        <NativeTextTree>
            <span className="octane-catalog-purchase-confirm-raffle-text">
                {localizeWithFallback('catalog.purchase.confirmation.dialog.raffling', 'We are processing your LTD purchase. Please wait')}
                {'.'.repeat(dots)}
            </span>
        </NativeTextTree>
    );
};

export const CatalogPurchaseConfirmView: FC<CatalogPurchaseConfirmViewProps> = (props) => {
    const { offer = null, quantity = 1, bundleDiscountRuleset = null, isGift = false, isSubmitting = false, isRaffling = false, onConfirm = null, onCancel = null } = props;
    const spendingDisclaimerEnabled = GetConfigurationValue<boolean>('disclaimer.credit_spending.enabled', false) === true;
    const [spendingDisclaimerAccepted, setSpendingDisclaimerAccepted] = useState(!spendingDisclaimerEnabled);

    if (!offer) return null;

    const credits = getCatalogBundlePrice(offer.priceInCredits, quantity, offer.bundlePurchaseAllowed, bundleDiscountRuleset).price;
    const activityPoints = getCatalogBundlePrice(offer.priceInActivityPoints, quantity, offer.bundlePurchaseAllowed, bundleDiscountRuleset).price;
    const freeItemCount = offer.bundlePurchaseAllowed ? getCatalogBundlePrice(1, quantity, true, bundleDiscountRuleset).freeItemCount : 0;
    const hasCredits = credits > 0;
    const hasActivityPoints = activityPoints > 0;
    const title = LocalizeText(isGift ? 'catalog.purchase_confirmation.gift.title' : 'catalog.purchase_confirmation.title');
    const iconUrl = typeof offer.product?.getIconUrl === 'function' ? offer.product.getIconUrl(offer) : null;
    const isFurniture = offer.product?.productType === ProductTypeEnum.FLOOR || offer.product?.productType === ProductTypeEnum.WALL;
    const isLimited = !!offer.product?.isUniqueLimitedItem;
    const contentClassNames = [
        'octane-catalog-purchase-confirm-content',
        spendingDisclaimerEnabled ? 'has-disclaimer' : '',
        isLimited ? 'has-limited' : ''
    ].filter(Boolean);

    return (
        <NativeTextTree>
            <InlineDialog
                aria-label={title}
                aria-modal="true"
                modal="trap-focus"
                render={({ ref, ...popupProps }) => (
                    <OctaneCardView {...popupProps} innerRef={ref as MutableRefObject<HTMLDivElement>} classNames={['octane-catalog-purchase-confirm']} frameStyle={3} isResizable={false} theme="primary-slim" />
                )}
                onClose={onCancel}
            >
                <OctaneCardHeaderView headerText={title} onCloseClick={onCancel} />
                <OctaneCardContentView classNames={contentClassNames} overflow="hidden">
                    <div className="octane-catalog-purchase-confirm-preview">
                        {isFurniture ? (
                            <LayoutFurniImageView
                                aria-label={offer.localizationName}
                                direction={90}
                                extraData={offer.product.extraParam}
                                productClassId={offer.product.productClassId}
                                productType={offer.product.productType}
                                role="img"
                                scale={0.5}
                            />
                        ) : offer.product?.productType === ProductTypeEnum.CHAT_STYLE ? (
                            <LayoutChatStyleImageView styleId={offer.product.extraParam} />
                        ) : (
                            !!iconUrl && <img alt={offer.localizationName} src={iconUrl} />
                        )}
                    </div>
                    <div className="octane-catalog-purchase-confirm-properties">
                        <strong className="octane-catalog-purchase-confirm-product">{offer.localizationName}</strong>
                        {quantity > 1 && <strong className="octane-catalog-purchase-confirm-quantity">X {quantity}</strong>}
                        {freeItemCount > 0 && (
                            <strong className="octane-catalog-purchase-confirm-free-quantity">
                                {LocalizeText('shop.bonus.items.count', ['amount'], [freeItemCount.toString()])}
                            </strong>
                        )}
                        <div className="octane-catalog-purchase-confirm-summary">
                            <span>{LocalizeText('catalog.purchase.confirmation.dialog.cost')}</span>
                            <span className="octane-catalog-purchase-confirm-cost">
                                {hasCredits && (
                                    <span className="octane-catalog-purchase-confirm-price" data-currency-type="-1">
                                        <strong>{credits}</strong>
                                        <LayoutCurrencyIcon type={-1} />
                                    </span>
                                )}
                                {hasActivityPoints && (
                                    <span className="octane-catalog-purchase-confirm-price" data-currency-type={offer.activityPointType}>
                                        <strong>{hasCredits ? `+ ${activityPoints}` : activityPoints}</strong>
                                        <LayoutCurrencyIcon type={offer.activityPointType} />
                                    </span>
                                )}
                                {!hasCredits && !hasActivityPoints && (
                                    <span className="octane-catalog-purchase-confirm-price" data-currency-type="-1">
                                        <strong>0</strong>
                                        <LayoutCurrencyIcon type={-1} />
                                    </span>
                                )}
                            </span>
                        </div>
                    </div>
                    {spendingDisclaimerEnabled && (
                        <label className="octane-catalog-purchase-confirm-disclaimer">
                            <Checkbox checked={spendingDisclaimerAccepted} onCheckedChange={(nextChecked) => setSpendingDisclaimerAccepted(nextChecked)} />
                            <span>{LocalizeText('disclaimer.credit_spending')}</span>
                        </label>
                    )}
                    {isRaffling && (
                        <div className="octane-catalog-purchase-confirm-limited is-raffling" role="status">
                            <CatalogPurchaseRaffleText />
                        </div>
                    )}
                    {isLimited && !isRaffling && (
                        <div className="octane-catalog-purchase-confirm-limited" role="status">
                            <span>
                                {LocalizeText('unique.items.left')} <strong>{offer.product.uniqueLimitedItemsLeft}</strong>
                                {' / '}
                                {LocalizeText('unique.items.number.sold')} <strong>{offer.product.uniqueLimitedItemSeriesSize}</strong>
                            </span>
                        </div>
                    )}
                    <div className="octane-catalog-purchase-confirm-actions">
                        <BaseButton className="octane-catalog-purchase-confirm-button is-cancel" disabled={isSubmitting} type="button" onClick={onCancel}>
                            {LocalizeText('catalog.purchase_confirmation.cancel')}
                        </BaseButton>
                        <BaseButton
                            className="octane-catalog-purchase-confirm-button is-buy"
                            disabled={isSubmitting || !spendingDisclaimerAccepted}
                            type="button"
                            onClick={onConfirm}
                        >
                            {LocalizeText(isGift ? 'catalog.purchase_confirmation.gift' : `catalog.purchase_confirmation.${offer.isRentOffer ? 'rent' : 'buy'}`)}
                        </BaseButton>
                    </div>
                </OctaneCardContentView>
            </InlineDialog>
        </NativeTextTree>
    );
};
15Sujets
1Dépôts
20Membres
2En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser