Skip to content

Commit

Permalink
move farcaster avatars to pinata (#1469)
Browse files Browse the repository at this point in the history
* feat: move farcaster avatars to pinata on profile update

* chore: restrict submit when uploading image

* feat: upload farcaster image to IPFS in EditProfile

* feat(EditProfilePicture): show spinner if progress is not available

* refactor: extract image uploader

* refactor: exclude not required fields

* chore: rename uploader

* cleanup(StartProfile): remove unnecessary loading condition
isUploadingShown already handles it, avoiding confusion about why the button might be disabled

---------

Co-authored-by: valid <[email protected]>
  • Loading branch information
dominik-stumpf and dovalid authored Sep 6, 2024
1 parent 81e2a2e commit c6a1b5a
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

import FarcasterImage from "@/../static/socialIcons/farcaster.svg"
import { ConnectFarcasterButton } from "@/components/Account/components/AccountModal/components/FarcasterProfile"
import {} from "@/components/ui/Avatar"
import { Button } from "@/components/ui/Button"
import {
FormControl,
Expand All @@ -12,15 +11,15 @@ import {
FormLabel,
} from "@/components/ui/Form"
import { Input } from "@/components/ui/Input"
import { uploadImageUrlToPinata } from "@/lib/uploadImageUrlToPinata"
import { EditProfilePicture } from "@app/(marketing)/profile/_components/EditProfile/EditProfilePicture"
import { Schemas, schemas } from "@guildxyz/types"
import { zodResolver } from "@hookform/resolvers/zod"
import {} from "@phosphor-icons/react"
import { ArrowRight } from "@phosphor-icons/react/dist/ssr"
import useUser from "components/[guild]/hooks/useUser"
import usePinata from "hooks/usePinata"
import useSubmitWithUpload from "hooks/useSubmitWithUpload"
import { useEffect, useState } from "react"
import { useEffect, useRef, useState } from "react"
import { FormProvider, useForm } from "react-hook-form"
import { useCreateProfile } from "../_hooks/useCreateProfile"
import { CreateProfileStep } from "../types"
Expand All @@ -37,19 +36,6 @@ export const StartProfile: CreateProfileStep = ({ data: chainData }) => {
farcasterProfile ? CreateMethod.FillByFarcaster : undefined
)

useEffect(() => {
if (!farcasterProfile) return
setMethod(CreateMethod.FillByFarcaster)
form.setValue(
"name",
farcasterProfile.username ?? form.getValues()?.name ?? "",
{ shouldValidate: true }
)
form.setValue("profileImageUrl", farcasterProfile.avatar, {
shouldValidate: true,
})
}, [farcasterProfile])

const form = useForm<Schemas["ProfileCreation"]>({
resolver: zodResolver(
schemas.ProfileCreationSchema.omit({ referrerUserId: true })
Expand Down Expand Up @@ -84,6 +70,23 @@ export const StartProfile: CreateProfileStep = ({ data: chainData }) => {
control: form.control,
fieldToSetOnSuccess: "profileImageUrl",
})
const isFarcasterAvatarUploaded = useRef(false)

useEffect(() => {
if (!farcasterProfile) return
setMethod(CreateMethod.FillByFarcaster)
form.setValue(
"name",
farcasterProfile.username ?? form.getValues()?.name ?? "",
{ shouldValidate: true }
)
if (!farcasterProfile.avatar || isFarcasterAvatarUploaded.current) return
uploadImageUrlToPinata({
onUpload: profilePicUploader.onUpload,
image: new URL(farcasterProfile.avatar),
})
isFarcasterAvatarUploaded.current = true
}, [farcasterProfile, profilePicUploader.onUpload, form.setValue, form.getValues])

const { handleSubmit, isUploadingShown, uploadLoadingText } = useSubmitWithUpload(
form.handleSubmit(onSubmit),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
DialogTitle,
DialogTrigger,
} from "@/components/ui/Dialog"
import {} from "@/components/ui/DropdownMenu"
import {
FormControl,
FormErrorMessage,
Expand Down Expand Up @@ -77,7 +76,7 @@ export const EditProfile = ({ children }: PropsWithChildren<any>) => {
uploader={profilePicUploader}
className="-bottom-2 absolute left-4 translate-y-1/2 bg-muted"
/>
<EditProfileDropdown />
<EditProfileDropdown uploader={profilePicUploader} />
</div>

<FormField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,25 @@ import {
DropdownMenuSeparator,
DropdownMenuTrigger,
} from "@/components/ui/DropdownMenu"
import { uploadImageUrlToPinata } from "@/lib/uploadImageUrlToPinata"
import {
ArrowsClockwise,
DotsThreeVertical,
Spinner,
TrashSimple,
} from "@phosphor-icons/react"
import useUser from "components/[guild]/hooks/useUser"
import { Uploader } from "hooks/usePinata/usePinata"
import { FunctionComponent } from "react"
import { useFormContext } from "react-hook-form"
import { useDeleteProfile } from "../../_hooks/useDeleteProfile"

export const EditProfileDropdown = () => {
export const EditProfileDropdown: FunctionComponent<{ uploader: Uploader }> = ({
uploader,
}) => {
const { farcasterProfiles } = useUser()
const farcasterProfile = farcasterProfiles?.at(0)
const { setValue } = useFormContext()

const deleteProfile = useDeleteProfile()

return (
Expand All @@ -38,16 +42,16 @@ export const EditProfileDropdown = () => {
<DropdownMenuItem
className="flex gap-2 px-4 py-6 font-semibold"
onClick={() => {
if (farcasterProfile.avatar) {
setValue("profileImageUrl", farcasterProfile.avatar, {
shouldValidate: true,
})
}
if (farcasterProfile.username) {
setValue("name", farcasterProfile.username, {
shouldValidate: true,
})
}
if (!farcasterProfile.avatar) return
uploadImageUrlToPinata({
onUpload: uploader.onUpload,
image: new URL(farcasterProfile.avatar),
})
}}
>
<ArrowsClockwise weight="bold" /> Fill data by Farcaster
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Button } from "@/components/ui/Button"
import { FormField } from "@/components/ui/Form"
import { toast } from "@/components/ui/hooks/useToast"
import { cn } from "@/lib/utils"
import { Image, UploadSimple, User } from "@phosphor-icons/react"
import { Image, Spinner, UploadSimple, User } from "@phosphor-icons/react"
import { AvatarImage } from "@radix-ui/react-avatar"
import useDropzone from "hooks/useDropzone"
import { Uploader } from "hooks/usePinata/usePinata"
Expand Down Expand Up @@ -74,7 +74,11 @@ export const EditProfilePicture = ({
)}
>
{isUploading ? (
<p>{(uploadProgress * 100).toFixed(0)}%</p>
uploadProgress ? (
<p>{(uploadProgress * 100).toFixed(0)}%</p>
) : (
<Spinner weight="bold" size={24} className="animate-spin" />
)
) : isDragActive ? (
<UploadSimple weight="bold" size={24} className="animate-wiggle" />
) : (
Expand Down
13 changes: 13 additions & 0 deletions src/v2/lib/uploadImageUrlToPinata.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Uploader } from "hooks/usePinata/usePinata"

export const uploadImageUrlToPinata = async ({
image,
onUpload,
}: { image: URL; onUpload: Uploader["onUpload"] }) => {
const data = await (await fetch(image)).blob()
const fileName = image.pathname.split("/").at(-1) || "unknown"
onUpload({
data: [new File([data], fileName)],
fileNames: [fileName],
})
}

0 comments on commit c6a1b5a

Please sign in to comment.