import Cookies from 'js-cookie'; import { type ChangeEvent, type FormEvent, useEffect, useRef, useState } from 'react'; import { TOKEN_COOKIE_NAME, removeAuthToken } from '../../lib/jwt'; interface PreviewFile extends File { preview: string; } type UploadProfilePictureProps = { isDisabled?: boolean; avatarUrl: string; type: 'avatar' | 'logo'; label?: string; teamId?: string; }; function getDimensions(file: File) { return new Promise<{ width: number; height: number; }>((resolve) => { const img = new Image(); img.onload = () => { resolve({ width: img.width, height: img.height }); }; img.onerror = () => { resolve({ width: 0, height: 0 }); }; img.src = URL.createObjectURL(file); }); } async function validateImage(file: File): Promise { const dimensions = await getDimensions(file); if (dimensions.width > 3000 || dimensions.height > 3000) { return 'Image dimensions are too big. Maximum 3000x3000 pixels.'; } if (dimensions.width < 100 || dimensions.height < 100) { return 'Image dimensions are too small. Minimum 100x100 pixels.'; } if (file.size > 1024 * 1024) { return 'Image size is too big. Maximum 1MB.'; } return null; } export default function UploadProfilePicture(props: UploadProfilePictureProps) { const { avatarUrl, teamId, type, isDisabled = false } = props; const [file, setFile] = useState(null); const [error, setError] = useState(''); const [isLoading, setIsLoading] = useState(false); const inputRef = useRef(null); const onImageChange = async (e: ChangeEvent) => { setError(''); const file = (e.target as HTMLInputElement).files?.[0]; if (!file) { return; } const error = await validateImage(file); if (error) { setError(error); return; } setFile( Object.assign(file, { preview: URL.createObjectURL(file), }) ); }; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); setError(''); setIsLoading(true); if (!file) { return; } const formData = new FormData(); formData.append('name', 'avatar'); formData.append('avatar', file); // FIXME: Use `httpCall` helper instead of fetch let res: Response; if (type === 'avatar') { res = await fetch( `${import.meta.env.PUBLIC_API_URL}/v1-upload-profile-picture`, { method: 'POST', body: formData, credentials: 'include', } ); } else { res = await fetch( `${import.meta.env.PUBLIC_API_URL}/v1-upload-team-logo/${teamId}`, { method: 'POST', body: formData, credentials: 'include', } ); } if (res.ok) { window.location.reload(); return; } const data = await res.json(); setError(data?.message || 'Something went wrong'); setIsLoading(false); // Logout user if token is invalid if (data.status === 401) { removeAuthToken(); window.location.reload(); } }; useEffect(() => { // Necessary to revoke the preview URL when the component unmounts for avoiding memory leaks return () => { if (file) { URL.revokeObjectURL(file.preview); } }; }, [file]); return (
{props.label && ( )}
{file && (
)}
{error && (

{error}

)}
); }