From bf25390e3984ba97dcab8e6b2581e618ba67ffd0 Mon Sep 17 00:00:00 2001 From: Gerald Leban Date: Tue, 6 Oct 2026 22:06:10 +0200 Subject: [PATCH] feat(explore): update frontend pages to Paginated shape with photo objects --- inertia/pages/explore/index.tsx | 27 +++++----- inertia/pages/explore/kit_detail.tsx | 63 ++++++------------------ inertia/pages/explore/photo_carousel.tsx | 12 +++-- inertia/types.ts | 15 ++++++ 4 files changed, 50 insertions(+), 67 deletions(-) diff --git a/inertia/pages/explore/index.tsx b/inertia/pages/explore/index.tsx index 6794a38..1dbdc4d 100644 --- a/inertia/pages/explore/index.tsx +++ b/inertia/pages/explore/index.tsx @@ -4,14 +4,11 @@ import { usePage } from '@inertiajs/react' import { router } from '@inertiajs/react' import { Search } from 'lucide-react' import { Dialog, DialogContent } from '~/components/ui/dialog' -import type { InertiaProps } from '~/types' -import { KitDetail, STATUS_STYLES } from './kit_detail' -import type { Kit } from './kit_detail' +import type { InertiaProps, Paginated } from '~/types' +import { KitDetail, type KitExplore } from './kit_detail' type PageProps = InertiaProps<{ - kits: Kit[] - hasMore: boolean - page: number + kits: Paginated q: string }> @@ -35,7 +32,7 @@ export default function Explore() { const { kits, q: initialQ } = usePage().props const [search, setSearch] = useState(initialQ) - const [selected, setSelected] = useState(null) + const [selected, setSelected] = useState(null) const isFirstRender = useRef(true) useEffect(() => { @@ -50,7 +47,7 @@ export default function Explore() { { preserveState: true, preserveScroll: false, - only: ['kits', 'hasMore', 'q'], + only: ['kits', 'q'], } ) }, 400) @@ -86,11 +83,11 @@ export default function Explore() { {/* Masonry grid */} - {kits.length === 0 ? ( + {kits.data.length === 0 ? (

No kits found.

) : (
- {kits.map((kit, i) => ( + {kits.data.map((kit, i) => (
@@ -119,15 +116,13 @@ export default function Explore() {

- @{kit.builderHandle.split('.')[0]} + @{(kit.handle ?? '').split('.')[0]}

    - {[kit.grade, kit.scale, kit.status].filter(Boolean).map((tag) => ( + {[kit.grade, kit.scale].filter(Boolean).map((tag) => (
  • - + {tag}
  • diff --git a/inertia/pages/explore/kit_detail.tsx b/inertia/pages/explore/kit_detail.tsx index 2ddecf4..a5002ad 100644 --- a/inertia/pages/explore/kit_detail.tsx +++ b/inertia/pages/explore/kit_detail.tsx @@ -2,29 +2,12 @@ import { Link } from '@adonisjs/inertia/react' import { X } from 'lucide-react' import { DialogClose } from '~/components/ui/dialog' import { PhotoCarousel } from './photo_carousel' +import type { InferVariants } from '@adonisjs/http-transformers/types' +import type KitTransformer from '#kits/transformers/kit_transformer' -export type BuildLogEntry = { date: string; stage: string; text: string } +export type KitExplore = InferVariants['forExplore'] -export type Kit = { - id: number - name: string - grade: string - scale: string - manufacturer: string - status: 'completed' | 'building' | 'backlog' - builderHandle: string - photos: string[] - notes: string - buildLog: BuildLogEntry[] -} - -export const STATUS_STYLES: Record = { - completed: 'bg-primary text-primary-foreground', - building: 'bg-secondary text-secondary-foreground', - backlog: 'bg-muted text-muted-foreground', -} - -export function KitDetail({ kit, onClose }: { kit: Kit; onClose: () => void }) { +export function KitDetail({ kit, onClose }: { kit: KitExplore; onClose: () => void }) { return (
    {/* Left — carousel */} @@ -37,29 +20,24 @@ export function KitDetail({ kit, onClose }: { kit: Kit; onClose: () => void }) { {/* Header */}
    -
    - {[kit.grade, kit.scale].filter(Boolean).join(' · ') && ( + {[kit.grade, kit.scale].filter(Boolean).join(' · ') && ( +
    {[kit.grade, kit.scale].filter(Boolean).join(' · ')} - )} - - {kit.status} - -
    +
    + )}

    {kit.name}

    {kit.manufacturer} - {' · '} + {kit.manufacturer && ' · '} - @{kit.builderHandle.split('.')[0]} + @{(kit.handle ?? '').split('.')[0]}

    @@ -76,30 +54,21 @@ export function KitDetail({ kit, onClose }: { kit: Kit; onClose: () => void }) { {/* Scrollable body */}
    - {kit.notes && ( -
    -

    - Notes -

    -

    {kit.notes}

    -
    - )} - - {kit.buildLog.length > 0 && ( + {kit.buildLogs && kit.buildLogs.length > 0 && (

    Build log

      - {kit.buildLog.map((entry, i) => ( + {kit.buildLogs.map((entry, i) => (
    1. - {i < kit.buildLog.length - 1 && ( + {i < kit.buildLogs!.length - 1 && (
      )}
      - {entry.date} + {entry.formattedDate}

      {entry.stage}

      {entry.text}

      @@ -110,7 +79,7 @@ export function KitDetail({ kit, onClose }: { kit: Kit; onClose: () => void }) {
      )} - {kit.buildLog.length === 0 && !kit.notes && ( + {(!kit.buildLogs || kit.buildLogs.length === 0) && (

      No details yet.

      diff --git a/inertia/pages/explore/photo_carousel.tsx b/inertia/pages/explore/photo_carousel.tsx index b59b512..691c914 100644 --- a/inertia/pages/explore/photo_carousel.tsx +++ b/inertia/pages/explore/photo_carousel.tsx @@ -1,6 +1,8 @@ import { useState, useEffect, useRef, type CSSProperties } from 'react' import { ChevronLeft, ChevronRight } from 'lucide-react' +type Photo = { thumbUrl: string; fullUrl: string } + function bgStyle(src: string, size: 'cover' | 'contain' = 'contain'): CSSProperties { if (src.startsWith('http') || src.startsWith('/')) { return { @@ -13,7 +15,7 @@ function bgStyle(src: string, size: 'cover' | 'contain' = 'contain'): CSSPropert return { background: src } } -export function PhotoCarousel({ photos }: { photos: string[] }) { +export function PhotoCarousel({ photos }: { photos: Photo[] }) { const [index, setIndex] = useState(0) const thumbRefs = useRef<(HTMLButtonElement | null)[]>([]) @@ -28,16 +30,18 @@ export function PhotoCarousel({ photos }: { photos: string[] }) { }) }, [index]) + const current = photos[index] + return (
      {/* Main photo */}