import { useState } from 'react' import { Head, useForm } from '@inertiajs/react' import Layout from '../Layout' import * as Form from '@radix-ui/react-form' import * as Checkbox from '@radix-ui/react-checkbox' export default function Search({ images, filters, tags, auth }) { const { data, setData, get, processing } = useForm({ 'q[title_cont]': filters['title_cont'] || '', 'q[tags_name_in][]': filters['tags_name_in'] || [], 'q[created_at_gteq]': filters['created_at_gteq'] || '', 'q[created_at_lteq]': filters['created_at_lteq'] || '', }) const handleSubmit = (e) => { e.preventDefault() get('/images/search', { preserveState: true, }) } const handleTagChange = (tagName) => { const currentTags = [...data['q[tags_name_in][]']] const tagIndex = currentTags.indexOf(tagName) if (tagIndex === -1) { currentTags.push(tagName) } else { currentTags.splice(tagIndex, 1) } setData('q[tags_name_in][]', currentTags) } const isTagSelected = (tagName) => { return data['q[tags_name_in][]'].includes(tagName) } return ( <Layout user={auth}> <Head title="Search Images" /> <div className="bg-white shadow overflow-hidden sm:rounded-lg"> <div className="px-4 py-5 sm:px-6"> <h1 className="text-2xl font-bold text-gray-900">Search Images</h1> <p className="mt-1 max-w-2xl text-sm text-gray-500"> Find images by title, tags, or date </p> </div> <div className="border-t border-gray-200"> <div className="grid grid-cols-1 md:grid-cols-4"> <div className="md:col-span-1 p-4 border-b md:border-b-0 md:border-r border-gray-200"> <Form.Root className="space-y-6" onSubmit={handleSubmit}> <Form.Field name="q[title_cont]" className="space-y-2"> <Form.Label className="block text-sm font-medium text-gray-700"> Title </Form.Label> <Form.Control asChild> <input type="text" name="q[title_cont]" value={data['q[title_cont]']} onChange={(e) => setData('q[title_cont]', e.target.value)} className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md" placeholder="Search by title" /> </Form.Control> </Form.Field> <div className="space-y-2"> <h3 className="block text-sm font-medium text-gray-700">Tags</h3> <div className="mt-2 space-y-2 max-h-60 overflow-y-auto"> {tags.map((tag) => ( <div key={tag} className="flex items-center"> <Checkbox.Root id={`tag-${tag}`} checked={isTagSelected(tag)} onCheckedChange={() => handleTagChange(tag)} className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500" > <Checkbox.Indicator> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="h-4 w-4 text-indigo-600" > <polyline points="20 6 9 17 4 12" /> </svg> </Checkbox.Indicator> </Checkbox.Root> <label htmlFor={`tag-${tag}`} className="ml-2 text-sm text-gray-700" > {tag} </label> </div> ))} </div> </div> <Form.Field name="q[created_at_gteq]" className="space-y-2"> <Form.Label className="block text-sm font-medium text-gray-700"> From Date </Form.Label> <Form.Control asChild> <input type="date" name="q[created_at_gteq]" value={data['q[created_at_gteq]']} onChange={(e) => setData('q[created_at_gteq]', e.target.value)} className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md" /> </Form.Control> </Form.Field> <Form.Field name="q[created_at_lteq]" className="space-y-2"> <Form.Label className="block text-sm font-medium text-gray-700"> To Date </Form.Label> <Form.Control asChild> <input type="date" name="q[created_at_lteq]" value={data['q[created_at_lteq]']} onChange={(e) => setData('q[created_at_lteq]', e.target.value)} className="mt-1 focus:ring-indigo-500 focus:border-indigo-500 block w-full shadow-sm sm:text-sm border-gray-300 rounded-md" /> </Form.Control> </Form.Field> <div className="flex justify-end"> <Form.Submit asChild> <button type="submit" disabled={processing} className="inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 disabled:opacity-50" > {processing ? 'Searching...' : 'Search'} </button> </Form.Submit> </div> </Form.Root> </div> <div className="md:col-span-3 p-4"> {images.length > 0 ? ( <div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3"> {images.map((image) => ( <div key={image.id} className="bg-white overflow-hidden shadow rounded-lg border border-gray-200" > <div className="relative pb-[75%]"> <img src={image.file_url} alt={image.title} className="absolute h-full w-full object-cover" /> </div> <div className="px-4 py-4"> <h3 className="text-lg font-medium text-gray-900 truncate"> {image.title} </h3> <div className="mt-2 flex flex-wrap gap-1"> {image.tags.map((tag) => ( <span key={tag.id} className="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-indigo-100 text-indigo-800" > {tag.name} </span> ))} </div> <div className="mt-4 flex justify-between"> <a href={`/images/${image.id}`} className="text-sm text-indigo-600 hover:text-indigo-900" > View details </a> <span className="text-sm text-gray-500"> {new Date(image.created_at).toLocaleDateString()} </span> </div> </div> </div> ))} </div> ) : ( <div className="text-center py-12"> <svg className="mx-auto h-12 w-12 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor" aria-hidden="true" > <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16l4.586-4.586a2 2 0 012.828 0L16 16m-2-2l1.586-1.586a2 2 0 012.828 0L20 14m-6-6h.01M6 20h12a2 2 0 002-2V6a2 2 0 00-2-2H6a2 2 0 00-2 2v12a2 2 0 002 2z" /> </svg> <h3 className="mt-2 text-sm font-medium text-gray-900"> No images found </h3> <p className="mt-1 text-sm text-gray-500"> Try adjusting your search criteria. </p> </div> )} </div> </div> </div> </div> </Layout> ) }