diff --git a/backend/schema.gql b/backend/schema.gql index cb445ebd0..336a510ed 100644 --- a/backend/schema.gql +++ b/backend/schema.gql @@ -38,6 +38,7 @@ type ChildrenShowForumForums { created: Int! description: [TextLanguage!]! id: Int! + last_posts: LastPostsShowForumForumsObj! name: [TextLanguage!]! position: Int! } @@ -48,6 +49,7 @@ type CreateForumForumsObj { created: Int! description: [TextLanguage!]! id: Int! + last_posts: LastPostsShowForumForumsObj! name: [TextLanguage!]! position: Int! } @@ -90,6 +92,35 @@ type LastChildShowForumForums { position: Int! } +type LastPostsShowForumForums { + created: Int! + id: Int! + topic: TopicLastPostsShowForumForums! + user: User! +} + +input LastPostsShowForumForumsArgs { + cursor: Int + first: Int + last: Int + sortBy: [LastPostsShowForumForumsSortByArgs!] +} + +type LastPostsShowForumForumsObj { + edges: [LastPostsShowForumForums!]! + pageInfo: PageInfo! +} + +input LastPostsShowForumForumsSortByArgs { + column: LastPostsShowForumForumsSortingColumnEnum! + direction: SortDirectionEnum! +} + +enum LastPostsShowForumForumsSortingColumnEnum { + created + updated +} + enum LayoutAdminInstallEnum { ACCOUNT DATABASE @@ -185,6 +216,7 @@ type Query { first: Int ids: [Int!] last: Int + last_posts_args: LastPostsShowForumForumsArgs parent_id: Int search: String @@ -204,6 +236,7 @@ type Query { first: Int ids: [Int!] last: Int + last_posts_args: LastPostsShowForumForumsArgs parent_id: Int search: String @@ -470,6 +503,7 @@ type ShowForumForumsAdmin { created: Int! description: [TextLanguage!]! id: Int! + last_posts: LastPostsShowForumForumsObj! name: [TextLanguage!]! permissions: PermissionsForumForumsAdmin! position: Int! @@ -498,6 +532,7 @@ type ShowForumForumsWithChildren { created: Int! description: [TextLanguage!]! id: Int! + last_posts: LastPostsShowForumForumsObj! name: [TextLanguage!]! permissions: PermissionsForumForums! position: Int! @@ -581,6 +616,11 @@ enum TopicActions { unlock } +type TopicLastPostsShowForumForums { + id: Int! + title: [TextLanguage!]! +} + """The `Upload` scalar type represents a file upload.""" scalar Upload diff --git a/backend/src/apps/admin/forum/forums/create/create.service.ts b/backend/src/apps/admin/forum/forums/create/create.service.ts index fb9a9b53b..34638a3e5 100644 --- a/backend/src/apps/admin/forum/forums/create/create.service.ts +++ b/backend/src/apps/admin/forum/forums/create/create.service.ts @@ -110,6 +110,17 @@ export class CreateForumForumsService { total_posts: 0, total_topics: 0 }, + last_posts: { + edges: [], + pageInfo: { + count: 0, + totalCount: 0, + hasNextPage: false, + hasPreviousPage: false, + startCursor: null, + endCursor: null + } + }, children: [] }; } diff --git a/backend/src/apps/admin/forum/forums/edit/edit.service.ts b/backend/src/apps/admin/forum/forums/edit/edit.service.ts index cd7932575..03b359418 100644 --- a/backend/src/apps/admin/forum/forums/edit/edit.service.ts +++ b/backend/src/apps/admin/forum/forums/edit/edit.service.ts @@ -15,12 +15,14 @@ import { } from "../../database/schema/forums"; import { TextLanguageInput } from "@/types/database/text-language.type"; import { StatsShowForumForumsService } from "@/apps/forum/forums/show/stats.service"; +import { LastPostsForumForumsService } from "@/apps/forum/forums/show/last_posts/last_posts.service"; @Injectable() export class EditForumForumsService { constructor( private databaseService: DatabaseService, - private statsService: StatsShowForumForumsService + private statsService: StatsShowForumForumsService, + private lastPostsService: LastPostsForumForumsService ) {} protected updateName = async ({ @@ -244,19 +246,40 @@ export class EditForumForumsService { } }); - const stats = await this.statsService.stats({ forumId: id }); + const { stats, topic_ids } = await this.statsService.topicsPosts({ + forumId: id + }); + const last_posts = await this.lastPostsService.lastPosts({ + topicIds: topic_ids, + first: null, + cursor: null, + last: null, + sortBy: null + }); return { ...dataUpdate, + last_posts, _count: { ...stats }, children: await Promise.all( children.map(async item => { - const stats = await this.statsService.stats({ forumId: item.id }); + const { stats, topic_ids } = await this.statsService.topicsPosts({ + forumId: item.id + }); + + const last_posts = await this.lastPostsService.lastPosts({ + topicIds: topic_ids, + first: null, + cursor: null, + last: null, + sortBy: null + }); return { ...item, + last_posts, children: [], _count: { ...stats diff --git a/backend/src/apps/forum/forums/forums.module.ts b/backend/src/apps/forum/forums/forums.module.ts index 2dad1e27b..de00c4f70 100644 --- a/backend/src/apps/forum/forums/forums.module.ts +++ b/backend/src/apps/forum/forums/forums.module.ts @@ -3,13 +3,19 @@ import { Module } from "@nestjs/common"; import { ShowForumForumsResolver } from "./show/show.resolver"; import { ShowForumForumsService } from "./show/show.service"; import { StatsShowForumForumsService } from "./show/stats.service"; +import { LastPostsForumForumsService } from "./show/last_posts/last_posts.service"; @Module({ providers: [ ShowForumForumsResolver, ShowForumForumsService, - StatsShowForumForumsService + StatsShowForumForumsService, + LastPostsForumForumsService ], - exports: [ShowForumForumsService, StatsShowForumForumsService] + exports: [ + ShowForumForumsService, + StatsShowForumForumsService, + LastPostsForumForumsService + ] }) export class ForumsForumModule {} diff --git a/backend/src/apps/forum/forums/show/dto/show.args.ts b/backend/src/apps/forum/forums/show/dto/show.args.ts index b10a4813d..379500dd2 100644 --- a/backend/src/apps/forum/forums/show/dto/show.args.ts +++ b/backend/src/apps/forum/forums/show/dto/show.args.ts @@ -1,5 +1,7 @@ import { ArgsType, Field, Int } from "@nestjs/graphql"; +import { LastPostsShowForumForumsArgs } from "../last_posts/dto/last_posts.args"; + @ArgsType() export class ShowForumForumsArgs { @Field(() => Int, { nullable: true }) @@ -25,4 +27,7 @@ export class ShowForumForumsArgs { @Field(() => String, { nullable: true }) search: string | null; + + @Field(() => LastPostsShowForumForumsArgs, { nullable: true }) + last_posts_args: LastPostsShowForumForumsArgs | null; } diff --git a/backend/src/apps/forum/forums/show/dto/show.obj.ts b/backend/src/apps/forum/forums/show/dto/show.obj.ts index 973255318..eca396b41 100644 --- a/backend/src/apps/forum/forums/show/dto/show.obj.ts +++ b/backend/src/apps/forum/forums/show/dto/show.obj.ts @@ -1,5 +1,7 @@ import { Field, Int, ObjectType, OmitType } from "@nestjs/graphql"; +import { LastPostsShowForumForumsObj } from "../last_posts/dto/last_posts.obj"; + import { PageInfo } from "@/types/database/pagination.type"; import { TextLanguage } from "@/types/database/text-language.type"; @@ -49,6 +51,9 @@ export class ShowForumForums { @Field(() => ShowForumForumsCounts) _count: ShowForumForumsCounts; + + @Field(() => LastPostsShowForumForumsObj) + last_posts: LastPostsShowForumForumsObj; } @ObjectType() @@ -59,7 +64,8 @@ export class FirstShowForumForums extends ShowForumForums { @ObjectType() class LastChildShowForumForums extends OmitType(ShowForumForums, [ - "_count" + "_count", + "last_posts" ] as const) {} @ObjectType() diff --git a/backend/src/apps/forum/forums/show/last_posts/dto/last_posts.args.ts b/backend/src/apps/forum/forums/show/last_posts/dto/last_posts.args.ts new file mode 100644 index 000000000..c51282401 --- /dev/null +++ b/backend/src/apps/forum/forums/show/last_posts/dto/last_posts.args.ts @@ -0,0 +1,36 @@ +import { Field, InputType, Int, registerEnumType } from "@nestjs/graphql"; + +import { SortDirectionEnum } from "@/types/database/sortDirection.type"; + +enum LastPostsShowForumForumsSortingColumnEnum { + created = "created", + updated = "updated" +} + +registerEnumType(LastPostsShowForumForumsSortingColumnEnum, { + name: "LastPostsShowForumForumsSortingColumnEnum" +}); + +@InputType() +class LastPostsShowForumForumsSortByArgs { + @Field(() => LastPostsShowForumForumsSortingColumnEnum) + column: LastPostsShowForumForumsSortingColumnEnum; + + @Field(() => SortDirectionEnum) + direction: SortDirectionEnum; +} + +@InputType() +export class LastPostsShowForumForumsArgs { + @Field(() => Int, { nullable: true }) + cursor: number | null; + + @Field(() => Int, { nullable: true }) + first: number | null; + + @Field(() => Int, { nullable: true }) + last: number | null; + + @Field(() => [LastPostsShowForumForumsSortByArgs], { nullable: true }) + sortBy: LastPostsShowForumForumsSortByArgs[] | null; +} diff --git a/backend/src/apps/forum/forums/show/last_posts/dto/last_posts.obj.ts b/backend/src/apps/forum/forums/show/last_posts/dto/last_posts.obj.ts new file mode 100644 index 000000000..f156c6d45 --- /dev/null +++ b/backend/src/apps/forum/forums/show/last_posts/dto/last_posts.obj.ts @@ -0,0 +1,38 @@ +import { Field, Int, ObjectType } from "@nestjs/graphql"; + +import { PageInfo } from "@/types/database/pagination.type"; +import { TextLanguage } from "@/types/database/text-language.type"; +import { User } from "@/utils/decorators/user.decorator"; + +@ObjectType() +export class TopicLastPostsShowForumForums { + @Field(() => Int) + id: number; + + @Field(() => [TextLanguage]) + title: TextLanguage[]; +} + +@ObjectType() +export class LastPostsShowForumForums { + @Field(() => Int) + id: number; + + @Field(() => Int) + created: number; + + @Field(() => User) + user: User; + + @Field(() => TopicLastPostsShowForumForums) + topic: TopicLastPostsShowForumForums; +} + +@ObjectType() +export class LastPostsShowForumForumsObj { + @Field(() => [LastPostsShowForumForums]) + edges: LastPostsShowForumForums[]; + + @Field(() => PageInfo) + pageInfo: PageInfo; +} diff --git a/backend/src/apps/forum/forums/show/last_posts/last_posts.service.ts b/backend/src/apps/forum/forums/show/last_posts/last_posts.service.ts new file mode 100644 index 000000000..0802f2590 --- /dev/null +++ b/backend/src/apps/forum/forums/show/last_posts/last_posts.service.ts @@ -0,0 +1,82 @@ +import { Injectable } from "@nestjs/common"; +import { and, count, inArray } from "drizzle-orm"; + +import { LastPostsShowForumForumsArgs } from "./dto/last_posts.args"; +import { LastPostsShowForumForumsObj } from "./dto/last_posts.obj"; + +import { DatabaseService } from "@/database/database.service"; +import { + inputPaginationCursor, + outputPagination +} from "@/functions/database/pagination"; +import { forum_posts } from "@/apps/admin/forum/database/schema/posts"; +import { SortDirectionEnum } from "@/types/database/sortDirection.type"; + +interface Args extends LastPostsShowForumForumsArgs { + topicIds: number[]; +} + +@Injectable() +export class LastPostsForumForumsService { + constructor(private databaseService: DatabaseService) {} + + async lastPosts({ + cursor, + first, + last, + sortBy, + topicIds + }: Args): Promise { + const pagination = await inputPaginationCursor({ + cursor, + database: forum_posts, + databaseService: this.databaseService, + first, + last, + primaryCursor: { order: "ASC", key: "id", schema: forum_posts.id }, + defaultSortBy: { + direction: SortDirectionEnum.desc, + column: "created" + }, + sortBy + }); + + const where = + topicIds.length > 0 ? inArray(forum_posts.topic_id, topicIds) : undefined; + + const edges = await this.databaseService.db.query.forum_posts.findMany({ + ...pagination, + where: and(pagination.where, where), + with: { + topic: { + with: { + title: true + } + }, + user: { + with: { + group: { + with: { + name: true + } + }, + avatar: true + } + } + } + }); + + const totalCount = await this.databaseService.db + .select({ count: count() }) + .from(forum_posts) + .where(where); + + return outputPagination({ + edges, + totalCount, + first, + cursor, + last + }); + } +} diff --git a/backend/src/apps/forum/forums/show/show.service.ts b/backend/src/apps/forum/forums/show/show.service.ts index 0ec20a07e..934b5f65e 100644 --- a/backend/src/apps/forum/forums/show/show.service.ts +++ b/backend/src/apps/forum/forums/show/show.service.ts @@ -7,6 +7,7 @@ import { ShowForumForumsWithChildren } from "./dto/show.obj"; import { StatsShowForumForumsService } from "./stats.service"; +import { LastPostsForumForumsService } from "./last_posts/last_posts.service"; import { User } from "@/utils/decorators/user.decorator"; import { AccessDeniedError } from "@/utils/errors/AccessDeniedError"; @@ -46,7 +47,8 @@ interface ShowForumForumsWithPermissions export class ShowForumForumsService { constructor( private databaseService: DatabaseService, - private statsService: StatsShowForumForumsService + private statsService: StatsShowForumForumsService, + private lastPostsService: LastPostsForumForumsService ) {} protected async whereAccessToView({ @@ -84,6 +86,7 @@ export class ShowForumForumsService { ids, isAdmin, last, + last_posts_args, parent_id, search, show_all_forums @@ -158,10 +161,17 @@ export class ShowForumForumsService { } }); - const stats = await this.statsService.stats({ forumId: forum.id }); + const { stats, topic_ids } = await this.statsService.topicsPosts({ + forumId: forum.id + }); + const last_posts = await this.lastPostsService.lastPosts({ + topicIds: topic_ids, + ...last_posts_args + }); return { ...forum, + last_posts, _count: { ...stats }, @@ -178,13 +188,18 @@ export class ShowForumForumsService { } }); - const stats = await this.statsService.stats({ + const { stats, topic_ids } = await this.statsService.topicsPosts({ forumId: child.id }); + const last_posts = await this.lastPostsService.lastPosts({ + topicIds: topic_ids, + ...last_posts_args + }); return { ...child, children, + last_posts, _count: { ...stats } diff --git a/backend/src/apps/forum/forums/show/stats.service.ts b/backend/src/apps/forum/forums/show/stats.service.ts index 28a37f51d..bb8bd1bb9 100644 --- a/backend/src/apps/forum/forums/show/stats.service.ts +++ b/backend/src/apps/forum/forums/show/stats.service.ts @@ -124,15 +124,18 @@ export class StatsShowForumForumsService { return posts[0].count; } - async stats({ forumId }: { forumId: number }): Promise<{ + async topicsPosts({ forumId }: { forumId: number }): Promise<{ children: { id: number; name: TextLanguage[]; }[]; - posts: number; - topics: number; - total_posts: number; - total_topics: number; + stats: { + posts: number; + topics: number; + total_posts: number; + total_topics: number; + }; + topic_ids: number[]; }> { const children = await this.getAllChildren({ forumId }); const totalTopics = await this.getTotalTopics({ @@ -146,11 +149,14 @@ export class StatsShowForumForumsService { const posts = await this.getCountPosts({ topicIds: topics.ids }); return { - total_posts: totalPosts - totalTopics.totalCount, - total_topics: totalTopics.totalCount, children, - topics: topics.count, - posts: posts - topics.count + stats: { + total_posts: totalPosts - totalTopics.totalCount, + total_topics: totalTopics.totalCount, + topics: topics.count, + posts: posts - topics.count + }, + topic_ids: totalTopics.ids }; } } diff --git a/frontend/admin/forum/views/forums/table/hooks/use-forum-forums-admin-api.ts b/frontend/admin/forum/views/forums/table/hooks/use-forum-forums-admin-api.ts index f82316467..ee9958818 100644 --- a/frontend/admin/forum/views/forums/table/hooks/use-forum-forums-admin-api.ts +++ b/frontend/admin/forum/views/forums/table/hooks/use-forum-forums-admin-api.ts @@ -7,7 +7,7 @@ import { buildTree, flattenTree, type FlatTree } from "../use-functions"; import type { ShowForumForumsAdmin } from "@/graphql/hooks"; export interface ShowForumForumsAdminWithChildren - extends Omit { + extends Omit { children: ShowForumForumsAdminWithChildren[]; } diff --git a/frontend/app/[locale]/(apps)/(main)/(container)/forum/[id]/page.tsx b/frontend/app/[locale]/(apps)/(main)/(container)/forum/[id]/page.tsx index 9be593292..e1aeee5f4 100644 --- a/frontend/app/[locale]/(apps)/(main)/(container)/forum/[id]/page.tsx +++ b/frontend/app/[locale]/(apps)/(main)/(container)/forum/[id]/page.tsx @@ -20,7 +20,10 @@ const getData = async ({ id }: { id: string }) => { query: Forum_Forums__Show_Item, variables: { forumId: getIdFormString(id), - first: 25 + first: 25, + lastPostsArgs: { + first: 1 + } }, cache: "force-cache", next: { diff --git a/frontend/app/[locale]/(apps)/(main)/(container)/page.tsx b/frontend/app/[locale]/(apps)/(main)/(container)/page.tsx index 17cc64346..b6ea50f4c 100644 --- a/frontend/app/[locale]/(apps)/(main)/(container)/page.tsx +++ b/frontend/app/[locale]/(apps)/(main)/(container)/page.tsx @@ -15,6 +15,11 @@ const getData = async () => { Forum_Forums__ShowQueryVariables >({ query: Forum_Forums__Show, + variables: { + lastPostsArgs: { + first: 1 + } + }, cache: "force-cache", next: { tags: ["Forum_Forums__Show"] diff --git a/frontend/app/[locale]/global.scss b/frontend/app/[locale]/global.scss index a1423163f..489016513 100644 --- a/frontend/app/[locale]/global.scss +++ b/frontend/app/[locale]/global.scss @@ -13,8 +13,6 @@ a { @apply text-primary; - @apply underline; - @apply hover:no-underline; @apply cursor-pointer; } } diff --git a/frontend/graphql/hooks.ts b/frontend/graphql/hooks.ts index a5887e362..8ffc824f6 100644 --- a/frontend/graphql/hooks.ts +++ b/frontend/graphql/hooks.ts @@ -57,6 +57,7 @@ export type ChildrenShowForumForums = { created: Scalars['Int']['output']; description: Array; id: Scalars['Int']['output']; + last_posts: LastPostsShowForumForumsObj; name: Array; position: Scalars['Int']['output']; }; @@ -68,6 +69,7 @@ export type CreateForumForumsObj = { created: Scalars['Int']['output']; description: Array; id: Scalars['Int']['output']; + last_posts: LastPostsShowForumForumsObj; name: Array; position: Scalars['Int']['output']; }; @@ -115,6 +117,38 @@ export type LastChildShowForumForums = { position: Scalars['Int']['output']; }; +export type LastPostsShowForumForums = { + __typename?: 'LastPostsShowForumForums'; + created: Scalars['Int']['output']; + id: Scalars['Int']['output']; + topic: TopicLastPostsShowForumForums; + user: User; +}; + +export type LastPostsShowForumForumsArgs = { + cursor?: InputMaybe; + first?: InputMaybe; + last?: InputMaybe; + sortBy?: InputMaybe>; +}; + +export type LastPostsShowForumForumsObj = { + __typename?: 'LastPostsShowForumForumsObj'; + edges: Array; + pageInfo: PageInfo; +}; + +export type LastPostsShowForumForumsSortByArgs = { + column: LastPostsShowForumForumsSortingColumnEnum | `${LastPostsShowForumForumsSortingColumnEnum}`; + direction: SortDirectionEnum | `${SortDirectionEnum}`; +}; + +export const LastPostsShowForumForumsSortingColumnEnum = { + created: 'created', + updated: 'updated' +} as const; + +export type LastPostsShowForumForumsSortingColumnEnum = typeof LastPostsShowForumForumsSortingColumnEnum[keyof typeof LastPostsShowForumForumsSortingColumnEnum]; export const LayoutAdminInstallEnum = { account: 'ACCOUNT', database: 'DATABASE', @@ -514,6 +548,7 @@ export type QueryAdmin__Forum_Forums__ShowArgs = { first?: InputMaybe; ids?: InputMaybe>; last?: InputMaybe; + last_posts_args?: InputMaybe; parent_id?: InputMaybe; search?: InputMaybe; show_all_forums?: InputMaybe; @@ -556,6 +591,7 @@ export type QueryForum_Forums__ShowArgs = { first?: InputMaybe; ids?: InputMaybe>; last?: InputMaybe; + last_posts_args?: InputMaybe; parent_id?: InputMaybe; search?: InputMaybe; show_all_forums?: InputMaybe; @@ -866,6 +902,7 @@ export type ShowForumForumsAdmin = { created: Scalars['Int']['output']; description: Array; id: Scalars['Int']['output']; + last_posts: LastPostsShowForumForumsObj; name: Array; permissions: PermissionsForumForumsAdmin; position: Scalars['Int']['output']; @@ -898,6 +935,7 @@ export type ShowForumForumsWithChildren = { created: Scalars['Int']['output']; description: Array; id: Scalars['Int']['output']; + last_posts: LastPostsShowForumForumsObj; name: Array; permissions: PermissionsForumForums; position: Scalars['Int']['output']; @@ -993,6 +1031,12 @@ export const TopicActions = { } as const; export type TopicActions = typeof TopicActions[keyof typeof TopicActions]; +export type TopicLastPostsShowForumForums = { + __typename?: 'TopicLastPostsShowForumForums'; + id: Scalars['Int']['output']; + title: Array; +}; + export type UploadAvatarCoreMembersObj = { __typename?: 'UploadAvatarCoreMembersObj'; dir_folder: Scalars['String']['output']; @@ -1483,20 +1527,23 @@ export type Admin__Forum_Forums__ShowQueryVariables = Exact<{ export type Admin__Forum_Forums__ShowQuery = { __typename?: 'Query', admin__forum_forums__show: { __typename?: 'ShowForumForumsAdminObj', edges: Array<{ __typename?: 'ShowForumForumsAdmin', id: number, position: number, created: number, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'ChildrenShowForumForums', created: number, id: number, position: number, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, _count: { __typename?: 'ShowForumForumsCounts', posts: number, topics: number, total_posts: number, total_topics: number } }>, permissions: { __typename?: 'PermissionsForumForumsAdmin', can_all_create: boolean, can_all_read: boolean, can_all_reply: boolean, can_all_view: boolean, groups: Array<{ __typename?: 'GroupsPermissionsForumForums', can_create: boolean, can_read: boolean, can_reply: boolean, can_view: boolean, id: number }> }, _count: { __typename?: 'ShowForumForumsCounts', posts: number, topics: number, total_posts: number, total_topics: number } }>, pageInfo: { __typename?: 'PageInfo', count: number, endCursor?: number | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: number | null, totalCount: number } } }; -export type Forum_Forums__ShowQueryVariables = Exact<{ [key: string]: never; }>; +export type Forum_Forums__ShowQueryVariables = Exact<{ + lastPostsArgs?: InputMaybe; +}>; -export type Forum_Forums__ShowQuery = { __typename?: 'Query', forum_forums__show: { __typename?: 'ShowForumForumsObj', edges: Array<{ __typename?: 'ShowForumForumsWithChildren', id: number, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'ChildrenShowForumForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'LastChildShowForumForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> }>, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, _count: { __typename?: 'ShowForumForumsCounts', total_posts: number, total_topics: number, topics: number, posts: number } }>, _count: { __typename?: 'ShowForumForumsCounts', total_posts: number, total_topics: number, topics: number, posts: number } }> } }; +export type Forum_Forums__ShowQuery = { __typename?: 'Query', forum_forums__show: { __typename?: 'ShowForumForumsObj', edges: Array<{ __typename?: 'ShowForumForumsWithChildren', id: number, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'ChildrenShowForumForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'LastChildShowForumForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> }>, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, _count: { __typename?: 'ShowForumForumsCounts', total_posts: number, total_topics: number, topics: number, posts: number }, last_posts: { __typename?: 'LastPostsShowForumForumsObj', edges: Array<{ __typename?: 'LastPostsShowForumForums', id: number, created: number, user: { __typename?: 'User', avatar_color: string, id: number, name: string, name_seo: string, avatar?: { __typename?: 'AvatarUser', dir_folder: string, id: number, name: string } | null, group: { __typename?: 'GroupUser', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } }, topic: { __typename?: 'TopicLastPostsShowForumForums', id: number, title: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } }> } }> }> } }; export type Forum_Forums__Show_ItemQueryVariables = Exact<{ cursor?: InputMaybe; first?: InputMaybe; last?: InputMaybe; forumId: Scalars['Int']['input']; + lastPostsArgs?: InputMaybe; }>; -export type Forum_Forums__Show_ItemQuery = { __typename?: 'Query', forum_forums__show: { __typename?: 'ShowForumForumsObj', edges: Array<{ __typename?: 'ShowForumForumsWithChildren', id: number, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'ChildrenShowForumForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'LastChildShowForumForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> }>, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, _count: { __typename?: 'ShowForumForumsCounts', total_posts: number, total_topics: number, topics: number, posts: number } }>, permissions: { __typename?: 'PermissionsForumForums', can_create: boolean }, _count: { __typename?: 'ShowForumForumsCounts', total_posts: number, total_topics: number, topics: number, posts: number } }> }, forum_topics__show: { __typename?: 'ShowTopicsForumsObj', edges: Array<{ __typename?: 'ShowTopicsForums', created: number, id: number, locked: boolean, title: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, user: { __typename?: 'User', id: number, name_seo: string, name: string, avatar_color: string, avatar?: { __typename?: 'AvatarUser', id: number, dir_folder: string, name: string } | null, group: { __typename?: 'GroupUser', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } }, content: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, forum: { __typename?: 'ForumTopicsForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } }>, pageInfo: { __typename?: 'PageInfo', count: number, endCursor?: number | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: number | null, totalCount: number } } }; +export type Forum_Forums__Show_ItemQuery = { __typename?: 'Query', forum_forums__show: { __typename?: 'ShowForumForumsObj', edges: Array<{ __typename?: 'ShowForumForumsWithChildren', id: number, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'ChildrenShowForumForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, children: Array<{ __typename?: 'LastChildShowForumForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> }>, description: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, _count: { __typename?: 'ShowForumForumsCounts', total_posts: number, total_topics: number, topics: number, posts: number }, last_posts: { __typename?: 'LastPostsShowForumForumsObj', edges: Array<{ __typename?: 'LastPostsShowForumForums', created: number, id: number, user: { __typename?: 'User', avatar_color: string, id: number, name: string, name_seo: string, avatar?: { __typename?: 'AvatarUser', dir_folder: string, id: number, name: string } | null, group: { __typename?: 'GroupUser', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } }, topic: { __typename?: 'TopicLastPostsShowForumForums', id: number, title: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } }> } }>, permissions: { __typename?: 'PermissionsForumForums', can_create: boolean } }> }, forum_topics__show: { __typename?: 'ShowTopicsForumsObj', edges: Array<{ __typename?: 'ShowTopicsForums', created: number, id: number, locked: boolean, title: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, user: { __typename?: 'User', id: number, name_seo: string, name: string, avatar_color: string, avatar?: { __typename?: 'AvatarUser', id: number, dir_folder: string, name: string } | null, group: { __typename?: 'GroupUser', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } }, content: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }>, forum: { __typename?: 'ForumTopicsForums', id: number, name: Array<{ __typename?: 'TextLanguage', language_code: string, value: string }> } }>, pageInfo: { __typename?: 'PageInfo', count: number, endCursor?: number | null, hasNextPage: boolean, hasPreviousPage: boolean, startCursor?: number | null, totalCount: number } } }; export type Forum_Forums__Show_Item_MoreQueryVariables = Exact<{ cursor?: InputMaybe; @@ -2516,8 +2563,8 @@ export const Admin__Forum_Forums__Show = gql` } `; export const Forum_Forums__Show = gql` - query Forum_forums__show { - forum_forums__show { + query Forum_forums__show($lastPostsArgs: LastPostsShowForumForumsArgs) { + forum_forums__show(last_posts_args: $lastPostsArgs) { edges { id description { @@ -2551,20 +2598,45 @@ export const Forum_Forums__Show = gql` topics posts } - } - _count { - total_posts - total_topics - topics - posts + last_posts { + edges { + id + user { + avatar { + dir_folder + id + name + } + avatar_color + group { + id + name { + language_code + value + } + } + id + name + name_seo + } + topic { + id + title { + language_code + value + } + } + created + } + } } } } } `; export const Forum_Forums__Show_Item = gql` - query Forum_forums__show_item($cursor: Int, $first: Int, $last: Int, $forumId: Int!) { - forum_forums__show(ids: [$forumId]) { + query Forum_forums__show_item($cursor: Int, $first: Int, $last: Int, $forumId: Int!, $lastPostsArgs: LastPostsShowForumForumsArgs) { + forum_forums__show(ids: [$forumId], last_posts_args: $lastPostsArgs) { edges { id description { @@ -2598,16 +2670,41 @@ export const Forum_Forums__Show_Item = gql` topics posts } + last_posts { + edges { + created + id + user { + avatar { + dir_folder + id + name + } + avatar_color + group { + id + name { + language_code + value + } + } + id + name + name_seo + } + topic { + id + title { + language_code + value + } + } + } + } } permissions { can_create } - _count { - total_posts - total_topics - topics - posts - } } } forum_topics__show( diff --git a/frontend/graphql/queries/forum/forum_forums__show.gql b/frontend/graphql/queries/forum/forum_forums__show.gql index b5bcac9e3..77ea4bba8 100644 --- a/frontend/graphql/queries/forum/forum_forums__show.gql +++ b/frontend/graphql/queries/forum/forum_forums__show.gql @@ -1,5 +1,5 @@ -query Forum_forums__show { - forum_forums__show { +query Forum_forums__show($lastPostsArgs: LastPostsShowForumForumsArgs) { + forum_forums__show(last_posts_args: $lastPostsArgs) { edges { id description { @@ -33,12 +33,37 @@ query Forum_forums__show { topics posts } - } - _count { - total_posts - total_topics - topics - posts + last_posts { + edges { + id + user { + avatar { + dir_folder + id + name + } + avatar_color + group { + id + name { + language_code + value + } + } + id + name + name_seo + } + topic { + id + title { + language_code + value + } + } + created + } + } } } } diff --git a/frontend/graphql/queries/forum/forum_forums__show_item.gql b/frontend/graphql/queries/forum/forum_forums__show_item.gql index d79be009b..052174931 100644 --- a/frontend/graphql/queries/forum/forum_forums__show_item.gql +++ b/frontend/graphql/queries/forum/forum_forums__show_item.gql @@ -3,8 +3,9 @@ query Forum_forums__show_item( $first: Int $last: Int $forumId: Int! + $lastPostsArgs: LastPostsShowForumForumsArgs ) { - forum_forums__show(ids: [$forumId]) { + forum_forums__show(ids: [$forumId], last_posts_args: $lastPostsArgs) { edges { id description { @@ -38,16 +39,41 @@ query Forum_forums__show_item( topics posts } + last_posts { + edges { + created + id + user { + avatar { + dir_folder + id + name + } + avatar_color + group { + id + name { + language_code + value + } + } + id + name + name_seo + } + topic { + id + title { + language_code + value + } + } + } + } } permissions { can_create } - _count { - total_posts - total_topics - topics - posts - } } } forum_topics__show( diff --git a/frontend/themes/1/forum/views/forum/forums/item/item.tsx b/frontend/themes/1/forum/views/forum/forums/item/item.tsx index 66edfa403..a315ffd85 100644 --- a/frontend/themes/1/forum/views/forum/forums/item/item.tsx +++ b/frontend/themes/1/forum/views/forum/forums/item/item.tsx @@ -1,20 +1,27 @@ import { MessagesSquare } from "lucide-react"; import { Link } from "@/i18n"; -import type { ShowForumForumsCounts, TextLanguage } from "@/graphql/hooks"; +import type { + LastPostsShowForumForumsObj, + ShowForumForumsCounts, + TextLanguage +} from "@/graphql/hooks"; import { useTextLang } from "@/hooks/core/use-text-lang"; import { ReadOnlyEditor } from "@/components/editor/read-only/read-only-editor"; import { WrapperItemForum } from "./wrapper-item-forum"; import { ChildButtonItemForum } from "./child"; import { StatsItemForum } from "./stats"; -import { LastPostItemForum } from "./last-post"; +import { LastPostItemForum } from "./last-post/last-post"; export interface ItemForumProps { _count: Pick; description: TextLanguage[]; id: number; + last_posts: Pick; name: TextLanguage[]; - children?: Omit[] | null; + children?: + | Omit[] + | null; } export const ItemForum = ({ @@ -22,6 +29,7 @@ export const ItemForum = ({ children, description, id, + last_posts: { edges: lastPosts }, name }: ItemForumProps) => { const { convertNameToLink, convertText } = useTextLang(); @@ -66,7 +74,7 @@ export const ItemForum = ({ {_count.total_topics > 0 && (
- +
)} diff --git a/frontend/themes/1/forum/views/forum/forums/item/last-post.tsx b/frontend/themes/1/forum/views/forum/forums/item/last-post.tsx deleted file mode 100644 index c86578345..000000000 --- a/frontend/themes/1/forum/views/forum/forums/item/last-post.tsx +++ /dev/null @@ -1,3 +0,0 @@ -export const LastPostItemForum = () => { - return
Last Post - Not Implemented!
; -}; diff --git a/frontend/themes/1/forum/views/forum/forums/item/last-post/last-post.tsx b/frontend/themes/1/forum/views/forum/forums/item/last-post/last-post.tsx new file mode 100644 index 000000000..1ce64d737 --- /dev/null +++ b/frontend/themes/1/forum/views/forum/forums/item/last-post/last-post.tsx @@ -0,0 +1,46 @@ +import { useTranslations } from "next-intl"; + +import { AvatarUser } from "@/components/user/avatar/avatar-user"; +import type { LastPostsShowForumForums } from "@/graphql/hooks"; +import { DateFormat } from "@/components/date-format"; +import { UserLastPostItemForum } from "./user"; +import { useTextLang } from "@/hooks/core/use-text-lang"; +import { WrapperLastPostItemForum } from "./wrapper"; +import { Link } from "@/i18n"; + +interface Props { + lastPosts: LastPostsShowForumForums[]; +} + +export const LastPostItemForum = ({ lastPosts }: Props) => { + const t = useTranslations("forum"); + const { convertNameToLink, convertText } = useTextLang(); + + if (lastPosts.length === 0) return null; + const { created, topic, user } = lastPosts[0]; + + const href = `/topic/${convertNameToLink({ id: topic.id, name: topic.title })}`; + + return ( + + +
+ + {convertText(topic.title)} + +
+ {t.rich("by", { + user: () => , + date: () => + })} +
+
+
+ ); +}; diff --git a/frontend/themes/1/forum/views/forum/forums/item/last-post/user.tsx b/frontend/themes/1/forum/views/forum/forums/item/last-post/user.tsx new file mode 100644 index 000000000..4378eac4e --- /dev/null +++ b/frontend/themes/1/forum/views/forum/forums/item/last-post/user.tsx @@ -0,0 +1,8 @@ +"use client"; + +import { UserLink } from "@/components/user/link/user-link"; +import type { User } from "@/graphql/hooks"; + +export const UserLastPostItemForum = (user: User) => { + return e.stopPropagation()} user={user} />; +}; diff --git a/frontend/themes/1/forum/views/forum/forums/item/last-post/wrapper.tsx b/frontend/themes/1/forum/views/forum/forums/item/last-post/wrapper.tsx new file mode 100644 index 000000000..55ae2d430 --- /dev/null +++ b/frontend/themes/1/forum/views/forum/forums/item/last-post/wrapper.tsx @@ -0,0 +1,33 @@ +/* eslint-disable jsx-a11y/no-static-element-interactions */ +/* eslint-disable jsx-a11y/click-events-have-key-events */ +"use client"; + +import type { ReactNode } from "react"; + +import { useRouter } from "@/i18n"; + +interface Props { + children: ReactNode; + href: string; + className?: string; +} + +export const WrapperLastPostItemForum = ({ + children, + className, + href +}: Props) => { + const { push } = useRouter(); + + return ( +
{ + e.stopPropagation(); + push(href); + }} + className={className} + > + {children} +
+ ); +}; diff --git a/frontend/themes/1/forum/views/forum/forums/views/[id]/topics-list/item.tsx b/frontend/themes/1/forum/views/forum/forums/views/[id]/topics-list/item.tsx index 3e979e106..7b68159e6 100644 --- a/frontend/themes/1/forum/views/forum/forums/views/[id]/topics-list/item.tsx +++ b/frontend/themes/1/forum/views/forum/forums/views/[id]/topics-list/item.tsx @@ -26,7 +26,10 @@ export const ItemTopicListForum = ({ >

- + {convertText(title)}

diff --git a/frontend/themes/1/forum/views/forum/topic/topic-view.tsx b/frontend/themes/1/forum/views/forum/topic/topic-view.tsx index f28ac80fb..76ede64dc 100644 --- a/frontend/themes/1/forum/views/forum/topic/topic-view.tsx +++ b/frontend/themes/1/forum/views/forum/topic/topic-view.tsx @@ -41,7 +41,7 @@ export default function TopicView({
-

+

{convertText(title)}