Release 202507061803

This commit is contained in:
pluja
2025-07-06 18:03:45 +00:00
parent 349c26a4df
commit 7a294cb0a1
11 changed files with 66 additions and 5 deletions

View File

@@ -0,0 +1,2 @@
-- AlterTable
ALTER TABLE "Service" ADD COLUMN "strictCommentingEnabled" BOOLEAN NOT NULL DEFAULT false;

View File

@@ -406,6 +406,8 @@ model Service {
Notification Notification[]
affiliatedUsers ServiceUser[] @relation("ServiceUsers")
strictCommentingEnabled Boolean @default(false)
@@index([listedAt])
@@index([approvedAt])
@@index([verifiedAt])

View File

@@ -720,6 +720,7 @@ const generateFakeService = (users: User[]) => {
}),
{ probability: 0.33 }
),
strictCommentingEnabled: faker.datatype.boolean(0.33333),
} as const satisfies Prisma.ServiceCreateInput
}

View File

@@ -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,

View File

@@ -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"
/>
</>

View File

@@ -20,6 +20,7 @@ type Props = Omit<HTMLAttributes<'form'>, 'action' | 'enctype' | 'method'> & {
serviceId: number
parentId?: number
commentId?: number
strictCommentingEnabled?: boolean
activeRatingComment?: Prisma.CommentGetPayload<{
select: {
id: true
@@ -28,7 +29,15 @@ type Props = Omit<HTMLAttributes<'form'>, '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"

View File

@@ -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<DiscussionForumPosting>}
/>
<CommentReply serviceId={service.id} activeRatingComment={activeRatingComment} class="xs:mb-4 mb-2" />
<CommentReply
serviceId={service.id}
activeRatingComment={activeRatingComment}
strictCommentingEnabled={service.strictCommentingEnabled}
class="xs:mb-4 mb-2"
/>
<div class="mb-6 flex flex-wrap items-center justify-between gap-2">
<div class="flex items-center">
@@ -258,6 +264,7 @@ function makeReplySchema(comment: CommentWithRepliesPopulated): Comment {
showPending={params.showPending}
serviceSlug={service.slug}
itemReviewedId={itemReviewedId}
strictCommentingEnabled={service.strictCommentingEnabled}
/>
))
) : (

View File

@@ -7,6 +7,8 @@ import type { ComponentProps } from 'astro/types'
type Props = Pick<ComponentProps<typeof InputWrapper>, 'error' | 'name' | 'required'> & {
disabled?: boolean
checked?: boolean
descriptionInline?: string
id?: string
} & (
| {
@@ -19,13 +21,11 @@ type Props = Pick<ComponentProps<typeof InputWrapper>, '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
---
{}
<div>
<label
class={cn(
@@ -41,9 +41,11 @@ const hasError = !!error && error.length > 0
name={name}
required={required}
disabled={disabled}
checked={checked}
class={cn(disabled && 'opacity-50')}
/>
<span class="text-sm leading-none text-pretty">{label ?? <slot />}</span>
{descriptionInline && <p class="text-day-400 text-xs">{descriptionInline}</p>}
</label>
{

View File

@@ -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"
/>
<InputCheckbox
label="Strict Commenting"
name="strictCommentingEnabled"
checked={service.strictCommentingEnabled}
descriptionInline="Require proof of being a client for comments."
/>
<InputSubmitButton label="Update" icon="ri:save-line" hideCancel />
</form>
</FormSection>

View File

@@ -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 : {}
}
</div>
<InputCheckbox
label="Strict Commenting"
name="strictCommentingEnabled"
checked={false}
descriptionInline="Require proof of being a client for comments."
/>
<button
type="submit"
class="font-title inline-flex justify-center rounded-md border border-green-500/30 bg-green-500/10 px-4 py-2 text-sm text-green-400 shadow-xs transition-colors duration-200 hover:bg-green-500/20 focus:ring-2 focus:ring-green-500 focus:ring-offset-2 focus:ring-offset-black focus:outline-hidden"

View File

@@ -102,6 +102,7 @@ const [service, dbNotificationPreferences] = await Astro.locals.banners.tryMany(
userSentimentAt: true,
averageUserRating: true,
isRecentlyApproved: true,
strictCommentingEnabled: true,
contactMethods: {
select: {
value: true,
@@ -1533,6 +1534,20 @@ const activeEventToShow =
<li>Moderation is light.</li>
<li>Double-check before trusting.</li>
</ul>
{
service.strictCommentingEnabled && (
<p class="mt-2">
<Icon
name="ri:verified-badge-fill"
class="me-0.5 inline-block size-4 align-[-0.3em] text-orange-100/95"
/>
<span class="font-medium text-orange-100/95">Proof of being a client required</span>, for this
service.
</p>
)
}
<div class="absolute inset-y-2 right-2 flex flex-col justify-center">
<Icon name="ri:alert-line" class="xs:opacity-20 h-full max-h-16 w-auto opacity-10" />
</div>