import React, { memo, useEffect, useState } from 'react'; import { Integration, Memori, Tenant, } from '@memori.ai/memori-api-client/dist/types'; import ErrorBoundary from '../ErrorBoundary/ErrorBoundary'; import Tooltip from '../ui/Tooltip'; import { getResourceUrl } from '../../helpers/media'; import Blob from '../Blob/Blob'; import ModelViewer from '../CustomGLBModelViewer/ModelViewer'; import Button from '../ui/Button'; import { useTranslation } from 'react-i18next'; import Eye from '../icons/Eye'; import EyeInvisible from '../icons/EyeInvisible'; import Edit from '../icons/Edit'; import cx from 'classnames'; import ContainerAvatarView from './AvatarView'; import { useViseme } from '../../context/visemeContext'; export interface Props { memori: Memori; integration?: Integration; integrationConfig?: { [key: string]: any }; tenant?: Tenant; instruct?: boolean; hasUserActivatedSpeak?: boolean; avatar3dVisible?: boolean; setAvatar3dVisible: (visible: boolean) => void; isPlayingAudio?: boolean; loading?: boolean; baseUrl?: string; apiUrl?: string; animation?: string; isZoomed?: boolean; chatProps?: any; enablePositionControls?: boolean; setEnablePositionControls: (value: boolean) => void; avatarType?: 'blob' | 'avatar3d' | null; isTotem?: boolean; } const Avatar: React.FC = ({ memori, integration, integrationConfig, tenant, instruct = false, avatar3dVisible = false, setAvatar3dVisible, hasUserActivatedSpeak = false, isPlayingAudio = false, loading = false, baseUrl, apiUrl, animation, isZoomed = false, chatProps, avatarType = null, enablePositionControls, setEnablePositionControls, isTotem = false, }) => { const { t } = useTranslation(); const [isClient, setIsClient] = useState(false); const { stopProcessing, updateCurrentViseme, resetVisemeQueue } = useViseme(); useEffect(() => { setIsClient(true); }, []); // Get the avatar URL, if the avatar is a user avatar, the avatar URL is the user avatar URL, if the avatar is a default avatar, the avatar URL is the default avatar URL const getAvatarUrl = () => { if ( integrationConfig?.avatar === 'userAvatar' && memori.avatarURL && memori.avatarURL.length > 0 ) { return getResourceUrl({ type: 'avatar', tenantID: tenant?.name, resourceURI: memori.avatarURL, baseURL: baseUrl, apiURL: apiUrl, }); } return undefined; }; const renderAvatar = () => { if ( (integrationConfig?.avatar === 'readyplayerme' || integrationConfig?.avatar === 'readyplayerme-full' || integrationConfig?.avatar === 'customglb' || integrationConfig?.avatar === 'customrpm') && integrationConfig?.avatarURL && avatarType && avatarType !== 'blob' ) { return ( <>
{renderAvatarContent()}
{renderAvatarToggle()} ); } return (
{isClient && }
); }; const renderAvatarContent = () => { if (!isClient) return null; if ( integrationConfig?.avatar === 'readyplayerme' || integrationConfig?.avatar === 'readyplayerme-full' || integrationConfig?.avatar === 'customrpm' ) { return ( {isClient && ( )} } > ); } if (integrationConfig?.avatar === 'customglb') { return ( ); } return null; }; // Render the avatar toggle const renderAvatarToggle = () => (
); const getAvatarStyle = () => { if (integrationConfig?.avatar === 'readyplayerme') { return { width: '100%', height: '100%', backgroundColor: 'none', // borderRadius: '100%', boxShadow: 'none', }; } return { width: '100%', height: '100%', backgroundColor: 'none', }; }; const renderIntegrationsLink = () => { if (!(instruct && !hasUserActivatedSpeak && memori.isGiver && tenant?.name)) return null; const href = `https://${tenant.name}/${ memori.culture === 'it-IT' ? 'it' : 'en' }/${memori.ownerUserName}/${memori.name}/integrations${ integration?.integrationID ? `?integration=${integration.integrationID}&openAvatarModal=true` : '' }`; return (
); }; return ( <> {renderAvatar()} {renderIntegrationsLink()} ); }; export default memo(Avatar, (prevProps, nextProps) => { return JSON.stringify(prevProps) === JSON.stringify(nextProps); });