Vercel/src/app/(auth-state)/admin/photos/page.tsx
Sam Becker df11a86181 Init
2023-09-05 09:00:57 -05:00

186 lines
5.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Fragment, ReactNode } from 'react';
import PhotoUploadInput from '@/photo/PhotoUploadInput';
import Link from 'next/link';
import PhotoTiny from '@/photo/PhotoTiny';
import { cc } from '@/utility/css';
import ImageTiny from '@/components/ImageTiny';
import FormWithConfirm from '@/components/FormWithConfirm';
import SiteGrid from '@/components/SiteGrid';
import {
deletePhotoAction,
deleteBlobPhotoAction,
} from '@/photo/actions';
import { FaRegEdit } from 'react-icons/fa';
import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus';
import {
pathForBlobUrl,
getBlobPhotoUrls,
getBlobUploadUrls,
} from '@/services/blob';
import { getPhotos } from '@/services/postgres';
import { routeForPhoto } from '@/site/routes';
export const runtime = 'edge';
const DEBUG_PHOTO_BLOBS = false;
export default async function AdminPage() {
const photos = await getPhotos('createdAt');
const blobUploadUrls = await getBlobUploadUrls();
const blobPhotoUrls = DEBUG_PHOTO_BLOBS
? await getBlobPhotoUrls()
: [];
return (
<SiteGrid
contentMain={
<div className="mt-4 space-y-4">
<div className="space-y-8">
<PhotoUploadInput />
{blobUploadUrls.length > 0 &&
<BlobUrls
blobUrls={blobUploadUrls}
label={`Uploads Files (${blobUploadUrls.length})`}
/>}
{blobPhotoUrls.length > 0 &&
<BlobUrls
blobUrls={blobPhotoUrls}
label={`Photos Files (${blobPhotoUrls.length})`}
/>}
<AdminGrid title={`Photos (${photos.length})`}>
{photos.map(photo =>
<Fragment key={photo.id}>
<PhotoTiny
className={cc(
'rounded-sm overflow-hidden',
'border border-gray-200 dark:border-gray-800',
)}
photo={photo}
/>
<Link
key={photo.id}
href={routeForPhoto(photo)}
className="grow flex items-center gap-2"
>
{photo.title}
{photo.priorityOrder !== null &&
<span className={cc(
'text-xs leading-none px-1.5 py-1 rounded-sm',
'dark:text-gray-300',
'bg-gray-100 dark:bg-gray-800',
)}>
{photo.priorityOrder}
</span>}
</Link>
<div className="text-gray-400 uppercase">
{photo.takenAtNaive}
</div>
<EditButton href={`/admin/photos/${photo.idShort}/edit`} />
<FormWithConfirm
action={deletePhotoAction}
confirmText={
`Are you sure you want to delete "${photo.title}?"`}
>
<input type="hidden" name="id" value={photo.id} />
<input type="hidden" name="url" value={photo.url} />
<DeleteButton />
</FormWithConfirm>
</Fragment>)}
</AdminGrid>
</div>
</div>}
/>
);
}
function AdminGrid ({
title,
children,
}: {
title: string,
children: ReactNode,
}) {
return <div className="space-y-2">
<div className="font-bold">
{title}
</div>
<div className="min-w-[14rem] overflow-x-scroll">
<div className={cc(
'w-full',
'grid grid-cols-[auto_auto_1fr_auto_auto] ',
'gap-3 items-center',
)}>
{children}
</div>
</div>
</div>;
}
function EditButton ({
href,
label = 'Edit',
}: {
href: string,
label?: string,
}) {
return <Link
href={href}
className="button"
>
<FaRegEdit className="translate-y-[-0.5px]" />
{label}
</Link>;
}
function DeleteButton () {
return <SubmitButtonWithStatus
icon={<span className="inline-flex text-[18px]">×</span>}
>
Delete
</SubmitButtonWithStatus>;
}
function BlobUrls ({
blobUrls,
label,
}: {
blobUrls: string[],
label: string,
}) {
return <AdminGrid title={label}>
{blobUrls.map(url => {
const href = `/admin/uploads/${encodeURIComponent(url)}`;
const fileName = url.split('/').pop();
return <Fragment key={url}>
<Link href={href}>
<ImageTiny
alt={`Photo: ${fileName}`}
src={url}
aspectRatio={3.0 / 2.0}
className={cc(
'rounded-sm overflow-hidden',
'border border-gray-200 dark:border-gray-800',
)}
/>
</Link>
<Link
href={href}
className="break-all"
title={url}
>
{pathForBlobUrl(url)}
</Link>
<div />
<EditButton href={href} label="Setup" />
<FormWithConfirm
action={deleteBlobPhotoAction}
confirmText="Are you sure you want to delete this upload?"
>
<input type="hidden" name="url" value={url} />
<DeleteButton />
</FormWithConfirm>
</Fragment>;})}
</AdminGrid>;
}