diff --git a/src/components/ImageUpload.tsx b/src/components/ImageUpload.tsx index de7b14aa..a914a0fb 100644 --- a/src/components/ImageUpload.tsx +++ b/src/components/ImageUpload.tsx @@ -6,8 +6,6 @@ import { Controller, useFormContext } from "react-hook-form"; import { toast } from "sonner"; import { IconButton } from "~/components/ui/Button"; -import { Spinner } from "~/components/ui/Spinner"; -import { useUploadMetadata } from "~/hooks/useMetadata"; export interface IImageUploadProps extends ComponentProps<"img"> { name?: string; @@ -22,7 +20,6 @@ export const ImageUpload = ({ const ref = useRef(null); const { control } = useFormContext(); - const upload = useUploadMetadata(); const select = useMutation({ mutationFn: async (file: File) => { if (file.size >= maxSize) { @@ -46,16 +43,10 @@ export const ImageUpload = ({ className={clsx("relative cursor-pointer overflow-hidden", className)} onClick={() => ref.current?.click()} > - +
{ - upload.mutate(file, { - onSuccess: (data) => { - onChange(data.url); - }, - }); + onSuccess: (objectUrl) => { + onChange(objectUrl); }, }); } diff --git a/src/components/ui/Tooltip.tsx b/src/components/ui/Tooltip.tsx index 4cf13a0d..5a41b87a 100644 --- a/src/components/ui/Tooltip.tsx +++ b/src/components/ui/Tooltip.tsx @@ -17,7 +17,7 @@ export const Tooltip = ({ description }: ITooltipProps): JSX.Element => { }, [setShowBlock]); return ( -
+
{showBlock && ( diff --git a/src/features/applications/components/ApplicationButtons.tsx b/src/features/applications/components/ApplicationButtons.tsx index 777b8276..9bfe58db 100644 --- a/src/features/applications/components/ApplicationButtons.tsx +++ b/src/features/applications/components/ApplicationButtons.tsx @@ -39,7 +39,35 @@ export const ApplicationButtons = ({ const form = useFormContext(); - const application = useMemo(() => form.getValues(), [form]); + const [ + name, + bio, + payoutAddress, + websiteUrl, + profileImageUrl, + bannerImageUrl, + contributionDescription, + impactDescription, + impactCategory, + contributionLinks, + fundingSources, + ] = useMemo( + () => + form.watch([ + "name", + "bio", + "payoutAddress", + "websiteUrl", + "profileImageUrl", + "bannerImageUrl", + "contributionDescription", + "impactDescription", + "impactCategory", + "contributionLinks", + "fundingSources", + ]), + [form], + ); const checkLinks = ( links: Pick[] | undefined, @@ -48,20 +76,6 @@ export const ApplicationButtons = ({ links.reduce((prev, link) => prev && link.description !== undefined && link.description.length > 0, true); const stepComplete = useMemo((): boolean => { - const { - name, - bio, - payoutAddress, - websiteUrl, - profileImageUrl, - bannerImageUrl, - contributionDescription, - impactDescription, - impactCategory, - contributionLinks, - fundingSources, - } = application; - if (step === EApplicationStep.PROFILE) { return ( bannerImageUrl !== undefined && @@ -76,6 +90,7 @@ export const ApplicationButtons = ({ if (step === EApplicationStep.ADVANCED) { return ( impactCategory !== undefined && + impactCategory.length > 0 && contributionDescription.length > 0 && impactDescription.length > 0 && checkLinks(contributionLinks) && @@ -84,15 +99,41 @@ export const ApplicationButtons = ({ } return true; - }, [step, application]); + }, [ + step, + bannerImageUrl, + profileImageUrl, + bio, + name, + payoutAddress, + websiteUrl, + impactCategory, + contributionDescription, + impactDescription, + contributionLinks, + fundingSources, + ]); + + const handleOnClickNextStep = useCallback( + (event: UIEvent) => { + event.preventDefault(); + + if (stepComplete) { + onNextStep(); + } else { + setShowDialog(true); + } + }, + [onNextStep, setShowDialog, stepComplete], + ); - const handleOnClickNextStep = useCallback(() => { - if (stepComplete) { - onNextStep(); - } else { - setShowDialog(true); - } - }, [onNextStep, setShowDialog, stepComplete]); + const handleOnClickBackStep = useCallback( + (event: UIEvent) => { + event.preventDefault(); + onBackStep(); + }, + [onBackStep], + ); const handleOnOpenChange = useCallback(() => { setShowDialog(false); @@ -109,7 +150,7 @@ export const ApplicationButtons = ({ /> {step !== EApplicationStep.PROFILE && ( - )} diff --git a/src/features/applications/components/ApplicationForm.tsx b/src/features/applications/components/ApplicationForm.tsx index 439d1185..95831675 100644 --- a/src/features/applications/components/ApplicationForm.tsx +++ b/src/features/applications/components/ApplicationForm.tsx @@ -117,11 +117,22 @@ export const ApplicationForm = (): JSX.Element => {
- + - +
diff --git a/src/features/applications/hooks/useCreateApplication.ts b/src/features/applications/hooks/useCreateApplication.ts index 06a4ef8d..b7cefa9c 100644 --- a/src/features/applications/hooks/useCreateApplication.ts +++ b/src/features/applications/hooks/useCreateApplication.ts @@ -26,9 +26,25 @@ export function useCreateApplication(options: { const upload = useUploadMetadata(); const mutation = useMutation({ - mutationFn: async (values: Application) => - Promise.all([ - upload.mutateAsync(values).then(({ url: metadataPtr }) => + mutationFn: async (values: Application) => { + if (!values.bannerImageUrl || !values.profileImageUrl) { + throw new Error("No images included."); + } + + const [profileImageFile, bannerImageFile] = await Promise.all([ + fetch(values.profileImageUrl), + fetch(values.bannerImageUrl), + ]).then(([profileImage, bannerImage]) => Promise.all([profileImage.blob(), bannerImage.blob()])); + + const [profileImageUrl, bannerImageUrl] = await Promise.all([ + upload.mutateAsync(new File([profileImageFile], "profileImage")), + upload.mutateAsync(new File([bannerImageFile], "bannerImage")), + ]); + + const metadataValues = { ...values, profileImageUrl: profileImageUrl.url, bannerImageUrl: bannerImageUrl.url }; + + return Promise.all([ + upload.mutateAsync(metadataValues).then(({ url: metadataPtr }) => attestation.mutateAsync({ schemaUID: eas.schemas.metadata, values: { @@ -40,7 +56,8 @@ export function useCreateApplication(options: { }, }), ), - ]).then((attestations) => attest.mutateAsync(attestations.map((att) => ({ ...att, data: [att.data] })))), + ]).then((attestations) => attest.mutateAsync(attestations.map((att) => ({ ...att, data: [att.data] })))); + }, ...options, }); diff --git a/src/pages/applications/confirmation.tsx b/src/pages/applications/confirmation.tsx index fe301d47..ba4d8e7b 100644 --- a/src/pages/applications/confirmation.tsx +++ b/src/pages/applications/confirmation.tsx @@ -14,7 +14,7 @@ const ConfirmProjectPage = (): JSX.Element => { const state = useAppState(); const searchParams = useSearchParams(); - const txHash = searchParams.get("txHash"); + const txHash = useMemo(() => searchParams.get("txHash"), [searchParams]); const project = useApplicationByTxHash(txHash ?? ""); const attestation = useMemo(() => project.data, [project]);