import { LoadingOutlined, PlusOutlined } from '@ant-design/icons'; import { Button, Card, Flex, Form, Input, Tooltip, Typography, Spin, Skeleton, } from 'antd'; import { useEffect, useState, useRef } from 'react'; import { useTranslation } from 'react-i18next'; import { changeUserName, setUser } from '@features/user/userSlice'; import { useAppDispatch } from '@/hooks/useAppDispatch'; import { useDocumentTitle } from '@/hooks/useDoumentTItle'; import { useMixpanelTracking } from '@/hooks/useMixpanelTracking'; import { evt_settings_profile_visit, evt_settings_profile_name_change, evt_settings_profile_picture_update, } from '@/shared/worklenz-analytics-events'; import { useAuthService } from '@/hooks/useAuth'; import { getBase64 } from '@/utils/file-utils'; import './profile-settings.css'; import { profileSettingsApiService } from '@/api/settings/profile/profile-settings.api.service'; import taskAttachmentsApiService from '@/api/tasks/task-attachments.api.service'; import logger from '@/utils/errorLogger'; import { setSession } from '@/utils/session-helper'; import { authApiService } from '@/api/auth/auth.api.service'; const ProfileSettings = () => { const { t } = useTranslation('settings/profile'); const dispatch = useAppDispatch(); const { trackMixpanelEvent } = useMixpanelTracking(); const [loading, setLoading] = useState(false); const [uploading, setUploading] = useState(false); const [updating, setUpdating] = useState(false); const [imageUrl, setImageUrl] = useState(); const [form] = Form.useForm(); const currentSession = useAuthService().getCurrentSession(); const fileInputRef = useRef(null); useDocumentTitle(t('title') || 'Profile Settings'); useEffect(() => { trackMixpanelEvent(evt_settings_profile_visit); }, [trackMixpanelEvent]); const handleFileChange = async (event: React.ChangeEvent) => { if (uploading || !event.target.files || event.target.files.length === 0) return; const file = event.target.files[0]; setUploading(true); try { const base64 = await getBase64(file); const res = await taskAttachmentsApiService.createAvatarAttachment({ file: base64 as string, file_name: file.name, size: file.size, }); if (res.done) { trackMixpanelEvent(evt_settings_profile_picture_update); const authorizeResponse = await authApiService.verify(); if (authorizeResponse.authenticated) { setSession(authorizeResponse.user); dispatch(setUser(authorizeResponse.user)); } } } catch (e) { logger.error('Error uploading avatar', e); } finally { setUploading(false); } // Reset file input const dt = new DataTransfer(); event.target.files = dt.files; }; const triggerFileInput = () => { if (!uploading) { fileInputRef.current?.click(); } }; const avatarPreview = (
{uploading && (
} />
)} {loading ? ( ) : imageUrl || currentSession?.avatar_url ? ( avatar ) : ( {t('upload')} )}
); const handleFormSubmit = async ({ name }: { name: string }) => { if (name === currentSession?.name) { return; } setUpdating(true); try { const res = await profileSettingsApiService.updateProfile({ name }); if (res.done) { trackMixpanelEvent(evt_settings_profile_name_change, { newName: name }); dispatch(changeUserName(name)); // Refresh user session to get updated data const authorizeResponse = await authApiService.verify(); if (authorizeResponse.authenticated) { setSession(authorizeResponse.user); dispatch(setUser(authorizeResponse.user)); } } } catch (error) { logger.error('Error changing name', error); } finally { setUpdating(false); } }; return ( {updating ? ( ) : (
{avatarPreview}
)} {t('profileJoinedText', { date: currentSession?.created_at ? new Date(currentSession.created_at).toLocaleDateString() : '', })} {t('profileLastUpdatedText', { date: currentSession?.updated_at ? new Date(currentSession.updated_at).toLocaleDateString() : '', })}
); }; export default ProfileSettings;