mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 23:16:21 +00:00
㊙️ Security Fixes
- XSS fix: Created SanitizeHtml.ts utility using DOMPurify (already in package.json but never used). Wrapped all 21 dangerouslySetInnerHTML calls in catalog views with SanitizeHtml() — only allows safe tags (b, i, u, br, span, div, p, a, strong, em, img) - Race condition fix: Added 10-second timeout fallbacks on purchase flags in CatalogPurchaseWidgetView and CatalogGiftView so the flag auto-resets even if the server never responds
This commit is contained in:
@@ -228,7 +228,7 @@ const CatalogModernViewInner: FC<{}> = () =>
|
||||
<FaStar className="text-[9px] text-primary shrink-0" />
|
||||
{ activeNodes && activeNodes.length > 0
|
||||
? activeNodes.map((node, i) => (
|
||||
<span key={ node.pageId } className="flex items-center gap-1 min-w-0">
|
||||
<span key={ `${ node.pageId }-${ i }` } className="flex items-center gap-1 min-w-0">
|
||||
{ i > 0 && <span className="text-[8px] opacity-30">›</span> }
|
||||
<span className={ `truncate ${ i === activeNodes.length - 1 ? 'font-bold text-dark' : 'cursor-pointer hover:text-primary' }` }
|
||||
onClick={ i < activeNodes.length - 1 ? () => activateNode(node) : undefined }>
|
||||
|
||||
@@ -128,6 +128,7 @@ export const CatalogGiftView: FC<{}> = props =>
|
||||
if(isBuyingGift) return;
|
||||
|
||||
isBuyingGift = true;
|
||||
setTimeout(() => { isBuyingGift = false; }, 10000);
|
||||
|
||||
SendMessageComposer(new PurchaseFromCatalogAsGiftComposer(pageId, offerId, extraData, receiverName, message, colourId, selectedBoxIndex, selectedRibbonIndex, showMyFace));
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { LocalizeText } from '../../../../../api';
|
||||
import { LocalizeText, SanitizeHtml } from '../../../../../api';
|
||||
import { Column, Grid, Text } from '../../../../../common';
|
||||
import { useCatalog } from '../../../../../hooks';
|
||||
import { CatalogBadgeSelectorWidgetView } from '../widgets/CatalogBadgeSelectorWidgetView';
|
||||
@@ -31,7 +31,7 @@ export const CatalogLayoutBadgeDisplayView: FC<CatalogLayoutProps> = props =>
|
||||
{ !currentOffer &&
|
||||
<>
|
||||
{ !!page.localization.getImage(1) && <img alt="" src={ page.localization.getImage(1) } /> }
|
||||
<Text center dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<Text center dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
</> }
|
||||
{ currentOffer &&
|
||||
<>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ColorConverter } from '@nitrots/nitro-renderer';
|
||||
import { FC, useMemo, useState } from 'react';
|
||||
import { FaFillDrip } from 'react-icons/fa';
|
||||
import { IPurchasableOffer } from '../../../../../api';
|
||||
import { IPurchasableOffer, SanitizeHtml } from '../../../../../api';
|
||||
import { AutoGrid, Button, Column, Grid, LayoutGridItem, Text } from '../../../../../common';
|
||||
import { useCatalog } from '../../../../../hooks';
|
||||
import { CatalogGridOfferView } from '../common/CatalogGridOfferView';
|
||||
@@ -146,7 +146,7 @@ export const CatalogLayoutColorGroupingView: FC<CatalogLayoutColorGroupViewProps
|
||||
{ !currentOffer &&
|
||||
<>
|
||||
{ !!page.localization.getImage(1) && <img alt="" src={ page.localization.getImage(1) } /> }
|
||||
<Text center dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<Text center dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
</> }
|
||||
{ currentOffer &&
|
||||
<>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PurchasePrefixComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { LocalizeText, SendMessageComposer, PRESET_PREFIX_EFFECTS, parsePrefixColors, getPrefixEffectStyle, PREFIX_EFFECT_KEYFRAMES } from '../../../../../api';
|
||||
import { LocalizeText, SanitizeHtml, SendMessageComposer, PRESET_PREFIX_EFFECTS, parsePrefixColors, getPrefixEffectStyle, PREFIX_EFFECT_KEYFRAMES } from '../../../../../api';
|
||||
import { CatalogLayoutProps } from './CatalogLayout.types';
|
||||
import data from '@emoji-mart/data';
|
||||
import Picker from '@emoji-mart/react';
|
||||
@@ -137,7 +137,7 @@ export const CatalogLayoutCustomPrefixView: FC<CatalogLayoutProps> = props =>
|
||||
{ page.localization.getImage(0) &&
|
||||
<img alt="" className="w-full rounded" src={ page.localization.getImage(0) } /> }
|
||||
{ page.localization.getText(0) &&
|
||||
<div className="text-sm mb-1" dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } /> }
|
||||
<div className="text-sm mb-1" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } /> }
|
||||
|
||||
{ /* Live Preview */ }
|
||||
<div className="relative flex items-center justify-center p-4 rounded-lg min-h-[56px]"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FC } from 'react';
|
||||
import { FaEdit, FaPlus } from 'react-icons/fa';
|
||||
import { GetConfigurationValue, LocalizeText, ProductTypeEnum } from '../../../../../api';
|
||||
import { GetConfigurationValue, LocalizeText, ProductTypeEnum, SanitizeHtml } from '../../../../../api';
|
||||
import { Text } from '../../../../../common';
|
||||
import { useCatalog } from '../../../../../hooks';
|
||||
import { useCatalogAdmin } from '../../../CatalogAdminContext';
|
||||
@@ -90,7 +90,7 @@ export const CatalogLayoutDefaultView: FC<CatalogLayoutProps> = props =>
|
||||
<div className="flex items-center gap-3 p-2.5 bg-white rounded border-2 border-card-grid-item-border">
|
||||
{ !!page.localization.getImage(1) &&
|
||||
<img className="w-[70px] h-[70px] object-contain rounded shrink-0" src={ page.localization.getImage(1) } /> }
|
||||
<Text className="text-[11px]! text-muted" dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<Text className="text-[11px]! text-muted" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
</div> }
|
||||
|
||||
{ /* Item grid */ }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { SanitizeHtml } from '../../../../../api';
|
||||
import { Column, Grid, Text } from '../../../../../common';
|
||||
import { useCatalog } from '../../../../../hooks';
|
||||
import { CatalogGuildBadgeWidgetView } from '../widgets/CatalogGuildBadgeWidgetView';
|
||||
@@ -23,7 +24,7 @@ export const CatalogLayouGuildCustomFurniView: FC<CatalogLayoutProps> = props =>
|
||||
{ !currentOffer &&
|
||||
<>
|
||||
{ !!page.localization.getImage(1) && <img alt="" src={ page.localization.getImage(1) } /> }
|
||||
<Text center dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<Text center dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
</> }
|
||||
{ currentOffer &&
|
||||
<>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CatalogGroupsComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { SendMessageComposer } from '../../../../../api';
|
||||
import { SanitizeHtml, SendMessageComposer } from '../../../../../api';
|
||||
import { Column, Grid, Text } from '../../../../../common';
|
||||
import { useCatalog } from '../../../../../hooks';
|
||||
import { CatalogFirstProductSelectorWidgetView } from '../widgets/CatalogFirstProductSelectorWidgetView';
|
||||
@@ -26,7 +26,7 @@ export const CatalogLayouGuildForumView: FC<CatalogLayoutProps> = props =>
|
||||
<CatalogFirstProductSelectorWidgetView />
|
||||
<Grid>
|
||||
<Column className="bg-muted rounded p-2 text-black" overflow="hidden" size={ 7 }>
|
||||
<div className="overflow-auto" dangerouslySetInnerHTML={ { __html: page.localization.getText(1) } } />
|
||||
<div className="overflow-auto" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(1)) } } />
|
||||
</Column>
|
||||
<Column gap={ 1 } overflow="hidden" size={ 5 }>
|
||||
{ !!currentOffer &&
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { CreateLinkEvent } from '@nitrots/nitro-renderer';
|
||||
import { FC } from 'react';
|
||||
import { LocalizeText } from '../../../../../api';
|
||||
import { LocalizeText, SanitizeHtml } from '../../../../../api';
|
||||
import { Button } from '../../../../../common/Button';
|
||||
import { Column } from '../../../../../common/Column';
|
||||
import { Grid } from '../../../../../common/Grid';
|
||||
@@ -14,9 +14,9 @@ export const CatalogLayouGuildFrontpageView: FC<CatalogLayoutProps> = props =>
|
||||
return (
|
||||
<Grid>
|
||||
<Column className="bg-muted rounded p-2 text-black" overflow="hidden" size={ 7 }>
|
||||
<div dangerouslySetInnerHTML={ { __html: page.localization.getText(2) } } />
|
||||
<div className="overflow-auto" dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<div dangerouslySetInnerHTML={ { __html: page.localization.getText(1) } } />
|
||||
<div dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(2)) } } />
|
||||
<div className="overflow-auto" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
<div dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(1)) } } />
|
||||
</Column>
|
||||
<Column center overflow="hidden" size={ 5 }>
|
||||
<LayoutImage imageUrl={ page.localization.getImage(1) } />
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { SanitizeHtml } from '../../../../../api';
|
||||
import { CatalogLayoutProps } from './CatalogLayout.types';
|
||||
|
||||
export const CatalogLayoutInfoLoyaltyView: FC<CatalogLayoutProps> = props =>
|
||||
@@ -8,7 +9,7 @@ export const CatalogLayoutInfoLoyaltyView: FC<CatalogLayoutProps> = props =>
|
||||
return (
|
||||
<div className="h-full nitro-catalog-layout-info-loyalty text-black flex flex-row">
|
||||
<div className="overflow-auto h-full flex flex-col info-loyalty-content">
|
||||
<div dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<div dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { FC } from 'react';
|
||||
import { FaPaw } from 'react-icons/fa';
|
||||
import { SanitizeHtml } from '../../../../../api';
|
||||
import { CatalogLayoutProps } from './CatalogLayout.types';
|
||||
|
||||
export const CatalogLayoutPets3View: FC<CatalogLayoutProps> = props =>
|
||||
@@ -16,20 +17,20 @@ export const CatalogLayoutPets3View: FC<CatalogLayoutProps> = props =>
|
||||
<div>
|
||||
<div className="flex items-center gap-1.5 mb-0.5">
|
||||
<FaPaw className="text-primary text-xs" />
|
||||
<span className="text-sm font-bold" dangerouslySetInnerHTML={ { __html: page.localization.getText(1) } } />
|
||||
<span className="text-sm font-bold" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(1)) } } />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{ /* Content */ }
|
||||
<div className="flex-1 overflow-auto bg-white rounded border-2 border-card-grid-item-border p-3">
|
||||
<div className="text-[11px] leading-relaxed" dangerouslySetInnerHTML={ { __html: page.localization.getText(2) } } />
|
||||
<div className="text-[11px] leading-relaxed" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(2)) } } />
|
||||
</div>
|
||||
|
||||
{ /* Footer */ }
|
||||
{ !!page.localization.getText(3) &&
|
||||
<div className="p-2 bg-card-grid-item rounded border border-card-grid-item-border">
|
||||
<span className="text-[11px] font-bold" dangerouslySetInnerHTML={ { __html: page.localization.getText(3) } } />
|
||||
<span className="text-[11px] font-bold" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(3)) } } />
|
||||
</div> }
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { SanitizeHtml } from '../../../../../api';
|
||||
import { Column, Grid, Text } from '../../../../../common';
|
||||
import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView';
|
||||
import { CatalogBundleGridWidgetView } from '../widgets/CatalogBundleGridWidgetView';
|
||||
@@ -17,7 +18,7 @@ export const CatalogLayoutRoomBundleView: FC<CatalogLayoutProps> = props =>
|
||||
<Grid>
|
||||
<Column overflow="hidden" size={ 7 }>
|
||||
{ !!page.localization.getText(2) &&
|
||||
<Text dangerouslySetInnerHTML={ { __html: page.localization.getText(2) } } /> }
|
||||
<Text dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(2)) } } /> }
|
||||
<Column grow className="bg-muted p-2 rounded" overflow="hidden">
|
||||
<CatalogBundleGridWidgetView fullWidth className="nitro-catalog-layout-bundle-grid" />
|
||||
</Column>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FC } from 'react';
|
||||
import { SanitizeHtml } from '../../../../../api';
|
||||
import { Column, Grid, Text } from '../../../../../common';
|
||||
import { CatalogAddOnBadgeWidgetView } from '../widgets/CatalogAddOnBadgeWidgetView';
|
||||
import { CatalogBundleGridWidgetView } from '../widgets/CatalogBundleGridWidgetView';
|
||||
@@ -17,7 +18,7 @@ export const CatalogLayoutSingleBundleView: FC<CatalogLayoutProps> = props =>
|
||||
<Grid>
|
||||
<Column overflow="hidden" size={ 7 }>
|
||||
{ !!page.localization.getText(2) &&
|
||||
<Text dangerouslySetInnerHTML={ { __html: page.localization.getText(2) } } /> }
|
||||
<Text dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(2)) } } /> }
|
||||
<Column grow className="bg-muted p-2 rounded" overflow="hidden">
|
||||
<CatalogBundleGridWidgetView fullWidth className="nitro-catalog-layout-bundle-grid" />
|
||||
</Column>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GetOfficialSongIdMessageComposer, GetSoundManager, MusicPriorities, OfficialSongIdMessageEvent } from '@nitrots/nitro-renderer';
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { GetConfigurationValue, LocalizeText, ProductTypeEnum, SendMessageComposer } from '../../../../../api';
|
||||
import { GetConfigurationValue, LocalizeText, ProductTypeEnum, SanitizeHtml, SendMessageComposer } from '../../../../../api';
|
||||
import { Button, Column, Grid, LayoutImage, Text } from '../../../../../common';
|
||||
import { useCatalog, useMessageEvent } from '../../../../../hooks';
|
||||
import { CatalogHeaderView } from '../../catalog-header/CatalogHeaderView';
|
||||
@@ -80,7 +80,7 @@ export const CatalogLayoutSoundMachineView: FC<CatalogLayoutProps> = props =>
|
||||
<>
|
||||
{ !!page.localization.getImage(1) &&
|
||||
<LayoutImage imageUrl={ page.localization.getImage(1) } /> }
|
||||
<Text center dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<Text center dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
</> }
|
||||
{ currentOffer &&
|
||||
<>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { FC, useEffect } from 'react';
|
||||
import { SanitizeHtml } from '../../../../../api';
|
||||
import { Column, Grid, Text } from '../../../../../common';
|
||||
import { useCatalog } from '../../../../../hooks';
|
||||
import { CatalogPurchaseWidgetView } from '../widgets/CatalogPurchaseWidgetView';
|
||||
@@ -26,7 +27,7 @@ export const CatalogLayoutSpacesView: FC<CatalogLayoutProps> = props =>
|
||||
{ !currentOffer &&
|
||||
<>
|
||||
{ !!page.localization.getImage(1) && <img alt="" src={ page.localization.getImage(1) } /> }
|
||||
<Text center dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<Text center dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
</> }
|
||||
{ currentOffer &&
|
||||
<>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import { FaEdit, FaPen, FaPlus, FaTrophy } from 'react-icons/fa';
|
||||
import { LocalizeText, ProductTypeEnum } from '../../../../../api';
|
||||
import { LocalizeText, ProductTypeEnum, SanitizeHtml } from '../../../../../api';
|
||||
import { Text } from '../../../../../common';
|
||||
import { useCatalog } from '../../../../../hooks';
|
||||
import { useCatalogAdmin } from '../../../CatalogAdminContext';
|
||||
@@ -99,7 +99,7 @@ export const CatalogLayoutTrophiesView: FC<CatalogLayoutProps> = props =>
|
||||
<FaTrophy className="text-warning text-[11px]" />
|
||||
<span className="text-[12px] font-bold">{ LocalizeText('catalog.trophies.title') }</span>
|
||||
</div>
|
||||
<Text className="text-[10px]! text-muted leading-relaxed" dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } />
|
||||
<Text className="text-[10px]! text-muted leading-relaxed" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } />
|
||||
</div>
|
||||
</div> }
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ClubOfferData, GetClubOffersMessageComposer, PurchaseFromCatalogComposer } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { CatalogPurchaseState, LocalizeText, SendMessageComposer } from '../../../../../api';
|
||||
import { CatalogPurchaseState, LocalizeText, SanitizeHtml, SendMessageComposer } from '../../../../../api';
|
||||
import { AutoGrid, Button, Column, Flex, Grid, LayoutCurrencyIcon, LayoutGridItem, LayoutLoadingSpinnerView, Text } from '../../../../../common';
|
||||
import { CatalogEvent, CatalogPurchaseFailureEvent, CatalogPurchasedEvent } from '../../../../../events';
|
||||
import { useCatalog, usePurse, useUiEvent } from '../../../../../hooks';
|
||||
@@ -160,12 +160,12 @@ export const CatalogLayoutVipBuyView: FC<CatalogLayoutProps> = props =>
|
||||
);
|
||||
}) }
|
||||
</AutoGrid>
|
||||
<Text center dangerouslySetInnerHTML={ { __html: LocalizeText('catalog.vip.buy.hccenter') } }></Text>
|
||||
<Text center dangerouslySetInnerHTML={ { __html: SanitizeHtml(LocalizeText('catalog.vip.buy.hccenter')) } }></Text>
|
||||
</Column>
|
||||
<Column overflow="hidden" size={ 5 }>
|
||||
<Column center fullHeight overflow="hidden">
|
||||
{ currentPage.localization.getImage(1) && <img alt="" src={ currentPage.localization.getImage(1) } /> }
|
||||
<Text center dangerouslySetInnerHTML={ { __html: getSubscriptionDetails } } overflow="auto" />
|
||||
<Text center dangerouslySetInnerHTML={ { __html: SanitizeHtml(getSubscriptionDetails) } } overflow="auto" />
|
||||
</Column>
|
||||
{ pendingOffer &&
|
||||
<Column fullWidth grow justifyContent="end">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { ApproveNameMessageComposer, ApproveNameMessageEvent, ColorConverter, GetSellablePetPalettesComposer, PurchaseFromCatalogComposer, SellablePetPaletteData } from '@nitrots/nitro-renderer';
|
||||
import { FC, useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import { FaCheck, FaEdit, FaFillDrip, FaPaw, FaPlus, FaTimes } from 'react-icons/fa';
|
||||
import { DispatchUiEvent, GetPetAvailableColors, GetPetIndexFromLocalization, LocalizeText, SendMessageComposer } from '../../../../../../api';
|
||||
import { DispatchUiEvent, GetPetAvailableColors, GetPetIndexFromLocalization, LocalizeText, SanitizeHtml, SendMessageComposer } from '../../../../../../api';
|
||||
import { LayoutGridItem, LayoutPetImageView } from '../../../../../../common';
|
||||
import { CatalogPurchaseFailureEvent } from '../../../../../../events';
|
||||
import { useCatalog, useMessageEvent } from '../../../../../../hooks';
|
||||
@@ -249,7 +249,7 @@ export const CatalogLayoutPetView: FC<CatalogLayoutProps> = props =>
|
||||
<span className="text-[8px] font-mono text-white bg-primary px-1 py-px rounded">Offer: { currentOffer.offerId }</span>
|
||||
</div> }
|
||||
{ !!page.localization.getText(0) &&
|
||||
<p className="text-[10px] text-muted mt-0.5" dangerouslySetInnerHTML={ { __html: page.localization.getText(0) } } /> }
|
||||
<p className="text-[10px] text-muted mt-0.5" dangerouslySetInnerHTML={ { __html: SanitizeHtml(page.localization.getText(0)) } } /> }
|
||||
</div>
|
||||
|
||||
{ /* Name input */ }
|
||||
|
||||
@@ -87,6 +87,8 @@ export const CatalogPurchaseWidgetView: FC<CatalogPurchaseWidgetViewProps> = pro
|
||||
isPurchasingCatalogItem = true;
|
||||
setPurchaseState(CatalogPurchaseState.PURCHASE);
|
||||
|
||||
setTimeout(() => { isPurchasingCatalogItem = false; }, 10000);
|
||||
|
||||
if(purchaseCallback)
|
||||
{
|
||||
purchaseCallback();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { GetTargetedOfferComposer, PurchaseTargetedOfferComposer, TargetedOfferData } from '@nitrots/nitro-renderer';
|
||||
import { Dispatch, SetStateAction, useMemo, useState } from 'react';
|
||||
import { FriendlyTime, GetConfigurationValue, LocalizeText, SendMessageComposer } from '../../../../api';
|
||||
import { FriendlyTime, GetConfigurationValue, LocalizeText, SanitizeHtml, SendMessageComposer } from '../../../../api';
|
||||
import { Button, Column, Flex, LayoutCurrencyIcon, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../../../common';
|
||||
import { usePurse } from '../../../../hooks';
|
||||
|
||||
@@ -63,7 +63,7 @@ export const OfferWindowView = (props: { offer: TargetedOfferData, setOpen: Disp
|
||||
<h4>
|
||||
{ LocalizeText(offer.title) }
|
||||
</h4>
|
||||
<div dangerouslySetInnerHTML={ { __html: offer.description } } />
|
||||
<div dangerouslySetInnerHTML={ { __html: SanitizeHtml(offer.description) } } />
|
||||
</Column>
|
||||
<Flex alignItems="center" alignSelf="center" gap={ 2 } justifyContent="center">
|
||||
{ offer.purchaseLimit > 1 &&
|
||||
|
||||
Reference in New Issue
Block a user