mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 23:16:21 +00:00
172 lines
7.2 KiB
TypeScript
172 lines
7.2 KiB
TypeScript
import { CreateLinkEvent, PurchaseFromCatalogComposer } from '@nitrots/nitro-renderer';
|
|
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
|
import { CatalogPurchaseState, DispatchUiEvent, GetClubMemberLevel, LocalStorageKeys, LocalizeText, Offer, SendMessageComposer } from '../../../../../api';
|
|
import { Button, LayoutLoadingSpinnerView } from '../../../../../common';
|
|
import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, CatalogPurchasedEvent } from '../../../../../events';
|
|
import { useCatalog, useLocalStorage, usePurse, useUiEvent } from '../../../../../hooks';
|
|
|
|
interface CatalogPurchaseWidgetViewProps
|
|
{
|
|
noGiftOption?: boolean;
|
|
purchaseCallback?: () => void;
|
|
}
|
|
|
|
let isPurchasingCatalogItem = false;
|
|
|
|
export const CatalogPurchaseWidgetView: FC<CatalogPurchaseWidgetViewProps> = props =>
|
|
{
|
|
const { noGiftOption = false, purchaseCallback = null } = props;
|
|
const [ purchaseWillBeGift, setPurchaseWillBeGift ] = useState(false);
|
|
const [ purchaseState, setPurchaseState ] = useState(CatalogPurchaseState.NONE);
|
|
const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useLocalStorage(LocalStorageKeys.CATALOG_SKIP_PURCHASE_CONFIRMATION, false);
|
|
const { currentOffer = null, currentPage = null, purchaseOptions = null, setPurchaseOptions = null } = useCatalog();
|
|
const { getCurrencyAmount = null } = usePurse();
|
|
|
|
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
|
{
|
|
switch(event.type)
|
|
{
|
|
case CatalogPurchasedEvent.PURCHASE_SUCCESS:
|
|
isPurchasingCatalogItem = false;
|
|
setPurchaseState(CatalogPurchaseState.NONE);
|
|
return;
|
|
case CatalogPurchaseFailureEvent.PURCHASE_FAILED:
|
|
isPurchasingCatalogItem = false;
|
|
setPurchaseState(CatalogPurchaseState.FAILED);
|
|
return;
|
|
case CatalogPurchaseNotAllowedEvent.NOT_ALLOWED:
|
|
isPurchasingCatalogItem = false;
|
|
setPurchaseState(CatalogPurchaseState.FAILED);
|
|
return;
|
|
case CatalogPurchaseSoldOutEvent.SOLD_OUT:
|
|
isPurchasingCatalogItem = false;
|
|
setPurchaseState(CatalogPurchaseState.SOLD_OUT);
|
|
return;
|
|
}
|
|
}, []);
|
|
|
|
useUiEvent(CatalogPurchasedEvent.PURCHASE_SUCCESS, onCatalogEvent);
|
|
useUiEvent(CatalogPurchaseFailureEvent.PURCHASE_FAILED, onCatalogEvent);
|
|
useUiEvent(CatalogPurchaseNotAllowedEvent.NOT_ALLOWED, onCatalogEvent);
|
|
useUiEvent(CatalogPurchaseSoldOutEvent.SOLD_OUT, onCatalogEvent);
|
|
|
|
const isLimitedSoldOut = useMemo(() =>
|
|
{
|
|
if(!currentOffer) return false;
|
|
|
|
if(purchaseOptions.extraParamRequired && (!purchaseOptions.extraData || !purchaseOptions.extraData.length)) return false;
|
|
|
|
if(currentOffer.pricingModel === Offer.PRICING_MODEL_SINGLE)
|
|
{
|
|
const product = currentOffer.product;
|
|
|
|
if(product && product.isUniqueLimitedItem) return !product.uniqueLimitedItemsLeft;
|
|
}
|
|
|
|
return false;
|
|
}, [ currentOffer, purchaseOptions ]);
|
|
|
|
const purchase = (isGift: boolean = false) =>
|
|
{
|
|
if(!currentOffer || isPurchasingCatalogItem) return;
|
|
|
|
if(GetClubMemberLevel() < currentOffer.clubLevel)
|
|
{
|
|
CreateLinkEvent('habboUI/open/hccenter');
|
|
|
|
return;
|
|
}
|
|
|
|
if(isGift)
|
|
{
|
|
DispatchUiEvent(new CatalogInitGiftEvent(currentOffer.page.pageId, currentOffer.offerId, purchaseOptions.extraData));
|
|
|
|
return;
|
|
}
|
|
|
|
isPurchasingCatalogItem = true;
|
|
setPurchaseState(CatalogPurchaseState.PURCHASE);
|
|
|
|
if(purchaseCallback)
|
|
{
|
|
purchaseCallback();
|
|
|
|
return;
|
|
}
|
|
|
|
let pageId = currentOffer.page.pageId;
|
|
|
|
// if(pageId === -1)
|
|
// {
|
|
// const nodes = getNodesByOfferId(currentOffer.offerId);
|
|
|
|
// if(nodes) pageId = nodes[0].pageId;
|
|
// }
|
|
|
|
SendMessageComposer(new PurchaseFromCatalogComposer(pageId, currentOffer.offerId, purchaseOptions.extraData, purchaseOptions.quantity));
|
|
};
|
|
|
|
useEffect(() =>
|
|
{
|
|
if(!currentOffer) return;
|
|
|
|
setPurchaseState(CatalogPurchaseState.NONE);
|
|
}, [ currentOffer, setPurchaseOptions ]);
|
|
|
|
useEffect(() =>
|
|
{
|
|
let timeout: ReturnType<typeof setTimeout> = null;
|
|
|
|
if((purchaseState === CatalogPurchaseState.CONFIRM) || (purchaseState === CatalogPurchaseState.FAILED))
|
|
{
|
|
timeout = setTimeout(() => setPurchaseState(CatalogPurchaseState.NONE), 3000);
|
|
}
|
|
|
|
return () =>
|
|
{
|
|
if(timeout) clearTimeout(timeout);
|
|
};
|
|
}, [ purchaseState ]);
|
|
|
|
if(!currentOffer) return null;
|
|
|
|
const PurchaseButton = () =>
|
|
{
|
|
const priceCredits = (currentOffer.priceInCredits * purchaseOptions.quantity);
|
|
const pricePoints = (currentOffer.priceInActivityPoints * purchaseOptions.quantity);
|
|
|
|
if(GetClubMemberLevel() < currentOffer.clubLevel) return <Button disabled variant="danger">{ LocalizeText('catalog.alert.hc.required') }</Button>;
|
|
|
|
if(isLimitedSoldOut) return <Button disabled variant="danger">{ LocalizeText('catalog.alert.limited_edition_sold_out.title') }</Button>;
|
|
|
|
if(priceCredits > getCurrencyAmount(-1)) return <Button disabled variant="danger">{ LocalizeText('catalog.alert.notenough.title') }</Button>;
|
|
|
|
if(pricePoints > getCurrencyAmount(currentOffer.activityPointType)) return <Button disabled variant="danger">{ LocalizeText('catalog.alert.notenough.activitypoints.title.' + currentOffer.activityPointType) }</Button>;
|
|
|
|
switch(purchaseState)
|
|
{
|
|
case CatalogPurchaseState.CONFIRM:
|
|
return <Button variant="warning" onClick={ event => purchase() }>{ LocalizeText('catalog.marketplace.confirm_title') }</Button>;
|
|
case CatalogPurchaseState.PURCHASE:
|
|
return <Button disabled><LayoutLoadingSpinnerView /></Button>;
|
|
case CatalogPurchaseState.FAILED:
|
|
return <Button variant="danger">{ LocalizeText('generic.failed') }</Button>;
|
|
case CatalogPurchaseState.SOLD_OUT:
|
|
return <Button variant="danger">{ LocalizeText('generic.failed') + ' - ' + LocalizeText('catalog.alert.limited_edition_sold_out.title') }</Button>;
|
|
case CatalogPurchaseState.NONE:
|
|
default:
|
|
return <Button disabled={ (purchaseOptions.extraParamRequired && (!purchaseOptions.extraData || !purchaseOptions.extraData.length)) } onClick={ event => setPurchaseState(CatalogPurchaseState.CONFIRM) }>{ LocalizeText('catalog.purchase_confirmation.' + (currentOffer.isRentOffer ? 'rent' : 'buy')) }</Button>;
|
|
}
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<PurchaseButton />
|
|
{ (!noGiftOption && !currentOffer.isRentOffer) &&
|
|
<Button disabled={ ((purchaseOptions.quantity > 1) || !currentOffer.giftable || isLimitedSoldOut || (purchaseOptions.extraParamRequired && (!purchaseOptions.extraData || !purchaseOptions.extraData.length))) } onClick={ event => purchase(true) }>
|
|
{ LocalizeText('catalog.purchase_confirmation.gift') }
|
|
</Button> }
|
|
</>
|
|
);
|
|
};
|