mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 23:16:21 +00:00
🆙 Security Fix - Will not go into details
This commit is contained in:
@@ -7,6 +7,8 @@ import { CatalogEvent, CatalogInitGiftEvent, CatalogPurchasedEvent } from '../..
|
||||
import { useCatalog, useFriends, useMessageEvent, useUiEvent } from '../../../../hooks';
|
||||
import { classNames } from '../../../../layout';
|
||||
|
||||
let isBuyingGift = false;
|
||||
|
||||
export const CatalogGiftView: FC<{}> = props =>
|
||||
{
|
||||
const [ isVisible, setIsVisible ] = useState<boolean>(false);
|
||||
@@ -32,6 +34,7 @@ export const CatalogGiftView: FC<{}> = props =>
|
||||
|
||||
const onClose = useCallback(() =>
|
||||
{
|
||||
isBuyingGift = false;
|
||||
setIsVisible(false);
|
||||
setPageId(0);
|
||||
setOfferId(0);
|
||||
@@ -122,6 +125,10 @@ export const CatalogGiftView: FC<{}> = props =>
|
||||
return;
|
||||
}
|
||||
|
||||
if(isBuyingGift) return;
|
||||
|
||||
isBuyingGift = true;
|
||||
|
||||
SendMessageComposer(new PurchaseFromCatalogAsGiftComposer(pageId, offerId, extraData, receiverName, message, colourId, selectedBoxIndex, selectedRibbonIndex, showMyFace));
|
||||
return;
|
||||
}
|
||||
@@ -136,6 +143,7 @@ export const CatalogGiftView: FC<{}> = props =>
|
||||
switch(event.type)
|
||||
{
|
||||
case CatalogPurchasedEvent.PURCHASE_SUCCESS:
|
||||
isBuyingGift = false;
|
||||
onClose();
|
||||
return;
|
||||
case CatalogEvent.INIT_GIFT:
|
||||
|
||||
@@ -6,6 +6,8 @@ import { useCatalog, useMessageEvent, useNavigator, useRoomPromote } from '../..
|
||||
import { NitroInput } from '../../../../../layout';
|
||||
import { CatalogLayoutProps } from './CatalogLayout.types';
|
||||
|
||||
let isPurchasingAd = false;
|
||||
|
||||
export const CatalogLayoutRoomAdsView: FC<CatalogLayoutProps> = props =>
|
||||
{
|
||||
const { page = null } = props;
|
||||
@@ -45,6 +47,10 @@ export const CatalogLayoutRoomAdsView: FC<CatalogLayoutProps> = props =>
|
||||
|
||||
const purchaseAd = () =>
|
||||
{
|
||||
if(isPurchasingAd) return;
|
||||
|
||||
isPurchasingAd = true;
|
||||
|
||||
const pageId = page.pageId;
|
||||
const offerId = page.offers.length >= 1 ? page.offers[0].offerId : -1;
|
||||
const flatId = roomId;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ClubOfferData, GetClubOffersMessageComposer, PurchaseFromCatalogComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { CatalogPurchaseState, LocalizeText, SendMessageComposer } from '../../../../../api';
|
||||
import { AutoGrid, Button, Column, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, LayoutLoadingSpinnerView, Text } from '../../../../../common';
|
||||
import { CatalogEvent, CatalogPurchaseFailureEvent, CatalogPurchasedEvent } from '../../../../../events';
|
||||
@@ -13,15 +13,18 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutProps> = props =>
|
||||
const { currentPage = null, catalogOptions = null } = useCatalog();
|
||||
const { purse = null, getCurrencyAmount = null } = usePurse();
|
||||
const { clubOffers = null } = catalogOptions;
|
||||
const isPurchasingRef = useRef<boolean>(false);
|
||||
|
||||
const onCatalogEvent = useCallback((event: CatalogEvent) =>
|
||||
{
|
||||
switch(event.type)
|
||||
{
|
||||
case CatalogPurchasedEvent.PURCHASE_SUCCESS:
|
||||
isPurchasingRef.current = false;
|
||||
setPurchaseState(CatalogPurchaseState.NONE);
|
||||
return;
|
||||
case CatalogPurchaseFailureEvent.PURCHASE_FAILED:
|
||||
isPurchasingRef.current = false;
|
||||
setPurchaseState(CatalogPurchaseState.FAILED);
|
||||
return;
|
||||
}
|
||||
@@ -83,8 +86,9 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutProps> = props =>
|
||||
|
||||
const purchaseSubscription = useCallback(() =>
|
||||
{
|
||||
if(!pendingOffer) return;
|
||||
if(!pendingOffer || isPurchasingRef.current) return;
|
||||
|
||||
isPurchasingRef.current = true;
|
||||
setPurchaseState(CatalogPurchaseState.PURCHASE);
|
||||
SendMessageComposer(new PurchaseFromCatalogComposer(currentPage.pageId, pendingOffer.offerId, null, 1));
|
||||
}, [ pendingOffer, currentPage ]);
|
||||
|
||||
+15
-1
@@ -1,5 +1,5 @@
|
||||
import { CancelMarketplaceOfferMessageComposer, GetMarketplaceOwnOffersMessageComposer, MarketplaceCancelOfferResultEvent, MarketplaceOwnOffersEvent, RedeemMarketplaceOfferCreditsMessageComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { LocalizeText, MarketplaceOfferData, MarketPlaceOfferState, NotificationAlertType, SendMessageComposer } from '../../../../../../api';
|
||||
import { Button, Column, Text } from '../../../../../../common';
|
||||
import { useMessageEvent, useNotification } from '../../../../../../hooks';
|
||||
@@ -11,6 +11,8 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
|
||||
const [ creditsWaiting, setCreditsWaiting ] = useState(0);
|
||||
const [ offers, setOffers ] = useState<MarketplaceOfferData[]>([]);
|
||||
const { simpleAlert = null } = useNotification();
|
||||
const isRedeemingRef = useRef<boolean>(false);
|
||||
const pendingCancelsRef = useRef<Set<number>>(new Set());
|
||||
|
||||
useMessageEvent<MarketplaceOwnOffersEvent>(MarketplaceOwnOffersEvent, event =>
|
||||
{
|
||||
@@ -54,6 +56,10 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
|
||||
|
||||
const redeemSoldOffers = useCallback(() =>
|
||||
{
|
||||
if(isRedeemingRef.current) return;
|
||||
|
||||
isRedeemingRef.current = true;
|
||||
|
||||
setOffers(prevValue =>
|
||||
{
|
||||
const idsToDelete = soldOffers.map(value => value.offerId);
|
||||
@@ -62,11 +68,19 @@ export const CatalogLayoutMarketplaceOwnItemsView: FC<CatalogLayoutProps> = prop
|
||||
});
|
||||
|
||||
SendMessageComposer(new RedeemMarketplaceOfferCreditsMessageComposer());
|
||||
|
||||
setTimeout(() => isRedeemingRef.current = false, 3000);
|
||||
}, [ soldOffers ]);
|
||||
|
||||
const takeItemBack = (offerData: MarketplaceOfferData) =>
|
||||
{
|
||||
if(pendingCancelsRef.current.has(offerData.offerId)) return;
|
||||
|
||||
pendingCancelsRef.current.add(offerData.offerId);
|
||||
|
||||
SendMessageComposer(new CancelMarketplaceOfferMessageComposer(offerData.offerId));
|
||||
|
||||
setTimeout(() => pendingCancelsRef.current.delete(offerData.offerId), 2000);
|
||||
};
|
||||
|
||||
useEffect(() =>
|
||||
|
||||
+7
-1
@@ -1,5 +1,5 @@
|
||||
import { BuyMarketplaceOfferMessageComposer, GetMarketplaceOffersMessageComposer, MarketplaceBuyOfferResultEvent, MarketPlaceOffersEvent } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useMemo, useState } from 'react';
|
||||
import { FC, useCallback, useMemo, useRef, useState } from 'react';
|
||||
import { IMarketplaceSearchOptions, LocalizeText, MarketplaceOfferData, MarketplaceSearchType, NotificationAlertType, SendMessageComposer } from '../../../../../../api';
|
||||
import { Button, Column, Text } from '../../../../../../common';
|
||||
import { useMessageEvent, useNotification, usePurse } from '../../../../../../hooks';
|
||||
@@ -23,6 +23,7 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
const [ lastSearch, setLastSearch ] = useState<IMarketplaceSearchOptions>({ minPrice: -1, maxPrice: -1, query: '', type: 3 });
|
||||
const { getCurrencyAmount = null } = usePurse();
|
||||
const { simpleAlert = null, showConfirm = null } = useNotification();
|
||||
const isBuyingRef = useRef<boolean>(false);
|
||||
|
||||
const requestOffers = useCallback((options: IMarketplaceSearchOptions) =>
|
||||
{
|
||||
@@ -56,6 +57,9 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
|
||||
showConfirm(LocalizeText('catalog.marketplace.confirm_header'), () =>
|
||||
{
|
||||
if(isBuyingRef.current) return;
|
||||
|
||||
isBuyingRef.current = true;
|
||||
SendMessageComposer(new BuyMarketplaceOfferMessageComposer(offerId));
|
||||
},
|
||||
null, null, null, LocalizeText('catalog.marketplace.confirm_title'));
|
||||
@@ -83,6 +87,8 @@ export const CatalogLayoutMarketplacePublicItemsView: FC<CatalogLayoutMarketplac
|
||||
{
|
||||
const parser = event.getParser();
|
||||
|
||||
isBuyingRef.current = false;
|
||||
|
||||
if(!parser) return;
|
||||
|
||||
switch(parser.result)
|
||||
|
||||
@@ -6,6 +6,8 @@ import { CatalogPostMarketplaceOfferEvent } from '../../../../../../events';
|
||||
import { useCatalog, useMessageEvent, useNotification, useUiEvent } from '../../../../../../hooks';
|
||||
import { NitroInput } from '../../../../../../layout';
|
||||
|
||||
let isPostingMarketplaceOffer = false;
|
||||
|
||||
export const MarketplacePostOfferView: FC<{}> = props =>
|
||||
{
|
||||
const [ item, setItem ] = useState<FurnitureItem>(null);
|
||||
@@ -65,10 +67,15 @@ export const MarketplacePostOfferView: FC<{}> = props =>
|
||||
|
||||
const postItem = () =>
|
||||
{
|
||||
if(!item || (askingPrice < marketplaceConfiguration.minimumPrice)) return;
|
||||
if(!item || (askingPrice < marketplaceConfiguration.minimumPrice) || isPostingMarketplaceOffer) return;
|
||||
|
||||
showConfirm(LocalizeText('inventory.marketplace.confirm_offer.info', [ 'furniname', 'price' ], [ getFurniTitle, askingPrice.toString() ]), () =>
|
||||
{
|
||||
if(isPostingMarketplaceOffer) return;
|
||||
|
||||
isPostingMarketplaceOffer = true;
|
||||
setTimeout(() => isPostingMarketplaceOffer = false, 5000);
|
||||
|
||||
SendMessageComposer(new MakeOfferMessageComposer(askingPrice, item.isWallItem ? 2 : 1, item.id));
|
||||
setItem(null);
|
||||
},
|
||||
|
||||
@@ -6,6 +6,8 @@ import { useCatalog, useNotification, usePurse } from '../../../../../../hooks';
|
||||
import { CatalogLayoutProps } from '../CatalogLayout.types';
|
||||
import { VipGiftItem } from './VipGiftItemView';
|
||||
|
||||
let isSelectingGift = false;
|
||||
|
||||
export const CatalogLayoutVipGiftsView: FC<CatalogLayoutProps> = props =>
|
||||
{
|
||||
const { purse = null } = usePurse();
|
||||
@@ -30,6 +32,10 @@ export const CatalogLayoutVipGiftsView: FC<CatalogLayoutProps> = props =>
|
||||
{
|
||||
showConfirm(LocalizeText('catalog.club_gift.confirm'), () =>
|
||||
{
|
||||
if(isSelectingGift) return;
|
||||
|
||||
isSelectingGift = true;
|
||||
|
||||
SendMessageComposer(new SelectClubGiftComposer(localizationId));
|
||||
|
||||
setCatalogOptions(prevValue =>
|
||||
@@ -38,6 +44,8 @@ export const CatalogLayoutVipGiftsView: FC<CatalogLayoutProps> = props =>
|
||||
|
||||
return { ...prevValue };
|
||||
});
|
||||
|
||||
setTimeout(() => isSelectingGift = false, 5000);
|
||||
}, null);
|
||||
}, [ setCatalogOptions, showConfirm ]);
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ interface CatalogPurchaseWidgetViewProps
|
||||
purchaseCallback?: () => void;
|
||||
}
|
||||
|
||||
let isPurchasingCatalogItem = false;
|
||||
|
||||
export const CatalogPurchaseWidgetView: FC<CatalogPurchaseWidgetViewProps> = props =>
|
||||
{
|
||||
const { noGiftOption = false, purchaseCallback = null } = props;
|
||||
@@ -25,15 +27,19 @@ export const CatalogPurchaseWidgetView: FC<CatalogPurchaseWidgetViewProps> = pro
|
||||
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;
|
||||
}
|
||||
@@ -62,7 +68,7 @@ export const CatalogPurchaseWidgetView: FC<CatalogPurchaseWidgetViewProps> = pro
|
||||
|
||||
const purchase = (isGift: boolean = false) =>
|
||||
{
|
||||
if(!currentOffer) return;
|
||||
if(!currentOffer || isPurchasingCatalogItem) return;
|
||||
|
||||
if(GetClubMemberLevel() < currentOffer.clubLevel)
|
||||
{
|
||||
@@ -78,6 +84,7 @@ export const CatalogPurchaseWidgetView: FC<CatalogPurchaseWidgetViewProps> = pro
|
||||
return;
|
||||
}
|
||||
|
||||
isPurchasingCatalogItem = true;
|
||||
setPurchaseState(CatalogPurchaseState.PURCHASE);
|
||||
|
||||
if(purchaseCallback)
|
||||
|
||||
@@ -4,6 +4,8 @@ import { FriendlyTime, GetConfigurationValue, LocalizeText, SendMessageComposer
|
||||
import { Button, Column, Flex, LayoutCurrencyIcon, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||
import { usePurse } from '../../../../hooks';
|
||||
|
||||
let isBuyingOffer = false;
|
||||
|
||||
export const OfferWindowView = (props: { offer: TargetedOfferData, setOpen: Dispatch<SetStateAction<boolean>> }) =>
|
||||
{
|
||||
const { offer = null, setOpen = null } = props;
|
||||
@@ -37,8 +39,14 @@ export const OfferWindowView = (props: { offer: TargetedOfferData, setOpen: Disp
|
||||
|
||||
const buyOffer = () =>
|
||||
{
|
||||
if(isBuyingOffer) return;
|
||||
|
||||
isBuyingOffer = true;
|
||||
|
||||
SendMessageComposer(new PurchaseTargetedOfferComposer(offer.id, amount));
|
||||
SendMessageComposer(new GetTargetedOfferComposer());
|
||||
|
||||
setTimeout(() => isBuyingOffer = false, 5000);
|
||||
};
|
||||
|
||||
if(!offer) return;
|
||||
|
||||
Reference in New Issue
Block a user