diff --git a/src/components/AvatarWithImagePicker.js b/src/components/AvatarWithImagePicker.js index 3a43ede5a8f4..4cc70f00d1ae 100644 --- a/src/components/AvatarWithImagePicker.js +++ b/src/components/AvatarWithImagePicker.js @@ -21,6 +21,7 @@ import stylePropTypes from '../styles/stylePropTypes'; import * as FileUtils from '../libs/fileDownload/FileUtils'; import getImageResolution from '../libs/fileDownload/getImageResolution'; import PressableWithoutFeedback from './Pressable/PressableWithoutFeedback'; +import AttachmentModal from './AttachmentModal'; import DotIndicatorMessage from './DotIndicatorMessage'; import * as Browser from '../libs/Browser'; import withNavigationFocus, {withNavigationFocusPropTypes} from './withNavigationFocus'; @@ -81,6 +82,15 @@ const propTypes = { // eslint-disable-next-line react/forbid-prop-types errors: PropTypes.object, + /** Title for avatar preview modal */ + headerTitle: PropTypes.string, + + /** Avatar source for avatar preview modal */ + previewSource: PropTypes.oneOfType([PropTypes.string, PropTypes.func]), + + /** File name of the avatar */ + originalFileName: PropTypes.string, + ...withLocalizePropTypes, ...withNavigationFocusPropTypes, }; @@ -101,6 +111,9 @@ const defaultProps = { onErrorClose: () => {}, pendingAction: null, errors: null, + headerTitle: '', + previewSource: '', + originalFileName: '', }; class AvatarWithImagePicker extends React.Component { @@ -279,58 +292,72 @@ class AvatarWithImagePicker extends React.Component { - - {({openPicker}) => { - const menuItems = [ - { - icon: Expensicons.Upload, - text: this.props.translate('avatarWithImagePicker.uploadPhoto'), - onSelected: () => { - if (Browser.isSafari()) { - return; - } - openPicker({ - onPicked: this.showAvatarCropModal, + + {({show}) => ( + + {({openPicker}) => { + const menuItems = [ + { + icon: Expensicons.Upload, + text: this.props.translate('avatarWithImagePicker.uploadPhoto'), + onSelected: () => { + if (Browser.isSafari()) { + return; + } + openPicker({ + onPicked: this.showAvatarCropModal, + }); + }, + }, + ]; + + // If current avatar isn't a default avatar, allow Remove Photo option + if (!this.props.isUsingDefaultAvatar) { + menuItems.push({ + icon: Expensicons.Trashcan, + text: this.props.translate('avatarWithImagePicker.removePhoto'), + onSelected: () => { + this.setError(null, {}); + this.props.onImageRemoved(); + }, }); - }, - }, - ]; - - // If current avatar isn't a default avatar, allow Remove Photo option - if (!this.props.isUsingDefaultAvatar) { - menuItems.push({ - icon: Expensicons.Trashcan, - text: this.props.translate('avatarWithImagePicker.removePhoto'), - onSelected: () => { - this.setError(null, {}); - this.props.onImageRemoved(); - }, - }); - } - return ( - this.setState({isMenuVisible: false})} - onItemSelected={(item, index) => { - this.setState({isMenuVisible: false}); - // In order for the file picker to open dynamically, the click - // function must be called from within a event handler that was initiated - // by the user on Safari. - if (index === 0 && Browser.isSafari()) { - openPicker({ - onPicked: this.showAvatarCropModal, - }); - } - }} - menuItems={menuItems} - anchorPosition={this.props.anchorPosition} - withoutOverlay - anchorRef={this.anchorRef} - anchorAlignment={this.props.anchorAlignment} - /> - ); - }} - + + menuItems.push({ + icon: Expensicons.Eye, + text: this.props.translate('avatarWithImagePicker.viewPhoto'), + onSelected: () => show(), + }); + } + return ( + this.setState({isMenuVisible: false})} + onItemSelected={(item, index) => { + this.setState({isMenuVisible: false}); + // In order for the file picker to open dynamically, the click + // function must be called from within a event handler that was initiated + // by the user on Safari. + if (index === 0 && Browser.isSafari()) { + openPicker({ + onPicked: this.showAvatarCropModal, + }); + } + }} + menuItems={menuItems} + anchorPosition={this.props.anchorPosition} + withoutOverlay + anchorRef={this.anchorRef} + anchorAlignment={this.props.anchorAlignment} + /> + ); + }} + + )} + {this.state.validationError && ( `The selected image exceeds the maximum upload size of ${maxUploadSizeInMB}MB.`, resolutionConstraints: ({minHeightInPx, minWidthInPx, maxHeightInPx, maxWidthInPx}: ResolutionConstraintsParams) => @@ -583,6 +585,7 @@ export default { online: 'Online', offline: 'Offline', syncing: 'Syncing', + profileAvatar: 'Profile avatar', }, loungeAccessPage: { loungeAccess: 'Lounge access', @@ -1299,6 +1302,7 @@ export default { memberNotFound: 'Member not found. To invite a new member to the workspace, please use the Invite button above.', notAuthorized: `You do not have access to this page. Are you trying to join the workspace? Please reach out to the owner of this workspace so they can add you as a member! Something else? Reach out to ${CONST.EMAIL.CONCIERGE}`, goToRoom: ({roomName}: GoToRoomParams) => `Go to ${roomName} room`, + workspaceAvatar: 'Workspace avatar', }, emptyWorkspace: { title: 'Create a new workspace', diff --git a/src/languages/es.ts b/src/languages/es.ts index 036c5fc0d266..2606bfb7af1a 100644 --- a/src/languages/es.ts +++ b/src/languages/es.ts @@ -557,6 +557,8 @@ export default { uploadPhoto: 'Subir foto', removePhoto: 'Eliminar foto', editImage: 'Editar foto', + viewPhoto: 'Ver foto', + imageUploadFailed: 'Error al cargar la imagen', deleteWorkspaceError: 'Lo sentimos, hubo un problema eliminando el avatar de su espacio de trabajo.', sizeExceeded: ({maxUploadSizeInMB}: SizeExceededParams) => `La imagen supera el tamaño máximo de ${maxUploadSizeInMB}MB.`, resolutionConstraints: ({minHeightInPx, minWidthInPx, maxHeightInPx, maxWidthInPx}: ResolutionConstraintsParams) => @@ -576,6 +578,7 @@ export default { online: 'En línea', offline: 'Desconectado', syncing: 'Sincronizando', + profileAvatar: 'Perfil avatar', }, loungeAccessPage: { loungeAccess: 'Acceso a la sala vip', @@ -1318,6 +1321,7 @@ export default { memberNotFound: 'Miembro no encontrado. Para invitar a un nuevo miembro al espacio de trabajo, por favor, utiliza el botón Invitar que está arriba.', notAuthorized: `No tienes acceso a esta página. ¿Estás tratando de unirte al espacio de trabajo? Comunícate con el propietario de este espacio de trabajo para que pueda añadirte como miembro. ¿Necesitas algo más? Comunícate con ${CONST.EMAIL.CONCIERGE}`, goToRoom: ({roomName}: GoToRoomParams) => `Ir a la sala ${roomName}`, + workspaceAvatar: 'Espacio de trabajo avatar', }, emptyWorkspace: { title: 'Crear un nuevo espacio de trabajo', diff --git a/src/libs/actions/Policy.js b/src/libs/actions/Policy.js index 87c77e722a5c..93b46f2e53da 100644 --- a/src/libs/actions/Policy.js +++ b/src/libs/actions/Policy.js @@ -421,6 +421,7 @@ function updateWorkspaceAvatar(policyID, file) { key: `${ONYXKEYS.COLLECTION.POLICY}${policyID}`, value: { avatar: file.uri, + originalFileName: file.name, errorFields: { avatar: null, }, diff --git a/src/pages/settings/Profile/ProfilePage.js b/src/pages/settings/Profile/ProfilePage.js index b0cbe7c9cc32..1864ba60524c 100755 --- a/src/pages/settings/Profile/ProfilePage.js +++ b/src/pages/settings/Profile/ProfilePage.js @@ -65,6 +65,8 @@ function ProfilePage(props) { }; const currentUserDetails = props.currentUserPersonalDetails || {}; const contactMethodBrickRoadIndicator = UserUtils.getLoginListBrickRoadIndicator(props.loginList); + const avatarURL = lodashGet(currentUserDetails, 'avatar', ''); + const accountID = lodashGet(currentUserDetails, 'accountID', ''); const emojiCode = lodashGet(props, 'currentUserPersonalDetails.status.emojiCode', ''); const profileSettingsOptions = [ @@ -113,7 +115,7 @@ function ProfilePage(props) { diff --git a/src/pages/workspace/WorkspaceSettingsPage.js b/src/pages/workspace/WorkspaceSettingsPage.js index 7aff9093c4dd..2a9576d5d8d3 100644 --- a/src/pages/workspace/WorkspaceSettingsPage.js +++ b/src/pages/workspace/WorkspaceSettingsPage.js @@ -20,6 +20,7 @@ import {withNetwork} from '../../components/OnyxProvider'; import OfflineWithFeedback from '../../components/OfflineWithFeedback'; import Form from '../../components/Form'; import * as ReportUtils from '../../libs/ReportUtils'; +import * as UserUtils from '../../libs/UserUtils'; import Avatar from '../../components/Avatar'; import Navigation from '../../libs/Navigation/Navigation'; import ROUTES from '../../ROUTES'; @@ -125,6 +126,9 @@ function WorkspaceSettingsPage(props) { pendingAction={lodashGet(props.policy, 'pendingFields.avatar', null)} errors={lodashGet(props.policy, 'errorFields.avatar', null)} onErrorClose={() => Policy.clearAvatarErrors(props.policy.id)} + previewSource={UserUtils.getFullSizeAvatar(props.policy.avatar, '')} + headerTitle={props.translate('workspace.common.workspaceAvatar')} + originalFileName={props.policy.originalFileName} />