From 2da60e68c10916d394216b044ee80c7867afd36f Mon Sep 17 00:00:00 2001 From: Sam Becker Date: Wed, 29 May 2024 14:13:48 -0500 Subject: [PATCH] Refactor admin AI/sync buttons --- src/admin/AdminPhotosTable.tsx | 29 +++------- src/admin/PhotoSyncButton.tsx | 58 +++++++++++++++++++ src/components/FormWithConfirm.tsx | 10 ++-- src/components/SubmitButtonWithStatus.tsx | 14 ++--- src/components/primitives/LoaderButton.tsx | 8 ++- .../primitives/PathLoaderButton.tsx | 4 +- src/photo/PhotoEditPageClient.tsx | 17 ++---- src/photo/ai/AiButton.tsx | 18 ++---- src/photo/ai/index.ts | 1 - src/site/Footer.tsx | 2 +- 10 files changed, 98 insertions(+), 63 deletions(-) create mode 100644 src/admin/PhotoSyncButton.tsx diff --git a/src/admin/AdminPhotosTable.tsx b/src/admin/AdminPhotosTable.tsx index 15d6c6fc..a8db1804 100644 --- a/src/admin/AdminPhotosTable.tsx +++ b/src/admin/AdminPhotosTable.tsx @@ -11,8 +11,6 @@ import { AiOutlineEyeInvisible } from 'react-icons/ai'; import PhotoDate from '@/photo/PhotoDate'; import FormWithConfirm from '@/components/FormWithConfirm'; import EditButton from './EditButton'; -import SubmitButtonWithStatus from '@/components/SubmitButtonWithStatus'; -import IconGrSync from '@/site/IconGrSync'; import DeleteButton from './DeleteButton'; import { deletePhotoFormAction, @@ -20,6 +18,7 @@ import { } from '@/photo/actions'; import { useAppState } from '@/state/AppState'; import { RevalidatePhoto } from '@/photo/InfinitePhotoScroll'; +import PhotoSyncButton from './PhotoSyncButton'; export default function AdminPhotosTable({ photos, @@ -82,25 +81,15 @@ export default function AdminPhotosTable({ 'gap-2 sm:gap-3 items-center', )}> - - - } - onFormSubmitToastMessage={` - "${titleForPhoto(photo)}" EXIF data synced - `} - onFormSubmit={invalidateSwr} - /> - + photoTitle={titleForPhoto(photo)} + formData={{ photoId: photo.id }} + onFormSubmit={invalidateSwr} + includeLabel={false} + shouldConfirm + shouldToast + /> void + includeLabel?: boolean + formData?: { + photoId?: string + photoUrl?: string + } + photoTitle?: string + shouldConfirm?: boolean + shouldToast?: boolean +} & ComponentProps) { + const confirmText = + 'Are you sure you want to overwrite EXIF data ' + (photoTitle + ? `for "${photoTitle}" from source file? ` + : 'from source file? ' + ) + 'This action cannot be undone.'; + return ( + + {photoId && + } + {photoUrl && + } + } + onFormSubmitToastMessage={shouldToast + ? photoTitle + ? `"${photoTitle}" EXIF data synced` + : 'EXIF data synced' + : undefined} + onFormSubmit={onFormSubmit} + > + {includeLabel ? 'EXIF' : null} + + + ); +} diff --git a/src/components/FormWithConfirm.tsx b/src/components/FormWithConfirm.tsx index 07450dcc..d0d68a17 100644 --- a/src/components/FormWithConfirm.tsx +++ b/src/components/FormWithConfirm.tsx @@ -8,8 +8,8 @@ export default function FormWithConfirm({ onSubmit, children, }: { - action: (data: FormData) => Promise - confirmText: string + action: (formData: FormData) => void + confirmText?: string onSubmit?: () => void children: ReactNode }) { @@ -17,11 +17,11 @@ export default function FormWithConfirm({
{ - if (!confirm(confirmText)) { - e.preventDefault(); - } else { + if (!confirmText || confirm(confirmText)) { e.currentTarget.requestSubmit(); onSubmit?.(); + } else { + e.preventDefault(); } }} > diff --git a/src/components/SubmitButtonWithStatus.tsx b/src/components/SubmitButtonWithStatus.tsx index 502d714e..9ab870a8 100644 --- a/src/components/SubmitButtonWithStatus.tsx +++ b/src/components/SubmitButtonWithStatus.tsx @@ -1,16 +1,12 @@ 'use client'; -import { HTMLProps, useEffect, useRef } from 'react'; +import { ComponentProps, useEffect, useRef } from 'react'; import { useFormStatus } from 'react-dom'; -import { SpinnerColor } from './Spinner'; import { clsx } from 'clsx/lite'; import { toastSuccess } from '@/toast'; import LoaderButton from '@/components/primitives/LoaderButton'; -interface Props extends HTMLProps { - icon?: JSX.Element - styleAsLink?: boolean - spinnerColor?: SpinnerColor +interface Props extends ComponentProps { onFormStatusChange?: (pending: boolean) => void onFormSubmitToastMessage?: string onFormSubmit?: () => void @@ -19,7 +15,7 @@ interface Props extends HTMLProps { export default function SubmitButtonWithStatus({ icon, - styleAsLink, + styleAs, spinnerColor, onFormStatusChange, onFormSubmitToastMessage, @@ -36,7 +32,7 @@ export default function SubmitButtonWithStatus({ const pendingPrevious = useRef(pending); useEffect(() => { - if (pending && !pendingPrevious.current) { + if (!pending && pendingPrevious.current) { if (onFormSubmitToastMessage) { toastSuccess(onFormSubmitToastMessage); } @@ -60,7 +56,7 @@ export default function SubmitButtonWithStatus({ )} icon={icon} spinnerColor={spinnerColor} - styleAs={styleAsLink ? 'link' : undefined} + styleAs={styleAs} isLoading={pending} {...buttonProps} > diff --git a/src/components/primitives/LoaderButton.tsx b/src/components/primitives/LoaderButton.tsx index 81460ccb..91ede1b6 100644 --- a/src/components/primitives/LoaderButton.tsx +++ b/src/components/primitives/LoaderButton.tsx @@ -3,12 +3,12 @@ import { clsx } from 'clsx/lite'; import { ButtonHTMLAttributes, ReactNode } from 'react'; export default function LoaderButton(props: { - children?: ReactNode isLoading?: boolean icon?: ReactNode spinnerColor?: SpinnerColor styleAs?: 'button' | 'link' | 'link-without-hover' hideTextOnMobile?: boolean + shouldPreventDefault?: boolean } & ButtonHTMLAttributes) { const { children, @@ -17,7 +17,9 @@ export default function LoaderButton(props: { spinnerColor, styleAs = 'button', hideTextOnMobile = true, + shouldPreventDefault, type = 'button', + onClick, disabled, className, ...rest @@ -27,6 +29,10 @@ export default function LoaderButton(props: { + isLoading={isLoading} + /> ); } diff --git a/src/photo/ai/index.ts b/src/photo/ai/index.ts index 91db8318..92fba516 100644 --- a/src/photo/ai/index.ts +++ b/src/photo/ai/index.ts @@ -69,5 +69,4 @@ export const cleanUpAiTextResponse = (text?: string) => text .replaceAll('\n', ' ') .replaceAll('"', '') .replace(/\.$/, '') - .trim() : undefined; diff --git a/src/site/Footer.tsx b/src/site/Footer.tsx index 7daa878d..2bedaf0b 100644 --- a/src/site/Footer.tsx +++ b/src/site/Footer.tsx @@ -50,7 +50,7 @@ export default function Footer() {
signOutAndRedirectAction() .then(() => setUserEmail?.(undefined))}> - + Sign out