complete reviews system (phases 4-6)
All checks were successful
deploy / deploy (push) Successful in 1m4s

- review display: photos with lightbox, verified badge, pagination
- admin moderation: pending/approved/rejected tabs, bulk actions, nav badge
- SEO: JSON-LD AggregateRating and Review markup on product pages
- automation: review request emails 7 days after delivery (Oban worker)
- rating cache: avg/count fields on products, updated on approval
- fix file size validation in media test (10MB limit)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jamey
2026-04-01 22:41:27 +01:00
parent 32eb0c6758
commit 6d2d0c9941
26 changed files with 2155 additions and 157 deletions

View File

@@ -205,12 +205,13 @@ const CartDrawer = {
}
}
// Hook for PDP image lightbox
// Hook for image lightbox (used by product gallery and review photos)
const Lightbox = {
mounted() {
const dialog = this.el
const lightboxImage = dialog.querySelector('#lightbox-image')
const lightboxCounter = dialog.querySelector('#lightbox-counter')
// Use class selectors so multiple lightboxes can coexist
const lightboxImage = dialog.querySelector('.lightbox-image')
const lightboxCounter = dialog.querySelector('.lightbox-counter')
// Get images from data attribute
const getImages = () => {
@@ -258,11 +259,15 @@ const Lightbox = {
dialog.close()
}
// Event listeners for custom events dispatched from LiveView.JS
// Event listeners - support both legacy pdp: events and new lightbox: events
dialog.addEventListener('pdp:open-lightbox', openLightbox)
dialog.addEventListener('pdp:close-lightbox', closeLightbox)
dialog.addEventListener('pdp:next-image', nextImage)
dialog.addEventListener('pdp:prev-image', prevImage)
dialog.addEventListener('lightbox:open', openLightbox)
dialog.addEventListener('lightbox:close', closeLightbox)
dialog.addEventListener('lightbox:next', nextImage)
dialog.addEventListener('lightbox:prev', prevImage)
// Close on clicking backdrop
dialog.addEventListener('click', (e) => {
@@ -288,6 +293,10 @@ const Lightbox = {
dialog.removeEventListener('pdp:close-lightbox', closeLightbox)
dialog.removeEventListener('pdp:next-image', nextImage)
dialog.removeEventListener('pdp:prev-image', prevImage)
dialog.removeEventListener('lightbox:open', openLightbox)
dialog.removeEventListener('lightbox:close', closeLightbox)
dialog.removeEventListener('lightbox:next', nextImage)
dialog.removeEventListener('lightbox:prev', prevImage)
}
},