Implement creator studio and upload updates
This commit is contained in:
116
resources/js/Pages/Studio/StudioFollowers.jsx
Normal file
116
resources/js/Pages/Studio/StudioFollowers.jsx
Normal file
@@ -0,0 +1,116 @@
|
||||
import React from 'react'
|
||||
import { router, usePage } from '@inertiajs/react'
|
||||
import StudioLayout from '../../Layouts/StudioLayout'
|
||||
import { studioSurface, trackStudioEvent } from '../../utils/studioEvents'
|
||||
|
||||
function SummaryCard({ label, value, icon }) {
|
||||
return (
|
||||
<div className="rounded-[24px] border border-white/10 bg-white/[0.03] p-5">
|
||||
<div className="flex items-center gap-3 text-slate-300">
|
||||
<i className={icon} />
|
||||
<span className="text-sm">{label}</span>
|
||||
</div>
|
||||
<div className="mt-3 text-3xl font-semibold text-white">{Number(value || 0).toLocaleString()}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default function StudioFollowers() {
|
||||
const { props } = usePage()
|
||||
const listing = props.listing || {}
|
||||
const filters = listing.filters || {}
|
||||
const summary = listing.summary || {}
|
||||
const items = listing.items || []
|
||||
const meta = listing.meta || {}
|
||||
|
||||
const updateQuery = (patch) => {
|
||||
trackStudioEvent('studio_filter_used', {
|
||||
surface: studioSurface(),
|
||||
module: 'followers',
|
||||
meta: {
|
||||
patch,
|
||||
},
|
||||
})
|
||||
|
||||
router.get(window.location.pathname, { ...filters, ...patch }, { preserveScroll: true, preserveState: true, replace: true })
|
||||
}
|
||||
|
||||
return (
|
||||
<StudioLayout title={props.title} subtitle={props.description}>
|
||||
<div className="mb-6 grid gap-4 md:grid-cols-3">
|
||||
<SummaryCard label="Total followers" value={summary.total_followers} icon="fa-solid fa-user-group" />
|
||||
<SummaryCard label="Following back" value={summary.following_back} icon="fa-solid fa-arrows-rotate" />
|
||||
<SummaryCard label="Not followed yet" value={summary.not_followed} icon="fa-solid fa-user-plus" />
|
||||
</div>
|
||||
|
||||
<section className="rounded-[28px] border border-white/10 bg-white/[0.03] p-5">
|
||||
<div className="grid gap-3 lg:grid-cols-[minmax(0,1fr)_220px_220px]">
|
||||
<label className="space-y-2 text-sm text-slate-300">
|
||||
<span className="block text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">Search</span>
|
||||
<input value={filters.q || ''} onChange={(event) => updateQuery({ q: event.target.value, page: 1 })} placeholder="Search followers" className="w-full rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-white" />
|
||||
</label>
|
||||
<label className="space-y-2 text-sm text-slate-300">
|
||||
<span className="block text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">Sort</span>
|
||||
<select value={filters.sort || 'recent'} onChange={(event) => updateQuery({ sort: event.target.value, page: 1 })} className="w-full rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-white">
|
||||
{(listing.sort_options || []).map((option) => <option key={option.value} value={option.value} className="bg-slate-900">{option.label}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
<label className="space-y-2 text-sm text-slate-300">
|
||||
<span className="block text-[11px] font-semibold uppercase tracking-[0.2em] text-slate-500">Relationship</span>
|
||||
<select value={filters.relationship || 'all'} onChange={(event) => updateQuery({ relationship: event.target.value, page: 1 })} className="w-full rounded-2xl border border-white/10 bg-black/20 px-4 py-3 text-sm text-white">
|
||||
{(listing.relationship_options || []).map((option) => <option key={option.value} value={option.value} className="bg-slate-900">{option.label}</option>)}
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 space-y-3">
|
||||
{items.map((item) => (
|
||||
<article key={item.id} className="flex flex-col gap-4 rounded-[24px] border border-white/10 bg-black/20 p-4 md:flex-row md:items-center md:justify-between">
|
||||
<a href={item.profile_url} className="flex min-w-0 items-center gap-4">
|
||||
{item.avatar_url ? (
|
||||
<img src={item.avatar_url} alt={item.username} className="h-14 w-14 rounded-[18px] object-cover" />
|
||||
) : (
|
||||
<div className="flex h-14 w-14 items-center justify-center rounded-[18px] bg-white/5 text-slate-400"><i className="fa-solid fa-user" /></div>
|
||||
)}
|
||||
<div className="min-w-0">
|
||||
<div className="truncate text-base font-semibold text-white">{item.name}</div>
|
||||
<div className="text-sm text-slate-400">@{item.username}</div>
|
||||
</div>
|
||||
</a>
|
||||
<div className="grid grid-cols-2 gap-4 text-sm text-slate-400 md:grid-cols-4 md:text-right">
|
||||
<div>
|
||||
<div>Uploads</div>
|
||||
<div className="mt-1 font-semibold text-white">{Number(item.uploads_count || 0).toLocaleString()}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>Followers</div>
|
||||
<div className="mt-1 font-semibold text-white">{Number(item.followers_count || 0).toLocaleString()}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>Followed</div>
|
||||
<div className="mt-1 font-semibold text-white">{item.followed_at ? new Date(item.followed_at).toLocaleDateString() : '—'}</div>
|
||||
</div>
|
||||
<div>
|
||||
<div>Status</div>
|
||||
<div className="mt-1 font-semibold text-white">{item.is_following_back ? 'Following back' : 'Not followed'}</div>
|
||||
</div>
|
||||
</div>
|
||||
</article>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="mt-6 flex items-center justify-between rounded-[24px] border border-white/10 bg-white/[0.03] px-4 py-3 text-sm text-slate-300">
|
||||
<button type="button" disabled={(meta.current_page || 1) <= 1} onClick={() => updateQuery({ page: Math.max(1, (meta.current_page || 1) - 1) })} className="inline-flex items-center gap-2 rounded-full border border-white/10 px-4 py-2 disabled:opacity-40">
|
||||
<i className="fa-solid fa-arrow-left" />
|
||||
Previous
|
||||
</button>
|
||||
<span>Page {meta.current_page || 1} of {meta.last_page || 1}</span>
|
||||
<button type="button" disabled={(meta.current_page || 1) >= (meta.last_page || 1)} onClick={() => updateQuery({ page: (meta.current_page || 1) + 1 })} className="inline-flex items-center gap-2 rounded-full border border-white/10 px-4 py-2 disabled:opacity-40">
|
||||
Next
|
||||
<i className="fa-solid fa-arrow-right" />
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</StudioLayout>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user