Show spinner when creating/updating photos
This commit is contained in:
parent
a26a574a9e
commit
b71f9e94e8
@ -1,9 +1,8 @@
|
||||
import PhotoForm from '@/photo/form/PhotoForm';
|
||||
import AdminChildPage from '@/components/AdminChildPage';
|
||||
import { PATH_ADMIN, PATH_ADMIN_UPLOADS } from '@/site/paths';
|
||||
import { PATH_ADMIN } from '@/site/paths';
|
||||
import { extractExifDataFromBlobPath } from '@/photo/server';
|
||||
import { redirect } from 'next/navigation';
|
||||
import { getUniqueTagsCached } from '@/photo/cache';
|
||||
import UploadPageClient from '@/photo/UploadPageClient';
|
||||
|
||||
interface Params {
|
||||
params: { uploadPath: string }
|
||||
@ -20,15 +19,6 @@ export default async function UploadPage({ params: { uploadPath } }: Params) {
|
||||
if (!photoFormExif) { redirect(PATH_ADMIN); }
|
||||
|
||||
return (
|
||||
<AdminChildPage
|
||||
backPath={PATH_ADMIN_UPLOADS}
|
||||
backLabel="Uploads"
|
||||
breadcrumb={blobId}
|
||||
>
|
||||
<PhotoForm
|
||||
initialPhotoForm={photoFormExif}
|
||||
uniqueTags={uniqueTags}
|
||||
/>
|
||||
</AdminChildPage>
|
||||
<UploadPageClient {...{ blobId, photoFormExif, uniqueTags }} />
|
||||
);
|
||||
};
|
||||
|
||||
@ -4,18 +4,21 @@ import { FiArrowLeft } from 'react-icons/fi';
|
||||
import SiteGrid from './SiteGrid';
|
||||
import { clsx } from 'clsx/lite';
|
||||
import Badge from './Badge';
|
||||
import Spinner from './Spinner';
|
||||
|
||||
function AdminChildPage({
|
||||
backPath,
|
||||
backLabel,
|
||||
breadcrumb,
|
||||
accessory,
|
||||
isLoading,
|
||||
children,
|
||||
}: {
|
||||
backPath?: string
|
||||
backLabel?: string
|
||||
breadcrumb?: ReactNode
|
||||
accessory?: ReactNode
|
||||
isLoading?: boolean
|
||||
children: ReactNode,
|
||||
}) {
|
||||
return (
|
||||
@ -42,10 +45,14 @@ function AdminChildPage({
|
||||
{breadcrumb &&
|
||||
<>
|
||||
<span>/</span>
|
||||
<Badge>
|
||||
{breadcrumb}
|
||||
</Badge>
|
||||
<span className={clsx(isLoading && 'opacity-50')}>
|
||||
<Badge>
|
||||
{breadcrumb}
|
||||
</Badge>
|
||||
</span>
|
||||
</>}
|
||||
{isLoading &&
|
||||
<Spinner />}
|
||||
</div>
|
||||
{accessory &&
|
||||
<div>{accessory}</div>}
|
||||
|
||||
@ -10,6 +10,7 @@ interface Props extends HTMLProps<HTMLButtonElement> {
|
||||
icon?: JSX.Element
|
||||
styleAsLink?: boolean
|
||||
spinnerColor?: SpinnerColor
|
||||
onFormStatusChange?: (pending: boolean) => void
|
||||
onFormSubmitToastMessage?: string
|
||||
}
|
||||
|
||||
@ -17,6 +18,7 @@ export default function SubmitButtonWithStatus({
|
||||
icon,
|
||||
styleAsLink,
|
||||
spinnerColor,
|
||||
onFormStatusChange,
|
||||
onFormSubmitToastMessage,
|
||||
children,
|
||||
disabled,
|
||||
@ -24,8 +26,8 @@ export default function SubmitButtonWithStatus({
|
||||
type: _type,
|
||||
...buttonProps
|
||||
}: Props) {
|
||||
|
||||
const { pending } = useFormStatus();
|
||||
|
||||
const pendingPrevious = useRef(pending);
|
||||
|
||||
useEffect(() => {
|
||||
@ -39,6 +41,10 @@ export default function SubmitButtonWithStatus({
|
||||
pendingPrevious.current = pending;
|
||||
}, [pending, onFormSubmitToastMessage]);
|
||||
|
||||
useEffect(() => {
|
||||
onFormStatusChange?.(pending);
|
||||
}, [onFormStatusChange, pending]);
|
||||
|
||||
return (
|
||||
<button
|
||||
type="submit"
|
||||
|
||||
@ -11,6 +11,7 @@ import { areSimpleObjectsEqual } from '@/utility/object';
|
||||
import IconGrSync from '@/site/IconGrSync';
|
||||
import { getExifDataAction } from './actions';
|
||||
import { Tags } from '@/tag';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function PhotoEditPageClient({
|
||||
photo,
|
||||
@ -26,6 +27,8 @@ export default function PhotoEditPageClient({
|
||||
seedExifData,
|
||||
);
|
||||
|
||||
const [pending, setIsPending] = useState(false);
|
||||
|
||||
const hasExifDataBeenFound = !areSimpleObjectsEqual(
|
||||
updatedExifData,
|
||||
seedExifData,
|
||||
@ -47,6 +50,7 @@ export default function PhotoEditPageClient({
|
||||
EXIF
|
||||
</SubmitButtonWithStatus>
|
||||
</form>}
|
||||
isLoading={pending}
|
||||
>
|
||||
<PhotoForm
|
||||
type="edit"
|
||||
@ -55,6 +59,7 @@ export default function PhotoEditPageClient({
|
||||
? updatedExifData
|
||||
: undefined}
|
||||
uniqueTags={uniqueTags}
|
||||
onFormStatusChange={setIsPending}
|
||||
/>
|
||||
</AdminChildPage>
|
||||
);
|
||||
|
||||
35
src/photo/UploadPageClient.tsx
Normal file
35
src/photo/UploadPageClient.tsx
Normal file
@ -0,0 +1,35 @@
|
||||
'use client';
|
||||
|
||||
import AdminChildPage from '@/components/AdminChildPage';
|
||||
import { PATH_ADMIN_UPLOADS } from '@/site/paths';
|
||||
import { PhotoFormData } from './form';
|
||||
import { Tags } from '@/tag';
|
||||
import PhotoForm from './form/PhotoForm';
|
||||
import { useState } from 'react';
|
||||
|
||||
export default function UploadPageClient({
|
||||
blobId,
|
||||
photoFormExif,
|
||||
uniqueTags,
|
||||
}: {
|
||||
blobId?: string
|
||||
photoFormExif: Partial<PhotoFormData>
|
||||
uniqueTags: Tags
|
||||
}) {
|
||||
const [pending, setIsPending] = useState(false);
|
||||
|
||||
return (
|
||||
<AdminChildPage
|
||||
backPath={PATH_ADMIN_UPLOADS}
|
||||
backLabel="Uploads"
|
||||
breadcrumb={blobId}
|
||||
isLoading={pending}
|
||||
>
|
||||
<PhotoForm
|
||||
initialPhotoForm={photoFormExif}
|
||||
uniqueTags={uniqueTags}
|
||||
onFormStatusChange={setIsPending}
|
||||
/>
|
||||
</AdminChildPage>
|
||||
);
|
||||
}
|
||||
@ -34,12 +34,14 @@ export default function PhotoForm({
|
||||
type = 'create',
|
||||
uniqueTags,
|
||||
debugBlur,
|
||||
onFormStatusChange,
|
||||
}: {
|
||||
initialPhotoForm: Partial<PhotoFormData>
|
||||
updatedExifData?: Partial<PhotoFormData>
|
||||
type?: 'create' | 'edit'
|
||||
uniqueTags?: Tags
|
||||
debugBlur?: boolean
|
||||
onFormStatusChange?: (pending: boolean) => void
|
||||
}) {
|
||||
const [formData, setFormData] =
|
||||
useState<Partial<PhotoFormData>>(initialPhotoForm);
|
||||
@ -206,7 +208,10 @@ export default function PhotoForm({
|
||||
>
|
||||
Cancel
|
||||
</Link>
|
||||
<SubmitButtonWithStatus disabled={!isFormValid(formData)}>
|
||||
<SubmitButtonWithStatus
|
||||
disabled={!isFormValid(formData)}
|
||||
onFormStatusChange={onFormStatusChange}
|
||||
>
|
||||
{type === 'create' ? 'Create' : 'Update'}
|
||||
</SubmitButtonWithStatus>
|
||||
</div>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user