import { useEffect, useState, ReactNode, FC, useRef } from 'react'; import { observer } from 'mobx-react'; import { FilePicker, ButtonGroup, Tooltip, Button, Card, Banner, Grid, } from '@servicetitan/design-system'; import { Label } from '@servicetitan/form'; import { getImageSize, formatBytes } from '../../../utils/helpers'; export const LOGO_MIN_SIZE = 180; export const DEFAULT_MIN_DIMENSIONS = { width: LOGO_MIN_SIZE, height: LOGO_MIN_SIZE }; export const DEFAULT_LOGO_TIPS = ( ); import * as Styles from './logo-picker.module.less'; export interface LogoPickerProps { error?: string; image?: File; imageUrl?: string; loaded?: boolean; maxSize?: number; minDimensions?: { width: number; height: number }; tips?: ReactNode; deletable?: boolean; isGrid?: boolean; deleteImage(): void; downloadImage?(): void; onBadImage?(opts: { category: string; error: string; data: { imageUrl: string } }): void; onFileChange(files: FileList | null): void; setError?(error: string): void; } export const LogoPicker: FC = observer( ({ deleteImage, downloadImage, error, image, imageUrl, loaded = true, maxSize, minDimensions = DEFAULT_MIN_DIMENSIONS, onBadImage, onFileChange, setError, deletable = true, tips = DEFAULT_LOGO_TIPS, isGrid = true, }) => { const [recommendLargerImage, setRecommendLargerImage] = useState(false); const [localError, setLocalError] = useState(''); const [isLoading, setIsLoading] = useState(false); const [sizeError, setSizeError] = useState(''); const formattedMaxSize = useRef(formatBytes(maxSize, 2, false)); useEffect(() => { const handleImageUrlChange = async () => { if (!imageUrl || !minDimensions) { return; } setIsLoading(true); try { const size = await getImageSize(imageUrl); setRecommendLargerImage( size.height < minDimensions.height || size.width < minDimensions.width, ); setLocalError(''); if (setError) { setError(''); } } catch { onBadImage?.({ category: 'LogoPicker', error: 'Got a bad image', data: { imageUrl }, }); deleteImage(); setLocalError('File is not a valid image'); setRecommendLargerImage(false); if (setError) { setError('File is not a valid image'); } } finally { setIsLoading(false); } }; handleImageUrlChange(); }, [imageUrl, minDimensions, setError, deleteImage, onBadImage]); useEffect(() => { if (!image?.size || !maxSize) { return; } setIsLoading(true); if (image && image.size > maxSize) { deleteImage(); setSizeError(`File size should be less than ${formattedMaxSize.current}.`); if (setError) { setError(`File size should be less than ${formattedMaxSize.current}.`); } } else { setSizeError(''); if (setError) { setError(''); } } setIsLoading(false); }, [image, maxSize, setError, deleteImage]); if (!loaded || isLoading) { return null; } return (
); }, ); interface LogoCardProps { imageUrl: string; image?: File; deletable?: boolean; onFileChange(files: FileList | null): void; downloadImage?(): void; deleteImage(): void; } const LogoCard: FC = ({ imageUrl, onFileChange, image, downloadImage, deletable = true, deleteImage, }) => { const fileRef = useRef(null); const handleClick = () => fileRef.current?.click(); return ( logo
); };