Add next open/close day panel + refactor common funcs to util

This commit is contained in:
2018-03-19 14:00:34 +05:30
parent eb3151471a
commit 047bc7c291
11 changed files with 309 additions and 118 deletions
+27
View File
@@ -47,7 +47,34 @@
height: 100%; height: 100%;
} }
.App .upper-half {
width: 100%;
height: 80vh;
}
.App .lower-half {
width: 100%;
height: 20vh;
border-top: 5px solid antiquewhite;
}
.App .OpenXDay-container { .App .OpenXDay-container {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
.App .OpenXPlusOneDay-container {
float: left;
width: 40%;
height: 100%;
}
.App .OpenXPlusOneDay-container .OpenXDayMini {
border-right: 5px solid rgba(255, 255, 255, 0.5);
}
.App .NextOpenClose-container {
float: right;
width: 60%;
height: 100%;
}
+25 -6
View File
@@ -1,10 +1,12 @@
import * as React from 'react'; import * as React from 'react';
import { Switch, Route, Redirect } from 'react-router-dom'; import { Switch, Route, Redirect } from 'react-router-dom';
import * as moment from 'moment-timezone';
import './App.css'; import './App.css';
import { OpenXDay } from '../OpenXDay'; import { OpenXDay } from '../OpenXDay';
import { OpenXDayMini } from '../OpenXDayMini'; import { OpenXDayMini } from '../OpenXDayMini';
import { NextOpenCloseMini } from '../NextOpenCloseMini';
import { allHolidays } from '../../Data'; import { allHolidays } from '../../Data';
import { Utils } from "../../Utils"; import { Utils, OpenOrClose } from "../../Utils";
enum OpenOrCloseOrClosed { enum OpenOrCloseOrClosed {
Open = "open", Open = "open",
@@ -13,19 +15,26 @@ enum OpenOrCloseOrClosed {
} }
class IsNiftyOpenApp extends React.Component { class IsNiftyOpenApp extends React.Component {
calcOpenOrCloseForOpenCloseMini(xDay: moment.Moment) {
var isTodayEventHoliday = Utils.getEventHolidayOnDate(xDay, allHolidays) !== undefined;
return isTodayEventHoliday ? OpenOrClose.Open : OpenOrClose.Close;
}
renderOpenXDay(questionString: OpenOrCloseOrClosed): React.ReactElement<{}> { renderOpenXDay(questionString: OpenOrCloseOrClosed): React.ReactElement<{}> {
var question: OpenXDay.OpenOrClose; var question: OpenOrClose;
if (questionString === OpenOrCloseOrClosed.Open) { if (questionString === OpenOrCloseOrClosed.Open) {
question = OpenXDay.OpenOrClose.Open; question = OpenOrClose.Open;
} else { } else {
question = OpenXDay.OpenOrClose.Close; question = OpenOrClose.Close;
} }
const xDay = Utils.createTodayDateInIndiaTZ(); const xDay = Utils.createTodayDateInIndiaTZ();
const XPlusOneDay = xDay.add(1, "d"); const xPlusOneDay = xDay.clone().add(1, "d");
return ( return (
<div className="IsNiftyOpenApp"> <div className="IsNiftyOpenApp">
<div className="upper-half">
<div className="OpenXDay-container"> <div className="OpenXDay-container">
<OpenXDay <OpenXDay
question={question} question={question}
@@ -33,13 +42,23 @@ class IsNiftyOpenApp extends React.Component {
allHolidays={allHolidays} allHolidays={allHolidays}
/> />
</div> </div>
</div>
<div className="lower-half">
<div className="OpenXPlusOneDay-container"> <div className="OpenXPlusOneDay-container">
<OpenXDayMini <OpenXDayMini
xDay={XPlusOneDay} xDay={xPlusOneDay}
dateDescription={"tomorrow"} dateDescription={"tomorrow"}
allHolidays={allHolidays} allHolidays={allHolidays}
/> />
</div> </div>
<div className="NextOpenClose-container">
<NextOpenCloseMini
xDay={xDay}
openOrClose={this.calcOpenOrCloseForOpenCloseMini(xDay)}
allHolidays={allHolidays}
/>
</div>
</div>
</div> </div>
); );
} }
@@ -0,0 +1,26 @@
@import "../../Utils/utils.css";
.NextOpenCloseMini {
width: 100%;
height: 100%;
font-size: 1em;
background-color: rgba(0, 0, 0, 0.75);
color: rgba(255, 255, 255, 0.60);
font-size: 2em;
position: relative;
}
@media screen and (max-width: 600px) {
.NextOpenCloseMini {
font-size: 3em;
}
}
.NextOpenCloseMini-inner {
position: absolute;
text-align: center;
left: 50%;
top: 50%;
width: 80%;
transform: translate(-50%, -50%);
}
@@ -0,0 +1,75 @@
import * as React from 'react';
import * as moment from 'moment-timezone';
import "./Component.css";
import { HolidayList } from '../../Data';
import { Utils, OpenOrClose } from "../../Utils";
export interface NextOpenCloseMiniProps {
xDay: moment.Moment;
openOrClose: OpenOrClose;
allHolidays: HolidayList;
}
export class NextOpenCloseMini extends React.Component<NextOpenCloseMiniProps, {}> {
xDay: moment.Moment;
openOrClose: OpenOrClose;
allHolidays: HolidayList;
nextOpenOrCloseDate: moment.Moment | undefined;
constructor(props: NextOpenCloseMiniProps) {
super(props);
this.xDay = props.xDay;
this.openOrClose = props.openOrClose;
this.allHolidays = props.allHolidays;
this.nextOpenOrCloseDate = Utils.findNextOpenOrCloseFromDate(this.xDay, this.allHolidays, this.openOrClose);
}
getOpeningClosingString() {
return this.openOrClose === OpenOrClose.Open ? "opening" : "closing";
}
renderDate(): JSX.Element[] {
const tmpNextDate = this.nextOpenOrCloseDate as moment.Moment;
var nextDateString = tmpNextDate.format("DD-MM-YYYY");
return [
(
<div className="openCloseDecription" key="title">
Next {this.getOpeningClosingString()} on
</div>
),
(
<div className="dateDescription" key="subTitle">
{nextDateString}
</div>
)
];
}
renderNotFound(): JSX.Element[] {
return [
(
<div className="openCloseDecription" key="title">
No more {this.getOpeningClosingString()}s
</div>
),
(
<div className="dateDescription" key="subTitle">
this year
</div>
)
];
}
render() {
return (
<div className="NextOpenCloseMini">
<div className="NextOpenCloseMini-inner">
{this.nextOpenOrCloseDate === undefined ? this.renderNotFound() : this.renderDate()}
</div>
</div>
);
}
}
@@ -0,0 +1 @@
export { NextOpenCloseMini } from './Component';
+7 -48
View File
@@ -1,33 +1,23 @@
import * as React from 'react'; import * as React from 'react';
import * as moment from 'moment-timezone'; import * as moment from 'moment-timezone';
import * as Linq from 'linq';
import * as classnames from 'classnames'; import * as classnames from 'classnames';
import "./Component.css"; import "./Component.css";
import { Holiday, HolidayList, getWeekendHoliday } from '../../Data/index'; import { Holiday, HolidayList } from '../../Data/index';
import { ClosedReason } from '../ClosedReason'; import { ClosedReason } from '../ClosedReason';
import { Utils, HolidayAnswer, OpenOrClose } from "../../Utils";
export interface OpenXDayProps { export interface OpenXDayProps {
question: OpenXDay.OpenOrClose; question: OpenOrClose;
xDay: moment.Moment; xDay: moment.Moment;
allHolidays: HolidayList; allHolidays: HolidayList;
} }
export class OpenXDay extends React.Component<OpenXDayProps, {}> { export class OpenXDay extends React.Component<OpenXDayProps, {}> {
question: OpenXDay.OpenOrClose; question: OpenOrClose;
xDay: moment.Moment; xDay: moment.Moment;
allHolidays: HolidayList; allHolidays: HolidayList;
answer: { open: boolean, holiday: Holiday | undefined }; answer: HolidayAnswer;
static checkSameDayInSameTZ(moment1: moment.Moment, moment2: moment.Moment, raiseErrorTZMismatch: boolean = true) {
// tslint:disable-next-line:triple-equals
if (raiseErrorTZMismatch && (moment1.tz() != moment2.tz())) {
throw new Error("Timezones don't match");
}
// tslint:disable-next-line:triple-equals
return (moment1.startOf("day").format() == moment2.startOf("day").format());
}
constructor(props: OpenXDayProps) { constructor(props: OpenXDayProps) {
super(props); super(props);
@@ -35,35 +25,11 @@ export class OpenXDay extends React.Component<OpenXDayProps, {}> {
this.xDay = props.xDay; this.xDay = props.xDay;
this.allHolidays = props.allHolidays; this.allHolidays = props.allHolidays;
this.processAnswer(); this.answer = Utils.getHolidayAnswerOnDate(this.xDay, this.allHolidays);
}
processAnswer(): void {
{
const matchingHoliday = Linq
.from<Holiday>(this.allHolidays)
.firstOrDefault(
(eachHoliday, _tmp) => OpenXDay.checkSameDayInSameTZ(this.xDay, eachHoliday.Date)
);
if (matchingHoliday === null) {
this.answer = { open: true, holiday: undefined };
} else {
this.answer = { open: false, holiday: matchingHoliday };
}
}
{
const weekendHoliday = getWeekendHoliday(this.xDay);
if (typeof weekendHoliday !== "undefined") {
this.answer = { open: false, holiday: weekendHoliday };
}
}
} }
render() { render() {
const answerBoolean = (this.question === OpenXDay.OpenOrClose.Open ? this.answer.open : !this.answer.open); const answerBoolean = (this.question === OpenOrClose.Open ? this.answer.open : !this.answer.open);
const bgColorClass = (this.answer.open ? "green" : "red"); const bgColorClass = (this.answer.open ? "green" : "red");
return ( return (
@@ -89,10 +55,3 @@ export class OpenXDay extends React.Component<OpenXDayProps, {}> {
); );
} }
} }
export module OpenXDay {
export enum OpenOrClose {
Open = 'open',
Close = 'closed'
}
}
+24 -6
View File
@@ -1,16 +1,34 @@
@import "../../Utils/utils.css"; @import "../../Utils/utils.css";
.OpenXDayMini { .OpenXDayMini {
width: 100%; width: 100%;
height: 100%; height: 100%;
font-size: 4em;
background-color: rgba(0, 0, 0, 0.75); background-color: rgba(0, 0, 0, 0.75);
color: rgba(255, 255, 255, 0.60);
font-size: 2em;
position: relative;
} }
.OpenXDayMini.green { @media screen and (max-width: 600px) {
background-color: #2ECC40; .OpenXDayMini {
font-size: 3em;
}
} }
.OpenXDayMini.red { .OpenXDayMini-inner {
background-color: #FF4136; position: absolute;
text-align: right;
right: 1em;
top: 50%;
width: 80%;
transform: translate(0, -50%);
}
.OpenXDayMini .green-text {
color: rgba(46, 204, 64, 0.75);
}
.OpenXDayMini .red-text {
color: rgba(255, 64, 54, 0.75);
} }
+10 -44
View File
@@ -1,73 +1,39 @@
import * as React from 'react'; import * as React from 'react';
import * as moment from 'moment-timezone'; import * as moment from 'moment-timezone';
import * as Linq from 'linq';
import * as classnames from 'classnames'; import * as classnames from 'classnames';
import "./Component.css"; import "./Component.css";
import { Holiday, HolidayList, getWeekendHoliday } from '../../Data/index'; import { HolidayList } from '../../Data';
import { Utils, HolidayAnswer } from "../../Utils";
export interface OpenXDayProps { export interface OpenXDayMiniProps {
xDay: moment.Moment; xDay: moment.Moment;
dateDescription: string; dateDescription: string;
allHolidays: HolidayList; allHolidays: HolidayList;
} }
export class OpenXDayMini extends React.Component<OpenXDayProps, {}> { export class OpenXDayMini extends React.Component<OpenXDayMiniProps, {}> {
xDay: moment.Moment; xDay: moment.Moment;
dateDescription: string; dateDescription: string;
allHolidays: HolidayList; allHolidays: HolidayList;
answer: { open: boolean, holiday: Holiday | undefined }; answer: HolidayAnswer;
static checkSameDayInSameTZ(moment1: moment.Moment, moment2: moment.Moment, raiseErrorTZMismatch: boolean = true) { constructor(props: OpenXDayMiniProps) {
// tslint:disable-next-line:triple-equals
if (raiseErrorTZMismatch && (moment1.tz() != moment2.tz())) {
throw new Error("Timezones don't match");
}
// tslint:disable-next-line:triple-equals
return (moment1.startOf("day").format() == moment2.startOf("day").format());
}
constructor(props: OpenXDayProps) {
super(props); super(props);
this.xDay = props.xDay; this.xDay = props.xDay;
this.dateDescription = props.dateDescription; this.dateDescription = props.dateDescription;
this.allHolidays = props.allHolidays; this.allHolidays = props.allHolidays;
this.processAnswer(); this.answer = Utils.getHolidayAnswerOnDate(this.xDay, this.allHolidays);
}
processAnswer(): void {
{
const matchingHoliday = Linq
.from<Holiday>(this.allHolidays)
.firstOrDefault(
(eachHoliday, _tmp) => OpenXDayMini.checkSameDayInSameTZ(this.xDay, eachHoliday.Date)
);
if (matchingHoliday === null) {
this.answer = { open: true, holiday: undefined };
} else {
this.answer = { open: false, holiday: matchingHoliday };
}
}
{
const weekendHoliday = getWeekendHoliday(this.xDay);
if (typeof weekendHoliday !== "undefined") {
this.answer = { open: false, holiday: weekendHoliday };
}
}
} }
render() { render() {
const bgColorClass = (this.answer.open ? "green" : "red"); const textColorClass = (this.answer.open ? "green-text" : "red-text");
return ( return (
<div className={classnames([bgColorClass, "OpenXDayMini"])} > <div className={"OpenXDayMini"} >
<div className="OpenXDayMini-inner"> <div className="OpenXDayMini-inner">
<div className="openOrCloseText"> <div className={classnames([textColorClass, "openOrCloseText"])}>
{this.answer.open ? "Open" : "Closed"} {this.answer.open ? "Open" : "Closed"}
</div> </div>
<div className="dateDescription"> <div className="dateDescription">
+1 -1
View File
@@ -53,7 +53,7 @@ export function isWeekend(date: moment.Moment): boolean {
} }
} }
export function getWeekendHoliday(date: moment.Moment): Holiday | undefined { export function getWeekendHolidayOnDate(date: moment.Moment): Holiday | undefined {
if (isWeekend(date)) { if (isWeekend(date)) {
const dateWeekDay = date.isoWeekday(); const dateWeekDay = date.isoWeekday();
return { "Description": "Weekend", "Date": date, "Day": ISOWeekDay[dateWeekDay] }; return { "Description": "Weekend", "Date": date, "Day": ISOWeekDay[dateWeekDay] };
+1 -1
View File
@@ -1 +1 @@
export { Utils } from "./utils"; export { Utils, HolidayAnswer, OpenOrClose } from "./utils";
+100
View File
@@ -1,7 +1,107 @@
import * as moment from 'moment-timezone'; import * as moment from 'moment-timezone';
import * as Linq from 'linq';
import { Holiday, HolidayList, getWeekendHolidayOnDate } from '../Data';
export interface HolidayAnswer {
open: boolean;
holiday: Holiday | undefined;
}
export enum OpenOrClose {
Open = 'open',
Close = 'closed'
}
export class Utils { export class Utils {
static invertOpenOrClose(openOrClose: OpenOrClose) {
return (openOrClose === OpenOrClose.Open) ? OpenOrClose.Close : OpenOrClose.Open;
}
static createTodayDateInIndiaTZ(): moment.Moment { static createTodayDateInIndiaTZ(): moment.Moment {
return moment.tz(moment.tz.guess()).tz("Asia/Kolkata"); return moment.tz(moment.tz.guess()).tz("Asia/Kolkata");
} }
static checkSameDayInSameTZ(moment1: moment.Moment, moment2: moment.Moment, raiseErrorTZMismatch: boolean = true) {
// tslint:disable-next-line:triple-equals
if (raiseErrorTZMismatch && (moment1.tz() != moment2.tz())) {
throw new Error("Timezones don't match");
}
// tslint:disable-next-line:triple-equals
return (moment1.clone().startOf("day").format() == moment2.clone().startOf("day").format());
}
static checkSameYearInSameTZ(moment1: moment.Moment, moment2: moment.Moment, raiseErrorTZMismatch: boolean = true) {
// tslint:disable-next-line:triple-equals
if (raiseErrorTZMismatch && (moment1.tz() != moment2.tz())) {
throw new Error("Timezones don't match");
}
// tslint:disable-next-line:triple-equals
return (moment1.clone().startOf("year").format() == moment2.clone().startOf("year").format());
}
static getHolidayAnswerOnDate(xDay: moment.Moment, allHolidays: HolidayList): HolidayAnswer {
let tmpHolidayAnswer: HolidayAnswer;
{
const eventHoliday = this.getEventHolidayOnDate(xDay, allHolidays);
if (typeof eventHoliday !== "undefined") {
tmpHolidayAnswer = { open: false, holiday: eventHoliday };
} else {
tmpHolidayAnswer = { open: true, holiday: undefined };
}
}
{
const weekendHoliday = getWeekendHolidayOnDate(xDay);
if (typeof weekendHoliday !== "undefined") {
tmpHolidayAnswer = { open: false, holiday: weekendHoliday };
}
}
return tmpHolidayAnswer;
}
static getEventHolidayOnDate(xDay: moment.Moment, allHolidays: HolidayList): Holiday | undefined {
{
const matchingHoliday = Linq
.from<Holiday>(allHolidays)
.firstOrDefault(
(eachHoliday, _tmp) => Utils.checkSameDayInSameTZ(xDay, eachHoliday.Date)
);
if (matchingHoliday === null) {
return undefined;
} else {
return matchingHoliday;
}
}
}
static findNextOpenOrCloseFromDate(
xDay: moment.Moment,
allHolidays: HolidayList,
openOrClose: OpenOrClose): moment.Moment | undefined {
let currentDay = xDay.clone().add(1, "day");
while (this.checkSameYearInSameTZ(currentDay, xDay)) {
var holidayAnswerOnCurrentDay = this.getHolidayAnswerOnDate(currentDay, allHolidays);
if ((openOrClose === OpenOrClose.Open) && holidayAnswerOnCurrentDay.open) {
return currentDay;
}
if ((openOrClose === OpenOrClose.Close) && !holidayAnswerOnCurrentDay.open) {
return currentDay;
}
currentDay = currentDay.add(1, "day");
}
return undefined;
}
} }