88 lines
2.3 KiB
TypeScript
88 lines
2.3 KiB
TypeScript
import type { ChangeEvent } from 'react';
|
|
import type { FC } from '../../lib/teact/teact';
|
|
import React, {
|
|
memo, useCallback, useEffect, useState,
|
|
} from '../../lib/teact/teact';
|
|
|
|
import buildClassName from '../../util/buildClassName';
|
|
|
|
import CropModal from './CropModal';
|
|
|
|
import './AvatarEditable.scss';
|
|
|
|
interface OwnProps {
|
|
title?: string;
|
|
disabled?: boolean;
|
|
isForForum?: boolean;
|
|
currentAvatarBlobUrl?: string;
|
|
onChange: (file: File) => void;
|
|
}
|
|
|
|
const AvatarEditable: FC<OwnProps> = ({
|
|
title = 'Change your profile picture',
|
|
disabled,
|
|
isForForum,
|
|
currentAvatarBlobUrl,
|
|
onChange,
|
|
}) => {
|
|
const [selectedFile, setSelectedFile] = useState<File | undefined>();
|
|
const [croppedBlobUrl, setCroppedBlobUrl] = useState<string | undefined>(currentAvatarBlobUrl);
|
|
|
|
useEffect(() => {
|
|
setCroppedBlobUrl(currentAvatarBlobUrl);
|
|
}, [currentAvatarBlobUrl]);
|
|
|
|
function handleSelectFile(event: ChangeEvent<HTMLInputElement>) {
|
|
const target = event.target as HTMLInputElement;
|
|
|
|
if (!target?.files?.[0]) {
|
|
return;
|
|
}
|
|
|
|
setSelectedFile(target.files[0]);
|
|
target.value = '';
|
|
}
|
|
|
|
const handleAvatarCrop = useCallback((croppedImg: File) => {
|
|
setSelectedFile(undefined);
|
|
onChange(croppedImg);
|
|
|
|
if (croppedBlobUrl && croppedBlobUrl !== currentAvatarBlobUrl) {
|
|
URL.revokeObjectURL(croppedBlobUrl);
|
|
}
|
|
setCroppedBlobUrl(URL.createObjectURL(croppedImg));
|
|
}, [croppedBlobUrl, currentAvatarBlobUrl, onChange]);
|
|
|
|
const handleModalClose = useCallback(() => {
|
|
setSelectedFile(undefined);
|
|
}, []);
|
|
|
|
const labelClassName = buildClassName(
|
|
croppedBlobUrl && 'filled',
|
|
disabled && 'disabled',
|
|
isForForum && 'rounded-square',
|
|
);
|
|
|
|
return (
|
|
<div className="AvatarEditable">
|
|
<label
|
|
className={labelClassName}
|
|
role="button"
|
|
tabIndex={0}
|
|
title={title}
|
|
>
|
|
<input
|
|
type="file"
|
|
onChange={handleSelectFile}
|
|
accept="image/png, image/jpeg"
|
|
/>
|
|
<i className="icon icon-camera-add" />
|
|
{croppedBlobUrl && <img src={croppedBlobUrl} draggable={false} alt="Avatar" />}
|
|
</label>
|
|
<CropModal file={selectedFile} onClose={handleModalClose} onChange={handleAvatarCrop} />
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default memo(AvatarEditable);
|