diff --git a/apps/client/src/features/app-settings/panel/project-panel/ProjectForm.tsx b/apps/client/src/features/app-settings/panel/project-panel/ProjectForm.tsx index 271868d1d..57fca85d7 100644 --- a/apps/client/src/features/app-settings/panel/project-panel/ProjectForm.tsx +++ b/apps/client/src/features/app-settings/panel/project-panel/ProjectForm.tsx @@ -2,8 +2,6 @@ import { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { Button, Input } from '@chakra-ui/react'; -import * as Panel from '../PanelUtils'; - import style from './ProjectPanel.module.scss'; export type ProjectFormValues = { @@ -15,10 +13,9 @@ interface ProjectFormProps { filename: string; onCancel: () => void; onSubmit: (values: ProjectFormValues) => Promise; - submitError: string | null; } -export default function ProjectForm({ action, filename, onSubmit, onCancel, submitError }: ProjectFormProps) { +export default function ProjectForm({ action, filename, onSubmit, onCancel }: ProjectFormProps) { const { handleSubmit, register, @@ -37,34 +34,31 @@ export default function ProjectForm({ action, filename, onSubmit, onCancel, subm }, [setFocus]); return ( - <> -
- + +
+ + - -
-
- {submitError && {submitError}} - + isDisabled={!isDirty || !isValid || isSubmitting} + type='submit' + className={style.saveButton} + > + {action} + + + ); } diff --git a/apps/client/src/features/app-settings/panel/project-panel/ProjectListItem.tsx b/apps/client/src/features/app-settings/panel/project-panel/ProjectListItem.tsx index b08ea15b6..a97728d0c 100644 --- a/apps/client/src/features/app-settings/panel/project-panel/ProjectListItem.tsx +++ b/apps/client/src/features/app-settings/panel/project-panel/ProjectListItem.tsx @@ -11,6 +11,7 @@ import { renameProject, } from '../../../../common/api/db'; import { invalidateAllCaches, maybeAxiosError } from '../../../../common/api/utils'; +import * as Panel from '../PanelUtils'; import ProjectForm, { ProjectFormValues } from './ProjectForm'; @@ -40,36 +41,53 @@ export default function ProjectListItem({ onToggleEditMode, }: ProjectListItemProps) { const [submitError, setSubmitError] = useState(null); + const [loading, setLoading] = useState(false); - const handleSubmitRename = async (values: ProjectFormValues) => { - try { + const handleSubmitAction = (actionType: 'rename' | 'duplicate') => { + return async (values: ProjectFormValues) => { + setLoading(true); setSubmitError(null); - - if (!values.filename) { - setSubmitError('Filename cannot be blank'); - return; + try { + if (!values.filename) { + setSubmitError('Filename cannot be blank'); + return; + } + const action = actionType === 'rename' ? renameProject : duplicateProject; + await action(filename, values.filename); + await onRefetch(); + onSubmit(); + } catch (error) { + setSubmitError(maybeAxiosError(error)); + } finally { + setLoading(false); } - await renameProject(filename, values.filename); + }; + }; + + const handleLoad = async (filename: string) => { + setLoading(true); + setSubmitError(null); + try { + await loadProject(filename); await onRefetch(); - onSubmit(); + await invalidateAllCaches(); } catch (error) { setSubmitError(maybeAxiosError(error)); + } finally { + setLoading(false); } }; - const handleSubmitDuplicate = async (values: ProjectFormValues) => { + const handleDelete = async (filename: string) => { + setLoading(true); + setSubmitError(null); try { - setSubmitError(null); - - if (!values.filename) { - setSubmitError('Filename cannot be blank'); - return; - } - await duplicateProject(filename, values.filename); + await deleteProject(filename); await onRefetch(); - onSubmit(); } catch (error) { setSubmitError(maybeAxiosError(error)); + } finally { + setLoading(false); } }; @@ -86,50 +104,55 @@ export default function ProjectListItem({ const classes = current && !isCurrentlyBeingEdited ? style.current : undefined; return ( - - {isCurrentlyBeingEdited ? ( - - - - ) : ( - <> - {filename} - {new Date(updatedAt).toLocaleString()} - - + {submitError && ( + + + {submitError} + + + )} + + {isCurrentlyBeingEdited ? ( + + - - )} - + ) : ( + <> + {filename} + {new Date(updatedAt).toLocaleString()} + + + + + )} + + ); } -function ActionMenu({ - current, - filename, - onChangeEditMode, - onRefetch, -}: { +interface ActionMenuProps { current?: boolean; filename: string; + isDisabled: boolean; onChangeEditMode: (editMode: EditMode, filename: string) => void; - onRefetch: () => Promise; -}) { - const handleLoad = async () => { - await loadProject(filename); - await invalidateAllCaches(); - }; + onDelete: (filename: string) => void; + onLoad: (filename: string) => void; +} +function ActionMenu(props: ActionMenuProps) { + const { current, filename, isDisabled, onChangeEditMode, onDelete, onLoad } = props; const handleRename = () => { onChangeEditMode('rename', filename); @@ -139,11 +162,6 @@ function ActionMenu({ onChangeEditMode('duplicate', filename); }; - const handleDelete = async () => { - await deleteProject(filename); - await onRefetch(); - }; - const handleDownload = async () => { await downloadProject(filename); }; @@ -161,16 +179,17 @@ function ActionMenu({ color='#e2e2e2' // $gray-200 variant='ontime-ghosted' size='sm' + isDisabled={isDisabled} /> - + onLoad(filename)} isDisabled={current}> Load Rename Duplicate Download Export CSV Rundown - + onDelete(filename)}> Delete