Skip to content

Add Read More component to Story pages

shraddha-kesari edited this page Feb 1, 2023 · 1 revision

To implement Read more component, we need to create a js and a css file. At first, we need to fetch the stories from the API and then show them in the front end.

Below is the code snippet for read more component

import { StoryCard } from "@quintype/arrow";
import React, { useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import get from "lodash/get";

import "./read-more-stories.m.css";

// Fetching the stories from the API
const getStories = async (limit, offset = 0) => {
  const FIELDS =
    "id,authors,headline,slug,hero-image-s3-key,hero-image-metadata,published-at,first-published-at,last-published-at,alternative,author-name,author-id,sections,story-template,url,read-time";

  const { stories } = await (
    await fetch(`/api/v1/stories?fields=${FIELDS}&limit=${limit}&offset=${offset}&sort=latest-published`)
  ).json();

  return stories;
};

// Read more component
const ReadMoreStories = () => {
  const [alsoReadStories, setAlsoReadStories] = useState(null);
  const [offset, setOffset] = useState(0);
  const [checker, setChecker] = useState(4);


  const getAlsoReadStories = async () => {
    const stories = await getStories(5); // Mention the number of stories to be picked up initially
    setAlsoReadStories(stories);
  };

  useEffect(() => {
    getAlsoReadStories();
  }, []);

  if (!alsoReadStories) {
    return null;
  }

  const config = {
    localizationConfig: { showAuthor: false, showTime: false, showReadTime: false }, // Customise your component with this localization config
    fallbackImageUrl: fallbackImageUrl, // This is a hard coded url 
    showSection: false, 
  };

  const dispatch = useDispatch();

  const setLoading = (isloading) => {
    dispatch(isloading ? { type: "QT-PAGE_LOADING" } : { type: "QT-PAGE_FINISHED_LOADING" });
  };

// When clicked on the read more button, it fetches the next 4 stories to show
  const fetchStories = async () => {
    setLoading(true);
    const currentOffset = offset + 4; // Number can be customized
    setChecker(checker + 4);
    setOffset(currentOffset);

    const stories = await getStories(4, currentOffset + 1);
    setAlsoReadStories(alsoReadStories.concat(stories));
    setLoading(false);
  };

  return (
    <div styleName="wrapper" className="read-more-wrapper">
      <div styleName="heading">Related Stories</div>
      <div styleName="stories-wrapper">
        {alsoReadStories.slice(0, checker).map((story, index) => (
          <StoryCard story={story} config={config} aspectRatio={[[16, 9]]} isHorizontalWithImageLast key={index} />
        ))}
      </div>
      {alsoReadStories.length > checker && (
        <button aria-label="read-more-button" onClick={fetchStories} styleName="read-more-button">
          Read More
        </button>
      )}
    </div>
  );
};

export default ReadMoreStories;

Import this CSS file to your JS file. CSS styles are mentioned below - replace the variables and add your own styles

.wrapper {
  padding-bottom: 3.2rem;
  margin-bottom: 2.4rem;
  border-bottom: solid 1px #dedede;

  @media (min-width: 768px) {
    margin-bottom: 3.2rem;
  }
}

.heading {
  position: relative;
  font-family: var(--primary-font);
  font-size: 2rem;
  font-weight: var(--bold);
  margin-bottom: 1.6rem;

  &::before {
    content: "";
    width: 2.4rem;
    height: 0.4rem;
    background-color: var(--brand-secondary);
    position: absolute;
    top: 100%;
    left: 0;
  }

  @media (min-width: 768px) {
    margin-bottom: 3.2rem;
  }
}

.stories-wrapper {
  :global {
    .arr--story-card {
      margin-bottom: 2.4rem;
    }

    .arr--sub-headline {
      display: none;
    }

    .section-tag {
      margin-bottom: 1.2rem;
      position: relative;
      color: #333333;
      text-transform: uppercase;

      &::before {
        content: "";
        width: 1.8rem ;
        height: 0.2rem;
        background-color: var(--brand-secondary);
        position: absolute;
        top: 100%;
      }
    }

    .author-name,
    time,
    .arr--read-time {
      color: #636363;
    }

    .arr-separator {
      font-size: 1.4rem !important;
    }

    h6 {
      margin-bottom: 0.8rem;
      color: #333333;
    }
  }

  @media (min-width: 768px) {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    grid-gap: 2.4rem;

    :global {
      .arr--story-card {
        margin-bottom: 0;
        flex-direction: column;
      }

      .arr--hero-image {
        padding-left: 0;
        padding-bottom: 0.8rem;
        flex-grow: 0;
      }
    }
  }
}

.read-more-button {
  font-family: var(--secondary-font);
  font-size: 1.6rem;
  font-weight: var(--bold);
  color: var(--white);
  padding: 0.8rem 2.4rem;
  background-color: var(--brand-primary);
  border-radius: 3px;
  display: block;
  margin: 1.6rem auto 0;
  border: none;
}

Import this component to your story template file like below -

<ReadMoreStories />