Adding images uploading support in profile edit page

This commit is contained in:
kiuusai 2025-02-12 19:43:30 -03:00
parent a0dfb6c076
commit de6f39d3d1
No known key found for this signature in database
GPG Key ID: 99D962682DD15C7F
2 changed files with 101 additions and 14 deletions

View File

@ -0,0 +1,37 @@
import { ChangeEventHandler, ClipboardEventHandler, useCallback } from "react";
import useUploadFile from "./use-upload-file";
import { UseFormSetValue } from "react-hook-form";
export function useInputUploadFileWithForm(setValue: UseFormSetValue<any>, field: string) {
const setText = useCallback((text: string) => setValue(field, text), [setValue]);
return useInputUploadFile(setText);
}
export default function useInputUploadFile(setText: (text: string) => void) {
const { uploadFile, uploading } = useUploadFile();
const privateUploadFile = useCallback(async (file: File) => {
const imageUrl = await uploadFile(file);
if (imageUrl)
setText(imageUrl);
}, [uploadFile])
const onFileInputChange = useCallback<ChangeEventHandler<HTMLInputElement>>(
(e) => {
const img = e.target.files?.[0];
if (img) privateUploadFile(img);
},
[privateUploadFile],
);
const onPaste = useCallback<ClipboardEventHandler<HTMLInputElement>>(
(e) => {
const imageFile = Array.from(e.clipboardData.files).find((f) => f.type.includes("image"));
if (imageFile) privateUploadFile(imageFile);
},
[privateUploadFile],
);
return { uploadFile, uploading, onPaste, onFileInputChange };
}

View File

@ -1,4 +1,4 @@
import { useEffect, useMemo } from "react";
import { useEffect, useMemo, useRef } from "react";
import {
Avatar,
Button,
@ -9,11 +9,15 @@ import {
Input,
Link,
Textarea,
InputGroup,
InputRightElement,
IconButton,
VisuallyHiddenInput,
} from "@chakra-ui/react";
import { useForm } from "react-hook-form";
import { ProfileContent, unixNow } from "applesauce-core/helpers";
import { ExternalLinkIcon } from "../../components/icons";
import { ExternalLinkIcon, OutboxIcon } from "../../components/icons";
import { isLNURL } from "../../helpers/lnurl";
import { useReadRelays } from "../../hooks/use-client-relays";
import { useActiveAccount } from "applesauce-react/hooks";
@ -24,6 +28,7 @@ import lnurlMetadataService from "../../services/lnurl-metadata";
import VerticalPageLayout from "../../components/vertical-page-layout";
import { COMMON_CONTACT_RELAYS } from "../../const";
import { usePublishEvent } from "../../providers/global/publish-provider";
import { useInputUploadFileWithForm } from "../../hooks/use-input-upload-file";
const isEmail =
/^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
@ -55,6 +60,7 @@ const MetadataForm = ({ defaultValues, onSubmit }: MetadataFormProps) => {
reset,
handleSubmit,
watch,
setValue,
formState: { errors, isSubmitting },
} = useForm<FormData>({
mode: "onBlur",
@ -65,6 +71,12 @@ const MetadataForm = ({ defaultValues, onSubmit }: MetadataFormProps) => {
reset(defaultValues);
}, [defaultValues]);
const pictureUploadManage = useInputUploadFileWithForm(setValue, "picture");
const pictureUploadRef = useRef<HTMLInputElement | null>(null);
const bannerUploadManage = useInputUploadFileWithForm(setValue, "banner");
const bannerUploadRef = useRef<HTMLInputElement | null>(null);
return (
<VerticalPageLayout as="form" onSubmit={handleSubmit(onSubmit)}>
<Flex gap="2">
@ -113,24 +125,62 @@ const MetadataForm = ({ defaultValues, onSubmit }: MetadataFormProps) => {
<Flex gap="2" alignItems="center">
<FormControl isInvalid={!!errors.picture}>
<FormLabel>Picture</FormLabel>
<Input
autoComplete="off"
isDisabled={isSubmitting}
placeholder="https://domain.com/path/picture.png"
{...register("picture", { maxLength: 150 })}
/>
<InputGroup>
<Input
onPaste={pictureUploadManage.onPaste}
autoComplete="off"
isDisabled={isSubmitting}
placeholder="https://domain.com/path/picture.png"
{...register("picture", { maxLength: 150 })}
/>
<InputRightElement>
<IconButton
isLoading={pictureUploadManage.uploading}
size="sm"
icon={<OutboxIcon />}
title="Upload picture"
aria-label="Upload picture"
onClick={() => pictureUploadRef.current?.click()}
/>
</InputRightElement>
<VisuallyHiddenInput
type="file"
accept="image/*"
ref={pictureUploadRef}
onChange={pictureUploadManage.onFileInputChange}
/>
</InputGroup>
</FormControl>
<Avatar src={watch("picture")} size="lg" ignoreFallback />
</Flex>
<Flex gap="2" alignItems="center">
<FormControl isInvalid={!!errors.banner}>
<FormLabel>Banner</FormLabel>
<Input
autoComplete="off"
isDisabled={isSubmitting}
placeholder="https://domain.com/path/banner.png"
{...register("banner", { maxLength: 150 })}
/>
<InputGroup>
<Input
onPaste={bannerUploadManage.onPaste}
autoComplete="off"
isDisabled={isSubmitting}
placeholder="https://domain.com/path/banner.png"
{...register("banner", { maxLength: 150 })}
/>
<InputRightElement>
<IconButton
isLoading={bannerUploadManage.uploading}
size="sm"
icon={<OutboxIcon />}
title="Upload baner"
aria-label="Upload banner"
onClick={() => bannerUploadRef.current?.click()}
/>
</InputRightElement>
<VisuallyHiddenInput
type="file"
accept="image/*"
ref={bannerUploadRef}
onChange={bannerUploadManage.onFileInputChange}
/>
</InputGroup>
</FormControl>
<Avatar src={watch("banner")} size="lg" ignoreFallback />
</Flex>