From c1865784abc437aacc92aa4b460c20ddfc6c13b3 Mon Sep 17 00:00:00 2001 From: tmalahie Date: Sat, 4 Dec 2021 22:08:52 +0100 Subject: [PATCH] Add topics list page (wip) --- v2/app/pages/forum/category/[id].tsx | 67 +++++++++++++++++++---- v2/node-api/package.json | 2 + v2/node-api/src/forum/forum.controller.ts | 66 ++++++++++++++++------ v2/node-api/yarn.lock | 5 ++ 4 files changed, 112 insertions(+), 28 deletions(-) diff --git a/v2/app/pages/forum/category/[id].tsx b/v2/app/pages/forum/category/[id].tsx index aee9ff1d..38d8211b 100644 --- a/v2/app/pages/forum/category/[id].tsx +++ b/v2/app/pages/forum/category/[id].tsx @@ -3,31 +3,78 @@ import ClassicPage, { commonStyles } from "../../../components/ClassicPage/Class import styles from "../../../styles/Forum.module.scss"; import Link from "next/link" import useLanguage, { plural } from "../../../hooks/useLanguage"; -import useUser from "../../../hooks/useUser"; +import cx from "classnames"; import WithAppContext from "../../../components/WithAppContext/WithAppContext"; import ForumAccount from "../../../components/Forum/Account/Account"; import Ad from "../../../components/Ad/Ad"; +import { formatDate } from "../../../helpers/dates"; +import useFetch from "../../../hooks/useFetch"; +import { useRouter } from "next/dist/client/router"; const ForumCategory: NextPage = () => { const language = useLanguage(); + const router = useRouter(); + const categoryID = +router.query.id; - const category = { - id: 1, - name: "Topics officiels", - description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - } + const { data: categoryPayload } = useFetch(`/api/forum/categories/${categoryID}`); + + // TODO make right API call + const { data: topicsPayload } = useFetch(`/api/forum/topics`); - const categoryID = category.id; return ( -

{category.name}

+

{categoryPayload?.name}

{language ? 'Back to the forum' : 'Retour au forum'}

-

{category.description}

+

{categoryPayload?.description}

{/* TODO handle rights */} - {categoryID &&

{language ? 'New topic' : 'Nouveau topic'}

} + {!!categoryID &&

+ {language ? 'New topic' : 'Nouveau topic'} +

} + + + + + + + + + + + + {topicsPayload?.data.map((topic, i) => ( + + + + + ))} +
{language ? 'Subjects' : 'Sujets'}{language ? 'Author' : 'Auteur'}{language ? 'Msgs nb' : 'Nb msgs'}{language ? 'Last message' : 'Dernier message'}
+ {topic.title} + + { + topic.firstMessage.author + ? {topic.firstMessage.author.name} + : {language ? "Deleted account" : "Compte supprimé"} + } + {topic.nbMessages} + {formatDate(topic.lastMessage.date, { + language, + mode: "datetime", + prefix: true, + case: "capitalize", + includeYear: "always", + includeSeconds: true + })} +
+ {/* TODO add pagination */} +

+ {/* TODO handle rights */} + {!!categoryID && {language ? 'New topic' : 'Nouveau topic'}} + {language ? 'Back to the forum' : 'Retour au forum'}
+ {language ? 'Back to home' : 'Retour à l\'accueil'} +

); } diff --git a/v2/node-api/package.json b/v2/node-api/package.json index f62a1fae..84dd5ae0 100644 --- a/v2/node-api/package.json +++ b/v2/node-api/package.json @@ -27,6 +27,7 @@ "@nestjs/platform-express": "^8.0.0", "@nestjs/typeorm": "^8.0.2", "cookie-parser": "^1.4.5", + "lodash": "^4.17.21", "luxon": "^2.1.1", "mysql2": "^2.3.3-rc.0", "nestjs-i18n": "^8.1.9", @@ -42,6 +43,7 @@ "@types/cookie-parser": "^1.4.2", "@types/express": "^4.17.13", "@types/jest": "^27.0.1", + "@types/lodash": "^4.14.177", "@types/luxon": "^2.0.7", "@types/node": "^16.0.0", "@types/supertest": "^2.0.11", diff --git a/v2/node-api/src/forum/forum.controller.ts b/v2/node-api/src/forum/forum.controller.ts index 60c9db09..6934b134 100644 --- a/v2/node-api/src/forum/forum.controller.ts +++ b/v2/node-api/src/forum/forum.controller.ts @@ -1,18 +1,19 @@ -import { Controller, Get, Req } from '@nestjs/common'; +import { Controller, Get, NotFoundException, Param, Req } from '@nestjs/common'; import { Auth } from '../auth/auth.decorator'; import { I18n, I18nContext } from 'nestjs-i18n'; import { AuthUser, GetUser } from 'src/user/user.decorator'; -import { EntityManager, MoreThan } from 'typeorm'; +import { EntityManager, In, MoreThan } from 'typeorm'; import { Message } from './message.entity'; import { Topic } from './topic.entity'; import { Category } from './category.entity'; import { Profile } from 'src/user/profile.entity'; import { DateTime } from 'luxon'; +import { keyBy, pick } from 'lodash' @Controller("/forum") export class ForumController { - constructor(private em: EntityManager) {} + constructor(private em: EntityManager) { } - @Auth({loadRoles: true}) + @Auth({ loadRoles: true }) @Get("/topics") async getTopics(@GetUser() user: AuthUser, @I18n() i18n: I18nContext) { let topics = await this.em.find(Topic, { @@ -31,16 +32,24 @@ export class ForumController { ...topics.filter(t => t.getLanguage() === "fr") ]; } + const firstMessages = await this.em.find(Message, { + where: { + id: 1, + topic: In(topics.map(topic => topic.id)) + }, + relations: ["author"] + }); + const firstMessagesByTopic = keyBy(firstMessages, "topic"); const lastMessages = await Promise.all(topics.map(topic => this.em.findOne(Message, { - where: { - topic: topic.id - }, - relations: ["author"], - order: { - id: "DESC" - } - }))); - const data = topics.map((topic,i) => ({ + where: { + topic: topic.id + }, + relations: ["author"], + order: { + id: "DESC" + } + }))); + const data = topics.map((topic, i) => ({ id: topic.id, title: topic.title, nbMessages: topic.nbMessages, @@ -48,9 +57,13 @@ export class ForumController { id: topic.category.id, name: topic.category.getName(i18n.detectedLanguage) }, + firstMessage: { + author: firstMessagesByTopic[topic.id]?.author && pick(firstMessagesByTopic[topic.id].author, "id", "name"), + date: firstMessagesByTopic[topic.id]?.date + }, lastMessage: { - author: lastMessages[i].author, - date: lastMessages[i].date + author: lastMessages[i]?.author && pick(lastMessages[i].author, "id", "name"), + date: lastMessages[i]?.date } })) return { @@ -62,7 +75,7 @@ export class ForumController { async getCategories(@I18n() i18n: I18nContext) { const lang = i18n.detectedLanguage; const categories = await this.em.find(Category); - const sortedCategories = categories.sort((c1,c2) => c1.getOrder(lang) - c2.getOrder(lang)) + const sortedCategories = categories.sort((c1, c2) => c1.getOrder(lang) - c2.getOrder(lang)) const categoriesWithData = await Promise.all(sortedCategories.map(async category => { const nbTopics = await this.em.count(Topic, { where: { @@ -77,13 +90,13 @@ export class ForumController { lastMessageDate: "DESC" } }); - return { + return { category, nbTopics, lastTopic }; })) - const data = categoriesWithData.map(({category,nbTopics,lastTopic}) => ({ + const data = categoriesWithData.map(({ category, nbTopics, lastTopic }) => ({ id: category.id, name: category.getName(lang), description: category.getDescription(lang), @@ -102,6 +115,23 @@ export class ForumController { } } + @Get("/categories/:id") + async getCategory(@I18n() i18n: I18nContext, @Param("id") id: number) { + const lang = i18n.detectedLanguage; + const category = await this.em.findOne(Category, { + where: { + id + } + }); + if (!category) + throw new NotFoundException(`Category with id ${id} does not exist`); + return { + id: category.id, + name: category.getName(lang), + description: category.getDescription(lang) + }; + } + @Get("/stats") async getStats() { const messagesStats = await this.em.getRepository(Topic).createQueryBuilder("t") diff --git a/v2/node-api/yarn.lock b/v2/node-api/yarn.lock index 21352545..1835f837 100644 --- a/v2/node-api/yarn.lock +++ b/v2/node-api/yarn.lock @@ -879,6 +879,11 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/lodash@^4.14.177": + version "4.14.177" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.177.tgz#f70c0d19c30fab101cad46b52be60363c43c4578" + integrity sha512-0fDwydE2clKe9MNfvXHBHF9WEahRuj+msTuQqOmAApNORFvhMYZKNGGJdCzuhheVjMps/ti0Ak/iJPACMaevvw== + "@types/luxon@^2.0.7": version "2.0.7" resolved "https://registry.yarnpkg.com/@types/luxon/-/luxon-2.0.7.tgz#6189930542400e2c48b4d5ed06c4f136ee38bb1a"