How can I create something akin to a "user rating" feature? I.e., each user can create and edit their own row for each article, either as a many-to-many relationship article_user_rating
or as a hasMany relationship field in the article
or in the user
collection. In both case, the row should includes a field for the rating (integer).
I couldn't find a way to constrain the [article_id, user_id] pair to be unique. Is something like a composite key unique constraint possible?
Also, how would I display the 5-stars widget for the current user to be able to rate the article in the admin edit page?
I'd approach it this way:
beforeChange
hook on RatingCollection
to save the user who is rating in a readonly or disabled fieldaccess:read
function to show the user only his own ratingsvalidate
function on the product
relation to check the uniqueness of the [user, products] ratingSomething like this:
const ProductsCollection: CollectionConfig = {
slug: 'products-for-rating',
labels: { plural: 'Products' },
admin: {
group: 'Rating',
useAsTitle: 'productName'
},
fields: [
{
name: 'productName',
type: 'text',
}
],
}
const RatingsCollection: CollectionConfig = {
slug: 'ratings',
admin: {
group: 'Rating',
},
fields: [
{
name: 'product',
type: 'relationship',
relationTo: 'products-for-rating',
validate: async (val, { user }) => {
const query = qs.stringify({
where: {
and: [
{
product: { equals: val }
},
{
user: { equals: user.id }
}
]
}
}, { addQueryPrefix: true })
const response = await fetch(`http://localhost:3000/api/ratings${query}`)
const sameRating = await response.json()
if (!sameRating.totalDocs) {
return true;
}
return 'You have already rated this product.';
},
},
{
name: 'rating',
type: 'number',
min: 1, max: 5,
// admin: {
// components: {
// Field: FiveStarsField
// }
// }
},
{
name: 'user',
type: 'relationship',
relationTo: 'users',
admin: {
readOnly: true
},
},
],
access: {
read: ({ req: { user }, id }) => {
return {
user: {
equals: user.id
}
}
}
},
hooks: {
beforeChange: [async ({
data,
req,
}) => {
data.user = req.user.id
return data;
}]
}
}
To show the 5-stars field you can provide a custom Field Component to the rating
field.
If I understand your problem correctly, this work for me, but I'm curious to know if there's a better approach.
@vibl You could create a ratings
collection, and store your data there. You would have a field for the user, the article and the rating.
To make them unique you could create a hidden field (set it to unique in the config) and use a beforeValidate hook to generate the value for that field by concatenating the userID and the articleID.
To display it on an article page within the admin panel, you could create a custom ui
field, that fetches the users rating based on the article they are viewing (the useDocumentInfo hook would be useful here). If there is a rating, set that as your value in your customStarComponent field. On change make a POST req to the ratings collection where user = userID and article = articleID.
How does that sound to you?
Star
Discord
online
Get dedicated engineering support directly from the Payload team.