diff --git a/app/hooks/projects/index.ts b/app/hooks/projects/index.ts index e6d180dd53..34530b0f25 100644 --- a/app/hooks/projects/index.ts +++ b/app/hooks/projects/index.ts @@ -219,11 +219,8 @@ export function useSaveProject({ }; return useMutation(saveProject, { - onSuccess: (data: any, variables, context) => { - const { id } = data; + onSuccess: () => { queryClient.invalidateQueries('projects'); - queryClient.invalidateQueries(['project', id]); - console.info('Succces', data, variables, context); }, onError: (error, variables, context) => { // An error happened! diff --git a/app/layout/project/sidebar/header/title/index.tsx b/app/layout/project/sidebar/header/title/index.tsx new file mode 100644 index 0000000000..26d2e3d5be --- /dev/null +++ b/app/layout/project/sidebar/header/title/index.tsx @@ -0,0 +1,238 @@ +import { ComponentProps, HTMLAttributes, useCallback, useRef, useState } from 'react'; + +import { Form as FormRFF, Field as FieldRFF, FormProps } from 'react-final-form'; + +import { useRouter } from 'next/router'; + +import { AnimatePresence, motion } from 'framer-motion'; +import { HiOutlinePencil, HiCheck, HiX } from 'react-icons/hi'; + +import { useCanEditProject } from 'hooks/permissions'; + +import { composeValidators } from 'components/forms/validations'; +import { cn } from 'utils/cn'; + +export type FormFields = { + name: string; + description: string; +}; + +const EditableTitle = ({ + title, + description, + className, + onEditTitle, +}: { + title: string; + description?: string; + className?: HTMLAttributes['className']; + onEditTitle: (newName: string) => void; +}): JSX.Element => { + const { query } = useRouter(); + const { pid } = query as { pid: string }; + const titleInputRef = useRef(null); + + const [editting, setEditting] = useState(false); + const textRefArea = useRef(null); + + const editable = useCanEditProject(pid); + + const handleSubmit = useCallback( + (data: Parameters>['onSubmit']>[0]) => { + titleInputRef.current?.blur(); + onEditTitle(data.name); + setEditting(false); + }, + [onEditTitle, titleInputRef] + ); + + const handleEdition = useCallback(() => { + if (!editting && editable && titleInputRef.current) { + setTimeout(() => { + titleInputRef.current.focus(); + }, 0); + } + setEditting(true); + }, [titleInputRef, editable, editting]); + + const handleCancel = useCallback((form: FormProps['form']) => { + setEditting(false); + form.reset(); + }, []); + + const invisibleValue = useCallback((value: string) => { + if (value) { + return value.replace(/\s/g, '-'); + } + return value; + }, []); + + return ( + + + + onSubmit={handleSubmit} + mutators={{ + setTrimName: (args, state, utils) => { + const [name] = args; + utils.changeValue(state, 'name', () => name.trim()); + }, + }} + initialValues={{ + name: title, + description, + }} + > + {(fprops) => ( +
+
+ + name="name" + validate={composeValidators([{ presence: true }])} + beforeSubmit={() => { + const { values } = fprops; + fprops.form.mutators.setTrimName(values.name); + }} + > + {({ input }) => ( +
+
+ + +

+ {invisibleValue(input?.value)} +

+
+
+ )} + + +
+ {editable && !editting && ( + + + + )} + {editable && editting && ( + + + + )} + + {editable && editting && ( + handleCancel(fprops.form)} + > + + + )} +
+
+ name="description"> + {({ input }) => ( +
+
+
+

+ {input.value} +

+