99 lines
6.8 KiB
JavaScript
99 lines
6.8 KiB
JavaScript
import React from 'react'
|
|
import { router, useForm, usePage } from '@inertiajs/react'
|
|
import StudioLayout from '../../Layouts/StudioLayout'
|
|
import Checkbox from '../../components/ui/Checkbox'
|
|
import NovaSelect from '../../components/ui/NovaSelect'
|
|
|
|
export default function StudioGroupAssets() {
|
|
const { props } = usePage()
|
|
const items = Array.isArray(props.listing?.items) ? props.listing.items : []
|
|
const filters = useForm({
|
|
q: props.listing?.filters?.q || '',
|
|
category: props.listing?.filters?.category || 'all',
|
|
bucket: props.listing?.filters?.bucket || 'all',
|
|
})
|
|
const form = useForm({
|
|
title: '',
|
|
description: '',
|
|
category: props.categoryOptions?.[0]?.value || 'misc',
|
|
visibility: props.visibilityOptions?.[0]?.value || 'members_only',
|
|
status: props.statusOptions?.[0]?.value || 'active',
|
|
linked_project_id: '',
|
|
is_featured: false,
|
|
file: null,
|
|
})
|
|
|
|
const submit = (event) => {
|
|
event.preventDefault()
|
|
if (!props.storeUrl) return
|
|
form.post(props.storeUrl, { forceFormData: true, preserveScroll: true })
|
|
}
|
|
|
|
const applyFilters = (event) => {
|
|
event.preventDefault()
|
|
router.get(props.studioGroup?.urls?.studio_assets || window.location.pathname, {
|
|
q: filters.data.q || undefined,
|
|
category: filters.data.category !== 'all' ? filters.data.category : undefined,
|
|
bucket: filters.data.bucket !== 'all' ? filters.data.bucket : undefined,
|
|
}, {
|
|
preserveState: true,
|
|
preserveScroll: true,
|
|
replace: true,
|
|
})
|
|
}
|
|
|
|
return (
|
|
<StudioLayout title={props.title} subtitle={props.description}>
|
|
{props.storeUrl ? (
|
|
<form onSubmit={submit} className="rounded-[28px] border border-white/10 bg-white/[0.03] p-6">
|
|
<div className="grid gap-4 lg:grid-cols-6">
|
|
<input value={form.data.title} onChange={(event) => form.setData('title', event.target.value)} placeholder="Asset title" className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none lg:col-span-2" />
|
|
<NovaSelect value={form.data.category} onChange={(val) => form.setData('category', val)} options={props.categoryOptions || []} searchable={false} />
|
|
<NovaSelect value={form.data.visibility} onChange={(val) => form.setData('visibility', val)} options={props.visibilityOptions || []} searchable={false} />
|
|
<NovaSelect value={form.data.status} onChange={(val) => form.setData('status', val)} options={props.statusOptions || []} searchable={false} />
|
|
<input type="file" onChange={(event) => form.setData('file', event.target.files?.[0] || null)} className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
|
|
</div>
|
|
<textarea value={form.data.description} onChange={(event) => form.setData('description', event.target.value)} placeholder="What is this asset for?" rows={3} className="mt-4 w-full rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
|
|
<div className="mt-4 grid gap-4 md:grid-cols-2">
|
|
<NovaSelect value={String(form.data.linked_project_id || '')} onChange={(val) => form.setData('linked_project_id', val)} placeholder="No linked project" options={(props.projectOptions || []).map((o) => ({ value: String(o.id), label: o.title }))} />
|
|
<div className="flex items-center gap-3 rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-white"><Checkbox checked={form.data.is_featured} onChange={(event) => form.setData('is_featured', event.target.checked)} label="Featured asset" /></div>
|
|
</div>
|
|
<button type="submit" className="mt-4 rounded-full border border-white/10 bg-white/[0.05] px-5 py-2.5 text-sm font-semibold text-white">Upload asset</button>
|
|
</form>
|
|
) : null}
|
|
|
|
<form onSubmit={applyFilters} className="mt-6 rounded-[28px] border border-white/10 bg-white/[0.03] p-6">
|
|
<div className="flex flex-wrap items-end justify-between gap-4">
|
|
<div>
|
|
<h2 className="text-lg font-semibold text-white">Browse library</h2>
|
|
<p className="mt-1 text-sm text-slate-400">Search and filter shared assets by visibility and category.</p>
|
|
</div>
|
|
<button type="submit" className="rounded-full border border-white/10 bg-white/[0.05] px-4 py-2 text-sm font-semibold text-white">Apply filters</button>
|
|
</div>
|
|
<div className="mt-4 grid gap-4 lg:grid-cols-3">
|
|
<input value={filters.data.q} onChange={(event) => filters.setData('q', event.target.value)} placeholder="Search title, description, or filename" className="rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-white outline-none" />
|
|
<NovaSelect value={filters.data.category} onChange={(val) => filters.setData('category', val)} options={[{ value: 'all', label: 'All categories' }, ...(props.categoryOptions || [])]} searchable={false} />
|
|
<NovaSelect value={filters.data.bucket} onChange={(val) => filters.setData('bucket', val)} options={[{ value: 'all', label: 'All visibility levels' }, ...(props.listing?.bucket_options || []).filter((option) => option.value !== 'all')]} searchable={false} />
|
|
</div>
|
|
</form>
|
|
|
|
<div className="mt-6 grid gap-4 lg:grid-cols-2">
|
|
{items.length > 0 ? items.map((asset) => (
|
|
<div key={asset.id} className="rounded-[24px] border border-white/10 bg-white/[0.03] p-5">
|
|
<div className="flex items-center justify-between gap-3">
|
|
<div>
|
|
<h2 className="text-xl font-semibold text-white">{asset.title}</h2>
|
|
<p className="mt-1 text-xs uppercase tracking-[0.16em] text-slate-500">{asset.category} • {asset.visibility} • {asset.status}</p>
|
|
</div>
|
|
<a href={asset.download_url} className="rounded-full border border-white/10 bg-white/[0.04] px-3 py-1.5 text-sm font-semibold text-white">Download</a>
|
|
</div>
|
|
{asset.description ? <p className="mt-3 text-sm leading-6 text-slate-400">{asset.description}</p> : null}
|
|
{props.updatePattern ? (
|
|
<button type="button" onClick={() => router.patch(props.updatePattern.replace('__ASSET__', String(asset.id)), { title: asset.title, description: asset.description || '', category: asset.category, visibility: asset.visibility, status: asset.status === 'active' ? 'archived' : 'active', linked_project_id: asset.linked_project?.id || '', is_featured: asset.is_featured })} className="mt-4 rounded-full border border-white/10 bg-white/[0.04] px-4 py-2 text-sm font-semibold text-white">{asset.status === 'active' ? 'Archive' : 'Reactivate'}</button>
|
|
) : null}
|
|
</div>
|
|
)) : <div className="rounded-[24px] border border-dashed border-white/10 bg-white/[0.02] p-6 text-sm text-slate-400">No assets yet.</div>}
|
|
</div>
|
|
</StudioLayout>
|
|
)
|
|
} |