From 318367de2d6c1d3c46c3fd44b81057ff5a1153b5 Mon Sep 17 00:00:00 2001 From: MTG2000 Date: Thu, 15 Sep 2022 15:27:27 +0300 Subject: [PATCH] feat: add images input components to list-project, connect with api --- .../CoverImageInput/CoverImageInput.tsx | 4 +- .../ScreenshotsInput.stories.tsx | 9 ++-- .../ScreenshotsInput/ScreenshotsInput.tsx | 21 ++++---- .../FormContainer/FormContainer.tsx | 6 +-- .../ProjectDetailsTab/ProjectDetailsTab.tsx | 52 ++++++++++++++++--- .../SaveChangesCard/SaveChangesCard.tsx | 24 ++++++--- .../pages/ListProjectPage/ListProjectPage.tsx | 1 + 7 files changed, 80 insertions(+), 37 deletions(-) diff --git a/src/Components/Inputs/FilesInputs/CoverImageInput/CoverImageInput.tsx b/src/Components/Inputs/FilesInputs/CoverImageInput/CoverImageInput.tsx index 975366d..b4975a4 100644 --- a/src/Components/Inputs/FilesInputs/CoverImageInput/CoverImageInput.tsx +++ b/src/Components/Inputs/FilesInputs/CoverImageInput/CoverImageInput.tsx @@ -34,7 +34,7 @@ export default function CoverImageInput(props: Props) { wrapperClass='h-full' render={({ img, isUploading, isDraggingOnWindow }) =>
- {!img &&
+ {!img &&

Drop a COVER IMAGE here or
Click to browse @@ -56,7 +56,7 @@ export default function CoverImageInput(props: Props) { } {isUploading &&
}>({ + WrapFormController<{ screenshots: Array }>({ logValues: true, name: "screenshots", defaultValues: { @@ -29,7 +30,7 @@ Empty.args = { export const WithValues = Template.bind({}); WithValues.decorators = [ - WrapFormController<{ screenshots: Array }>({ + WrapFormController<{ screenshots: Array }>({ logValues: true, name: "screenshots", defaultValues: { @@ -51,7 +52,7 @@ WithValues.args = { export const Full = Template.bind({}); Full.decorators = [ - WrapFormController<{ screenshots: Array }>({ + WrapFormController<{ screenshots: Array }>({ logValues: true, name: "screenshots", defaultValues: { diff --git a/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput.tsx b/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput.tsx index b5bf6c0..4893118 100644 --- a/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput.tsx +++ b/src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput.tsx @@ -11,6 +11,8 @@ import { getMockSenderEnhancer } from "@rpldy/mock-sender"; import ScreenshotThumbnail from "./ScreenshotThumbnail"; import { FiCamera } from "react-icons/fi"; import { Control, Path, useController } from "react-hook-form"; +import { ImageInput } from "src/graphql"; +import { fetchUploadImageUrl } from "src/api/uploading"; @@ -20,15 +22,10 @@ const mockSenderEnhancer = getMockSenderEnhancer({ const MAX_UPLOAD_COUNT = 4 as const; -export interface ScreenshotType { - id: string, - name: string, - url: string; -} interface Props { - value: ScreenshotType[], - onChange: (new_value: ScreenshotType[]) => void + value: ImageInput[], + onChange: (new_value: ImageInput[]) => void } @@ -49,7 +46,6 @@ export default function ScreenshotsInput(props: Props) { multiple={true} inputFieldName='file' grouped={false} - enhancer={mockSenderEnhancer} listeners={{ [UPLOADER_EVENTS.BATCH_ADD]: (batch) => { setUploadingCount(v => v + batch.items.length) @@ -96,17 +92,18 @@ const DropZone = forwardRef((props, ref) => { useRequestPreSend(async (data) => { - const filename = data.items?.[0].file.name ?? '' - // const url = await fetchUploadUrl({ filename }); + const res = await fetchUploadImageUrl({ filename }); + return { options: { destination: { - url: "URL" - } + url: res.uploadURL + }, } } + }) const onZoneClick = useCallback( diff --git a/src/features/Projects/pages/ListProjectPage/Components/FormContainer/FormContainer.tsx b/src/features/Projects/pages/ListProjectPage/Components/FormContainer/FormContainer.tsx index 09fb258..add3831 100644 --- a/src/features/Projects/pages/ListProjectPage/Components/FormContainer/FormContainer.tsx +++ b/src/features/Projects/pages/ListProjectPage/Components/FormContainer/FormContainer.tsx @@ -71,11 +71,11 @@ const schema: yup.SchemaOf = yup.object({ github: yup.string().url().ensure(), category_id: yup.number().required("Please choose a category"), capabilities: yup.array().of(yup.string().required()).default([]), - screenshots: yup.array().of(yup.string().required()).default([]), + screenshots: yup.array().of(imageSchema.required()).default([]), members: yup.array().of(yup.object() as any).default([]), - recruit_roles: yup.array().of(yup.object() as any).default([]), + recruit_roles: yup.array().of(yup.number().required()).default([]), launch_status: yup.mixed().oneOf(['wip', 'launched']).default('wip'), - tournaments: yup.array().default([]) + tournaments: yup.array().of(yup.number().required()).default([]) }).required(); export default function FormContainer(props: PropsWithChildren) { diff --git a/src/features/Projects/pages/ListProjectPage/Components/ProjectDetailsTab/ProjectDetailsTab.tsx b/src/features/Projects/pages/ListProjectPage/Components/ProjectDetailsTab/ProjectDetailsTab.tsx index 68ff942..11a2dce 100644 --- a/src/features/Projects/pages/ListProjectPage/Components/ProjectDetailsTab/ProjectDetailsTab.tsx +++ b/src/features/Projects/pages/ListProjectPage/Components/ProjectDetailsTab/ProjectDetailsTab.tsx @@ -5,6 +5,9 @@ import { FiCamera, FiGithub, FiTwitter } from "react-icons/fi"; import CategoriesInput from "../CategoriesInput/CategoriesInput"; import CapabilitiesInput from "../CapabilitiesInput/CapabilitiesInput"; import { IListProjectForm } from "../FormContainer/FormContainer"; +import AvatarInput from "src/Components/Inputs/FilesInputs/AvatarInput/AvatarInput"; +import CoverImageInput from "src/Components/Inputs/FilesInputs/CoverImageInput/CoverImageInput"; +import ScreenshotsInput from "src/Components/Inputs/FilesInputs/ScreenshotsInput/ScreenshotsInput"; interface Props { } @@ -21,15 +24,28 @@ export default function ProjectDetailsTab(props: Props) {
+ { + onChange(e) + }} + // uploadText='Add a cover image' + /> + + } + />
- {/* */} -
- - Add image -
+ ( + + )} + />
@@ -184,6 +200,26 @@ export default function ProjectDetailsTab(props: Props) { {errors.capabilities &&

{errors.capabilities?.message}

}
+ + +

📷 Screenshots

+

Choose up to 4 images from your project

+
+ { + onChange(e) + }} + /> + + } + /> + {errors.capabilities &&

{errors.capabilities?.message}

} +
+
) } diff --git a/src/features/Projects/pages/ListProjectPage/Components/SaveChangesCard/SaveChangesCard.tsx b/src/features/Projects/pages/ListProjectPage/Components/SaveChangesCard/SaveChangesCard.tsx index 6b4c539..549982f 100644 --- a/src/features/Projects/pages/ListProjectPage/Components/SaveChangesCard/SaveChangesCard.tsx +++ b/src/features/Projects/pages/ListProjectPage/Components/SaveChangesCard/SaveChangesCard.tsx @@ -9,31 +9,40 @@ import { tabs } from '../../ListProjectPage' import { NotificationsService } from 'src/services' import { useAppDispatch } from 'src/utils/hooks'; import { openModal } from 'src/redux/features/modals.slice'; +import { useCreateProjectMutation, useUpdateProjectMutation } from 'src/graphql' interface Props { currentTab: keyof typeof tabs onNext: () => void + onBackToFirstPage: () => void } export default function SaveChangesCard(props: Props) { const { handleSubmit, formState: { errors, isDirty, }, reset, getValues, watch } = useFormContext(); - const navigate = useNavigate(); const dispatch = useAppDispatch(); const [isLoading, setIsLoading] = useState(false); const isUpdating = useMemo(() => !!getValues('id'), [getValues]); + const [update, updatingStatus] = useUpdateProjectMutation(); + const [create, creatingStatus] = useCreateProjectMutation() - const [img, name, tagline] = watch(['thumbnail_image', 'title', 'tagline']) + + const [img, name, tagline] = watch(['thumbnail_image', 'title', 'tagline',]) const clickCancel = () => { if (window.confirm('You might lose some unsaved changes. Are you sure you want to continue?')) reset(); } - const clickSubmit = handleSubmit(data => { - + const clickSubmit = handleSubmit(async data => { + try { + await (isUpdating ? update({ variables: { input: data } }) : create({ variables: { input: data } })) + } catch (error) { + NotificationsService.error("A network error happened..."); + return; + } if (isUpdating) NotificationsService.success("Saved changes successfully") else { @@ -48,10 +57,9 @@ export default function SaveChangesCard(props: Props) { } })) } - console.log(data); - }, () => { + }, (errors) => { NotificationsService.error("Please fill all the required fields"); - navigate(tabs['project-details'].path) + props.onBackToFirstPage() }) @@ -91,7 +99,7 @@ export default function SaveChangesCard(props: Props) { > List your product - }, [clickSubmit, isDirty, isLoading, isUpdating, props.currentTab]) + }, [clickSubmit, isDirty, isLoading, isUpdating, props.currentTab, props.onNext]) return ( diff --git a/src/features/Projects/pages/ListProjectPage/ListProjectPage.tsx b/src/features/Projects/pages/ListProjectPage/ListProjectPage.tsx index 5cf82b5..9f70496 100644 --- a/src/features/Projects/pages/ListProjectPage/ListProjectPage.tsx +++ b/src/features/Projects/pages/ListProjectPage/ListProjectPage.tsx @@ -117,6 +117,7 @@ export default function ListProjectPage() { if (curTab === 'project-details') setCurTab(tabs['team'].path) else if (curTab === 'team') setCurTab(tabs['extras'].path) }} + onBackToFirstPage={() => setCurTab(tabs["project-details"].path)} />