OurBigBook
web/back/IndexPage.ts
import { GetServerSideProps } from 'next'

import { getLoggedInUser } from 'back'
import { articleLimit } from 'front/config'
import { getOrderAndPage } from 'front/js'
import { IndexPageProps } from 'front/IndexPage'
import { MyGetServerSideProps } from 'front/types'

export const getServerSidePropsIndexHoc = ({
  followed=false,
  itemType=undefined,
}={}): MyGetServerSideProps => {
  return async ({ query, req, res }) => {
    const loggedInUser = await getLoggedInUser(req, res)
    let followedEff = followed
    if (!loggedInUser) {
      followedEff = false;
    }
    let itemTypeEff = itemType
    if (itemTypeEff === undefined) {
      if (loggedInUser) {
        itemTypeEff = 'article'
      } else {
        itemTypeEff = 'topic'
      }
    }
    const getOrderAndPageOpts: {
      defaultOrder?: string;
      urlToDbSort?: any;
    } = {}
    if (itemTypeEff === 'topic') {
      getOrderAndPageOpts.defaultOrder = 'articleCount'
      getOrderAndPageOpts.urlToDbSort = {
        'article-count': 'articleCount'
      }
    }
    const [order, pageNum, err] = getOrderAndPage(req, query.page, getOrderAndPageOpts)
    if (err) { res.statusCode = 422 }
    const offset = pageNum * articleLimit
    const limit = articleLimit
    const sequelize = req.sequelize
    const [[articles, articlesCount], pinnedArticle] = await Promise.all([
      (async () => {
        let articles
        let articlesCount
        let articlesAndCounts
        switch (itemTypeEff) {
          case 'article':
            if (followedEff) {
              articlesAndCounts = await loggedInUser.findAndCountArticlesByFollowedToJson(
                offset, limit, order)
              articles = articlesAndCounts.articles
              articlesCount = articlesAndCounts.articlesCount
            } else {
              articlesAndCounts = await sequelize.models.Article.getArticles({
                sequelize,
                offset,
                order,
                limit,
              })
              articles = await Promise.all(articlesAndCounts.rows.map(
                (article) => {return article.toJson(loggedInUser) }))
              articlesCount = articlesAndCounts.count
            }
            break
          case 'discussion':
              articlesAndCounts = await sequelize.models.Issue.getIssues({
                sequelize,
                includeArticle: true,
                offset,
                order,
                limit,
              })
              articles = await Promise.all(articlesAndCounts.rows.map(
                (article) => {
                  return article.toJson(loggedInUser)
                }))
              articlesCount = articlesAndCounts.count
            break
          case 'topic':
              articlesAndCounts = await sequelize.models.Topic.getTopics({
                sequelize,
                offset,
                order,
                limit,
              })
              articles = await Promise.all(articlesAndCounts.rows.map(
                (article) => {return article.toJson(loggedInUser) }))
              articlesCount = articlesAndCounts.count
            break
          default:
            throw new Error(`unknown itemType: ${itemTypeEff}`)
        }
        return [articles, articlesCount]
      })(),
      sequelize.models.Site.findOne({ include:
        [{
          model: sequelize.models.Article,
          as: 'pinnedArticle',
        }]
      }).then(site => {
        const pinnedArticle = site.pinnedArticle
        if (pinnedArticle) {
          return pinnedArticle.toJson(loggedInUser)
        } else {
          return null
        }
      }),
    ])
    const props: IndexPageProps = {
      articles,
      articlesCount,
      followed: followedEff,
      itemType: itemTypeEff,
      order,
      page: pageNum,
      pinnedArticle,
    }
    if (loggedInUser) {
      props.loggedInUser = await loggedInUser.toJson()
    }
    return { props }
  }
}