Merge branch 'master' into refactoring/text-heading

This commit is contained in:
Daniil Senkiv 2019-12-10 09:36:05 +03:00
commit 6b6c4569cf
21 changed files with 187 additions and 275 deletions

View File

@ -23,7 +23,7 @@ import {
updateUserStatus,
fetchPeople
} from "../../../../../store/people/actions";
import { fetchProfile } from "../../../../../store/profile/actions";
import { fetchProfile, getUserPhoto } from "../../../../../store/profile/actions";
import styled from "styled-components";
import { store, api, constants } from "asc-web-common";
const { isAdmin, isMe } = store.auth.selectors;
@ -82,9 +82,7 @@ class SectionHeaderContent extends React.PureComponent {
},
avatar: {
tmpFile: "",
image: profile.avatarDefault
? "data:image/png;base64," + profile.avatarDefault
: null,
image: null,
defaultWidth: 0,
defaultHeight: 0
}
@ -94,24 +92,31 @@ class SectionHeaderContent extends React.PureComponent {
};
openAvatarEditor = () => {
let avatarDefault = this.state.profile.avatarDefault
? "data:image/png;base64," + this.state.profile.avatarDefault
: null;
let _this = this;
if (avatarDefault !== null) {
let img = new Image();
img.onload = function() {
_this.setState({
avatar: {
defaultWidth: img.width,
defaultHeight: img.height
}
});
};
img.src = avatarDefault;
}
this.setState({
visibleAvatarEditor: true
getUserPhoto(this.state.profile.id).then(userPhotoData => {
if(userPhotoData.original){
let avatarDefaultSizes = /_(\d*)-(\d*)./g.exec(userPhotoData.original);
if (avatarDefaultSizes !== null && avatarDefaultSizes.length > 2) {
this.setState({
avatar: {
tmpFile: this.state.avatar.tmpFile,
defaultWidth: avatarDefaultSizes[1],
defaultHeight: avatarDefaultSizes[2],
image: userPhotoData.original ? userPhotoData.original.indexOf('default_user_photo') !== -1 ? null : userPhotoData.original : null
},
visibleAvatarEditor: true
});
}else{
this.setState({
avatar: {
tmpFile: this.state.avatar.tmpFile,
defaultWidth: 0,
defaultHeight: 0,
image: null
},
visibleAvatarEditor: true
});
}
}
});
};

View File

@ -52,6 +52,7 @@ class PasswordField extends React.Component {
isDisabled={radioIsDisabled}
onClick={radioOnChange}
className="radio-group"
spacing='33px'
/>
<PasswordInput
inputName={inputName}

View File

@ -40,6 +40,7 @@ class RadioField extends React.Component {
isDisabled={radioIsDisabled}
onClick={radioOnChange}
className="radio-group"
spacing='33px'
/>
</FieldContainer>
);

View File

@ -4,7 +4,7 @@ import { connect } from 'react-redux'
import { Avatar, Button, Textarea, toastr, AvatarEditor, Text } from 'asc-web-components'
import { withTranslation, Trans } from 'react-i18next';
import { toEmployeeWrapper, getUserRole, getUserContactsPattern, getUserContacts, mapGroupsToGroupSelectorOptions, mapGroupSelectorOptionsToGroups, filterGroupSelectorOptions } from "../../../../../store/people/selectors";
import { createProfile } from '../../../../../store/profile/actions';
import { createProfile, getUserPhoto } from '../../../../../store/profile/actions';
import { MainContainer, AvatarContainer, MainFieldsContainer } from './FormFields/Form'
import TextField from './FormFields/TextField'
import PasswordField from './FormFields/PasswordField'
@ -69,19 +69,17 @@ class CreateUserForm extends React.Component {
}
openAvatarEditor(){
let avatarDefault = this.state.profile.avatarDefault ? "data:image/png;base64," + this.state.profile.avatarDefault : null;
let _this = this;
if(avatarDefault !== null){
let img = new Image();
img.onload = function () {
_this.setState({
avatar:{
defaultWidth: img.width,
defaultHeight: img.height
}
})
};
img.src = avatarDefault;
let avatarDefault = this.state.avatar.image;
let avatarDefaultSizes = /_orig_(\d*)-(\d*)./g.exec(this.state.avatar.image);
if (avatarDefault !== null && avatarDefaultSizes !== null && avatarDefaultSizes.length > 2) {
this.setState({
avatar: {
tmpFile: this.state.avatar.tmpFile,
image: this.state.avatar.image,
defaultWidth: avatarDefaultSizes[1],
defaultHeight: avatarDefaultSizes[2]
}
})
}
this.setState({
visibleAvatarEditor: true,
@ -149,7 +147,21 @@ class CreateUserForm extends React.Component {
});
var allOptions = mapGroupsToGroupSelectorOptions(props.groups);
var selected = mapGroupsToGroupSelectorOptions(profile.groups);
getUserPhoto(profile.id).then(userPhotoData => {
if(userPhotoData.original){
let avatarDefaultSizes = /_(\d*)-(\d*)./g.exec(userPhotoData.original);
if (avatarDefaultSizes !== null && avatarDefaultSizes.length > 2) {
this.setState({
avatar: {
tmpFile: this.state.avatar.tmpFile,
defaultWidth: avatarDefaultSizes[1],
defaultHeight: avatarDefaultSizes[2],
image: userPhotoData.original ? userPhotoData.original.indexOf('default_user_photo') !== -1 ? null : userPhotoData.original : null
}
});
}
}
});
return {
visibleAvatarEditor: false,
croppedAvatarImage: "",
@ -169,7 +181,7 @@ class CreateUserForm extends React.Component {
},
avatar: {
tmpFile:"",
image: profile.avatarDefault ? "data:image/png;base64," + profile.avatarDefault : null,
image: null,
defaultWidth: 0,
defaultHeight: 0,
x: 0,

View File

@ -4,7 +4,7 @@ import { connect } from 'react-redux'
import { Avatar, Button, Textarea, Text, toastr, ModalDialog, TextInput, AvatarEditor, Link } from 'asc-web-components'
import { withTranslation, Trans } from 'react-i18next';
import { toEmployeeWrapper, getUserRole, getUserContactsPattern, getUserContacts, mapGroupsToGroupSelectorOptions, mapGroupSelectorOptionsToGroups, filterGroupSelectorOptions } from "../../../../../store/people/selectors";
import { updateProfile } from '../../../../../store/profile/actions';
import { updateProfile, getUserPhoto } from '../../../../../store/profile/actions'
import { MainContainer, AvatarContainer, MainFieldsContainer } from './FormFields/Form'
import TextField from './FormFields/TextField'
import TextChangeField from './FormFields/TextChangeField'
@ -82,6 +82,22 @@ class UpdateUserForm extends React.Component {
var allOptions = mapGroupsToGroupSelectorOptions(props.groups);
var selected = mapGroupsToGroupSelectorOptions(profile.groups);
getUserPhoto(profile.id).then(userPhotoData => {
if(userPhotoData.original){
let avatarDefaultSizes = /_(\d*)-(\d*)./g.exec(userPhotoData.original);
if (avatarDefaultSizes !== null && avatarDefaultSizes.length > 2) {
this.setState({
avatar: {
tmpFile: this.state.avatar.tmpFile,
defaultWidth: avatarDefaultSizes[1],
defaultHeight: avatarDefaultSizes[2],
image: userPhotoData.original ? userPhotoData.original.indexOf('default_user_photo') !== -1 ? null : userPhotoData.original : null
}
});
}
}
});
const newState = {
isLoading: false,
errors: {
@ -105,7 +121,7 @@ class UpdateUserForm extends React.Component {
},
avatar: {
tmpFile:"",
image: profile.avatarDefault ? "data:image/png;base64," + profile.avatarDefault : null,
image: null,
defaultWidth: 0,
defaultHeight: 0
}
@ -323,19 +339,17 @@ class UpdateUserForm extends React.Component {
}
openAvatarEditor(){
let avatarDefault = this.state.profile.avatarDefault ? "data:image/png;base64," + this.state.profile.avatarDefault : null;
let _this = this;
if(avatarDefault !== null){
let img = new Image();
img.onload = function () {
_this.setState({
avatar:{
defaultWidth: img.width,
defaultHeight: img.height
}
})
};
img.src = avatarDefault;
let avatarDefault = this.state.avatar.image;
let avatarDefaultSizes = /_orig_(\d*)-(\d*)./g.exec(this.state.avatar.image);
if (avatarDefault !== null && avatarDefaultSizes !== null && avatarDefaultSizes.length > 2) {
this.setState({
avatar: {
tmpFile: this.state.avatar.tmpFile,
image: this.state.avatar.image,
defaultWidth: avatarDefaultSizes[1],
defaultHeight: avatarDefaultSizes[2]
}
})
}
this.setState({
visibleAvatarEditor: true,

View File

@ -93,3 +93,6 @@ export function updateProfileCulture(id, culture) {
};
};
export function getUserPhoto(id) {
return api.people.getUserPhoto(id);
};

View File

@ -747,109 +747,7 @@ namespace ASC.Employee.Core.Controllers
return new ThumbnailsDataWrapper(user.ID, UserPhotoManager);
}
public FormFile Base64ToImage(string base64String, string fileName)
{
byte[] imageBytes = Convert.FromBase64String(base64String);
MemoryStream ms = new MemoryStream(imageBytes, 0, imageBytes.Length);
ms.Write(imageBytes, 0, imageBytes.Length);
return new FormFile(ms, 0, ms.Length, fileName, fileName);
}
[Create("{userid}/photo/cropped")]
public People.Models.FileUploadResult UploadCroppedMemberPhoto(string userid, UploadCroppedPhotoModel model)
{
var result = new People.Models.FileUploadResult();
try
{
Guid userId;
try
{
userId = new Guid(userid);
}
catch
{
userId = SecurityContext.CurrentAccount.ID;
}
PermissionContext.DemandPermissions(new UserSecurityProvider(userId), Constants.Action_EditUser);
var userPhoto = Base64ToImage(model.base64CroppedImage, "userPhoto_" + userId.ToString());
var defaultUserPhoto = Base64ToImage(model.base64DefaultImage, "defaultPhoto" + userId.ToString());
if (userPhoto.Length > SetupInfo.MaxImageUploadSize)
{
result.Success = false;
result.Message = FileSizeComment.FileImageSizeExceptionString;
return result;
}
var data = new byte[userPhoto.Length];
using var inputStream = userPhoto.OpenReadStream();
var br = new BinaryReader(inputStream);
br.Read(data, 0, (int)userPhoto.Length);
br.Close();
var defaultData = new byte[defaultUserPhoto.Length];
using var defaultInputStream = defaultUserPhoto.OpenReadStream();
var defaultBr = new BinaryReader(defaultInputStream);
defaultBr.Read(defaultData, 0, (int)defaultUserPhoto.Length);
defaultBr.Close();
CheckImgFormat(data);
if (model.Autosave)
{
if (data.Length > SetupInfo.MaxImageUploadSize)
throw new ImageSizeLimitException();
var mainPhoto = UserPhotoManager.SaveOrUpdateCroppedPhoto(userId, data, defaultData);
result.Data =
new
{
main = mainPhoto,
retina = UserPhotoManager.GetRetinaPhotoURL(userId),
max = UserPhotoManager.GetMaxPhotoURL(userId),
big = UserPhotoManager.GetBigPhotoURL(userId),
medium = UserPhotoManager.GetMediumPhotoURL(userId),
small = UserPhotoManager.GetSmallPhotoURL(userId),
};
}
else
{
result.Data = UserPhotoManager.SaveTempPhoto(data, SetupInfo.MaxImageUploadSize, UserPhotoManager.OriginalFotoSize.Width, UserPhotoManager.OriginalFotoSize.Height);
}
result.Success = true;
}
catch (UnknownImageFormatException)
{
result.Success = false;
result.Message = PeopleResource.ErrorUnknownFileImageType;
}
catch (ImageWeightLimitException)
{
result.Success = false;
result.Message = PeopleResource.ErrorImageWeightLimit;
}
catch (ImageSizeLimitException)
{
result.Success = false;
result.Message = PeopleResource.ErrorImageSizetLimit;
}
catch (Exception ex)
{
result.Success = false;
result.Message = ex.Message.HtmlEncode();
}
return result;
}
[Create("{userid}/photo")]
public People.Models.FileUploadResult UploadMemberPhoto(string userid, IFormCollection model)
{
@ -1002,6 +900,7 @@ namespace ASC.Employee.Core.Controllers
var settings = new UserPhotoThumbnailSettings(thumbnailsModel.X, thumbnailsModel.Y, thumbnailsModel.Width, thumbnailsModel.Height);
SettingsManager.SaveForUser(settings, user.ID);
UserPhotoManager.RemovePhoto(user.ID);
UserPhotoManager.SaveOrUpdatePhoto(user.ID, data);
UserPhotoManager.RemoveTempPhoto(fileName);
}

View File

@ -89,9 +89,6 @@ namespace ASC.Web.Api.Models
[DataMember(Order = 20)]
public string AvatarMax { get; set; }
[DataMember(Order = 20)]
public string AvatarDefault { get; set; }
[DataMember(Order = 20)]
public string AvatarMedium { get; set; }
@ -252,11 +249,6 @@ namespace ASC.Web.Api.Models
var userInfoLM = userInfo.LastModified.GetHashCode();
if (Context.Check("avatarDefault"))
{
result.AvatarDefault = Convert.ToBase64String(UserManager.GetUserPhoto(userInfo.ID));
}
if (Context.Check("avatarMax"))
{
result.AvatarMax = UserPhotoManager.GetMaxPhotoURL(userInfo.ID, out var isdef) + (isdef ? "" : $"?_={userInfoLM}");

View File

@ -8,12 +8,6 @@ namespace ASC.People.Models
public List<IFormFile> Files { get; set; }
public bool Autosave { get; set; }
}
public class UploadCroppedPhotoModel
{
public string base64CroppedImage { get; set; }
public string base64DefaultImage { get; set; }
public bool Autosave { get; set; }
}
public class FileUploadResult
{

View File

@ -11,14 +11,6 @@ const ProjectsContainer = styled.div`
align-items: flex-start;
flex-direction: row;
flex-wrap: wrap;
.display-block {
display: block;
}
div label:not(:first-child) {
margin: 0;
}
`;
const RadioButtonContainer = styled.div`
@ -104,7 +96,8 @@ class PureModulesSettings extends Component {
})
}
]}
className="display-block"
orientation='vertical'
spacing='10px'
/>
</RadioButtonContainer>
<ProjectsBody>

View File

@ -21,6 +21,12 @@ export function getUserList(filter = Filter.getDefault()) {
url: `/people/${userName || '@self'}.json`
});
}
export function getUserPhoto(userId) {
return request({
method: "get",
url: `/people/${userId}/photo`
});
}
export function createUser(data, confirmKey = null) {
const options = {

View File

@ -1,6 +1,6 @@
{
"name": "asc-web-components",
"version": "1.0.220",
"version": "1.0.222",
"description": "Ascensio System SIA component library",
"license": "AGPL-3.0",
"main": "dist/asc-web-components.js",

View File

@ -74,6 +74,9 @@ class AvatarEditor extends React.Component {
if (this.props.visible !== prevProps.visible) {
this.setState({ visible: this.props.visible });
}
if (this.props.image !== prevProps.image) {
this.setState({ isContainsFile: !!this.props.image });
}
}
render() {

View File

@ -159,10 +159,12 @@ class AvatarEditorBody extends React.Component {
this.props.deleteImage();
}
onImageChange() {
this.setState({
croppedImage: this.setEditorRef.current.getImage().toDataURL()
});
this.props.onImageChange(this.setEditorRef.current.getImage().toDataURL());
if(this.setEditorRef.current !== null){
this.setState({
croppedImage: this.setEditorRef.current.getImage().toDataURL()
});
this.props.onImageChange(this.setEditorRef.current.getImage().toDataURL());
}
}
dist = 0
scaling = false
@ -247,6 +249,13 @@ class AvatarEditorBody extends React.Component {
height: this.setEditorRef.current.getImage().height
});
}
componentDidUpdate(prevProps){
if(prevProps.image !== this.props.image){
this.setState({
image: this.props.image
});
}
}
render() {
return (
<div

View File

@ -16,9 +16,6 @@ const StyledComboBox = styled(ComboBox)`
float: left;
width: 20%;
margin-left: 8px;
.display-block{
display: block;
}
@media ${mobile} {
width: 50px;
@ -90,11 +87,11 @@ class SortComboBox extends React.Component {
<>
<DropDownItem noHover >
<RadioButtonGroup
className="display-block"
orientation='vertical'
onClick={this.onChangeSortDirection}
isDisabled={this.props.isDisabled}
selected={this.state.sortDirection.toString()}
spacing={0}
spacing='0px'
name={'direction'}
options={sortDirectionArray}
/>
@ -102,11 +99,11 @@ class SortComboBox extends React.Component {
<DropDownItem isSeparator />
<DropDownItem noHover >
<RadioButtonGroup
className="display-block"
orientation='vertical'
onClick={this.onChangeSortId}
isDisabled={this.props.isDisabled}
selected={this.props.selectedOption.key}
spacing={0}
spacing='0px'
name={'sort'}
options={sortArray}
/>

View File

@ -22,14 +22,16 @@ import { RadioButtonGroup } from "asc-web-components";
### Properties
| Props | Type | Required | Values | Default | Description |
| ------------ | :------------: | :------: | :----: | :-----: | ---------------------------------------------------------------------------------------- |
| `className` | `string` | - | - | - | Accepts class |
| `id` | `string` | - | - | - | Accepts id |
| `isDisabled` | `bool` | - | - | `false` | Disabling all radiobutton in group |
| `name` | `string` | ✅ | - | - | Used as HTML `name` property for `<input>` tag. Used for identification RadioButtonGroup |
| `onClick` | `func` | - | - | - | Allow you to handle clicking events on `<RadioButton />` component |
| `options` | `arrayOf` | ✅ | - | - | Array of objects, contains props for each `<RadioButton />` component |
| `selected` | `string` | ✅ | - | - | Value of the selected radiobutton |
| `spacing` | `number` | - | - | `33` | Margin (in px) between radiobutton |
| `style` | `obj`, `array` | - | - | - | Accepts css style |
| Props | Type | Required | Values | Default | Description |
| ------------- | :------------: | :------: | :----------------------: | :----------: | ---------------------------------------------------------------------------------------- |
| `className` | `string` | - | - | - | Accepts class |
| `id` | `string` | - | - | - | Accepts id |
| `isDisabled` | `bool` | - | - | `false` | Disabling all radiobutton in group |
| `name` | `string` | ✅ | - | - | Used as HTML `name` property for `<input>` tag. Used for identification RadioButtonGroup |
| `onClick` | `func` | - | - | - | Allow you to handle clicking events on `<RadioButton />` component |
| `options` | `arrayOf` | ✅ | - | - | Array of objects, contains props for each `<RadioButton />` component |
| `selected` | `string` | ✅ | - | - | Value of the selected radiobutton |
| `style` | `obj`, `array` | - | - | - | Accepts css style |
| `orientation` | `oneOf` | - | `vertical`, `horizontal` | `horizontal` | Position of radiobuttons |
| `spacing` | `string` | - | - | `15px` | Margin between radiobutton. If orientation `horizontal`, it is `margin-left`(apply for all radiobuttons, except first), if orientation `vertical`, it is `margin-bottom`(apply for all radiobuttons, except last) |
| `width` | `string` | - | - | `100%` | Width of RadioButtonGroup container |

View File

@ -1,11 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import RadioButton from '../radio-button';
import styled from 'styled-components';
import styled, { css } from 'styled-components';
const StyledDiv = styled.div`
display: flex;
`;
// eslint-disable-next-line react/prop-types, no-unused-vars
const ClearDiv = ({ orientation, width, ...props }) => <div {...props} />
const StyledDiv = styled(ClearDiv)`
${props =>
(props.orientation === 'horizontal' && css`display: flex;`) ||
(props.orientation === 'vertical' && css`display: block;`)};
width: ${props => props.width};
`;
class RadioButtonGroup extends React.Component {
@ -38,6 +44,8 @@ class RadioButtonGroup extends React.Component {
id={this.props.id}
className={this.props.className}
style={this.props.style}
orientation={this.props.orientation}
width={this.props.width}
>
{options.map(option => {
return (
@ -54,6 +62,7 @@ class RadioButtonGroup extends React.Component {
isDisabled={this.props.isDisabled || option.disabled}
label={option.label}
spacing={this.props.spacing}
orientation={this.props.orientation}
/>
)
}
@ -74,16 +83,20 @@ RadioButtonGroup.propTypes = {
disabled: PropTypes.bool
})).isRequired,
selected: PropTypes.string.isRequired,
spacing: PropTypes.number,
spacing: PropTypes.string,
className: PropTypes.string,
id: PropTypes.string,
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
orientation: PropTypes.oneOf(['horizontal', 'vertical']),
width: PropTypes.string,
}
RadioButtonGroup.defaultProps = {
isDisabled: false,
selected: undefined,
spacing: 33
spacing: '15px',
orientation: 'horizontal',
width: '100%'
}
export default RadioButtonGroup;

View File

@ -3,17 +3,18 @@ import { storiesOf } from '@storybook/react';
import withReadme from 'storybook-readme/with-readme';
import RadioButtonGroup from '.';
import Section from '../../../.storybook/decorators/section';
import { withKnobs, text, boolean, number } from '@storybook/addon-knobs/react';
import { withKnobs, text, boolean, select } from '@storybook/addon-knobs/react';
import Readme from './README.md';
import { action } from '@storybook/addon-actions';
import { optionsKnob as options } from '@storybook/addon-knobs';
storiesOf('Components|Input', module)
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add('radio button group', () => {
.addDecorator(withKnobs)
.addDecorator(withReadme(Readme))
.add('radio button group', () => {
const orientation = ['horizontal', 'vertical'];
const values = ['first', 'second', 'third'];
const valuesMultiSelect = {
radio1: 'radio1',
@ -50,9 +51,11 @@ storiesOf('Components|Input', module)
action('onChange')(e);
console.log('Value of selected radiobutton: ', e.target.value);
}}
orientation={select('orientation', orientation, 'horizontal')}
width={text('width', '100%')}
isDisabled={boolean('isDisabled', false)}
selected={values[0]}
spacing={number('spacing', 33)}
spacing={text('spacing', '15px')}
name={text('name', 'group')}
options={children}
/>

View File

@ -16,14 +16,17 @@ import { RadioButton } from "asc-web-components";
`<RadioButtonGroup />` props supersede RadioButton props
| Props | Type | Required | Values | Default | Description |
| ------------ | :------------: | :------: | :----: | :-----: | ----------------------------------------------------------------------------------------- |
| `className` | `string` | - | - | - | Accepts class |
| `id` | `string` | - | - | - | Accepts id |
| `isChecked` | `bool` | - | - | `false` | Used as HTML `checked` property for each `<input>` tag |
| `isDisabled` | `bool` | - | - | `false` | Used as HTML `disabled` property for each `<input>` tag |
| `label` | `string` | - | - | - | Name of the radiobutton. If missed, `value` will be used |
| `name` | `string` | ✅ | - | - | Used as HTML `name` property for `<input>` tag. |
| `onClick` | `func` | - | - | - | Allow you to handle clicking events on component |
| `style` | `obj`, `array` | - | - | - | Accepts css style |
| `value` | `string` | ✅ | - | - | Used as HTML `value` property for `<input>` tag. Used for identification each radiobutton |
| Props | Type | Required | Values | Default | Description |
| ------------- | :------------: | :------: | :----------------------: | :----------: | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `className` | `string` | - | - | - | Accepts class |
| `id` | `string` | - | - | - | Accepts id |
| `isChecked` | `bool` | - | - | `false` | Used as HTML `checked` property for each `<input>` tag |
| `isDisabled` | `bool` | - | - | `false` | Used as HTML `disabled` property for each `<input>` tag |
| `label` | `string` | - | - | - | Name of the radiobutton. If missed, `value` will be used |
| `name` | `string` | ✅ | - | - | Used as HTML `name` property for `<input>` tag. |
| `onClick` | `func` | - | - | - | Allow you to handle clicking events on component |
| `style` | `obj`, `array` | - | - | - | Accepts css style |
| `value` | `string` | ✅ | - | - | Used as HTML `value` property for `<input>` tag. Used for identification each radiobutton |
| `orientation` | `oneOf` | - | `vertical`, `horizontal` | `horizontal` | Position of radiobuttons |
| `spacing` | `number` | - | - | `33` | Margin (in px) between radiobutton. If orientation `horizontal`, it is `margin-left`(apply for all radiobuttons, except first), if orientation `vertical`, it is `margin-bottom`(apply for all radiobuttons, except last) |
| `width` | `string` | - | - | `100%` | Width of RadioButtonGroup container |

View File

@ -10,7 +10,7 @@ const internalCircleDisabledColor = '#D0D5DA';
const externalCircleDisabledColor = '#eceef1';
// eslint-disable-next-line react/prop-types, no-unused-vars
const ClearLabel = ({ spacing, isDisabled, ...props }) => <label {...props} />
const ClearLabel = ({ spacing, isDisabled, orientation, ...props }) => <label {...props} />
const Label = styled(ClearLabel)`
display: flex;
align-items: center;
@ -47,7 +47,13 @@ const Label = styled(ClearLabel)`
`}
&:not(:first-child) {
margin-left: ${props => props.spacing}px;
${props =>
(props.orientation === 'horizontal' && css`margin-left: ${props.spacing};`)};
}
&:not(:last-child) {
${props =>
(props.orientation === 'vertical' && css`margin-bottom: ${props.spacing};`)};
}
`;
@ -99,6 +105,7 @@ class RadioButton extends React.Component {
return (
<Label
orientation={this.props.orientation}
spacing={this.props.spacing}
isDisabled={this.props.isDisabled}
id={this.props.id}
@ -133,10 +140,11 @@ RadioButton.propTypes = {
onChange: PropTypes.func,
onClick: PropTypes.func,
value: PropTypes.string.isRequired,
spacing: PropTypes.number,
spacing: PropTypes.string,
className: PropTypes.string,
id: PropTypes.string,
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array])
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
orientation: PropTypes.oneOf(['horizontal', 'vertical'])
}
RadioButton.defaultProps = {

View File

@ -516,10 +516,6 @@ namespace ASC.Web.Core.Users
{
return SaveOrUpdatePhoto(userID, data, -1, OriginalFotoSize, true, out _);
}
public string SaveOrUpdateCroppedPhoto(Guid userID, byte[] data, byte[] defaultData)
{
return SaveOrUpdateCroppedPhoto(userID, data, defaultData, -1, OriginalFotoSize, true, out _);
}
public void RemovePhoto(Guid idUser)
{
@ -543,49 +539,7 @@ namespace ASC.Web.Core.Users
UserManager.SaveUserPhoto(userID, data);
SetUserPhotoThumbnailSettings(userID, width, height);
UserPhotoManagerCache.ClearCache(userID);
}
var store = GetDataStore();
var photoUrl = GetDefaultPhotoAbsoluteWebPath();
if (data != null && data.Length > 0)
{
using (var stream = new MemoryStream(data))
{
photoUrl = store.Save(fileName, stream).ToString();
}
//Queue resizing
SizePhoto(userID, data, -1, SmallFotoSize, true);
SizePhoto(userID, data, -1, MediumFotoSize, true);
SizePhoto(userID, data, -1, BigFotoSize, true);
SizePhoto(userID, data, -1, MaxFotoSize, true);
SizePhoto(userID, data, -1, RetinaFotoSize, true);
}
return photoUrl;
}
private string SaveOrUpdateCroppedPhoto(Guid userID, byte[] data, byte[] defaultData, long maxFileSize, Size size, bool saveInCoreContext, out string fileName)
{
data = TryParseImage(data, maxFileSize, size, out var imgFormat, out var width, out var height);
var widening = CommonPhotoManager.GetImgFormatName(imgFormat);
fileName = string.Format("{0}_orig_{1}-{2}.{3}", userID, width, height, widening);
if (saveInCoreContext)
{
UserManager.SaveUserPhoto(userID, defaultData);
var max = Math.Max(Math.Max(width, height), SmallFotoSize.Width);
var min = Math.Max(Math.Min(width, height), SmallFotoSize.Width);
var pos = (max - min) / 2;
var settings = new UserPhotoThumbnailSettings(
width >= height ? new Point(pos, 0) : new Point(0, pos),
new Size(min, min));
SettingsManager.SaveForUser(settings, userID);
UserPhotoManagerCache.ClearCache(userID);
}
var store = GetDataStore();