mirror of
https://github.com/billsonnn/nitro-react.git
synced 2024-11-22 22:30:52 +01:00
parent
9f46f75a1e
commit
fc6852ee2f
BIN
src/assets/images/catalog/target-price.png
Normal file
BIN
src/assets/images/catalog/target-price.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.5 KiB |
@ -1,18 +1,23 @@
|
||||
import { FC, useMemo } from 'react';
|
||||
import { Flex, FlexProps } from '..';
|
||||
|
||||
export const NitroCardSubHeaderView: FC<FlexProps> = props =>
|
||||
interface NitroCardSubHeaderProps extends FlexProps {
|
||||
variant?: string;
|
||||
}
|
||||
export const NitroCardSubHeaderView: FC<NitroCardSubHeaderProps> = props =>
|
||||
{
|
||||
const { justifyContent = 'center', classNames = [], ...rest } = props;
|
||||
const { justifyContent = 'center', classNames = [], variant = 'muted', ...rest } = props;
|
||||
|
||||
const getClassNames = useMemo(() =>
|
||||
{
|
||||
const newClassNames: string[] = [ 'container-fluid', 'bg-muted', 'p-1' ];
|
||||
const newClassNames: string[] = [ 'container-fluid', 'p-1' ];
|
||||
|
||||
if(classNames.length) newClassNames.push(...classNames);
|
||||
|
||||
newClassNames.push('bg-' + variant);
|
||||
|
||||
return newClassNames;
|
||||
}, [ classNames ]);
|
||||
}, [ classNames, variant ]);
|
||||
|
||||
return <Flex justifyContent={ justifyContent } classNames={ getClassNames } { ...rest } />;
|
||||
}
|
||||
|
@ -126,3 +126,5 @@
|
||||
width: 290px;
|
||||
height: 60px;
|
||||
}
|
||||
|
||||
@import "./views/targeted-offer/Offer.scss";
|
||||
|
27
src/components/catalog/views/targeted-offer/Offer.scss
Normal file
27
src/components/catalog/views/targeted-offer/Offer.scss
Normal file
@ -0,0 +1,27 @@
|
||||
.nitro-targeted-offer {
|
||||
width: 500px;
|
||||
height: 350px;
|
||||
|
||||
a {
|
||||
color: orangered;
|
||||
}
|
||||
|
||||
.price-ray {
|
||||
bottom: 20px;
|
||||
left: 40px;
|
||||
right: 0;
|
||||
margin: auto;
|
||||
width: 136px;
|
||||
height: 136px;
|
||||
padding: 10px;
|
||||
background-image: url("../../../../assets/images/catalog/target-price.png");
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.nitro-targeted-offer-icon {
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
import { TargetedOfferData } from '@nitrots/nitro-renderer';
|
||||
import { Dispatch, SetStateAction } from 'react';
|
||||
import { GetConfiguration } from '../../../../api';
|
||||
import { Base, LayoutNotificationBubbleView, Text } from '../../../../common';
|
||||
|
||||
export const OfferBubbleView = (props: { offer: TargetedOfferData, setOpen: Dispatch<SetStateAction<boolean>> }) =>
|
||||
{
|
||||
const { offer = null, setOpen = null } = props;
|
||||
|
||||
if (!offer) return;
|
||||
|
||||
return <LayoutNotificationBubbleView fadesOut={ false } onClose={ null } onClick={ evt => setOpen(true) } gap={ 2 }>
|
||||
<Base className="nitro-targeted-offer-icon" style={ { backgroundImage: `url(${ GetConfiguration('image.library.url') + offer._Str_13452 })` } }/>
|
||||
<Text variant="light" className="ubuntu-bold">{ offer.title }</Text>
|
||||
</LayoutNotificationBubbleView>;
|
||||
}
|
32
src/components/catalog/views/targeted-offer/OfferView.tsx
Normal file
32
src/components/catalog/views/targeted-offer/OfferView.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { GetTargetedOfferComposer, TargetedOfferData, TargetedOfferEvent } from '@nitrots/nitro-renderer';
|
||||
import { useState } from 'react';
|
||||
import { SendMessageComposer } from '../../../../api';
|
||||
import { useMessageEvent, UseMountEffect } from '../../../../hooks';
|
||||
import { OfferBubbleView } from './OfferBubbleView';
|
||||
import { OfferWindowView } from './OfferWindowView';
|
||||
|
||||
export const OfferView = () =>
|
||||
{
|
||||
const [ offer, setOffer ] = useState<TargetedOfferData>(null);
|
||||
const [ opened, setOpened ] = useState<boolean>(false);
|
||||
|
||||
useMessageEvent<TargetedOfferEvent>(TargetedOfferEvent, evt =>
|
||||
{
|
||||
let parser = evt.getParser();
|
||||
|
||||
if (!parser) return;
|
||||
|
||||
setOffer(parser.data);
|
||||
});
|
||||
|
||||
UseMountEffect(() =>
|
||||
{
|
||||
SendMessageComposer(new GetTargetedOfferComposer());
|
||||
})
|
||||
|
||||
if (!offer) return;
|
||||
|
||||
return <>
|
||||
{ opened ? <OfferWindowView offer={ offer } setOpen={ setOpened } /> : <OfferBubbleView offer={ offer } setOpen={ setOpened } /> }
|
||||
</>
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
import { FriendlyTime, GetTargetedOfferComposer, PurchaseTargetedOfferComposer, TargetedOfferData } from '@nitrots/nitro-renderer';
|
||||
import { Dispatch, SetStateAction, useMemo, useState } from 'react';
|
||||
import { GetConfiguration, LocalizeText, SendMessageComposer } from '../../../../api';
|
||||
import { Base, Button, Column, Flex, LayoutCurrencyIcon, NitroCardContentView, NitroCardHeaderView, NitroCardSubHeaderView, NitroCardView, Text } from '../../../../common';
|
||||
import { usePurse } from '../../../../hooks';
|
||||
|
||||
export const OfferWindowView = (props: { offer: TargetedOfferData, setOpen: Dispatch<SetStateAction<boolean>> }) =>
|
||||
{
|
||||
const { offer = null, setOpen = null } = props;
|
||||
|
||||
const { getCurrencyAmount } = usePurse();
|
||||
|
||||
const [ amount, setAmount ] = useState<number>(1);
|
||||
|
||||
const canPurchase = useMemo(() =>
|
||||
{
|
||||
let credits = false;
|
||||
let points = false;
|
||||
let limit = false;
|
||||
|
||||
if (offer.priceInCredits > 0) credits = getCurrencyAmount(-1) >= offer.priceInCredits;
|
||||
|
||||
if (offer.priceInActivityPoints > 0) points = getCurrencyAmount(offer.activityPointType) >= offer.priceInActivityPoints;
|
||||
else points = true;
|
||||
|
||||
if (offer.purchaseLimit > 0) limit = true;
|
||||
|
||||
return (credits && points && limit);
|
||||
},[ offer,getCurrencyAmount ])
|
||||
|
||||
const expirationTime = () =>
|
||||
{
|
||||
let expirationTime = Math.max(0, (offer.expirationTime - Date.now() ) / 1000)
|
||||
|
||||
return FriendlyTime.format(expirationTime);
|
||||
}
|
||||
|
||||
const buyOffer = () =>
|
||||
{
|
||||
SendMessageComposer(new PurchaseTargetedOfferComposer(offer.id, amount));
|
||||
SendMessageComposer(new GetTargetedOfferComposer());
|
||||
}
|
||||
|
||||
if (!offer) return;
|
||||
|
||||
return <NitroCardView theme="primary-slim" uniqueKey="targeted-offer" className="nitro-targeted-offer">
|
||||
<NitroCardHeaderView headerText={ LocalizeText(offer.title) } onCloseClick={ event => setOpen(false) } />
|
||||
<NitroCardSubHeaderView position="relative" className="justify-content-center align-items-center cursor-pointer" variant="danger" gap={ 3 }>
|
||||
{ LocalizeText('targeted.offer.timeleft',[ 'timeleft' ],[ expirationTime() ]) }
|
||||
</NitroCardSubHeaderView>
|
||||
<NitroCardContentView gap={ 1 }>
|
||||
<Flex gap={ 1 } fullHeight>
|
||||
<Flex gap={ 1 } column className="w-75 text-black">
|
||||
<Column className="bg-warning p-2" fullHeight>
|
||||
<h4>
|
||||
{ LocalizeText(offer.title) }
|
||||
</h4>
|
||||
<Base dangerouslySetInnerHTML={ { __html: offer.description } }/>
|
||||
</Column>
|
||||
<Flex alignSelf="center" alignItems="center" justifyContent="center" gap={ 2 }>
|
||||
{ offer.purchaseLimit > 1 && <Flex gap={ 1 }>
|
||||
<Text variant="muted">{ LocalizeText('catalog.bundlewidget.quantity') }</Text>
|
||||
<input type="number" value={ amount } onChange={ evt => setAmount(parseInt(evt.target.value)) } min={ 1 } max={ offer.purchaseLimit } />
|
||||
</Flex> }
|
||||
<Button variant="primary" disabled={ !canPurchase } onClick={ () => buyOffer() }>{ LocalizeText('targeted.offer.button.buy') }</Button>
|
||||
</Flex>
|
||||
</Flex>
|
||||
<Base className="w-50" fullHeight style={ { background: `url(${ GetConfiguration('image.library.url') + offer.imageUrl }) no-repeat center` } } />
|
||||
</Flex>
|
||||
<Flex className="price-ray position-absolute" alignItems="center" justifyContent="center" column>
|
||||
<Text>{ LocalizeText('targeted.offer.price.label') }</Text>
|
||||
{ offer.priceInCredits > 0 && <Flex gap={ 1 }>
|
||||
<Text variant="light">{ offer.priceInCredits }</Text>
|
||||
<LayoutCurrencyIcon type={ -1 } />
|
||||
</Flex> }
|
||||
{ offer.priceInActivityPoints > 0 && <Flex gap={ 1 }>
|
||||
<Text className="ubuntu-bold" variant="light">+{ offer.priceInActivityPoints }</Text> <LayoutCurrencyIcon type={ offer.activityPointType }/>
|
||||
</Flex> }
|
||||
</Flex>
|
||||
</NitroCardContentView>
|
||||
</NitroCardView>;
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { FC } from 'react';
|
||||
import { Column } from '../../common';
|
||||
import { OfferView } from '../catalog/views/targeted-offer/OfferView';
|
||||
import { GroupRoomInformationView } from '../groups/views/GroupRoomInformationView';
|
||||
import { NotificationCenterView } from '../notification-center/NotificationCenterView';
|
||||
import { PurseView } from '../purse/PurseView';
|
||||
@ -12,6 +13,7 @@ export const RightSideView: FC<{}> = props =>
|
||||
<Column position="relative" gap={ 1 }>
|
||||
<PurseView />
|
||||
<GroupRoomInformationView />
|
||||
<OfferView/>
|
||||
<RoomPromotesWidgetView />
|
||||
<NotificationCenterView />
|
||||
</Column>
|
||||
|
Loading…
Reference in New Issue
Block a user