I am using the Upload component antd. For any reason it shows the upload file in red even though when submit image successfully change. I try returning false from beforeUpload but if I do this while using antd-img-crop, the cropping functionality does not work. How to remove color red when upload the file while keep ant-img-crop function?
How to make border not turn red when upload picture?
here the code
const Setting = () => {
const [memberData, setMemberData] = useState<MemberDataProps>();
const [name, setName] = useState('');
const [email, setEmail] = useState('');
const [phoneNumber, setPhoneNumber] = useState('');
const [expiredDate, setExpiredDate] = useState('');
const [isPhoneInvalid, setIsPhoneInvalid] = useState(false);
const [isSubscribe, setIsSubscribe] = useState(false);
const [newPicture, setNewPicture] = useState<any[]>([]);
const handleImageUpload = async (info: any) => {
let fileList = [...info.fileList];
fileList = fileList.slice(-1);
fileList = fileList.map((file) => {
if (file.response) {
file.url = file.response.url;
}
return file;
});
setNewPicture(fileList);
};
const onPreview = async (file: UploadFile) => {
let src = file.url as string;
if (!src) {
src = await new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file.originFileObj as RcFile);
reader.onload = () => resolve(reader.result as string);
});
}
const image = new (Image as any)();
image.src = src;
const imgWindow = window.open(src);
imgWindow?.document.write(image.outerHTML);
};
console.log(newPicture);
const toast = useToast();
const navigate = useNavigate();
const handlePhoneNumber = (value: string) => {
const isNumber = value.match(/^[0-9b]+$/);
setPhoneNumber(value);
if (isNumber) {
setIsPhoneInvalid(false);
} else {
setIsPhoneInvalid(true);
}
if (value.length < 11) {
setIsPhoneInvalid(true);
}
};
const handleSubmit = async () => {
const formData = new FormData();
formData.append('name', name);
formData.append('phoneNumber', phoneNumber);
if (newPicture) {
formData.append('profilePhoto', newPicture[0]?.originFileObj || newPicture[0]?.url);
}
formData.append('subscribeNewsletter', String(isSubscribe));
try {
await fetchFormData({
method: 'PATCH',
path: 'member/data',
data: formData,
}).then((response) => {
if (!response.error) {
toast({
title: 'Berhasil',
description: 'Profil Anda telah berhasil diperbaharui',
status: 'success',
duration: 9000,
isClosable: true,
});
getMemberData();
} else {
toast({
title: 'Error',
description: response.message,
status: 'error',
duration: 9000,
isClosable: true,
});
}
});
} catch (error) {
toast({
title: 'Error',
description: error.message,
status: 'error',
duration: 9000,
isClosable: true,
});
}
};
const getMemberData = async () => {
try {
await fetchRequest({ method: 'GET', path: 'member' }).then((response) => {
if (!response.error) {
setMemberData(response);
setPhoneNumber(response.phoneNumber);
setExpiredDate(
dayjs(response.membershipValidEnd).format('DD MMMM YYYY')
);
setEmail(response.email);
setName(response.name);
setIsSubscribe(response.subscribeNewsletter);
}
});
} catch (error) {
console.log(error);
}
};
useEffect(() => {
getMemberData();
}, []);
return (
<Box>
<Box h="30px" paddingLeft={{ base: '10px', lg: '3%' }} w="100%">
<CustomBreadcrumb breadcrumbs={BREADCRUMB_PENGATURAN} />
</Box>
<Stack
w={{ xl: '100%' }}
direction={['column', 'row']}
spacing={{ md: '50px', base: '30px' }}
paddingLeft={{ base: '3%' }}
paddingRight={{ base: '3%' }}
paddingTop={{ base: '0px', lg: '20px' }}
>
<Box
w={{ md: '20%' }}
h="400px"
display={{ md: 'inline', base: 'none' }}
/>
<Box w="100%">
<VStack w="100%" marginBottom="10px">
<ImgCrop cropShape="round">
<Upload
action="https://run.mocky.io/v3/435e224c-44fb-4773-9faf-380c5e6a2188"
name="Profile Picture"
listType="picture-circle"
fileList={newPicture}
onChange={handleImageUpload}
onPreview={onPreview}
// beforeUpload={()=> false}
showUploadList={{
showPreviewIcon:false
}}
>
{newPicture.length < 1 && '+ Edit'}
</Upload>
</ImgCrop>
</VStack>
<VStack align="start">
<Text className="fontSemiBold" fontSize={{ lg: 'md', base: 'sm' }}>
Name
</Text>
<InputGroup paddingTop="5px" zIndex={0}>
<InputLeftElement
pointerEvents="none"
children={<Image src={imgUsernameIcon} w="30%" />}
paddingTop="5px"
/>
<Input
type="text"
placeholder="Masukkan Nama"
_focus={{ boxShadow: 'none', borderColor: RED }}
fontSize={{ lg: 'md', base: 'sm' }}
value={name}
onChange={(e: any) => setName(e.target.value)}
errorBorderColor={RED}
isInvalid={name === ''}
/>
</InputGroup>
<Text className="fontSemiBold" fontSize={{ lg: 'md', base: 'sm' }}>
Email
</Text>
<InputGroup paddingTop="5px" zIndex={0}>
<InputLeftElement
pointerEvents="none"
children={<EmailIcon color="#AAAAAA" />}
paddingTop="5px"
/>
<Input
type="email"
placeholder="Masukkan Email"
_focus={{ boxShadow: 'none', borderColor: RED }}
fontSize={{ lg: 'md', base: 'sm' }}
value={email}
disabled
/>
</InputGroup>
<Checkbox
isChecked={isSubscribe}
onChange={(e: any) => setIsSubscribe(e.target.checked)}
colorScheme="red"
>
Kirimkan saya berita rutin dari Astagatra Institute
</Checkbox>
<Text className="fontSemiBold" fontSize={{ lg: 'md', base: 'sm' }}>
Nomor Telepon
</Text>
<InputGroup paddingTop="5px" zIndex={0}>
<InputLeftElement
pointerEvents="none"
children={<PhoneIcon color="#AAAAAA" />}
paddingTop="5px"
/>
<Input
type="text"
placeholder="Masukkan Nomor HP"
_focus={{ boxShadow: 'none', borderColor: RED }}
fontSize={{ lg: 'md', base: 'sm' }}
value={phoneNumber}
onChange={(e: any) => handlePhoneNumber(e.target.value)}
isInvalid={isPhoneInvalid}
errorBorderColor={RED}
/>
</InputGroup>
<Text className="fontSemiBold" fontSize={{ lg: 'md', base: 'sm' }}>
Masa Berlaku Keanggotaan
</Text>
<InputGroup paddingTop="5px" zIndex={0}>
<InputLeftElement
pointerEvents="none"
children={<CalendarIcon color="#AAAAAA" />}
paddingTop="5px"
/>
<Input
type="text"
placeholder="Masa Berlaku Keanggotaan"
_focus={{ boxShadow: 'none', borderColor: RED }}
fontSize={{ lg: 'md', base: 'sm' }}
value={expiredDate}
disabled
/>
</InputGroup>
<Text className="fontSemiBold" fontSize={{ lg: 'md', base: 'sm' }}>
Password
</Text>
<Button
rightIcon={<ChevronRightIcon color={GREY} />}
w="100%"
bg={LIGHTGREY}
color={GREY}
_focus={{ boxShadow: 'none' }}
justifyContent="space-between"
onClick={() => navigate(MEMBER_SETTING_RESET_PASSWORD)}
>
<Text>Ubah Password</Text>
</Button>
<Box textAlign="end" w="100%">
<CustomButton
text="SIMPAN"
variant="red"
icon="none"
w="150px"
onClick={handleSubmit}
/>
</Box>
</VStack>
</Box>
<Box
w={{ md: '20%' }}
h="400px"
display={{ md: 'inline', base: 'none' }}
/>
</Stack>
</Box>
);
};
export default Setting;
2
Answers
You should repelace
action
prop fromUpload
component to your backend upload route instead of pointing tomocky.io
so antd will auto upload your images to this url.You can find examples in antd docs here
First "beforeUpload" prop is to "Hook function which will be executed before uploading. Uploading will be stopped with false or a rejected Promise returned. When returned value is Upload.LIST_IGNORE, the list of files that have been uploaded will ignore it." according to ant design documentation.
Seems like you want to use ant design file upload as form field.
you can use "customRequest" property to fix your problem. demo