diff --git a/web/prisma/migrations/20250706140819_strict_commenting_enabled/migration.sql b/web/prisma/migrations/20250706140819_strict_commenting_enabled/migration.sql new file mode 100644 index 0000000..c704cd5 --- /dev/null +++ b/web/prisma/migrations/20250706140819_strict_commenting_enabled/migration.sql @@ -0,0 +1,2 @@ +-- AlterTable +ALTER TABLE "Service" ADD COLUMN "strictCommentingEnabled" BOOLEAN NOT NULL DEFAULT false; diff --git a/web/prisma/schema.prisma b/web/prisma/schema.prisma index 607f131..5fa5f75 100644 --- a/web/prisma/schema.prisma +++ b/web/prisma/schema.prisma @@ -406,6 +406,8 @@ model Service { Notification Notification[] affiliatedUsers ServiceUser[] @relation("ServiceUsers") + strictCommentingEnabled Boolean @default(false) + @@index([listedAt]) @@index([approvedAt]) @@index([verifiedAt]) diff --git a/web/prisma/seed.ts b/web/prisma/seed.ts index ebc33ca..41a2387 100755 --- a/web/prisma/seed.ts +++ b/web/prisma/seed.ts @@ -720,6 +720,7 @@ const generateFakeService = (users: User[]) => { }), { probability: 0.33 } ), + strictCommentingEnabled: faker.datatype.boolean(0.33333), } as const satisfies Prisma.ServiceCreateInput } diff --git a/web/src/actions/admin/service.ts b/web/src/actions/admin/service.ts index 199db64..5fb70fe 100644 --- a/web/src/actions/admin/service.ts +++ b/web/src/actions/admin/service.ts @@ -63,6 +63,7 @@ const serviceSchemaBase = z.object({ overallScore: zodCohercedNumber(z.number().int().min(0).max(10)).optional(), serviceVisibility: z.nativeEnum(ServiceVisibility), internalNote: z.string().optional(), + strictCommentingEnabled: z.boolean().optional().default(false), }) // Define schema for the create action input @@ -127,6 +128,7 @@ export const adminServiceActions = { verificationSummary: input.verificationSummary, verificationProofMd: input.verificationProofMd, acceptedCurrencies: input.acceptedCurrencies, + strictCommentingEnabled: input.strictCommentingEnabled, // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing referral: input.referral || null, serviceVisibility: input.serviceVisibility, @@ -247,6 +249,7 @@ export const adminServiceActions = { verificationSummary: input.verificationSummary, verificationProofMd: input.verificationProofMd, acceptedCurrencies: input.acceptedCurrencies, + strictCommentingEnabled: input.strictCommentingEnabled, // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing referral: input.referral || null, serviceVisibility: input.serviceVisibility, diff --git a/web/src/components/CommentItem.astro b/web/src/components/CommentItem.astro index 7749452..d2e6311 100644 --- a/web/src/components/CommentItem.astro +++ b/web/src/components/CommentItem.astro @@ -33,6 +33,7 @@ type Props = HTMLAttributes<'div'> & { highlightedCommentId: number | null serviceSlug: string itemReviewedId: string + strictCommentingEnabled?: boolean } const { @@ -42,6 +43,7 @@ const { highlightedCommentId = null, serviceSlug, itemReviewedId, + strictCommentingEnabled, class: className, ...htmlProps } = Astro.props @@ -492,6 +494,7 @@ const commentUrl = makeCommentUrl({ serviceSlug, commentId: comment.id, origin: serviceId={comment.serviceId} parentId={comment.id} commentId={comment.id} + strictCommentingEnabled={strictCommentingEnabled} class="mt-2 hidden peer-checked/collapse:hidden peer-checked/reply:block" /> diff --git a/web/src/components/CommentReply.astro b/web/src/components/CommentReply.astro index 824a749..b2227c0 100644 --- a/web/src/components/CommentReply.astro +++ b/web/src/components/CommentReply.astro @@ -20,6 +20,7 @@ type Props = Omit, 'action' | 'enctype' | 'method'> & { serviceId: number parentId?: number commentId?: number + strictCommentingEnabled?: boolean activeRatingComment?: Prisma.CommentGetPayload<{ select: { id: true @@ -28,7 +29,15 @@ type Props = Omit, 'action' | 'enctype' | 'method'> & { }> | null } -const { serviceId, parentId, commentId, activeRatingComment, class: className, ...htmlProps } = Astro.props +const { + serviceId, + parentId, + commentId, + activeRatingComment, + strictCommentingEnabled, + class: className, + ...htmlProps +} = Astro.props const MIN_COMMENT_LENGTH = parentId ? 10 : 30 @@ -117,6 +126,7 @@ const userCommentsDisabled = user ? user.karmaUnlocks.commentsDisabled : false maxlength: 100, placeholder: 'Order ID / URL / Proof', class: 'bg-night-800', + required: strictCommentingEnabled, }} descriptionLabel="Only visible to admins, to verify your comment" class="grow" diff --git a/web/src/components/CommentSection.astro b/web/src/components/CommentSection.astro index bc8d3db..69e72e3 100644 --- a/web/src/components/CommentSection.astro +++ b/web/src/components/CommentSection.astro @@ -35,6 +35,7 @@ type Props = { name: true description: true createdAt: true + strictCommentingEnabled: true } }> } @@ -173,7 +174,12 @@ function makeReplySchema(comment: CommentWithRepliesPopulated): Comment { comment: comments.map(makeReplySchema), } as WithContext} /> - +
@@ -258,6 +264,7 @@ function makeReplySchema(comment: CommentWithRepliesPopulated): Comment { showPending={params.showPending} serviceSlug={service.slug} itemReviewedId={itemReviewedId} + strictCommentingEnabled={service.strictCommentingEnabled} /> )) ) : ( diff --git a/web/src/components/InputCheckbox.astro b/web/src/components/InputCheckbox.astro index 8438ea4..3bea36e 100644 --- a/web/src/components/InputCheckbox.astro +++ b/web/src/components/InputCheckbox.astro @@ -7,6 +7,8 @@ import type { ComponentProps } from 'astro/types' type Props = Pick, 'error' | 'name' | 'required'> & { disabled?: boolean + checked?: boolean + descriptionInline?: string id?: string } & ( | { @@ -19,13 +21,11 @@ type Props = Pick, 'error' | 'name' | 'requi } ) -const { disabled, name, required, error, id, label } = Astro.props +const { disabled, name, required, error, id, label, checked, descriptionInline } = Astro.props const hasError = !!error && error.length > 0 --- -{} -
{ diff --git a/web/src/pages/admin/services/[slug]/edit.astro b/web/src/pages/admin/services/[slug]/edit.astro index 1989a2a..482e317 100644 --- a/web/src/pages/admin/services/[slug]/edit.astro +++ b/web/src/pages/admin/services/[slug]/edit.astro @@ -10,6 +10,7 @@ import Button from '../../../../components/Button.astro' import FormSection from '../../../../components/FormSection.astro' import FormSubSection from '../../../../components/FormSubSection.astro' import InputCardGroup from '../../../../components/InputCardGroup.astro' +import InputCheckbox from '../../../../components/InputCheckbox.astro' import InputCheckboxGroup from '../../../../components/InputCheckboxGroup.astro' import InputImageFile from '../../../../components/InputImageFile.astro' import InputSelect from '../../../../components/InputSelect.astro' @@ -545,6 +546,13 @@ const apiCalls = await Astro.locals.banners.try( cardSize="sm" /> + + diff --git a/web/src/pages/admin/services/new.astro b/web/src/pages/admin/services/new.astro index 7354c2c..bae54ab 100644 --- a/web/src/pages/admin/services/new.astro +++ b/web/src/pages/admin/services/new.astro @@ -3,6 +3,7 @@ import { AttributeCategory, Currency, VerificationStatus } from '@prisma/client' import { Icon } from 'astro-icon/components' import { actions, isInputError } from 'astro:actions' +import InputCheckbox from '../../../components/InputCheckbox.astro' import BaseLayout from '../../../layouts/BaseLayout.astro' import { cn } from '../../../lib/cn' import { prisma } from '../../../lib/prisma' @@ -368,6 +369,13 @@ const inputErrors = isInputError(result?.error) ? result.error.fields : {} }
+ +