diff --git a/src/assets/images/campaign/available.png b/src/assets/images/campaign/available.png new file mode 100644 index 00000000..1cc8fa62 Binary files /dev/null and b/src/assets/images/campaign/available.png differ diff --git a/src/assets/images/campaign/locked_bg.png b/src/assets/images/campaign/locked_bg.png new file mode 100644 index 00000000..93927dd5 Binary files /dev/null and b/src/assets/images/campaign/locked_bg.png differ diff --git a/src/assets/images/campaign/next.png b/src/assets/images/campaign/next.png new file mode 100644 index 00000000..88a2883a Binary files /dev/null and b/src/assets/images/campaign/next.png differ diff --git a/src/assets/images/campaign/prev.png b/src/assets/images/campaign/prev.png new file mode 100644 index 00000000..914a6592 Binary files /dev/null and b/src/assets/images/campaign/prev.png differ diff --git a/src/assets/images/campaign/unavailable.png b/src/assets/images/campaign/unavailable.png new file mode 100644 index 00000000..dc134c3f Binary files /dev/null and b/src/assets/images/campaign/unavailable.png differ diff --git a/src/assets/images/campaign/unlocked_bg.png b/src/assets/images/campaign/unlocked_bg.png new file mode 100644 index 00000000..31c35ba1 Binary files /dev/null and b/src/assets/images/campaign/unlocked_bg.png differ diff --git a/src/assets/images/campaign/unopened.png b/src/assets/images/campaign/unopened.png deleted file mode 100644 index 71a754ff..00000000 Binary files a/src/assets/images/campaign/unopened.png and /dev/null differ diff --git a/src/views/campaign/CampaignView.tsx b/src/views/campaign/CampaignView.tsx index eb205f51..0f2307ee 100644 --- a/src/views/campaign/CampaignView.tsx +++ b/src/views/campaign/CampaignView.tsx @@ -14,7 +14,7 @@ export const CampaignView: FC<{}> = props => const parser = event.getParser(); if(!parser) return; - + console.log(parser); setCalendarData(parser.calendarData); }, []); diff --git a/src/views/campaign/common/CalendarItemState.ts b/src/views/campaign/common/CalendarItemState.ts new file mode 100644 index 00000000..1b91ca3f --- /dev/null +++ b/src/views/campaign/common/CalendarItemState.ts @@ -0,0 +1,7 @@ +export class CalendarItemState +{ + public static readonly STATE_UNLOCKED = 1; + public static readonly STATE_LOCKED_AVAILABLE = 2; + public static readonly STATE_LOCKED_EXPIRED = 3; + public static readonly STATE_LOCKED_FUTURE = 4; +} diff --git a/src/views/campaign/common/Utils.ts b/src/views/campaign/common/Utils.ts new file mode 100644 index 00000000..2695539e --- /dev/null +++ b/src/views/campaign/common/Utils.ts @@ -0,0 +1,4 @@ +export const getNumItemsDisplayed = (): number => +{ + return Math.max(Math.min(2, window.screen.width / 135), 7); +} diff --git a/src/views/campaign/views/calendar-item/CalendarItemView.tsx b/src/views/campaign/views/calendar-item/CalendarItemView.tsx index 172126ab..4841a67b 100644 --- a/src/views/campaign/views/calendar-item/CalendarItemView.tsx +++ b/src/views/campaign/views/calendar-item/CalendarItemView.tsx @@ -1,10 +1,46 @@ -import { FC } from 'react'; +import { FC, useCallback } from 'react'; +import { GetRoomEngine, GetSessionDataManager } from '../../../../api'; import { NitroLayoutFlexColumn } from '../../../../layout'; +import { CalendarItemState } from '../../common/CalendarItemState'; import { CalendarItemViewProps } from './CalendarItemView.types'; export const CalendarItemView: FC = 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 ( - + onClick(id)}> + { (state === CalendarItemState.STATE_UNLOCKED) && +
+ +
+ } + + { (state !== CalendarItemState.STATE_UNLOCKED) && +
+ { (state === CalendarItemState.STATE_LOCKED_AVAILABLE) && +
+ } + { (state === CalendarItemState.STATE_LOCKED_EXPIRED || state === CalendarItemState.STATE_LOCKED_FUTURE) && +
+ } +
+ } + ); } diff --git a/src/views/campaign/views/calendar-item/CalendarItemView.types.ts b/src/views/campaign/views/calendar-item/CalendarItemView.types.ts index 99f12758..038dc03c 100644 --- a/src/views/campaign/views/calendar-item/CalendarItemView.types.ts +++ b/src/views/campaign/views/calendar-item/CalendarItemView.types.ts @@ -1,4 +1,8 @@ export interface CalendarItemViewProps { - + id: number; + productName?: string; + state: number; + active?: boolean; + onClick(itemId: number): void; } diff --git a/src/views/campaign/views/calendar/CalendarView.scss b/src/views/campaign/views/calendar/CalendarView.scss index 7ef04128..f583ee0b 100644 --- a/src/views/campaign/views/calendar/CalendarView.scss +++ b/src/views/campaign/views/calendar/CalendarView.scss @@ -1,10 +1,69 @@ .nitro-campaign-calendar { - width: 800px; + width: 1010px; height: 400px; - .calendar-day { - background: url('../../../../assets/images/campaign/campaign_day_generic_bg.png'); + .calendar-item { + background: url("../../../../assets/images/campaign/campaign_day_generic_bg.png"); max-height: 100%; - min-width: 50px; + 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; + } + + .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; + } + } + } + + .button-container { + position: relative; + width: 100%; + height: 0px; + + .calendar-prev { + background: url("../../../../assets/images/campaign/prev.png"); + width: 33px; + height: 34px; + position: absolute; + margin-top: 15%; + left: 5px; + z-index: 10; + } + + .calendar-next { + background: url("../../../../assets/images/campaign/next.png"); + width: 33px; + height: 34px; + position: absolute; + margin-top: 15%; + right: 5px; + z-index: 10; + } } } diff --git a/src/views/campaign/views/calendar/CalendarView.tsx b/src/views/campaign/views/calendar/CalendarView.tsx index 42a6a010..b89864dc 100644 --- a/src/views/campaign/views/calendar/CalendarView.tsx +++ b/src/views/campaign/views/calendar/CalendarView.tsx @@ -1,6 +1,8 @@ import { FC, useCallback, useState } from 'react'; import { LocalizeText } from '../../../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView, NitroLayoutFlex } from '../../../../layout'; +import { CalendarItemState } from '../../common/CalendarItemState'; +import { getNumItemsDisplayed } from '../../common/Utils'; import { CalendarItemView } from '../calendar-item/CalendarItemView'; import { CalendarViewProps } from './CalendarView.types'; @@ -8,30 +10,104 @@ export const CalendarView: FC = props => { const { close = null, campaignName = null, currentDay = null, numDays = null, missedDays = null, openedDays = null } = props; const [ selectedDay, setSelectedDay ] = useState(currentDay); + const [ index, setIndex ] = useState(0); + + 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) => { - if(missedDays.includes(day)) + const state = getDayState(day); + + switch(state) { - return LocalizeText('campaign.calendar.info.expired'); + 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); } - if(openedDays.includes(day)) + }, [index, numDays, selectedDay]); + + const onClickPrev = useCallback(() => + { + const prevDay = selectedDay - 1; + + if( (prevDay < 0)) return; + + setSelectedDay(prevDay); + + if( index > prevDay) { - return LocalizeText('campaign.calendar.info.unlocked') + setIndex(index - 1); } - }, [missedDays, openedDays]); + }, [index, selectedDay]); + + const onClickItem = useCallback((item: number) => + { + if(selectedDay === item) + { + //handle opening + } + else + { + setSelectedDay(item); + } + }, [selectedDay]); return (
-

{ LocalizeText('campaign.calendar.heading.day', ['number'], [selectedDay.toString()]) }

-

{ LocalizeText('') }

+

{ LocalizeText('campaign.calendar.heading.day', ['number'], [(selectedDay + 1).toString()]) }

+

{ dayMessage(selectedDay) }

+
+
+
+
- { [...Array(7)].map((e, i) => ) } + { + [...Array(getNumItemsDisplayed())].map((e, i) => + { + const day = index + i; + return + }) + } diff --git a/src/views/room/widgets/word-quiz/WordQuizWidgetView.tsx b/src/views/room/widgets/word-quiz/WordQuizWidgetView.tsx index af258d59..271853e4 100644 --- a/src/views/room/widgets/word-quiz/WordQuizWidgetView.tsx +++ b/src/views/room/widgets/word-quiz/WordQuizWidgetView.tsx @@ -106,9 +106,8 @@ export const WordQuizWidgetView: FC<{}> = props => { setUserAnswers(prev => { - const copy = new Map(prev); const keysToRemove: number[] = []; - copy.forEach((value, key) => + prev.forEach((value, key) => { value.secondsLeft--; @@ -118,8 +117,10 @@ export const WordQuizWidgetView: FC<{}> = props => } }); - keysToRemove.forEach(key => copy.delete(key)); + if(keysToRemove.length === 0) return prev; + const copy = new Map(prev); + keysToRemove.forEach(key => copy.delete(key)); return copy; })