import * as React from 'react'; import styled from '@emotion/styled'; import {addErrorMessage, addSuccessMessage} from 'app/actionCreators/indicator'; import {Client} from 'app/api'; import Avatar from 'app/components/avatar'; import AvatarCropper from 'app/components/avatarCropper'; import Button from 'app/components/button'; import ExternalLink from 'app/components/links/externalLink'; import LoadingError from 'app/components/loadingError'; import LoadingIndicator from 'app/components/loadingIndicator'; import {Panel, PanelBody, PanelHeader} from 'app/components/panels'; import Well from 'app/components/well'; import {t} from 'app/locale'; import {AvatarUser, Organization, Team} from 'app/types'; import withApi from 'app/utils/withApi'; import RadioGroup from 'app/views/settings/components/forms/controls/radioGroup'; type Model = Pick; type AvatarType = Required['avatar']['avatarType']; type AvatarChooserType = 'user' | 'team' | 'organization'; type DefaultProps = { onSave: (model: Model) => void; allowGravatar?: boolean; allowLetter?: boolean; allowUpload?: boolean; type?: AvatarChooserType; }; type Props = { api: Client; endpoint: string; model: Model; disabled?: boolean; savedDataUrl?: string; isUser?: boolean; } & DefaultProps; type State = { model: Model; hasError: boolean; savedDataUrl?: string | null; dataUrl?: string | null; }; class AvatarChooser extends React.Component { static defaultProps: DefaultProps = { allowGravatar: true, allowLetter: true, allowUpload: true, type: 'user', onSave: () => {}, }; state: State = { model: this.props.model, savedDataUrl: null, dataUrl: null, hasError: false, }; UNSAFE_componentWillReceiveProps(nextProps: Props) { // Update local state if defined in props if (typeof nextProps.model !== 'undefined') { this.setState({model: nextProps.model}); } } updateState(model: Model) { this.setState({model}); } handleError(msg: string) { addErrorMessage(msg); } handleSuccess(model: Model) { const {onSave} = this.props; this.setState({model}); onSave(model); addSuccessMessage(t('Successfully saved avatar preferences')); } handleSaveSettings = (ev: React.MouseEvent) => { const {endpoint, api} = this.props; const {model, dataUrl} = this.state; ev.preventDefault(); let data = {}; const avatarType = model && model.avatar ? model.avatar.avatarType : undefined; const avatarPhoto = dataUrl ? dataUrl.split(',')[1] : undefined; data = { avatar_photo: avatarPhoto, avatar_type: avatarType, }; api.request(endpoint, { method: 'PUT', data, success: resp => { this.setState({savedDataUrl: this.state.dataUrl}); this.handleSuccess(resp); }, error: this.handleError.bind(this, 'There was an error saving your preferences.'), }); }; handleChange = (id: AvatarType) => this.updateState({ ...this.state.model, avatar: {avatarUuid: this.state.model.avatar?.avatarUuid ?? '', avatarType: id}, }); render() { const { allowGravatar, allowUpload, allowLetter, savedDataUrl, type, isUser, disabled, } = this.props; const {hasError, model} = this.state; if (hasError) { return ; } if (!model) { return ; } const avatarType = model.avatar?.avatarType ?? 'letter_avatar'; const isLetter = avatarType === 'letter_avatar'; const isTeam = type === 'team'; const isOrganization = type === 'organization'; const choices: [AvatarType, string][] = []; if (allowLetter) { choices.push(['letter_avatar', t('Use initials')]); } if (allowUpload) { choices.push(['upload', t('Upload an image')]); } if (allowGravatar) { choices.push(['gravatar', t('Use Gravatar')]); } return ( {t('Avatar')} {isLetter && ( )} {allowGravatar && avatarType === 'gravatar' && ( {t('Gravatars are managed through ')} Gravatar.com )} {model.avatar && avatarType === 'upload' && ( this.setState(dataState)} /> )} ); } } const AvatarGroup = styled('div')<{inline: boolean}>` display: flex; flex-direction: ${p => (p.inline ? 'row' : 'column')}; `; const AvatarForm = styled('div')` line-height: 1.5em; padding: 1em 1.25em; `; const AvatarSubmit = styled('fieldset')` display: flex; justify-content: flex-end; margin-top: 1em; `; const AvatarUploadSection = styled('div')` margin-top: 1em; `; export default withApi(AvatarChooser);