diff --git a/web/prisma/migrations/20250706180118_add_comment_section_message/migration.sql b/web/prisma/migrations/20250706180118_add_comment_section_message/migration.sql new file mode 100644 index 0000000..a4f6aea --- /dev/null +++ b/web/prisma/migrations/20250706180118_add_comment_section_message/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Service" ADD COLUMN "commentSectionMessage" TEXT; diff --git a/web/prisma/schema.prisma b/web/prisma/schema.prisma index 5fa5f75..6886c46 100644 --- a/web/prisma/schema.prisma +++ b/web/prisma/schema.prisma @@ -407,6 +407,7 @@ model Service { affiliatedUsers ServiceUser[] @relation("ServiceUsers") strictCommentingEnabled Boolean @default(false) + commentSectionMessage String? @@index([listedAt]) @@index([approvedAt]) diff --git a/web/prisma/seed.ts b/web/prisma/seed.ts index 41a2387..6594344 100755 --- a/web/prisma/seed.ts +++ b/web/prisma/seed.ts @@ -721,6 +721,7 @@ const generateFakeService = (users: User[]) => { { probability: 0.33 } ), strictCommentingEnabled: faker.datatype.boolean(0.33333), + commentSectionMessage: faker.helpers.maybe(() => faker.lorem.paragraph(), { probability: 0.3 }), } as const satisfies Prisma.ServiceCreateInput } diff --git a/web/src/actions/admin/service.ts b/web/src/actions/admin/service.ts index 5fb70fe..5d60166 100644 --- a/web/src/actions/admin/service.ts +++ b/web/src/actions/admin/service.ts @@ -64,6 +64,7 @@ const serviceSchemaBase = z.object({ serviceVisibility: z.nativeEnum(ServiceVisibility), internalNote: z.string().optional(), strictCommentingEnabled: z.boolean().optional().default(false), + commentSectionMessage: z.string().trim().min(3).max(1000).optional().nullable().default(null), }) // Define schema for the create action input @@ -129,6 +130,7 @@ export const adminServiceActions = { verificationProofMd: input.verificationProofMd, acceptedCurrencies: input.acceptedCurrencies, strictCommentingEnabled: input.strictCommentingEnabled, + commentSectionMessage: input.commentSectionMessage, // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing referral: input.referral || null, serviceVisibility: input.serviceVisibility, @@ -250,6 +252,7 @@ export const adminServiceActions = { verificationProofMd: input.verificationProofMd, acceptedCurrencies: input.acceptedCurrencies, strictCommentingEnabled: input.strictCommentingEnabled, + commentSectionMessage: input.commentSectionMessage, // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing referral: input.referral || null, serviceVisibility: input.serviceVisibility, diff --git a/web/src/actions/comment.ts b/web/src/actions/comment.ts index 9356e83..18c3969 100644 --- a/web/src/actions/comment.ts +++ b/web/src/actions/comment.ts @@ -17,6 +17,7 @@ import type { CommentStatus, Prisma } from '@prisma/client' const COMMENT_RATE_LIMIT_WINDOW_MINUTES = 2 const MAX_COMMENTS_PER_WINDOW = 1 const MAX_COMMENTS_PER_WINDOW_VERIFIED_USER = 10 +export const COMMENT_ORDER_ID_MAX_LENGTH = 600 export const commentActions = { vote: defineProtectedAction({ @@ -103,7 +104,7 @@ export const commentActions = { issueFundsBlocked: z.coerce.boolean().optional(), issueScam: z.coerce.boolean().optional(), issueDetails: z.string().max(120).optional(), - orderId: z.string().max(100).optional(), + orderId: z.string().max(COMMENT_ORDER_ID_MAX_LENGTH).optional(), }) .superRefine((data, ctx) => { if (data.rating && data.parentId) { diff --git a/web/src/components/CommentReply.astro b/web/src/components/CommentReply.astro index b2227c0..0aebd6d 100644 --- a/web/src/components/CommentReply.astro +++ b/web/src/components/CommentReply.astro @@ -1,7 +1,9 @@ --- import { Icon } from 'astro-icon/components' +import { Markdown } from 'astro-remote' import { actions } from 'astro:actions' +import { COMMENT_ORDER_ID_MAX_LENGTH } from '../actions/comment' import { cn } from '../lib/cn' import { makeLoginUrl } from '../lib/redirectUrls' @@ -21,6 +23,7 @@ type Props = Omit, 'action' | 'enctype' | 'method'> & { parentId?: number commentId?: number strictCommentingEnabled?: boolean + commentSectionMessage?: string | null activeRatingComment?: Prisma.CommentGetPayload<{ select: { id: true @@ -35,6 +38,7 @@ const { commentId, activeRatingComment, strictCommentingEnabled, + commentSectionMessage, class: className, ...htmlProps } = Astro.props @@ -97,70 +101,83 @@ const userCommentsDisabled = user ? user.karmaUnlocks.commentsDisabled : false {!parentId ? ( -
-
- + <> +
+
+ - - + + - - + + - -
+ +
-
- {!!activeRatingComment?.rating && ( -
- - + {!!activeRatingComment?.rating && ( +
- Your previous rating - - - of - {[ - activeRatingComment.rating.toLocaleString(), - , - ]} - won't count for the total. -
- )} + + + Your previous rating + + + of + {[ + activeRatingComment.rating.toLocaleString(), + , + ]} + won't count for the total. +
+ )} -
+
- + ) : (