Pen Settings

HTML

CSS

CSS Base

Vendor Prefixing

Add External Stylesheets/Pens

Any URL's added here will be added as <link>s in order, and before the CSS in the editor. If you link to another Pen, it will include the CSS from that Pen. If the preprocessor matches, it will attempt to combine them before processing.

+ add another resource

JavaScript

Babel is required to process package imports. If you need a different preprocessor remove all packages first.

Add External Scripts/Pens

Any URL's added here will be added as <script>s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.

+ add another resource

Behavior

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

Editor Settings

Code Indentation

Want to change your Syntax Highlighting theme, Fonts and more?

Visit your global Editor Settings.

HTML Settings

Here you can Sed posuere consectetur est at lobortis. Donec ullamcorper nulla non metus auctor fringilla. Maecenas sed diam eget risus varius blandit sit amet non magna. Donec id elit non mi porta gravida at eget metus. Praesent commodo cursus magna, vel scelerisque nisl consectetur et.

HTML

            
              <div id="root"></div>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-124047713-1"></script>
<script>
  window.dataLayer = window.dataLayer || [];

  function gtag() {
    dataLayer.push(arguments);
  }
  gtag('js', new Date());
  gtag('config', 'UA-124047713-1');
</script>
            
          
!

CSS

            
              html,
body,
div,
span,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
abbr,
code,
em,
img,
small,
strong,
sub,
sup,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
footer,
header,
nav,
section,
time,
audio,
video {
  background: transparent;
  border: 0;
  font-size: 100%;
  font-weight: inherit;
  margin: 0;
  padding: 0;
  vertical-align: baseline;
}

article,
aside,
figure,
footer,
header,
nav,
section {
  display: block;
}

*,
*::before,
*::after {
  box-sizing: inherit;
}

html {
  box-sizing: border-box;
  overflow-y: scroll;
}

body {
  background: #000;
  font-family: "Raleway", sans-serif;
  font-size: 16px;
  line-height: 1.75;
}

img,
object {
  max-width: 100%;
}

ul {
  list-style: none;
}
            
          
!

JS

            
              /*****************************
 *********** UTILS ************
 *****************************/
console.clear();
const sc = styled.default;
const keyframes = styled.keyframes;
const PureComponent = React.PureComponent;

/*****************************
Animations
*****************************/
const FadeOut = keyframes`
  to {
    background: rgba(0,0,0,.9);
  }
`;

const FadeIn = keyframes`
  to {
    background: rgba(0,0,0,.15);
  }
`;

const Stabbing = keyframes`
  to {
    transform: rotate(-90deg);
  }
`;

const StabbingFlipped = keyframes`
  to {
    transform: scaleX(-1) rotate(-90deg);
  }
`;

const Flash = keyframes`
  0%, 49.9% {
    background: rgba(0,0,0,.15);
  }
  50%, 100% {
    background: rgba(0,0,0,1);
  }
`;

const ShowScore = score => keyframes`
  to {
    stroke-dasharray: ${score * 10} 100;
  }
`;

/*****************************
Theme
*****************************/
const colors = {
  black: "rgb(0,0,0)",
  white: "rgb(255,255,255)",

  primary: "#4b0404",
  secondary: "#8c0f0f",
  tertiary: "#302f2f",
  darkGrey: "#444",
  lightGrey: "#b5b5b5",

  scoreBad: "#EE6352",
  scoreMid: "#FFF07C",
  scoreHigh: "#74ea80",
  scoreTrack: "#818181"
};

const space = {
  default: "12px",
  hori: "12px",
  vert: "12px"
};

const size = {
  borderRadius: "5px",
  dateBarHeight: "40px",
  headerHeight: "64px",
  maxContent: "1280px"
};

const fonts = {
  raleway: '"Raleway", sans-serif',
  oswald: '"Oswald", sans-serif'
};

const times = {
  base: "5s",
  delayXs: "1.15s",
  delaySm: "2.25s",
  delayMd: "3.15s",
  delayLg: "4.3s",
  delayXl: "6.65s"
};

const Days = {
  MONDAY: 'Monday of the Dead',
  TUESDAY: 'True Story Tuesday',
  WEDNESDAY: 'Wind-Up Wednesday',
  THURSDAY: 'Thursday',
  FRIDAY: 'Facepaint Friday',
  SATURDAY: 'Saturday',
  SUNDAY: 'Sunday',
  HALLOWEEN: 'Happy Halloween 🎃'
};

const Find = (source, field, target) => {
  return source.find(item => {
    return item[field] === target;
  });
};

/*****************************
 ********* COMPONENTS *********
 *****************************/

/*****************************
Close Icon
*****************************/
const Container = sc.div`
  background: ${colors.black};
  height: 50px;
  position: relative;
  width: 50px;

  &:hover path {
    stroke: ${colors.lightGrey};
  }

  &:hover span {
    color: ${colors.white};
  }
`;

const CloseButton = sc.button`
  appearance: none;
  -webkit-appearance: none;
  background: none;
  border: 0;
  cursor: pointer;
  height: 100%;
  padding: 0;
  width: 100%;
`;

const SVGContainer = sc.svg.attrs({
  height: "100%",
  viewBox: "0 0 36 36",
  width: "100%"
})``;

const CloseOutline = sc.path.attrs({
  d:
    "M18 2.0845a 15.9155 15.9155 0 0 1 0 31.831a 15.9155 15.9155 0 0 1 0 -31.831"
})`
  fill: none;
  stroke: ${colors.scoreTrack};
  stroke-width: 2.5;
  transition: stroke 0.25s ease;
`;

const CloseText = sc.span`
  color: ${colors.lightGrey};
  display: block;
  font-size: 1.5rem;
  font.weight: 700;
  position: absolute;
  text-align: center;
  top: 50%;
  transform: translateY(calc(-50% + 1px));
  transition: color 0.25s ease;
  width: 100%;
`;

const CloseIcon = ({ toggleTrailer }) => {
  return (
    <Container>
      <CloseButton
        onClick={e => {
          e.preventDefault();
          toggleTrailer();
        }}
      >
        <SVGContainer>
          <CloseOutline />
        </SVGContainer>
        <CloseText>X</CloseText>
      </CloseButton>
    </Container>
  );
};

CloseIcon.propTypes = {
  toggleTrailer: PropTypes.func.isRequired
};

/*****************************
Content Container
*****************************/
const ContentContainer = sc.div`
  margin: 0 auto;
  max-width: ${size.maxContent};
  position: relative;
  width: 100%;
`;

/*****************************
Date Box
*****************************/
const DateBoxContainer = sc.div`
  align-items: center;
  background: ${colors.tertiary};
  color: ${colors.white};
  display: flex;
  flex: 1;
  font: 1.25rem/1 ${fonts.raleway};
  justify-content: center;
  margin-left: 1rem;
  min-width: 40px;
  opacity: ${props => (props.trailerActive ? ".2" : 1)};
  outline: 1rem solid ${colors.black};
  transition: opacity 0.5s ease;
`;

const DateBox = ({ date, trailerActive }) => {
  return (
    <DateBoxContainer trailerActive={trailerActive}>
      {date < 10 ? `0${date}` : date}
    </DateBoxContainer>
  );
};

DateBox.propTypes = {
  date: PropTypes.number.isRequired,
  trailerActive: PropTypes.bool.isRequired
};

/*****************************
Day Box
*****************************/
const DayBoxContainer = sc.div`
  align-items: center;
  background: ${colors.secondary};
  color: ${colors.white};
  display: flex;
  flex: 3;
  font: 1.25rem/1 ${fonts.raleway};
  justify-content: center;
  letter-spacing: 1.15px;
  opacity: ${props => (props.trailerActive ? ".2" : 1)};
  outline: 1rem solid ${colors.black};
  padding: ${space.default};
  text-transform: uppercase;
  transition: opacity 0.5s ease;
`;

const DayBox = ({ day, trailerActive }) => {
  return <DayBoxContainer trailerActive={trailerActive}>{day}</DayBoxContainer>;
};

DayBox.propTypes = {
  day: PropTypes.string.isRequired,
  trailerActive: PropTypes.bool.isRequired
};

/*****************************
Grid Cell
*****************************/
const GridCell = sc.div`
  animation: ${FadeOut} ${times.base} ease infinite alternate;
  background: rgba(0, 0, 0, 0.15);
  grid-area: ${props => props.area};
  outline: 1rem solid ${colors.black};
  transition: background 1s ease;

  @media (max-width: 750px) {
    animation: none;
    display: none;
  }

  @media (max-width: 1000px) {
    ${props =>
      props.hideAt === "MD" &&
      `
      display: none;
    `};
  }

  ${props =>
    props.hide &&
    `
    animation: ${FadeIn} calc(${times.base} * 1.1) infinite alternate;
    background: rgba(0,0,0,1);
  `} ${props =>
      props.flash &&
      `
    animation: ${Flash} ${times.base} infinite alternate;
  `} ${props =>
      props.hide &&
      props.flash &&
      `
    animation: ${Flash} ${times.base} infinite alternate-reverse;
  `} ${props =>
      props.delayXS &&
      `
    animation-delay: ${times.delayXs};
  `} ${props =>
      props.delaySM &&
      `
    animation-delay: ${times.delaySm};
  `} ${props =>
      props.delayMD &&
      `
    animation-delay: ${times.delayMd};
  `} ${props =>
      props.delayLG &&
      `
    animation-delay: ${times.delayLg};
  `} ${props =>
      props.delayXL &&
      `
    animation-delay: ${times.delayXl};
  `} ${props =>
      props.noFade &&
      `
    animation: none;
  `} ${props =>
      props.slow &&
      `
    animation-duration: calc(${times.base} * 1.5);
  `} ${props =>
      props.fast &&
      `
    animation-duration: calc(${times.base} * .75);
  `} ${props =>
      props.focus &&
      `
    animation: ${FadeIn} calc(${times.base} * 1.1) ${
        times.delaySm
      } infinite alternate;
    background: rgba(0,0,0,1);
  `} ${props =>
      props.dim &&
      `
    animation: none;
    background: rgba(0,0,0,.9);
    transition: background 1s ease;
  `};
`;

const Cell = ({
  dim,
  focus,
  noFade,
  hide,
  hideAt,
  flash,
  delayXS,
  delaySM,
  delayMD,
  delayLG,
  delayXL,
  fast,
  slow,
  area,
  children
}) => {
  return (
    <GridCell
      dim={dim}
      focus={focus}
      noFade={noFade}
      hide={hide}
      hideAt={hideAt}
      flash={flash}
      delayXS={delayXS}
      delaySM={delaySM}
      delayMD={delayMD}
      delayLG={delayLG}
      delayXL={delayXL}
      fast={fast}
      slow={slow}
      area={area}
    >
      {children}
    </GridCell>
  );
};

Cell.propTypes = {
  dim: PropTypes.bool,
  focus: PropTypes.bool,
  noFade: PropTypes.bool,
  hide: PropTypes.bool,
  hideAt: PropTypes.oneOf(["MD", "SM"]),
  flash: PropTypes.bool,
  delayXS: PropTypes.bool,
  delaySM: PropTypes.bool,
  delayMD: PropTypes.bool,
  delayLG: PropTypes.bool,
  delayXL: PropTypes.bool,
  fast: PropTypes.bool,
  slow: PropTypes.bool,
  area: PropTypes.string.isRequired,
  children: PropTypes.any
};

/*****************************
Grid
*****************************/
const DayWrapper = sc.div`
  background: ${colors.black};
  display: flex;
  grid-area: D;
  justify-content: space-between;
  outline: 1rem solid ${colors.black};
  position: relative;
`;

const Grid = ({
  day,
  date,
  movie,
  dim,
  focus1,
  focus2,
  focus3,
  trailerActive,
  toggleTrailer
}) => {
  return [
    <DayWrapper key="cell-D">
      <DayBox trailerActive={trailerActive} day={day} />
      <DateBox trailerActive={trailerActive} date={date} />
    </DayWrapper>,
    <MovieCardContainer
      key="cell-C"
      movie={movie}
      trailerActive={trailerActive}
      toggleTrailer={toggleTrailer}
    />,
    <Cell dim={dim} area="F1" focus={focus1} delayLG key="cell-F1" />,
    <Cell dim={dim} area="F2" focus={focus2} delayXL key="cell-F2" />,
    <Cell dim={dim} area="F3" focus={focus3} noFade key="cell-F3" />,
    <Cell dim={dim} area="a" noFade key="cell-a" />,
    <Cell dim={dim} area="b" key="cell-b" />,
    <Cell dim={dim} area="c" noFade key="cell-c" />,
    <Cell dim={dim} area="d" noFade key="cell-d" />,
    <Cell dim={dim} area="e" hide noFade key="cell-e" />,
    <Cell dim={dim} area="f" noFade key="cell-f" />,
    <Cell dim={dim} area="g" noFade key="cell-g" />,
    <Cell dim={dim} area="h" delayLG fast key="cell-h" />,
    <Cell dim={dim} area="i" delaySM fast key="cell-i" />,
    <Cell dim={dim} area="j" noFade key="cell-j" />,
    <Cell dim={dim} area="k" hide noFade key="cell-k" />,
    <Cell dim={dim} area="l" hide noFade key="cell-l" />,
    <Cell dim={dim} area="m" hide noFade key="cell-m" />,
    <Cell dim={dim} area="n" hide noFade key="cell-n" />,
    <Cell dim={dim} area="o" noFade key="cell-o" />,
    <Cell dim={dim} area="p" noFade key="cell-p" />,
    <Cell dim={dim} area="q" noFade hideAt="MD" key="cell-q" />,
    <Cell dim={dim} area="r" slow noFade hideAt="MD" key="cell-r" />,
    <Cell dim={dim} area="s" noFade key="cell-s" />,
    <Cell dim={dim} area="t" noFade key="cell-t" />,
    <Cell dim={dim} area="u" hide noFade key="cell-u" />,
    <Cell dim={dim} area="v" hide noFade key="cell-v" />,
    <Cell dim={dim} area="w" hide slow key="cell-w" />,
    <Cell dim={dim} area="x" flash slow delaySM key="cell-x" />,
    <Cell dim={dim} area="y" noFade hideAt="MD" key="cell-y" />,
    <Cell dim={dim} area="z" noFade key="cell-z" />,
    <Cell dim={dim} area="aa" noFade key="cell-aa" />,
    <Cell dim={dim} area="bb" slow delayLG key="cell-bb" />,
    <Cell dim={dim} area="cc" noFade key="cell-cc" />,
    <Cell dim={dim} area="dd" flash fast delayLG key="cell-dd" />,
    <Cell dim={dim} area="ee" noFade key="cell-ee" />,
    <Cell dim={dim} area="ff" noFade key="cell-ff" />,
    <Cell dim={dim} area="gg" noFade key="cell-gg" />
  ];
};

Grid.propTypes = {
  day: PropTypes.string.isRequired,
  date: PropTypes.number.isRequired,
  movie: PropTypes.shape({
    title: PropTypes.string.isRequired,
    tagline: PropTypes.string.isRequired,
    overview: PropTypes.string.isRequired,
    release: PropTypes.string.isRequired,
    language: PropTypes.string.isRequired,
    rating: PropTypes.string.isRequired,
    score: PropTypes.number.isRequired,
    trailer: PropTypes.string.isRequired,
    services: PropTypes.shape({
      netflix: PropTypes.string,
      hulu: PropTypes.string,
      shudder: PropTypes.string,
      youtube: PropTypes.string,
      amazon: PropTypes.string,
      imdb: PropTypes.string
    }).isRequired
  }).isRequired,
  dim: PropTypes.bool.isRequired,
  focus1: PropTypes.bool,
  focus2: PropTypes.bool,
  focus3: PropTypes.bool,
  trailerActive: PropTypes.bool.isRequired,
  toggleTrailer: PropTypes.func.isRequired
};

/*****************************
Header
*****************************/
const HeaderContainer = sc.header`
  background: ${colors.black};
  min-height: ${size.headerHeight};
  padding: ${space.default};
  position: sticky;
  top: 0;
  z-index: 10;
`;

const HeaderContent = sc(ContentContainer)`
  color: #fff;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  position: relative;

  @media (min-width: 500px) {
    justify-content: space-between;
  }
`;

const LogoImage = sc.img.attrs({
  src: `https://yuschick.github.io/31-Nights-of-Horror-2018/static/media/logo.3cac25fa.svg`,
  alt: "31 Nights of Horror - 2018"
})`
  height: calc(${size.headerHeight} - calc(${space.default} * 2));
`;

const Header = () => (
  <HeaderContainer>
    <HeaderContent>
      <LogoImage />
      <Nav />
      <SocialNav />
    </HeaderContent>
  </HeaderContainer>
);

/*****************************
Loading Screen
*****************************/
const LoadingScreenContainer = sc.div`
  align-items: center;
  display: flex;
  height: 100vh;
  justify-content: center;
  width: 100%;
`;

const Image = styled.img.attrs({
  src: `https://yuschick.github.io/31-Nights-of-Horror-2018/static/media/stab.904e08e6.svg`,
  alt: "Loading"
})`
  animation: ${Stabbing} 0.35s ease infinite alternate;
  height: auto;
  transform-origin: left center;
  width: 100px;

  ${props =>
    props.flipped &&
    `
    animation: ${StabbingFlipped} .35s ease infinite alternate;
    margin-left: 0rem;
    transform: scaleX(-1);
  `};
`;

const LoadingScreen = () => (
  <LoadingScreenContainer>
    <Image />
    <Image flipped />
  </LoadingScreenContainer>
);

/*****************************
Movie Card Container
*****************************/
const MovieCardSection = sc.section`
  background: rgba(0, 0, 0, 0.85);
  box-shadow: none;
  color: #fff;
  grid-area: C;
  outline: 1rem solid rgba(0, 0, 0, 0.85);
  padding: ${space.vert} calc(${space.hori} * 2);
  z-index: 2;

  @media (min-width: 750px) {
    background: ${colors.black};
    box-shadow: 0px 0px 25px 20px rgba(0, 0, 0, 0.75);
    outline: none;
  }
`;

const ArticleContainer = sc.article`
  opacity: 1;
  transition: opacity 0.5s ease;

  ${props =>
    props.dim &&
    `
    opacity: 0;
  `};
`;

const CardContentContainer = sc.div`
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100%;
  position: relative;
`;

const CardFooter = styled.footer`
  align-items: center;
  display: flex;
  justify-content: space-between;
`;

const MovieCardContainer = ({ movie, trailerActive, toggleTrailer }) => {
  return (
    <MovieCardSection>
      <CardContentContainer>
        {trailerActive ? <MovieTrailer trailer={movie.trailer} /> : null}
        <ArticleContainer dim={trailerActive}>
          <header>
            <TitleAndTagline title={movie.title} tagline={movie.tagline} />
            <MovieDetailsBar
              release={movie.release}
              language={movie.language}
              rating={movie.rating}
              title={movie.title}
              toggleTrailer={toggleTrailer}
            />
          </header>
          <main>
            <MovieOverview overview={movie.overview} />
          </main>
        </ArticleContainer>
        <CardFooter>
          <MovieServices
            dim={trailerActive}
            title={movie.title}
            services={movie.services}
          />
          {trailerActive ? (
            <CloseIcon toggleTrailer={toggleTrailer} />
          ) : (
            <MovieScore score={movie.score} />
          )}
        </CardFooter>
      </CardContentContainer>
    </MovieCardSection>
  );
};

MovieCardContainer.propTypes = {
  movie: PropTypes.shape({
    title: PropTypes.string.isRequired,
    tagline: PropTypes.string.isRequired,
    overview: PropTypes.string.isRequired,
    release: PropTypes.string.isRequired,
    language: PropTypes.string.isRequired,
    rating: PropTypes.string.isRequired,
    score: PropTypes.number.isRequired,
    trailer: PropTypes.string.isRequired,
    services: PropTypes.shape({
      netflix: PropTypes.string,
      hulu: PropTypes.string,
      shudder: PropTypes.string,
      youtube: PropTypes.string,
      amazon: PropTypes.string,
      imdb: PropTypes.string
    }).isRequired
  }).isRequired,
  trailerActive: PropTypes.bool.isRequired,
  toggleTrailer: PropTypes.func.isRequired
};

/*****************************
Movie Details Bar
*****************************/
const ListContainer = sc.ul`
  align-items: center;
  display: flex;
  margin: calc(${space.vert} * 1.5) 0;

  @media (max-width: 750px) {
    flex-wrap: wrap;

    & li:first-child {
      clear: both;
      display: block;
      flex: 1 1 100%;
      margin: ${space.vert} auto;
      width: 100%;
    }
  }
`;

const ListItem = sc.li`
  align-content: center;
  display: flex;
  font: 1rem/1 ${fonts.raleway};

  & + li {
    padding-left: calc(${space.hori} * 2);
  }

  @media (max-width: 750px) {
    flex: 1;
    justify-content: center;
  }
`;

const Icon = sc.img.attrs({
  src: props => props.src,
  alt: props => props.alt
})`
  display: block;
  height: ${props => (props.small ? "13px" : "16px")};
  margin-right: calc(${space.hori} / 2);
  width: auto;
`;

const TrailerButton = sc.button`
  align-items: center;
  align-content: center;
  appearance: none;
  background: linear-gradient(
    to top,
    ${colors.primary} 0%,
    ${colors.secondary} 80%
  );
  border: 0;
  cursor: pointer;
  display: flex;
  font: 1rem/1 ${fonts.raleway};
  justify-content: center;
  padding: 5px ${space.hori};
  -webkit-text-fill-color: ${colors.white};
  -webkit-text-stroke: 0.25px rgba(0, 0, 0, 0.5);
  width: 100%;

  &:hover {
    background: linear-gradient(
      to top,
      ${colors.primary} 0%,
      ${colors.secondary} 40%
    );
  }

  @media (max-width: 750px) {
    padding: ${space.default};
  }
`;

class MovieDetailsBar extends PureComponent {
  handleClick() {
    this.props.toggleTrailer();
    Firebase.TrackClick(this.props.title, "trailer");
  }

  render() {
    return (
      <ListContainer>
        <ListItem>
          <TrailerButton
            onClick={() => {
              this.handleClick();
            }}
          >
            <Icon src={`https://yuschick.github.io/31-Nights-of-Horror-2018/static/media/play.4ff9fa46.svg`} alt="Watch Trailer" small /> Watch Trailer
          </TrailerButton>
        </ListItem>
        <ListItem>
          <Icon src={`https://yuschick.github.io/31-Nights-of-Horror-2018/static/media/calendar.8b17fece.svg`} alt="Release Year" /> {this.props.release}
        </ListItem>
        <ListItem>
          <Icon src={`https://yuschick.github.io/31-Nights-of-Horror-2018/static/media/language.00f0cff3.svg`} alt="Language" /> {this.props.language}
        </ListItem>
        <ListItem>
          <MovieRating rating={this.props.rating} />
        </ListItem>
      </ListContainer>
    );
  }
}

MovieDetailsBar.propTypes = {
  release: PropTypes.string.isRequired,
  language: PropTypes.string.isRequired,
  title: PropTypes.string.isRequired,
  rating: PropTypes.string.isRequired,
  toggleTrailer: PropTypes.func.isRequired
};

/*****************************
Movie Overview
*****************************/
const Overview = sc.p`
  letter-spacing: 1.2px;
  margin: ${space.vert} 0;
`;

const MovieOverview = ({ overview }) => {
  return <Overview>{overview}</Overview>;
};

MovieOverview.propTypes = {
  overview: PropTypes.string.isRequired
};

/*****************************
Movie Rating
*****************************/
const RatingContainer = sc.div`
  background: ${props =>
    props.rating === "nr"
      ? colors.black
      : props.rating === "r" ? colors.tertiary : colors.darkGrey};
  border-radius: 2px;
  color: ${colors.white};
  letter-spacing: 1.25px;
  line-height: 1.5;
  padding: 0 ${space.hori};
  text-transform: uppercase;
`;

const MovieRating = ({ rating }) => {
  return (
    <RatingContainer rating={rating.toLowerCase()}>
      <span>{rating}</span>
    </RatingContainer>
  );
};

MovieRating.propTypes = {
  rating: PropTypes.string.isRequired
};

/*****************************
Movie Score
*****************************/
const MovieScoreContainer = sc.div`
  height: 50px;
  position: relative;
  width: 50px;
`;

const MovieScoreSVGContainer = sc.svg.attrs({
  height: "100%",
  viewBox: "0 0 36 36",
  width: "100%"
})``;

const TrackPath = sc.path.attrs({
  d:
    "M18 2.0845a 15.9155 15.9155 0 0 1 0 31.831a 15.9155 15.9155 0 0 1 0 -31.831"
})`
  fill: none;
  stroke: ${colors.scoreTrack};
  stroke-width: 2.5;
`;

const ScorePath = sc.path.attrs({
  d:
    "M18 2.0845a 15.9155 15.9155 0 0 1 0 31.831a 15.9155 15.9155 0 0 1 0 -31.831",
  strokeDasharray: "0, 100"
})`
  animation: ${props => ShowScore(props.score)} 1.5s 0.5s ease forwards;
  fill: none;
  stroke: ${props =>
    props.score < 7
      ? props.score < 5.7 ? colors.scoreBad : colors.scoreMid
      : colors.scoreHigh};
  stroke-width: 3;
  stroke-linecap: butt;
`;

const ScoreText = sc.span`
  display: block;
  font-size: 0.75rem;
  position: absolute;
  text-align: center;
  top: 50%;
  transform: translateY(calc(-50% + 1px));
  width: 100%;
`;

const MovieScore = ({ score }) => {
  return (
    <MovieScoreContainer>
      <MovieScoreSVGContainer>
        <TrackPath />
        <ScorePath score={score} />
      </MovieScoreSVGContainer>
      <ScoreText>
        {score.toString().length === 1 ? `${score}0` : score}
      </ScoreText>
    </MovieScoreContainer>
  );
};

MovieScore.propTypes = {
  score: PropTypes.number.isRequired
};

/*****************************
Movie Services
*****************************/
const MovieServicesListContainer = sc.ul`
  display: flex;
  height: 35px;
  opacity: 1;
  transition: opacity 0.5s ease;

  ${props =>
    props.dim &&
    `
    opacity: 0;
  `};
`;

const MovieServicesListItem = sc.li`
  height: 35px;

  & + li {
    padding-left: ${space.hori};
  }

  & img {
    display: block;
    height: 35px;
    width: 35px;
  }
`;

class MovieServices extends PureComponent {
  handleClick(service) {
    Firebase.TrackClick(this.props.title, service);
  }

  render() {
    return (
      <MovieServicesListContainer dim={this.props.dim}>
        {this.props.services.imdb ? (
          <MovieServicesListItem>
            <a
              href={`https://www.imdb.com/title/${this.props.services.imdb}`}
              onClick={() => {
                this.handleClick("imdb");
              }}
            >
              <img
                src={`https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/services/imdb.jpg?raw=true`}
                alt="Visit on IMDB"
              />
            </a>
          </MovieServicesListItem>
        ) : null}

        {this.props.services.netflix ? (
          <MovieServicesListItem>
            <a
              href={this.props.services.netflix}
              onClick={() => {
                this.handleClick("netflix");
              }}
            >
              <img
                src={`https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/services/netflix.jpg?raw=true`}
                alt="Watch now on Netflix"
              />
            </a>
          </MovieServicesListItem>
        ) : null}
        
        {this.props.services.itunes
          ? <ListItem>
            <a
              href={this.props.services.itunes}
              onClick={() => { this.handleClick('itunes'); }}
            >
              <img src={`https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/services/itunes.jpg?raw=true`} alt="Watch now on iTunes" height="35"/>
            </a>
          </ListItem>
          : null
        }

        {this.props.services.shudder ? (
          <MovieServicesListItem>
            <a
              href={this.props.services.shudder}
              onClick={() => {
                this.handleClick("shudder");
              }}
            >
              <img
                src={`https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/services/shudder.jpg?raw=true`}
                alt="Watch now on Shudder"
              />
            </a>
          </MovieServicesListItem>
        ) : null}

        {this.props.services.youtube ? (
          <MovieServicesListItem>
            <a
              href={this.props.services.youtube}
              onClick={() => {
                this.handleClick("youtube");
              }}
            >
              <img
                src={`https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/services/youtube.jpg?raw=true`}
                alt="Watch now on Youtube"
              />
            </a>
          </MovieServicesListItem>
        ) : null}

        {this.props.services.amazon ? (
          <MovieServicesListItem>
            <a
              href={this.props.services.amazon}
              onClick={() => {
                this.handleClick("amazon");
              }}
            >
              <img
                src={`https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/services/amazon.jpg?raw=true`}
                alt="Watch now on Amazon"
              />
            </a>
          </MovieServicesListItem>
        ) : null}

        {this.props.services.hulu ? (
          <MovieServicesListItem>
            <a
              href={this.props.services.hulu}
              onClick={() => {
                this.handleClick("hulu");
              }}
            >
              <img
                src={`https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/services/hulu.jpg?raw=true`}
                alt="Watch now on Hulu"
              />
            </a>
          </MovieServicesListItem>
        ) : null}
      </MovieServicesListContainer>
    );
  }
}

MovieServices.propTypes = {
  dim: PropTypes.bool.isRequired,
  title: PropTypes.string.isRequired,
  services: PropTypes.shape({
    netflix: PropTypes.string,
    hulu: PropTypes.string,
    shudder: PropTypes.string,
    youtube: PropTypes.string,
    amazon: PropTypes.string,
    imdb: PropTypes.string
  }).isRequired
};

/*****************************
Movie Trailer
*****************************/
const MovieTrailerContainer = sc.div`
  bottom: 0;
  left: 0;
  position: absolute;
  right: 0;
  top: 0;
`;

const IFrame = sc.iframe.attrs({
  frameBorder: 0,
  height: "100%",
  src: props => props.src,
  width: "100%"
})`
  height: 100%;
  width: 100%;
`;

const MovieTrailer = ({ trailer }) => {
  return (
    <MovieTrailerContainer>
      <IFrame
        src={`https://www.youtube.com/embed/${trailer}?rel=0&amp;controls=0&amp;showinfo=0;autoplay=1`}
      />
    </MovieTrailerContainer>
  );
};

MovieTrailer.propTypes = {
  trailer: PropTypes.string.isRequired
};

/*****************************
Nav
*****************************/
const NavList = styled.ul`
  display: flex;
  height: calc(${size.headerHeight} - calc(${space.default} * 2));
`;

const NavItem = styled.li`
  align-self: center;
  color: #999;
  font: 1.5rem/1 ${fonts.raleway};
  padding: 0 ${space.hori};

  & + li {
    border-left: 1px solid ${colors.secondary};
  }

  a {
    color: inherit;
    text-decoration: none;
    transition: color 0.25s ease;

    &:hover {
      color: #aaa;
    }
  }
`;

const Nav = () => (
  <nav>
    <NavList>
      <NavItem>
        <a
          href="https://yuschick.github.io/31-Nights-of-Horror-2017/"
          target="_blank"
          rel="noopener noreferrer"
          title="31 Nights of Horror"
        >
          2017
        </a>
      </NavItem>
      <NavItem>
        <a
          href="http://www.danyuschick.com/31-nights-of-horror/"
          target="_blank"
          rel="noopener noreferrer"
          title="31 Nights of Horror"
        >
          2016
        </a>
      </NavItem>
      <NavItem>
        <a
          href="https://yuschick.github.io/31-Nights-of-Horror-2015/"
          target="_blank"
          rel="noopener noreferrer"
          title="31 Nights of Horror"
        >
          2015
        </a>
      </NavItem>
    </NavList>
  </nav>
);

/*****************************
Social Nav
*****************************/
const SocialNavContainer = sc.section`
  background: ${colors.black};
  bottom: -40px;
  padding: calc(${space.vert} / 2) ${space.hori};
  position: absolute;
  right: 0;
`;

const SocialNavList = sc.ul`
  box-shadow: 0px 0px 22px 11px rgba(0, 0, 0, 0.75);
  display: flex;
`;

const SocialNavItem = sc.li`
  cursor: pointer;
  opacity: 0.85;
  transition: opacity 0.25s ease;

  &:hover {
    opacity: 1;
  }

  & svg {
    display: block;
  }

  & + li {
    margin-left: ${space.hori};
  }
`;

const SocialIcon = sc.img.attrs({
  src: props => props.src,
  alt: props => props.alt
})`
  display: block;
  height: 24px;
  width: auto;
`;

const shareUrl = "https://bit.ly/2wqncxt";
const shareTitle =
  "31 Nights of Horror - 2018. 31 Movies for a terrifying October.";

const handleClick = type => {
  Firebase.TrackClick("Share", type);
};

const SocialNav = () => (
  <SocialNavContainer>
    <SocialNavList>
      <SocialNavItem>
        <a
          href="https://github.com/yuschick/31-Nights-of-Horror-2018"
          target="_blank"
          rel="noopener noreferrer"
          title="31 Nights of Horror"
          onClick={() => {
            handleClick("GitHub");
          }}
        >
          <SocialIcon
            src={`https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/services/github.jpg?raw=true`}
            alt="Visit on Github"
          />
        </a>
      </SocialNavItem>
    </SocialNavList>
  </SocialNavContainer>
);

/*****************************
Title and Tagline
*****************************/
const MovieTitle = sc.h2`
  color: ${colors.white};
  font: 2.75rem/1 ${fonts.oswald};
  -webkit-text-fill-color: ${colors.white};
  -webkit-text-stroke: 1px ${colors.black};
  text-shadow: 3px 3px 0 #000, -1px -1px 0 #000, 1px -1px 0 #000,
    -1px 1px 0 #000, 1px 1px 0 #000;
  text-transform: uppercase;
`;

const MovieTagLine = sc.h3`
  color: ${colors.lightGrey};
  font: 1.2rem/1.15 ${fonts.raleway};
  padding: calc(${space.vert} / 2) 0;
`;

const TitleAndTagline = ({ title, tagline }) => {
  return [
    <MovieTitle key="title">{title}</MovieTitle>,
    <MovieTagLine key="tagline">{tagline}</MovieTagLine>
  ];
};

TitleAndTagline.propTypes = {
  title: PropTypes.string.isRequired,
  tagline: PropTypes.string.isRequired
};

/*****************************
 ********* CONTAINERS *********
 *****************************/

/*****************************
Calendar
*****************************/
class Calendar extends React.Component {
  constructor() {
    super();
    this.state = {
      inView: true
    };

    FB.init();
  }

  componentDidMount() {
    window.addEventListener('focus', () => {
      this.setState({ inView: true });
    });

    window.addEventListener('blur', () => {
      this.setState({ inView: false });
    });
  }

  componentWillUnmount() {
    window.removeEventListener('focus', () => {
      this.setState({ inView: true });
    });

    window.removeEventListener('blur', () => {
      this.setState({ inView: false });
    });
  }

  detectInnerWidth() {
    return window.innerWidth <= 750;
  }
  
  render() {
    return (
      <div>
        <Header />
        <main>
          {movieList.map(movie => {
            return (
              <MovieScreen
                id={movie.movieId}
                day={movie.day}
                date={movie.date}
                backdrop={this.detectInnerWidth() ? movie.backdropSM : movie.backdrop}
                services={movie.services}
                focus={movie.focus}
                inView={this.state.inView}
                />
            );
          })}
        </main>
      </div>
    );
  }
}

/*****************************
Movie Screen
*****************************/
const NewGridContainer = sc.section.attrs({
  id: props => props.id
})`
  background: url(${props => props.backdrop}) top left;
  background-size: cover;
  display: ${props => (props.loading || props.preloading ? "block" : "grid")};
  grid-gap: 1rem;
  grid-template-areas:
      ". . ."
      ". D ."
      ". C ."
      ". . .";
  grid-template-columns: auto fit-content(90%) auto;
  grid-template-rows: 2rem 40px fit-content(50%) auto;
  margin-bottom: 2rem;
  min-height: calc(100vh - ${size.headerHeight});
  opacity: ${props => (props.loading || props.preloading ? 0 : 1)};
  overflow hidden;
  padding-bottom: 2rem;
  position: relative;
  transition: opacity 1s ease;
  width: 100%;

  @media (min-width: 750px) {
    border-bottom: 1rem solid ${colors.black};
    grid-template-areas:
      "a  b  b  c  c  c  c  d  d  d  d  e  f  f  g  g"
      "h  b  b  i  F1 j  j  j  j  k  k  k  f  f  l  m"
      "h  n  n  n  F1 o  o  p  p  p  D  D  D  D  D  m"
      "F2 F2 F2 F2 F1 C  C  C  C  C  C  C  C  C  C  s"
      "F2 F2 F2 F2 F3 C  C  C  C  C  C  C  C  C  C  s"
      "t  t  t  t  F3 C  C  C  C  C  C  C  C  C  C  s"
      "u  u  v  w  x  C  C  C  C  C  C  C  C  C  C  s"
      "u  u  z  w  aa aa aa aa bb bb bb cc cc dd ee ee"
      "ff ff z  w  aa aa aa aa gg gg gg cc cc dd ee ee";
    grid-template-columns: .5fr .75fr repeat(13, 1fr) .75fr;
    grid-template-rows: repeat(2, 1fr) .65fr repeat(3, 1fr) 1.25fr repeat(2, 1fr);
    margin-bottom: 0;
    padding-bottom: 0;
  }

  @media (min-width: 1000px) {
    grid-template-areas:
      "a  b  b  c  c  c  c  d  d  d  d  e  f  f  g  g"
      "h  b  b  i  F1 F1 j  j  j  k  k  k  f  f  l  m"
      "h  n  n  n  F1 F1 o  p  p  p  D  D  D  D  q  m"
      "F2 F2 F2 F2 F1 F1 r  C  C  C  C  C  C  C  s  s"
      "F2 F2 F2 F2 F3 F3 F3 C  C  C  C  C  C  C  s  s"
      "t  t  t  t  F3 F3 F3 C  C  C  C  C  C  C  s  s"
      "u  u  v  w  x  y  y  C  C  C  C  C  C  C  s  s"
      "u  u  z  w  aa aa aa aa bb bb bb cc cc dd ee ee"
      "ff ff z  w  aa aa aa aa gg gg gg cc cc dd ee ee";
  }
`;

class MovieScreen extends PureComponent {
  constructor() {
    super();

    this.state = {
      loading: true,
      preloading: true,
      trailerActive: false,
      movie: {},
      testing: false
    };

    this.toggleTrailer = this.toggleTrailer.bind(this);
  }

  componentDidMount() {
    GetMovieDetails(this.props.id).then((data) => {
      this.formatData(data);
    });
  }

  toggleTrailer() {
    this.setState({ trailerActive: !this.state.trailerActive });
  }

  preloadBackdrop() {
    const img = document.createElement('img');
    img.src = this.props.backdrop;

    img.addEventListener('load', () => {
      this.setState({ preloading: false });
    }, false);
  }

  formatData(data) {
    const backdrop = this.preloadBackdrop();
    const release = Find(data.releases.countries, 'iso_3166_1', 'US') || data.releases.countries[Object.keys(data.releases.countries)[0]];
    const trailer = Find(data.videos.results, 'type', 'Trailer') || Find(data.videos.results, 'type', 'Teaser');
    const language = data.original_language === 'en'
      ? { name: 'English' }
      : Find(data.spoken_languages, 'name', 'English') || data.spoken_languages[0];

    Promise.all([release, trailer, language, backdrop]).then(() => {
      const movie = {
        title: data.title || data.original_title,
        tagline: data.tagline,
        overview: data.overview,
        release: release.release_date.substring(0, 4),
        rating: release.certification || 'NR',
        language: language.name,
        score: data.vote_average,
        trailer: trailer.key,
        services: {
          ...this.props.services,
          imdb: data.imdb_id
        }
      }

      this.setState({ movie, loading: false });
    })
  }

  render() {
    return (
      <NewGridContainer
        id={`movie-${this.props.date}`}
        loading={this.state.loading}
        preloading={this.state.preloading}
        backdrop={this.state.loading || this.state.preloading ? '' : this.props.backdrop}
      >
        {this.state.loading || this.state.preloading
          ? <LoadingScreen />
          : <Grid
            day={this.props.day}
            date={this.props.date}
            movie={this.state.movie}
            dim={this.state.testing || this.state.trailerActive || !this.props.inView}
            trailerActive={this.state.trailerActive}
            toggleTrailer={this.toggleTrailer}
            focus1={this.props.focus === 1}
            focus2={this.props.focus === 2}
            focus3={this.props.focus === 3}
          />
        }
      </NewGridContainer>
    );
  }
}

MovieScreen.propTypes = {
  id: PropTypes.number.isRequired,
  day: PropTypes.string.isRequired,
  date: PropTypes.number.isRequired,
  backdrop: PropTypes.string.isRequired,
  focus: PropTypes.number.isRequired,
  services: PropTypes.shape({
    netflix: PropTypes.string,
    hulu: PropTypes.string,
    shudder: PropTypes.string,
    youtube: PropTypes.string,
    amazon: PropTypes.string,
    imdb: PropTypes.string
  }).isRequired,
  inView: PropTypes.bool.isRequired
}

/*****************************
APIs
*****************************/
const keys = {
  tmdb: "84d2690223f00a8cc05141e0c91c56b8",
  fire: "AIzaSyC8YvGL_rt62if5-PYmriFE5ydEjPaDVQU"
};
const FB = {
  TrackClick(item, type) {
    let data;
    firebase
      .database()
      .ref(`${item}`)
      .once("value")
      .then(res => {
        data = res.val();
        data[type] ? data[type]++ : data[type] = 1;

        firebase
          .database()
          .ref(`${item}`)
          .set(data);
      });
  },

  init() {
    const config = {
      apiKey: keys.fire,
      authDomain: "horror-calendar-2018.firebaseapp.com",
      databaseURL: "https://horror-calendar-2018.firebaseio.com",
      projectId: "horror-calendar-2018",
      storageBucket: "horror-calendar-2018.appspot.com"
    };

    firebase.initializeApp(config);
    this.database = firebase.database();
  }
};

const GetMovieDetails = id => {
  return fetch(
    `https://api.themoviedb.org/3/movie/${id}?language=en-US&api_key=${
      keys.tmdb
    }&append_to_response=releases,videos`
  ).then(data => data.json());
};

/*****************************
Movie List
*****************************/
const movieList = [
  {
    title: 'Dawn of the Dead',
    date: 1,
    day: Days.MONDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/dawn-of-the-dead.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/dawn-of-the-dead-sm.jpg?raw=true',
    movieId: 923,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: '',
      youtube: 'https://www.youtube.com/watch?v=jV_xEwb0ZiQ'
    }
  },
  {
    title: 'The Amityville Horror',
    date: 2,
    day: Days.TUESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-amityville-horror.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-amityville-horror-sm.jpg?raw=true',
    movieId: 11449,
    focus: 1,
    services: {
      netflix: '',
      hulu: 'https://www.hulu.com/movie/the-amityville-horror-f1b7dfea-6678-49a7-8e45-758e8bad119e',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B001NV3ZVG',
      youtube: ''
    }
  },
  {
    title: 'Child\'s Play',
    date: 3,
    day: Days.WEDNESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/childs-play.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/childs-play-sm.jpg?raw=true',
    movieId: 10585,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B000IZ21BS',
      youtube: 'https://www.youtube.com/watch?v=QDqSIsuRDxc',
      itunes: 'https://itunes.apple.com/us/movie/childs-play/id220251867?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Maniac',
    date: 4,
    day: Days.THURSDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/maniac.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/maniac-sm.jpg?raw=true',
    movieId: 103620,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B00F7H1SDY',
      youtube: '',
      itunes: 'https://itunes.apple.com/us/movie/maniac/id658109926?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'House of 1000 Corpses',
    date: 5,
    day: Days.FRIDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/house-of-1000-corpses.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/house-of-1000-corpses-sm.jpg?raw=true',
    movieId: 2662,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B000JNQ1HE',
      youtube: 'https://www.youtube.com/watch?v=Kg6-E2KNOso',
      itunes: 'https://itunes.apple.com/us/movie/house-of-1000-corpses/id219953731?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Split',
    date: 6,
    day: Days.SATURDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/split.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/split-sm.jpg?raw=true',
    movieId: 381288,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B01MYFLG5H',
      youtube: 'https://www.youtube.com/watch?v=fRXxlS48pkQ'
    }
  },
  {
    title: 'The House at the End of Time',
    date: 7,
    day: Days.SUNDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-house-at-the-end-of-time.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-house-at-the-end-of-time-sm.jpg?raw=true',
    movieId: 207686,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B00O7HNDLU',
      youtube: ''
    }
  },
  {
    title: 'The Girl With All the Gifts',
    date: 6,
    day: Days.MONDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-girl-with-all-the-gifts.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-girl-with-all-the-gifts-sm.jpg?raw=true',
    movieId: 375366,
    focus: 2,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B06VXZJ4CJ',
      youtube: 'https://www.youtube.com/watch?v=odLorGwE9EQ',
      itunes: 'https://itunes.apple.com/us/movie/the-girl-with-all-the-gifts/id1199019294?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'The Girl Next Door',
    date: 9,
    day: Days.TUESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-girl-next-door.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-girl-next-door-sm.jpg?raw=true',
    movieId: 15356,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: '',
      youtube: ''
    }
  },
  {
    title: 'Dead Silence',
    date: 10,
    day: Days.WEDNESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/dead-silence.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/dead-silence-sm.jpg?raw=true',
    movieId: 14001,
    focus: 2,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B000T2NATC',
      youtube: '',
      itunes: 'https://itunes.apple.com/us/movie/dead-silence-unrated-2007/id315045965?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Hidden',
    date: 11,
    day: Days.THURSDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/hidden.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/hidden-sm.jpg?raw=true',
    movieId: 360784,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B0143H1RHU',
      youtube: 'https://www.youtube.com/watch?v=bZI0j94LRhg',
      itunes: 'https://itunes.apple.com/us/movie/hidden/id1030976725?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'It',
    date: 12,
    day: Days.FRIDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/it.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/it-sm.jpg?raw=true',
    movieId: 346364,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/dp/B0756VMDV5',
      youtube: 'https://www.youtube.com/watch?v=NKYqOT2xMGE'
    }
  },
  {
    title: 'Life',
    date: 13,
    day: Days.SATURDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/life.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/life-sm.jpg?raw=true',
    movieId: 395992,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: '',
      youtube: 'https://www.youtube.com/watch?v=7csml5A7Ciw'
    }
  },
  {
    title: 'Session 9',
    date: 14,
    day: Days.SUNDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/session-9.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/session-9-sm.jpg?raw=true',
    movieId: 10972,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: '',
      youtube: ''
    }
  },
  {
    title: 'The Beyond',
    date: 15,
    day: Days.MONDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-beyond.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/the-beyond-sm.jpg?raw=true',
    movieId: 19204,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: 'https://www.shudder.com/watch/the-beyond/2325608/1',
      amazon: 'https://www.amazon.com/gp/product/B075KMR3W8?camp=1789&creativeASIN=B075KMR3W8&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: ''
    }
  },
  {
    title: 'Ravenouse',
    date: 16,
    day: Days.TUESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/ravenous.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/ravenous-sm.jpg?raw=true',
    movieId: 10212,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B000I9U8K0?camp=1789&creativeASIN=B000I9U8K0&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: 'https://www.youtube.com/watch?v=WkPCOeY5aW0',
      itunes: 'https://itunes.apple.com/us/movie/ravenous/id280626622?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Saw',
    date: 17,
    day: Days.WEDNESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/saw.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/saw-sm.jpg?raw=true',
    movieId: 176,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B000XSEPYQ?camp=1789&creativeASIN=B000XSEPYQ&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: 'https://www.youtube.com/watch?v=Rvf_PfVd7dU',
      itunes: 'https://itunes.apple.com/us/movie/saw/id265727087?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Pumpkinhead',
    date: 18,
    day: Days.THURSDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/pumpkinhead.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/pumpkinhead-sm.jpg?raw=true',
    movieId: 26515,
    focus: 1,
    services: {
      netflix: '',
      hulu: 'http://www.hulu.com/watch/15153',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B000VEPL4U?camp=1789&creativeASIN=B000VEPL4U&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: 'https://www.youtube.com/watch?v=7YR9xq5ZWzI',
      itunes: 'https://itunes.apple.com/us/movie/pumpkinhead/id258692590?uo=4&at=1000l3V2'
    }
  },
  {
    titler: 'Terrifier',
    date: 19,
    day: Days.FRIDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/terrifier.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/terrifier-sm.jpg?raw=true',
    movieId: 420634,
    focus: 3,
    services: {
      netflix: 'http://www.netflix.com/title/81004223',
      hulu: '',
      shudder: '',
      amazon: '',
      youtube: '',
      itunes: 'https://itunes.apple.com/us/movie/terrifier/id1343789417?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Stir of Echoes',
    date: 20,
    day: Days.SATURDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/stir-of-echoes.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/stir-of-echoes-sm.jpg?raw=true',
    movieId: 11601,
    focus: 3,
    services: {
      netflix: '',
      hulu: 'http://www.hulu.com/watch/795802',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B07G1YV6HD?camp=1789&creativeASIN=B07G1YV6HD&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: 'https://www.youtube.com/watch?v=8NC0S8fDlJo',
      itunes: 'https://itunes.apple.com/us/movie/stir-of-echoes/id265725786?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Ouija: Origin of Evil',
    date: 21,
    day: Days.SUNDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/origin-of-evil.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/origin-of-evil-sm.jpg?raw=true',
    movieId: 335796,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: '',
      youtube: 'https://www.youtube.com/watch?v=yLV2deHatsw'
    }
  },
  {
    title: 'Train to Busan',
    date: 22,
    day: Days.MONDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/train-to-busan.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/train-to-busan-sm.jpg?raw=true',
    movieId: 396535,
    focus: 1,
    services: {
      netflix: 'http://www.netflix.com/title/80117824',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B01N2POCJX?camp=1789&creativeASIN=B01N2POCJX&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: 'https://www.youtube.com/watch?v=Dpm5fvZJtaA',
      itunes: 'https://itunes.apple.com/us/movie/train-to-busan/id1163982660?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Wolf Creek',
    date: 23,
    day: Days.TUESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/wolf-creek.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/wolf-creek-smjpg?raw=true',
    movieId: 9885,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B002HU5KII?camp=1789&creativeASIN=B002HU5KII&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: '',
      itunes: 'https://itunes.apple.com/us/movie/wolf-creek/id307017019?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Annabelle: Creation',
    date: 24,
    day: Days.WEDNESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/annabelle-creation.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/annabelle-creation-sm.jpg?raw=true',
    movieId: 396422,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: '',
      youtube: 'https://www.youtube.com/watch?v=jkQ9khXS65s'
    }
  },
  {
    title: 'Ghost Stories',
    date: 25,
    day: Days.THURSDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/ghost-stories.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/ghost-stories-sm.jpg?raw=true',
    movieId: 429417,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B07FKXYPX3?camp=1789&creativeASIN=B07FKXYPX3&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: '',
      itunes: 'https://itunes.apple.com/us/movie/ghost-stories/id1401813378?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Hell House LLC',
    date: 26,
    day: Days.FRIDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/hell-house-llc.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/hell-house-llc-sm.jpg?raw=true',
    movieId: 359246,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B01LYLJBQF?camp=1789&creativeASIN=B01LYLJBQF&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: '',
      itunes: 'https://itunes.apple.com/us/movie/hell-house-llc/id1150208694?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'A Quiet Place',
    date: 27,
    day: Days.SATURDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/a-quiet-place.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/a-quiet-place-sm.jpg?raw=true',
    movieId: 447332,
    focus: 3,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B07BZ2YYPF?camp=1789&creativeASIN=B07BZ2YYPF&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: 'https://www.youtube.com/watch?v=A31oH-EN9dU',
      itunes: 'https://itunes.apple.com/us/movie/a-quiet-place/id1356850151?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Hereditary',
    date: 28,
    day: Days.SUNDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/hereditary.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/hereditary-sm.jpg?raw=true',
    movieId: 493922,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B07DHYZF7H?camp=1789&creativeASIN=B07DHYZF7H&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: '',
      itunes: 'https://itunes.apple.com/us/movie/hereditary/id1382447562?uo=4&at=1000l3V2'
    }
  },
  {
    title: '28 Days Later',
    date: 29,
    day: Days.MONDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/28-days-later.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/28-days-later-sm.jpg?raw=true',
    movieId: 170,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B00C4QIFBO?camp=1789&creativeASIN=B00C4QIFBO&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: 'https://www.youtube.com/watch?v=xL7CMLz3PTo',
      itunes: 'https://itunes.apple.com/us/movie/28-days-later/id569220589?uo=4&at=1000l3V2'
    }
  },
  {
    title: 'Veronica',
    date: 30,
    day: Days.TUESDAY,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/veronica.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/veronica-sm.jpg?raw=true',
    movieId: 441701,
    focus: 1,
    services: {
      netflix: 'http://www.netflix.com/title/80109295',
      hulu: '',
      shudder: '',
      amazon: '',
      youtube: 'https://www.youtube.com/watch?v=Pv-UkJ3y5dE'
    }
  },
  {
    title: 'Ghostland',
    date: 31,
    day: Days.HALLOWEEN,
    backdrop: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/ghostland.jpg?raw=true',
    backdropSM: 'https://github.com/yuschick/31-Nights-of-Horror-2018/blob/master/src/images/backdrops/ghostland-sm.jpg?raw=true',
    movieId: 476299,
    focus: 1,
    services: {
      netflix: '',
      hulu: '',
      shudder: '',
      amazon: 'https://www.amazon.com/gp/product/B07DPW8VP1?camp=1789&creativeASIN=B07DPW8VP1&ie=UTF8&linkCode=xm2&tag=justwatch09-20',
      youtube: 'https://www.youtube.com/watch?v=lkCg4MiVcvQ',
      itunes: 'https://itunes.apple.com/us/movie/incident-in-a-ghostland/id1389640628?uo=4&at=1000l3V2'
    }
  }
]

/*****************************
Mount the full Calendar
*****************************/
ReactDOM.render(<Calendar />, document.getElementById("root"));

            
          
!
999px

Console