import { AnimatePresence } from 'framer-motion';
import { useCallback, useMemo, useRef, useState } from 'react';
import { channelAPI } from '../../../../../api';
import { CUSTOM_AVATAR_NAME } from '../../../../../helpers';
import { dashboard as $content } from '../../../../../content';
import {
MaximumSizeExceededError,
UnsupportedFileFormatError
} from '../../../../../hooks/useImageUpload';
import { isS3Url } from '../../../../../utils';
import { useNotif } from '../../../../../contexts/Notification';
import { useUser } from '../../../../../contexts/User';
import * as userAvatars from '../../../../../assets/avatars';
import IconSelect from '../../../../../components/IconSelect';
import ImageUploader from '../ImageUploader';
import SettingContainer from '../../SettingContainer';
import UploadAvatarMarker from './UploadAvatarMarker';
import useStateWithCallback from '../../../../../hooks/useStateWithCallback';
const Avatar = () => {
const { userData, fetchUserData } = useUser();
const { avatar, channelAssetUrls } = userData || {};
const { notifySuccess, notifyError } = useNotif();
const [isAvatarLoading, setIsAvatarLoading] = useState(false);
const [selectedAvatar, setSelectedAvatar] = useState(avatar);
const [avatarUrl, setAvatarUrl] = useStateWithCallback(
channelAssetUrls?.avatar || ''
);
const [isAvatarUploaderOpen, setIsAvatarUploaderOpen] = useState(
avatar === CUSTOM_AVATAR_NAME
);
const isAvatarUploaded = useRef(!!avatarUrl);
const userAvatarItems = useMemo(
() => [
[
CUSTOM_AVATAR_NAME,
avatarUrl,
{
CustomMarker: (
)
}
],
...Object.entries(userAvatars)
],
[avatarUrl, isAvatarUploaded, isAvatarUploaderOpen]
);
const imageUploaderRef = useRef();
const handleChangeAvatar = useCallback(
async ({
newSelection,
previewUrl,
uploadDateTime,
action = 'selection'
}) => {
const isCustomAvatar = newSelection === CUSTOM_AVATAR_NAME;
const isSameAvatarSelected = avatar === newSelection;
if (isAvatarLoading) return;
setIsAvatarUploaderOpen((prev) => {
let shouldOpen = false;
if (isCustomAvatar) shouldOpen = isAvatarUploaded.current || !prev;
if (shouldOpen) {
setTimeout(
() =>
imageUploaderRef.current?.scrollIntoView({
behavior: 'smooth',
block: 'nearest'
}),
350
);
}
return shouldOpen;
});
if (
action !== 'upload' &&
(isSameAvatarSelected || (isCustomAvatar && !isAvatarUploaded.current))
)
return;
setSelectedAvatar(newSelection); // eagerly set the selected avatar
setIsAvatarLoading(true);
const { result, error } = await channelAPI.changeUserPreferences({
avatar: { name: newSelection, previewUrl, uploadDateTime }
});
if (result) {
let newUserData = await fetchUserData();
while (isS3Url(newUserData.channelAssetUrls.avatar)) {
newUserData = await fetchUserData();
}
newUserData = await fetchUserData();
setAvatarUrl(newUserData.channelAssetUrls.avatar);
setSelectedAvatar(result.avatar.name);
if (action === 'selection')
notifySuccess($content.notification.success.avatar_saved);
}
if (error) {
setSelectedAvatar(avatar);
notifyError($content.notification.error.avatar_failed_to_save);
}
setIsAvatarLoading(false);
},
[
avatar,
fetchUserData,
isAvatarLoading,
notifyError,
notifySuccess,
setAvatarUrl
]
);
const onUpload = useCallback(
({ result, error }) => {
if (result) {
const { previewUrl, uploadDateTime } = result;
isAvatarUploaded.current = true;
handleChangeAvatar({
action: 'upload',
newSelection: CUSTOM_AVATAR_NAME,
previewUrl,
uploadDateTime
});
}
if (error) {
switch (true) {
case error instanceof UnsupportedFileFormatError:
return notifyError($content.notification.error.cant_select_file);
case error instanceof MaximumSizeExceededError:
return notifyError(
$content.notification.error.image_exceeded_max_size
);
default:
return notifyError(
$content.notification.error.avatar_failed_to_upload
);
}
}
},
[handleChangeAvatar, notifyError]
);
const onImageDownload = useCallback(
() => notifySuccess($content.notification.success.avatar_uploaded),
[notifySuccess]
);
const onDelete = useCallback(
({ error }) => {
if (error)
return notifyError($content.notification.error.avatar_failed_to_delete);
setAvatarUrl('', () => {
isAvatarUploaded.current = false;
const avatarNames = Object.keys(userAvatars);
const randomAvatar =
avatarNames[Math.floor(Math.random() * avatarNames.length)];
handleChangeAvatar({ newSelection: randomAvatar, action: 'deletion' });
notifySuccess($content.notification.success.avatar_deleted);
});
},
[handleChangeAvatar, notifyError, notifySuccess, setAvatarUrl]
);
return (
{isAvatarUploaderOpen && (
)}
);
};
export default Avatar;