mirror of
https://github.com/duckietm/Nitro-Cool-UI.git
synced 2025-06-21 22:36:58 +00:00
🆙 Redesign HotelView
This commit is contained in:
parent
26e1b94abd
commit
e5c9759823
@ -1,106 +1,89 @@
|
|||||||
import { GetConfiguration, RoomSessionEvent } from '@nitrots/nitro-renderer';
|
import { GetConfiguration } from '@nitrots/nitro-renderer';
|
||||||
import { FC, useState } from 'react';
|
import { FC, useRef, useState } from 'react';
|
||||||
import { GetConfigurationValue } from '../../api';
|
import { GetConfigurationValue } from '../../api';
|
||||||
import { LayoutAvatarImageView } from '../../common';
|
import { RoomWidgetView } from './RoomWidgetView';
|
||||||
import { useNitroEvent, useSessionInfo } from '../../hooks';
|
|
||||||
import { WidgetSlotView } from './views/widgets/WidgetSlotView';
|
|
||||||
|
|
||||||
const widgetSlotCount = 7;
|
|
||||||
|
|
||||||
export const HotelView: FC<{}> = props =>
|
|
||||||
{
|
|
||||||
const [ isVisible, setIsVisible ] = useState(true);
|
|
||||||
const { userFigure = null } = useSessionInfo();
|
|
||||||
|
|
||||||
useNitroEvent<RoomSessionEvent>([
|
|
||||||
RoomSessionEvent.CREATED,
|
|
||||||
RoomSessionEvent.ENDED ], event =>
|
|
||||||
{
|
|
||||||
switch(event.type)
|
|
||||||
{
|
|
||||||
case RoomSessionEvent.CREATED:
|
|
||||||
setIsVisible(false);
|
|
||||||
return;
|
|
||||||
case RoomSessionEvent.ENDED:
|
|
||||||
setIsVisible(event.openLandingView);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if(!isVisible) return null;
|
|
||||||
|
|
||||||
|
export const HotelView: FC<{}> = props => {
|
||||||
const backgroundColor = GetConfigurationValue('hotelview')['images']['background.colour'];
|
const backgroundColor = GetConfigurationValue('hotelview')['images']['background.colour'];
|
||||||
const background = GetConfiguration().interpolate(GetConfigurationValue('hotelview')['images']['background']);
|
console.log('Background color:', backgroundColor);
|
||||||
const sun = GetConfiguration().interpolate(GetConfigurationValue('hotelview')['images']['sun']);
|
|
||||||
const drape = GetConfiguration().interpolate(GetConfigurationValue('hotelview')['images']['drape']);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
const left = GetConfiguration().interpolate(GetConfigurationValue('hotelview')['images']['left']);
|
const [isDragging, setIsDragging] = useState(false);
|
||||||
const rightRepeat = GetConfiguration().interpolate(GetConfigurationValue('hotelview')['images']['right.repeat']);
|
const [startX, setStartX] = useState(0);
|
||||||
const right = GetConfiguration().interpolate(GetConfigurationValue('hotelview')['images']['right']);
|
const [startY, setStartY] = useState(0);
|
||||||
|
const [scrollLeft, setScrollLeft] = useState(0);
|
||||||
|
const [scrollTop, setScrollTop] = useState(0);
|
||||||
|
|
||||||
|
const handleMouseDown = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
|
if (e.button !== 0) return; // Only left mouse button
|
||||||
|
setIsDragging(true);
|
||||||
|
setStartX(e.pageX + scrollLeft);
|
||||||
|
setStartY(e.pageY + scrollTop);
|
||||||
|
if (containerRef.current) {
|
||||||
|
containerRef.current.style.cursor = 'grabbing';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseMove = (e: React.MouseEvent<HTMLDivElement>) => {
|
||||||
|
if (!isDragging) return;
|
||||||
|
e.preventDefault();
|
||||||
|
const x = e.pageX;
|
||||||
|
const y = e.pageY;
|
||||||
|
const newScrollLeft = startX - x;
|
||||||
|
const newScrollTop = startY - y;
|
||||||
|
|
||||||
|
if (containerRef.current) {
|
||||||
|
containerRef.current.scrollLeft = newScrollLeft;
|
||||||
|
containerRef.current.scrollTop = newScrollTop;
|
||||||
|
setScrollLeft(newScrollLeft);
|
||||||
|
setScrollTop(newScrollTop);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseUp = () => {
|
||||||
|
setIsDragging(false);
|
||||||
|
if (containerRef.current) {
|
||||||
|
containerRef.current.style.cursor = 'grab';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleMouseLeave = () => {
|
||||||
|
setIsDragging(false);
|
||||||
|
if (containerRef.current) {
|
||||||
|
containerRef.current.style.cursor = 'grab';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="block fixed w-full h-[calc(100%-55px)] bg-[black] text-[#000]" style={ (backgroundColor && backgroundColor) ? { background: backgroundColor } : {} }>
|
<div
|
||||||
<div className="container h-full py-3 overflow-hidden z-10 relative">
|
ref={containerRef}
|
||||||
<div className="flex flex-wrap h-full justify-center">
|
className="nitro-hotel-view block fixed w-full h-[calc(100%-55px)] text-[#000]"
|
||||||
<div className="grid-rows-3 h-full grid w-min">
|
style={{
|
||||||
<WidgetSlotView
|
...(backgroundColor ? { background: backgroundColor } : {}),
|
||||||
className="grid grid-cols-2 gap-12 "
|
overflow: 'auto',
|
||||||
widgetConf={ GetConfigurationValue('hotelview')['widgets']['slot.' + 1 + '.conf'] }
|
WebkitOverflowScrolling: 'touch',
|
||||||
widgetSlot={ 1 }
|
maxWidth: '100vw',
|
||||||
widgetType={ GetConfigurationValue('hotelview')['widgets']['slot.' + 1 + '.widget'] }
|
maxHeight: '100vh',
|
||||||
/>
|
msOverflowStyle: 'none', // IE and Edge
|
||||||
<div className="grid grid-cols-12">
|
scrollbarWidth: 'none', // Firefox
|
||||||
<WidgetSlotView
|
'::-webkit-scrollbar': { display: 'none' }, // Chrome, Safari, and newer Edge
|
||||||
className="col-span-7"
|
cursor: 'grab' // Initial cursor state
|
||||||
widgetConf={ GetConfigurationValue('hotelview')['widgets']['slot.' + 2 + '.conf'] }
|
}}
|
||||||
widgetSlot={ 2 }
|
onMouseDown={handleMouseDown}
|
||||||
widgetType={ GetConfigurationValue('hotelview')['widgets']['slot.' + 2 + '.widget'] }
|
onMouseMove={handleMouseMove}
|
||||||
/>
|
onMouseUp={handleMouseUp}
|
||||||
<WidgetSlotView
|
onMouseLeave={handleMouseLeave}
|
||||||
className="col-span-5"
|
>
|
||||||
widgetConf={ GetConfigurationValue('hotelview')['widgets']['slot.' + 3 + '.conf'] }
|
<div
|
||||||
widgetSlot={ 3 }
|
className="hotelview position-relative"
|
||||||
widgetType={ GetConfigurationValue('hotelview')['widgets']['slot.' + 3 + '.widget'] }
|
style={{
|
||||||
/>
|
minWidth: '2600px', // 3000px width - 400px left margin
|
||||||
<WidgetSlotView
|
minHeight: '1425px' // 1185px height + 240px top margin
|
||||||
className="col-span-7"
|
}}
|
||||||
widgetConf={ GetConfigurationValue('hotelview')['widgets']['slot.' + 4 + '.conf'] }
|
>
|
||||||
widgetSlot={ 4 }
|
<div className="hotelview-background w-full h-full" style={{ position: 'absolute', top: 0, left: 0 }} />
|
||||||
widgetType={ GetConfigurationValue('hotelview')['widgets']['slot.' + 4 + '.widget'] }
|
<RoomWidgetView />
|
||||||
/>
|
|
||||||
<WidgetSlotView
|
|
||||||
className="col-span-5"
|
|
||||||
widgetConf={ GetConfigurationValue('hotelview')['widgets']['slot.' + 5 + '.conf'] }
|
|
||||||
widgetSlot={ 5 }
|
|
||||||
widgetType={ GetConfigurationValue('hotelview')['widgets']['slot.' + 5 + '.widget'] }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<WidgetSlotView
|
|
||||||
className="mt-auto"
|
|
||||||
widgetConf={ GetConfigurationValue('hotelview')['widgets']['slot.' + 6 + '.conf'] }
|
|
||||||
widgetSlot={ 6 }
|
|
||||||
widgetType={ GetConfigurationValue('hotelview')['widgets']['slot.' + 6 + '.widget'] }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-3 h-full">
|
|
||||||
<WidgetSlotView
|
|
||||||
widgetConf={ GetConfigurationValue('hotelview')['widgets']['slot.' + 7 + '.conf'] }
|
|
||||||
widgetSlot={ 7 }
|
|
||||||
widgetType={ GetConfigurationValue('hotelview')['widgets']['slot.' + 7 + '.widget'] }
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="background absolute top-[0] h-full w-full bg-left bg-repeat-y" style={ (background && background.length) ? { backgroundImage: `url(${ background })` } : {} } />
|
|
||||||
<div className="sun absolute w-full h-full top-[0] left-[0] right-[0] m-auto bg-no-repeat bg-[top_center]" style={ (sun && sun.length) ? { backgroundImage: `url(${ sun })` } : {} } />
|
|
||||||
<div className="drape absolute w-full h-full left-[0] top-[0] [animation-iteration-count:1] [animation-name:slideDown] [animation-duration:1s] bg-no-repeat" style={ (drape && drape.length) ? { backgroundImage: `url(${ drape })` } : {} } />
|
|
||||||
<div className="left absolute top-[0] right-[0] bottom-[0] left-[0] [animation-iteration-count:1] [animation-name:slideUp] [animation-duration:1s] bg-no-repeat bg-left-bottom" style={ (left && left.length) ? { backgroundImage: `url(${ left })` } : {} } />
|
|
||||||
<div className="right-repeat absolute w-full h-full right-[0] top-[0] bg-no-repeat bg-right-top" style={ (rightRepeat && rightRepeat.length) ? { backgroundImage: `url(${ rightRepeat })` } : {} } />
|
|
||||||
<div className="right absolute w-full h-full right-[0] bottom-[0] [animation-iteration-count:1] [animation-name:slideUp] [animation-duration:1s] bg-no-repeat bg-right-bottom" style={ (right && right.length) ? { backgroundImage: `url(${ right })` } : {} } />
|
|
||||||
{ GetConfigurationValue('hotelview')['show.avatar'] && (
|
|
||||||
<div>
|
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ userFigure } />
|
|
||||||
</div>
|
|
||||||
) }
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
42
src/components/hotel-view/RoomWidgetView.tsx
Normal file
42
src/components/hotel-view/RoomWidgetView.tsx
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { CreateLinkEvent } from '@nitrots/nitro-renderer';
|
||||||
|
import { FC } from 'react';
|
||||||
|
import { GetConfigurationValue } from '../../api';
|
||||||
|
import { Base } from '../../common';
|
||||||
|
|
||||||
|
export interface RoomWidgetViewProps {}
|
||||||
|
|
||||||
|
export const RoomWidgetView: FC<RoomWidgetViewProps> = props => {
|
||||||
|
const poolId = GetConfigurationValue<string>('hotelview')['room.pool'];
|
||||||
|
const picnicId = GetConfigurationValue<string>('hotelview')['room.picnic'];
|
||||||
|
const rooftopId = GetConfigurationValue<string>('hotelview')['room.rooftop'];
|
||||||
|
const rooftopPoolId = GetConfigurationValue<string>('hotelview')['room.rooftop.pool'];
|
||||||
|
const peacefulId = GetConfigurationValue<string>('hotelview')['room.peaceful'];
|
||||||
|
const infobusId = GetConfigurationValue<string>('hotelview')['room.infobus'];
|
||||||
|
const lobbyId = GetConfigurationValue<string>('hotelview')['room.lobby'];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Base className="nitro-hotel-view-rooftop position-absolute" onClick={event => CreateLinkEvent('navigator/goto/' + rooftopId)}>
|
||||||
|
<i className="arrow" />
|
||||||
|
</Base>
|
||||||
|
<Base className="nitro-hotel-view-rooftop-pool position-absolute" onClick={event => CreateLinkEvent('navigator/goto/' + rooftopPoolId)}>
|
||||||
|
<i className="arrow" />
|
||||||
|
</Base>
|
||||||
|
<Base className="nitro-hotel-view-picnic position-absolute" onClick={event => CreateLinkEvent('navigator/goto/' + picnicId)}>
|
||||||
|
<i className="arrow" />
|
||||||
|
</Base>
|
||||||
|
<Base className="nitro-hotel-view-infobus position-absolute" onClick={event => CreateLinkEvent('navigator/goto/' + infobusId)}>
|
||||||
|
<i className="arrow-infobus" />
|
||||||
|
</Base>
|
||||||
|
<Base className="nitro-hotel-view-pool position-absolute" onClick={event => CreateLinkEvent('navigator/goto/' + poolId)}>
|
||||||
|
<i className="arrow-pool" />
|
||||||
|
</Base>
|
||||||
|
<Base className="nitro-hotel-view-lobby position-absolute" onClick={event => CreateLinkEvent('navigator/goto/' + lobbyId)}>
|
||||||
|
<i className="arrow" />
|
||||||
|
</Base>
|
||||||
|
<Base className="nitro-hotel-view-peaceful position-absolute" onClick={event => CreateLinkEvent('navigator/goto/' + peacefulId)}>
|
||||||
|
<i className="arrow-peaceful" />
|
||||||
|
</Base>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
@ -1,29 +0,0 @@
|
|||||||
import { FC } from 'react';
|
|
||||||
import { BonusRareWidgetView } from './bonus-rare/BonusRareWidgetView';
|
|
||||||
import { HallOfFameWidgetView } from './hall-of-fame/HallOfFameWidgetView';
|
|
||||||
import { PromoArticleWidgetView } from './promo-article/PromoArticleWidgetView';
|
|
||||||
import { WidgetContainerView } from './widget-container/WidgetContainerView';
|
|
||||||
|
|
||||||
export interface GetWidgetLayoutProps
|
|
||||||
{
|
|
||||||
widgetType: string;
|
|
||||||
slot: number;
|
|
||||||
widgetConf: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const GetWidgetLayout: FC<GetWidgetLayoutProps> = props =>
|
|
||||||
{
|
|
||||||
switch(props.widgetType)
|
|
||||||
{
|
|
||||||
case 'promoarticle':
|
|
||||||
return <PromoArticleWidgetView />;
|
|
||||||
case 'achievementcompetition_hall_of_fame':
|
|
||||||
return <HallOfFameWidgetView conf={ props.widgetConf } slot={ props.slot } />;
|
|
||||||
case 'bonusrare':
|
|
||||||
return <BonusRareWidgetView />;
|
|
||||||
case 'widgetcontainer':
|
|
||||||
return <WidgetContainerView conf={ props.widgetConf } />;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,20 +0,0 @@
|
|||||||
import { DetailsHTMLAttributes, FC } from 'react';
|
|
||||||
import { GetWidgetLayout } from './GetWidgetLayout';
|
|
||||||
|
|
||||||
export interface WidgetSlotViewProps extends DetailsHTMLAttributes<HTMLDivElement>
|
|
||||||
{
|
|
||||||
widgetType: string;
|
|
||||||
widgetSlot: number;
|
|
||||||
widgetConf: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WidgetSlotView: FC<WidgetSlotViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { widgetType = null, widgetSlot = 0, widgetConf = null, className= '', ...rest } = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={ `widget-slot slot-${ widgetSlot } ${ (className || '') }` } { ...rest }>
|
|
||||||
<GetWidgetLayout slot={ widgetSlot } widgetConf={ widgetConf } widgetType={ widgetType } />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,42 +0,0 @@
|
|||||||
import { BonusRareInfoMessageEvent, GetBonusRareInfoMessageComposer } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useEffect, useState } from 'react';
|
|
||||||
import { SendMessageComposer } from '../../../../../api';
|
|
||||||
import { useMessageEvent } from '../../../../../hooks';
|
|
||||||
|
|
||||||
export interface BonusRareWidgetViewProps
|
|
||||||
{ }
|
|
||||||
|
|
||||||
export const BonusRareWidgetView: FC<BonusRareWidgetViewProps> = props =>
|
|
||||||
{
|
|
||||||
const [ productType, setProductType ] = useState<string>(null);
|
|
||||||
const [ productClassId, setProductClassId ] = useState<number>(null);
|
|
||||||
const [ totalCoinsForBonus, setTotalCoinsForBonus ] = useState<number>(null);
|
|
||||||
const [ coinsStillRequiredToBuy, setCoinsStillRequiredToBuy ] = useState<number>(null);
|
|
||||||
|
|
||||||
useMessageEvent<BonusRareInfoMessageEvent>(BonusRareInfoMessageEvent, event =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setProductType(parser.productType);
|
|
||||||
setProductClassId(parser.productClassId);
|
|
||||||
setTotalCoinsForBonus(parser.totalCoinsForBonus);
|
|
||||||
setCoinsStillRequiredToBuy(parser.coinsStillRequiredToBuy);
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
SendMessageComposer(new GetBonusRareInfoMessageComposer());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if(!productType) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="bonus-rare widget flex">
|
|
||||||
{ productType }
|
|
||||||
<div className="bg-light-dark rounded overflow-hidden relative bonus-bar-container">
|
|
||||||
<div className="flex justify-center items-center size-full absolute small top-0">{ (totalCoinsForBonus - coinsStillRequiredToBuy) + '/' + totalCoinsForBonus }</div>
|
|
||||||
<div className="small bg-info rounded absolute top-0 h-full" style={ { width: ((totalCoinsForBonus - coinsStillRequiredToBuy) / totalCoinsForBonus) * 100 + '%' } }></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,30 +0,0 @@
|
|||||||
import { HallOfFameEntryData } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC } from 'react';
|
|
||||||
import { LocalizeFormattedNumber, LocalizeText } from '../../../../../api';
|
|
||||||
import { LayoutAvatarImageView, UserProfileIconView } from '../../../../../common';
|
|
||||||
|
|
||||||
export interface HallOfFameItemViewProps
|
|
||||||
{
|
|
||||||
data: HallOfFameEntryData;
|
|
||||||
level: number;
|
|
||||||
active?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const HallOfFameItemView: FC<HallOfFameItemViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { data = null, level = 0, active = false } = props;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="group h-full relative">
|
|
||||||
<div className="invisible group-hover:visible absolute w-[125px] max-w-[125px] p-[2px] bg-[#1c323f] border-[2px] border-[solid] border-[rgba(255,255,255,.5)] rounded-[.25rem] z-40 -left-[15px] bottom-[calc(100%-10px)]">
|
|
||||||
<div className="flex items-center justify-center gap-[5px] bg-[#3d5f6e] text-[#fff] min-w-[117px] h-[25px] max-h-[25px] text-[16px] mb-[2px]">
|
|
||||||
{ level }. { data.userName } <UserProfileIconView userId={ data.userId } />
|
|
||||||
</div>
|
|
||||||
<div className="small text-center text-white">{ LocalizeText('landing.view.competition.hof.points', [ 'points' ], [ LocalizeFormattedNumber(data.currentScore).toString() ]) }</div>
|
|
||||||
</div>
|
|
||||||
<LayoutAvatarImageView direction={ 2 } figure={ data.figure } />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,37 +0,0 @@
|
|||||||
import { CommunityGoalHallOfFameData, CommunityGoalHallOfFameMessageEvent, GetCommunityGoalHallOfFameMessageComposer } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useEffect, useState } from 'react';
|
|
||||||
import { SendMessageComposer } from '../../../../../api';
|
|
||||||
import { useMessageEvent } from '../../../../../hooks';
|
|
||||||
import { HallOfFameItemView } from '../hall-of-fame-item/HallOfFameItemView';
|
|
||||||
import { HallOfFameWidgetViewProps } from './HallOfFameWidgetView.types';
|
|
||||||
|
|
||||||
export const HallOfFameWidgetView: FC<HallOfFameWidgetViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { slot = -1, conf = null } = props;
|
|
||||||
const [ data, setData ] = useState<CommunityGoalHallOfFameData>(null);
|
|
||||||
|
|
||||||
useMessageEvent<CommunityGoalHallOfFameMessageEvent>(CommunityGoalHallOfFameMessageEvent, event =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
|
|
||||||
setData(parser.data);
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
const campaign: string = conf ? conf['campaign'] : '';
|
|
||||||
SendMessageComposer(new GetCommunityGoalHallOfFameMessageComposer(campaign));
|
|
||||||
}, [ conf ]);
|
|
||||||
|
|
||||||
if(!data) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="bg-[#0000004d] rounded-[.25rem] justify-center flex">
|
|
||||||
{ data.hof && (data.hof.length > 0) && data.hof.map((entry, index) =>
|
|
||||||
{
|
|
||||||
return <HallOfFameItemView key={ index } data={ entry } level={ (index + 1) } />;
|
|
||||||
}
|
|
||||||
) }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,5 +0,0 @@
|
|||||||
export interface HallOfFameWidgetViewProps
|
|
||||||
{
|
|
||||||
slot: number;
|
|
||||||
conf: string;
|
|
||||||
}
|
|
@ -1,46 +0,0 @@
|
|||||||
import { GetPromoArticlesComposer, PromoArticleData, PromoArticlesMessageEvent } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC, useEffect, useState } from 'react';
|
|
||||||
import { LocalizeText, OpenUrl, SendMessageComposer } from '../../../../../api';
|
|
||||||
import { useMessageEvent } from '../../../../../hooks';
|
|
||||||
|
|
||||||
export const PromoArticleWidgetView: FC<{}> = props =>
|
|
||||||
{
|
|
||||||
const [ articles, setArticles ] = useState<PromoArticleData[]>(null);
|
|
||||||
const [ index, setIndex ] = useState(0);
|
|
||||||
|
|
||||||
useMessageEvent<PromoArticlesMessageEvent>(PromoArticlesMessageEvent, event =>
|
|
||||||
{
|
|
||||||
const parser = event.getParser();
|
|
||||||
setArticles(parser.articles);
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() =>
|
|
||||||
{
|
|
||||||
SendMessageComposer(new GetPromoArticlesComposer());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if(!articles) return null;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="promo-articles widget mb-2">
|
|
||||||
<div className="flex flex-row items-center w-full mb-1">
|
|
||||||
<small className="flex-shrink-0 pe-1">{ LocalizeText('landing.view.promo.article.header') }</small>
|
|
||||||
<hr className="w-full my-0" />
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row mb-1">
|
|
||||||
{ articles && (articles.length > 0) && articles.map((article, ind) =>
|
|
||||||
<div key={ article.id } className={ 'rounded-[50%] border-[1px] border-[solid] border-[#fff] h-[13px] w-[13px] mr-[3px] cursor-pointer ' + (article === articles[index] ? 'bg-[black]' : ' bg-[white] ') } onClick={ event => setIndex(ind) } />
|
|
||||||
) }
|
|
||||||
</div>
|
|
||||||
{ articles && articles[index] &&
|
|
||||||
<div className="grid-cols-2 grid">
|
|
||||||
<div className="promo-article-image w-[150px] h-[150px] mr-[10px] bg-no-repeat bg-[top_center] flex-shrink-0 w-full max-w-full" style={ { backgroundImage: `url(${ articles[index].imageUrl })` } } />
|
|
||||||
<div className="col-span-1 flex flex-col h-full">
|
|
||||||
<h3 className="my-0">{ articles[index].title }</h3>
|
|
||||||
<b>{ articles[index].bodyText }</b>
|
|
||||||
<button className="w-1/2 mt-auto px-[.5rem] py-[.25rem] rounded-[.2rem] text-[#000] bg-[#d9d9d9] border-[#d9d9d9] [box-shadow:inset_0_2px_#ffffff26,_inset_0_-2px_#0000001a,_0_1px_#0000001a]" onClick={ event => OpenUrl(articles[index].linkContent) }>{ articles[index].buttonText }</button>
|
|
||||||
</div>
|
|
||||||
</div> }
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
@ -1,39 +0,0 @@
|
|||||||
import { GetConfiguration } from '@nitrots/nitro-renderer';
|
|
||||||
import { FC } from 'react';
|
|
||||||
import { LocalizeText, OpenUrl } from '../../../../../api';
|
|
||||||
|
|
||||||
export interface WidgetContainerViewProps
|
|
||||||
{
|
|
||||||
conf: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const WidgetContainerView: FC<WidgetContainerViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { conf = null } = props;
|
|
||||||
|
|
||||||
const getOption = (key: string) =>
|
|
||||||
{
|
|
||||||
const option = conf[key];
|
|
||||||
|
|
||||||
if(!option) return null;
|
|
||||||
|
|
||||||
switch(key)
|
|
||||||
{
|
|
||||||
case 'image':
|
|
||||||
return GetConfiguration().interpolate(option);
|
|
||||||
}
|
|
||||||
|
|
||||||
return option;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="widgetcontainer widget flex flex-row overflow-hidden">
|
|
||||||
<div className="widgetcontainer-image flex-shrink-0" style={ { backgroundImage: `url(${ getOption('image') })` } } />
|
|
||||||
<div className="flex flex-col align-self-center">
|
|
||||||
<h3 className="my-0">{ LocalizeText(`landing.view.${ getOption('texts') }.header`) }</h3>
|
|
||||||
<i>{ LocalizeText(`landing.view.${ getOption('texts') }.body`) }</i>
|
|
||||||
<button className="px-[.5rem] py-[.25rem] rounded-[.2rem] align-self-start px-3 mt-auto text-[#000] bg-[#d9d9d9] border-[#d9d9d9] [box-shadow:inset_0_2px_#ffffff26,_inset_0_-2px_#0000001a,_0_1px_#0000001a]" onClick={ event => OpenUrl(getOption('btnLink')) }>{ LocalizeText(`landing.view.${ getOption('texts') }.button`) }</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
Loading…
x
Reference in New Issue
Block a user