mirror of
https://github.com/billsonnn/nitro-react.git
synced 2025-01-18 21:36:27 +01:00
Update calendar
This commit is contained in:
parent
dee2b25d8e
commit
722aaa5bbd
@ -86,6 +86,9 @@ $nitro-guide-tool-width: 250px;
|
|||||||
$nitro-floor-editor-width: 760px;
|
$nitro-floor-editor-width: 760px;
|
||||||
$nitro-floor-editor-height: 500px;
|
$nitro-floor-editor-height: 500px;
|
||||||
|
|
||||||
|
$nitro-calendar-width: 850px;
|
||||||
|
$nitro-calendar-height: 400px;
|
||||||
|
|
||||||
.nitro-app {
|
.nitro-app {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
BIN
src/assets/images/campaign/campaign_spritesheet.png
Normal file
BIN
src/assets/images/campaign/campaign_spritesheet.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 82 KiB |
@ -6,12 +6,13 @@ import { ColumnSizesType } from './types';
|
|||||||
export interface ColumnProps extends FlexProps
|
export interface ColumnProps extends FlexProps
|
||||||
{
|
{
|
||||||
size?: ColumnSizesType;
|
size?: ColumnSizesType;
|
||||||
|
offset?: ColumnSizesType;
|
||||||
column?: boolean;
|
column?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Column: FC<ColumnProps> = props =>
|
export const Column: FC<ColumnProps> = props =>
|
||||||
{
|
{
|
||||||
const { size = 0, column = true, gap = 2, classNames = [], ...rest } = props;
|
const { size = 0, offset = 0, column = true, gap = 2, classNames = [], ...rest } = props;
|
||||||
const { isCssGrid = false } = useGridContext();
|
const { isCssGrid = false } = useGridContext();
|
||||||
|
|
||||||
const getClassNames = useMemo(() =>
|
const getClassNames = useMemo(() =>
|
||||||
@ -27,10 +28,19 @@ export const Column: FC<ColumnProps> = props =>
|
|||||||
newClassNames.push(colClassName);
|
newClassNames.push(colClassName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(offset)
|
||||||
|
{
|
||||||
|
let colClassName = `offset-${ offset }`;
|
||||||
|
|
||||||
|
if(isCssGrid) colClassName = `g-start-${ offset }`;
|
||||||
|
|
||||||
|
newClassNames.push(colClassName);
|
||||||
|
}
|
||||||
|
|
||||||
if(classNames.length) newClassNames.push(...classNames);
|
if(classNames.length) newClassNames.push(...classNames);
|
||||||
|
|
||||||
return newClassNames;
|
return newClassNames;
|
||||||
}, [ size, isCssGrid, classNames ]);
|
}, [ size, offset, isCssGrid, classNames ]);
|
||||||
|
|
||||||
return <Flex classNames={ getClassNames } column={ column } gap={ gap } { ...rest } />;
|
return <Flex classNames={ getClassNames } column={ column } gap={ gap } { ...rest } />;
|
||||||
}
|
}
|
||||||
|
53
src/views/campaign/CalendarItemView.tsx
Normal file
53
src/views/campaign/CalendarItemView.tsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { FC } from 'react';
|
||||||
|
import { GetRoomEngine, GetSessionDataManager } from '../../api';
|
||||||
|
import { Base, Column, Flex, LayoutImage } from '../../common';
|
||||||
|
import { CalendarItemState } from './common/CalendarItemState';
|
||||||
|
|
||||||
|
interface CalendarItemViewProps
|
||||||
|
{
|
||||||
|
itemId: number;
|
||||||
|
state: number;
|
||||||
|
active?: boolean;
|
||||||
|
productName?: string;
|
||||||
|
onClick: (itemId: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CalendarItemView: FC<CalendarItemViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { itemId = -1, state = null, productName = null, active = false, onClick = null } = props;
|
||||||
|
|
||||||
|
const getFurnitureIcon = (name: string) =>
|
||||||
|
{
|
||||||
|
let furniData = GetSessionDataManager().getFloorItemDataByName(name);
|
||||||
|
let url = null;
|
||||||
|
|
||||||
|
if(furniData) url = GetRoomEngine().getFurnitureFloorIconUrl(furniData.id);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
furniData = GetSessionDataManager().getWallItemDataByName(name);
|
||||||
|
|
||||||
|
if(furniData) url = GetRoomEngine().getFurnitureWallIconUrl(furniData.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column fit center pointer className={`campaign-spritesheet campaign-day-generic-bg rounded calendar-item ${ active ? 'active' : '' }`} onClick={ () => onClick(itemId) }>
|
||||||
|
{ (state === CalendarItemState.STATE_UNLOCKED) &&
|
||||||
|
<Flex center className="campaign-spritesheet unlocked-bg">
|
||||||
|
<Flex center className="campaign-spritesheet campaign-opened">
|
||||||
|
{ productName &&
|
||||||
|
<LayoutImage imageUrl={ getFurnitureIcon(productName) } /> }
|
||||||
|
</Flex>
|
||||||
|
</Flex> }
|
||||||
|
{ (state !== CalendarItemState.STATE_UNLOCKED) &&
|
||||||
|
<Flex center className="campaign-spritesheet locked-bg">
|
||||||
|
{ (state === CalendarItemState.STATE_LOCKED_AVAILABLE) &&
|
||||||
|
<Base className="campaign-spritesheet available" /> }
|
||||||
|
{ ((state === CalendarItemState.STATE_LOCKED_EXPIRED) || (state === CalendarItemState.STATE_LOCKED_FUTURE)) &&
|
||||||
|
<Base className="campaign-spritesheet unavailable" /> }
|
||||||
|
</Flex> }
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
144
src/views/campaign/CalendarView.tsx
Normal file
144
src/views/campaign/CalendarView.tsx
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
import { FC, useState } from 'react';
|
||||||
|
import { GetSessionDataManager, LocalizeText } from '../../api';
|
||||||
|
import { Base, Button, Column, Flex, Grid, NitroCardContentView, NitroCardHeaderView, NitroCardView, Text } from '../../common';
|
||||||
|
import { CalendarItemView } from './CalendarItemView';
|
||||||
|
import { CalendarItemState } from './common/CalendarItemState';
|
||||||
|
|
||||||
|
interface CalendarViewProps
|
||||||
|
{
|
||||||
|
close(): void;
|
||||||
|
openPackage(id: number, asStaff: boolean): void;
|
||||||
|
receivedProducts: Map<number, string>;
|
||||||
|
campaignName: string;
|
||||||
|
currentDay: number;
|
||||||
|
numDays: number;
|
||||||
|
openedDays: number[];
|
||||||
|
missedDays: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
const TOTAL_SHOWN_ITEMS = 5;
|
||||||
|
|
||||||
|
export const CalendarView: FC<CalendarViewProps> = props =>
|
||||||
|
{
|
||||||
|
const { close = null, campaignName = null, currentDay = null, numDays = null, missedDays = null, openedDays = null, openPackage = null, receivedProducts = null } = props;
|
||||||
|
const [ selectedDay, setSelectedDay ] = useState(currentDay);
|
||||||
|
const [ index, setIndex ] = useState(Math.max(0, (selectedDay - 1)));
|
||||||
|
|
||||||
|
const getDayState = (day: number) =>
|
||||||
|
{
|
||||||
|
if(openedDays.includes(day)) return CalendarItemState.STATE_UNLOCKED;
|
||||||
|
|
||||||
|
if(day > currentDay) return CalendarItemState.STATE_LOCKED_FUTURE;
|
||||||
|
|
||||||
|
if(missedDays.includes(day)) return CalendarItemState.STATE_LOCKED_EXPIRED;
|
||||||
|
|
||||||
|
return CalendarItemState.STATE_LOCKED_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dayMessage = (day: number) =>
|
||||||
|
{
|
||||||
|
const state = getDayState(day);
|
||||||
|
|
||||||
|
switch(state)
|
||||||
|
{
|
||||||
|
case CalendarItemState.STATE_UNLOCKED:
|
||||||
|
return LocalizeText('campaign.calendar.info.unlocked');
|
||||||
|
case CalendarItemState.STATE_LOCKED_FUTURE:
|
||||||
|
return LocalizeText('campaign.calendar.info.future');
|
||||||
|
case CalendarItemState.STATE_LOCKED_EXPIRED:
|
||||||
|
return LocalizeText('campaign.calendar.info.expired');
|
||||||
|
default:
|
||||||
|
return LocalizeText('campaign.calendar.info.available.desktop');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClickNext = () =>
|
||||||
|
{
|
||||||
|
const nextDay = (selectedDay + 1);
|
||||||
|
|
||||||
|
if(nextDay === numDays) return;
|
||||||
|
|
||||||
|
setSelectedDay(nextDay);
|
||||||
|
|
||||||
|
if((index + TOTAL_SHOWN_ITEMS) < (nextDay + 1)) setIndex(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClickPrev = () =>
|
||||||
|
{
|
||||||
|
const prevDay = (selectedDay - 1);
|
||||||
|
|
||||||
|
if(prevDay < 0) return;
|
||||||
|
|
||||||
|
setSelectedDay(prevDay);
|
||||||
|
|
||||||
|
if(index > prevDay) setIndex(index - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const onClickItem = (item: number) =>
|
||||||
|
{
|
||||||
|
if(selectedDay === item)
|
||||||
|
{
|
||||||
|
const state = getDayState(item);
|
||||||
|
|
||||||
|
if(state === CalendarItemState.STATE_LOCKED_AVAILABLE) openPackage(item, false);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectedDay(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
const forceOpen = () =>
|
||||||
|
{
|
||||||
|
const id = selectedDay;
|
||||||
|
const state = getDayState(id);
|
||||||
|
|
||||||
|
if(state !== CalendarItemState.STATE_UNLOCKED) openPackage(id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<NitroCardView className="nitro-campaign-calendar" theme="primary-slim">
|
||||||
|
<NitroCardHeaderView headerText={ LocalizeText(`campaign.calendar.${ campaignName }.title`) } onCloseClick={ close } />
|
||||||
|
<NitroCardContentView>
|
||||||
|
<Grid fullHeight={ false } justifyContent="between" alignItems="center">
|
||||||
|
<Column size={ 1 } />
|
||||||
|
<Column size={ 10 }>
|
||||||
|
<Flex justifyContent="between" alignItems="center" gap={ 1 }>
|
||||||
|
<Column gap={ 1 }>
|
||||||
|
<Text fontSize={ 3 }>{ LocalizeText('campaign.calendar.heading.day', ['number'], [(selectedDay + 1).toString()]) }</Text>
|
||||||
|
<Text>{ dayMessage(selectedDay) }</Text>
|
||||||
|
</Column>
|
||||||
|
<div>
|
||||||
|
{ GetSessionDataManager().isModerator &&
|
||||||
|
<Button variant="danger" onClick={ forceOpen }>Force open</Button> }
|
||||||
|
</div>
|
||||||
|
</Flex>
|
||||||
|
</Column>
|
||||||
|
<Column size={ 1 } />
|
||||||
|
</Grid>
|
||||||
|
<Grid fullHeight alignItems="center" gap={ 1 }>
|
||||||
|
<Column fullHeight center size={ 1 }>
|
||||||
|
<Base pointer className="campaign-spritesheet prev" onClick={ onClickPrev } />
|
||||||
|
</Column>
|
||||||
|
<Column fullHeight size={ 10 }>
|
||||||
|
<Grid fullHeight columnCount={ TOTAL_SHOWN_ITEMS } gap={ 1 }>
|
||||||
|
{ [...Array(TOTAL_SHOWN_ITEMS)].map((e, i) =>
|
||||||
|
{
|
||||||
|
const day = (index + i);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column key={ i } overflow="hidden">
|
||||||
|
<CalendarItemView itemId={ day } state={ getDayState(day) } active={ (selectedDay === day) } productName={ receivedProducts.has(day) ? receivedProducts.get(day) : null } onClick={ onClickItem } />
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}) }
|
||||||
|
</Grid>
|
||||||
|
</Column>
|
||||||
|
<Column fullHeight center size={ 1 }>
|
||||||
|
<Base pointer className="campaign-spritesheet next" onClick={ onClickNext } />
|
||||||
|
</Column>
|
||||||
|
</Grid>
|
||||||
|
</NitroCardContentView>
|
||||||
|
</NitroCardView>
|
||||||
|
)
|
||||||
|
}
|
@ -1 +1,71 @@
|
|||||||
@import './views/calendar/CalendarView';
|
.nitro-campaign-calendar {
|
||||||
|
width: $nitro-calendar-width;
|
||||||
|
height: $nitro-calendar-height;
|
||||||
|
|
||||||
|
.calendar-item {
|
||||||
|
filter: brightness(80%);
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
filter: brightness(100%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.campaign-spritesheet {
|
||||||
|
display: block;
|
||||||
|
background: transparent url("../../assets/images/campaign/campaign_spritesheet.png") no-repeat;
|
||||||
|
|
||||||
|
&.available {
|
||||||
|
width: 69px;
|
||||||
|
height: 78px;
|
||||||
|
background-position: -5px -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.campaign-day-generic-bg {
|
||||||
|
max-width: 202px;
|
||||||
|
height: 447px;
|
||||||
|
background-position: -84px -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.campaign-opened {
|
||||||
|
width: 96px;
|
||||||
|
height: 66px;
|
||||||
|
background-position: -296px -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.locked {
|
||||||
|
width: 42px;
|
||||||
|
height: 42px;
|
||||||
|
background-position: -296px -81px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.locked-bg {
|
||||||
|
width: 132px;
|
||||||
|
height: 132px;
|
||||||
|
background-position: -402px -5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.next {
|
||||||
|
width: 33px;
|
||||||
|
height: 34px;
|
||||||
|
background-position: -5px -147px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.prev {
|
||||||
|
width: 33px;
|
||||||
|
height: 34px;
|
||||||
|
background-position: -296px -147px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unavailable {
|
||||||
|
width: 68px;
|
||||||
|
height: 78px;
|
||||||
|
background-position: -339px -147px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.unlocked-bg {
|
||||||
|
width: 190px;
|
||||||
|
height: 189px;
|
||||||
|
background-position: -296px -235px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@ import { CampaignCalendarData, CampaignCalendarDataMessageEvent, CampaignCalenda
|
|||||||
import { FC, useCallback, useEffect, useState } from 'react';
|
import { FC, useCallback, useEffect, useState } from 'react';
|
||||||
import { AddEventLinkTracker, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
|
import { AddEventLinkTracker, RemoveLinkEventTracker, SendMessageComposer } from '../../api';
|
||||||
import { BatchUpdates, UseMessageEventHook } from '../../hooks';
|
import { BatchUpdates, UseMessageEventHook } from '../../hooks';
|
||||||
import { CalendarView } from './views/calendar/CalendarView';
|
import { CalendarView } from './CalendarView';
|
||||||
|
|
||||||
export const CampaignView: FC<{}> = props =>
|
export const CampaignView: FC<{}> = props =>
|
||||||
{
|
{
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
export const getNumItemsDisplayed = (): number =>
|
|
||||||
{
|
|
||||||
return Math.min(Math.max(2, Math.floor(window.screen.width / 135) - 3), 7);
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
import { FC, useCallback } from 'react';
|
|
||||||
import { GetRoomEngine, GetSessionDataManager } from '../../../../api';
|
|
||||||
import { Column } from '../../../../common';
|
|
||||||
import { CalendarItemState } from '../../common/CalendarItemState';
|
|
||||||
|
|
||||||
interface CalendarItemViewProps
|
|
||||||
{
|
|
||||||
id: number;
|
|
||||||
productName?: string;
|
|
||||||
state: number;
|
|
||||||
active?: boolean;
|
|
||||||
onClick(itemId: number): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CalendarItemView: FC<CalendarItemViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { state = null, productName = null, active = false, onClick = null, id = null } = props;
|
|
||||||
|
|
||||||
const getFurnitureIcon = useCallback((name: string) =>
|
|
||||||
{
|
|
||||||
|
|
||||||
let furniData = GetSessionDataManager().getFloorItemDataByName(name);
|
|
||||||
let url = null;
|
|
||||||
if(furniData) url = GetRoomEngine().getFurnitureFloorIconUrl(furniData.id);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
furniData = GetSessionDataManager().getWallItemDataByName(name);
|
|
||||||
if(furniData) url = GetRoomEngine().getFurnitureWallIconUrl(furniData.id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return url;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Column className={`calendar-item h-100 w-100 cursor-pointer align-items-center justify-content-center ${active ? 'active' : ''}`} onClick={() => onClick(id)}>
|
|
||||||
{ (state === CalendarItemState.STATE_UNLOCKED) &&
|
|
||||||
<div className="unlocked-generic-bg d-flex justify-content-center align-items-center">
|
|
||||||
<div className="opened d-flex justify-content-center align-items-center">
|
|
||||||
{ productName &&
|
|
||||||
<img className="furni-icon" src={getFurnitureIcon(productName)} alt='' />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
|
|
||||||
{ (state !== CalendarItemState.STATE_UNLOCKED) &&
|
|
||||||
<div className="locked-generic-bg d-flex justify-content-center align-items-center">
|
|
||||||
{ (state === CalendarItemState.STATE_LOCKED_AVAILABLE) &&
|
|
||||||
<div className="available"/>
|
|
||||||
}
|
|
||||||
{ (state === CalendarItemState.STATE_LOCKED_EXPIRED || state === CalendarItemState.STATE_LOCKED_FUTURE) &&
|
|
||||||
<div className="unavailable" />
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
</Column>
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,68 +0,0 @@
|
|||||||
.nitro-campaign-calendar {
|
|
||||||
width: 1055px;
|
|
||||||
height: 400px;
|
|
||||||
|
|
||||||
.calendar-item {
|
|
||||||
background: url("../../../../assets/images/campaign/campaign_day_generic_bg.png");
|
|
||||||
max-height: 100%;
|
|
||||||
min-width: 135px;
|
|
||||||
filter: brightness(80%);
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
filter: brightness(100%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.unlocked-generic-bg {
|
|
||||||
background: url("../../../../assets/images/campaign/unlocked_bg.png");
|
|
||||||
background-size: 132px 132px;
|
|
||||||
width: 132px;
|
|
||||||
height: 132px;
|
|
||||||
|
|
||||||
//width: 190px;
|
|
||||||
//height: 189px;
|
|
||||||
|
|
||||||
.opened {
|
|
||||||
background: url("../../../../assets/images/campaign/campaign_opened.png");
|
|
||||||
width: 96px;
|
|
||||||
height: 66px;
|
|
||||||
|
|
||||||
.furni-icon
|
|
||||||
{
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.locked-generic-bg {
|
|
||||||
background: url("../../../../assets/images/campaign/locked_bg.png");
|
|
||||||
width: 132px;
|
|
||||||
height: 132px;
|
|
||||||
|
|
||||||
.available {
|
|
||||||
background: url("../../../../assets/images/campaign/available.png");
|
|
||||||
width: 69px;
|
|
||||||
height: 78px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unavailable {
|
|
||||||
background: url("../../../../assets/images/campaign/unavailable.png");
|
|
||||||
width: 68px;
|
|
||||||
height: 78px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-prev {
|
|
||||||
background: url("../../../../assets/images/campaign/prev.png");
|
|
||||||
width: 33px;
|
|
||||||
min-width: 33px;
|
|
||||||
height: 34px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.calendar-next {
|
|
||||||
background: url("../../../../assets/images/campaign/next.png");
|
|
||||||
width: 33px;
|
|
||||||
min-width: 33px;
|
|
||||||
height: 34px;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,145 +0,0 @@
|
|||||||
import { FC, useCallback, useState } from 'react';
|
|
||||||
import { GetSessionDataManager, LocalizeText } from '../../../../api';
|
|
||||||
import { Flex, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../common';
|
|
||||||
import { CalendarItemState } from '../../common/CalendarItemState';
|
|
||||||
import { getNumItemsDisplayed } from '../../common/Utils';
|
|
||||||
import { CalendarItemView } from '../calendar-item/CalendarItemView';
|
|
||||||
|
|
||||||
interface CalendarViewProps
|
|
||||||
{
|
|
||||||
close(): void;
|
|
||||||
openPackage(id: number, asStaff: boolean): void;
|
|
||||||
receivedProducts: Map<number, string>;
|
|
||||||
campaignName: string;
|
|
||||||
currentDay: number;
|
|
||||||
numDays: number;
|
|
||||||
openedDays: number[];
|
|
||||||
missedDays: number[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export const CalendarView: FC<CalendarViewProps> = props =>
|
|
||||||
{
|
|
||||||
const { close = null, campaignName = null, currentDay = null, numDays = null, missedDays = null, openedDays = null, openPackage = null, receivedProducts = null } = props;
|
|
||||||
const [selectedDay, setSelectedDay] = useState(currentDay);
|
|
||||||
const [index, setIndex] = useState(Math.max(0, selectedDay - 1));
|
|
||||||
|
|
||||||
const getDayState = useCallback((day: number) =>
|
|
||||||
{
|
|
||||||
if(openedDays.includes(day))
|
|
||||||
{
|
|
||||||
return CalendarItemState.STATE_UNLOCKED;
|
|
||||||
}
|
|
||||||
if(day > currentDay)
|
|
||||||
{
|
|
||||||
return CalendarItemState.STATE_LOCKED_FUTURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(missedDays.includes(day))
|
|
||||||
{
|
|
||||||
return CalendarItemState.STATE_LOCKED_EXPIRED;
|
|
||||||
}
|
|
||||||
|
|
||||||
return CalendarItemState.STATE_LOCKED_AVAILABLE;
|
|
||||||
}, [currentDay, missedDays, openedDays]);
|
|
||||||
|
|
||||||
const dayMessage = useCallback((day: number) =>
|
|
||||||
{
|
|
||||||
const state = getDayState(day);
|
|
||||||
|
|
||||||
switch(state)
|
|
||||||
{
|
|
||||||
case CalendarItemState.STATE_UNLOCKED:
|
|
||||||
return LocalizeText('campaign.calendar.info.unlocked');
|
|
||||||
case CalendarItemState.STATE_LOCKED_FUTURE:
|
|
||||||
return LocalizeText('campaign.calendar.info.future');
|
|
||||||
case CalendarItemState.STATE_LOCKED_EXPIRED:
|
|
||||||
return LocalizeText('campaign.calendar.info.expired');
|
|
||||||
default: return LocalizeText('campaign.calendar.info.available.desktop');
|
|
||||||
}
|
|
||||||
}, [getDayState]);
|
|
||||||
|
|
||||||
const onClickNext = useCallback(() =>
|
|
||||||
{
|
|
||||||
const nextDay = selectedDay + 1;
|
|
||||||
|
|
||||||
if((nextDay) === numDays) return;
|
|
||||||
|
|
||||||
setSelectedDay(nextDay);
|
|
||||||
|
|
||||||
if((index + getNumItemsDisplayed()) < nextDay + 1)
|
|
||||||
{
|
|
||||||
setIndex(index + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
}, [index, numDays, selectedDay]);
|
|
||||||
|
|
||||||
const onClickPrev = useCallback(() =>
|
|
||||||
{
|
|
||||||
const prevDay = selectedDay - 1;
|
|
||||||
|
|
||||||
if((prevDay < 0)) return;
|
|
||||||
|
|
||||||
setSelectedDay(prevDay);
|
|
||||||
|
|
||||||
if(index > prevDay)
|
|
||||||
{
|
|
||||||
setIndex(index - 1);
|
|
||||||
}
|
|
||||||
}, [index, selectedDay]);
|
|
||||||
|
|
||||||
const onClickItem = useCallback((item: number) =>
|
|
||||||
{
|
|
||||||
if(selectedDay === item)
|
|
||||||
{
|
|
||||||
//handle opening
|
|
||||||
const state = getDayState(item);
|
|
||||||
if(state === CalendarItemState.STATE_LOCKED_AVAILABLE) openPackage(item, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
setSelectedDay(item);
|
|
||||||
}
|
|
||||||
}, [getDayState, openPackage, selectedDay]);
|
|
||||||
|
|
||||||
const forceOpen = useCallback(() =>
|
|
||||||
{
|
|
||||||
const id = selectedDay;
|
|
||||||
const state = getDayState(id);
|
|
||||||
if(GetSessionDataManager().isModerator && state !== CalendarItemState.STATE_UNLOCKED)
|
|
||||||
{
|
|
||||||
openPackage(id, true);
|
|
||||||
}
|
|
||||||
}, [getDayState, openPackage, selectedDay]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<NitroCardView className="nitro-campaign-calendar">
|
|
||||||
<NitroCardHeaderView headerText={LocalizeText(`campaign.calendar.${campaignName}.title`)} onCloseClick={close} />
|
|
||||||
<NitroCardContentView>
|
|
||||||
<div className="d-flex justify-content-between mx-5">
|
|
||||||
<div className="text-black">
|
|
||||||
<h3>{LocalizeText('campaign.calendar.heading.day', ['number'], [(selectedDay + 1).toString()])}</h3>
|
|
||||||
<p>{dayMessage(selectedDay)}</p>
|
|
||||||
</div>
|
|
||||||
{GetSessionDataManager().isModerator &&
|
|
||||||
<button className="btn btn-sm btn-danger my-4" onClick={forceOpen}>Force open</button>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
<div className="button-container">
|
|
||||||
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<Flex className="h-100 align-items-center" gap={1}>
|
|
||||||
<div className="calendar-prev cursor-pointer" onClick={onClickPrev} />
|
|
||||||
{
|
|
||||||
[...Array(getNumItemsDisplayed())].map((e, i) =>
|
|
||||||
{
|
|
||||||
const day = index + i;
|
|
||||||
return <CalendarItemView key={i} state={getDayState(day)} active={selectedDay === day} onClick={onClickItem} id={day} productName={receivedProducts.has(day) ? receivedProducts.get(day) : null} />
|
|
||||||
})
|
|
||||||
}
|
|
||||||
<div className="calendar-next cursor-pointer" onClick={onClickNext} />
|
|
||||||
</Flex>
|
|
||||||
</NitroCardContentView>
|
|
||||||
</NitroCardView>
|
|
||||||
)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user