Client: delete useless

This commit is contained in:
Viktor Fomin 2022-09-05 13:55:09 +03:00
parent 00d281fba1
commit f69bf45e31
24 changed files with 1 additions and 3769 deletions

View File

@ -8,7 +8,6 @@ import AppLoader from "@docspace/common/components/AppLoader";
import { /*combineUrl,*/ updateTempContent } from "@docspace/common/utils";
import Home from "./AccountsHome";
import Profile from "./Profile";
import ProfileAction from "./ProfileAction";
import Filter from "@docspace/common/api/people/filter";
import { showLoader, hideLoader } from "@docspace/common/utils";
@ -23,17 +22,6 @@ const PeopleSection = React.memo(() => {
path={["/accounts/view/:userId"]}
component={Profile}
/>
<PrivateRoute
path={["/accounts/edit/:userId"]}
restricted
allowForMe
component={ProfileAction}
/>
<PrivateRoute
path={["/accounts/create/:type"]}
restricted
component={ProfileAction}
/>
<PrivateRoute
exact
path={["/accounts"]}

View File

@ -1,39 +0,0 @@
import i18n from "i18next";
import { initReactI18next } from "react-i18next";
import Backend from "@docspace/common/utils/i18next-http-backend";
import { LANGUAGE } from "@docspace/common/constants";
import config from "PACKAGE_FILE";
import { loadLanguagePath } from "@docspace/common/utils";
const newInstance = i18n.createInstance();
newInstance
.use(Backend)
.use(initReactI18next)
.init({
lng: localStorage.getItem(LANGUAGE) || "en",
fallbackLng: "en",
load: "currentOnly",
//debug: true,
interpolation: {
escapeValue: false, // not needed for react as it escapes by default
format: function (value, format) {
if (format === "lowercase") return value.toLowerCase();
return value;
},
},
backend: {
loadPath: loadLanguagePath(config.homepage),
},
ns: ["Profile", "ProfileAction", "Common"],
defaultNS: "Profile",
react: {
useSuspense: false,
},
});
export default newInstance;

View File

@ -1,161 +0,0 @@
import React from "react";
import MyProfileI18n from "./i18n";
import PeopleStore from "../../store/PeopleStore";
import PropTypes from "prop-types";
import Section from "@docspace/common/components/Section";
import toastr from "client/toastr";
import { withRouter } from "react-router";
import { Provider as PeopleProvider, inject, observer } from "mobx-react";
import { I18nextProvider, withTranslation } from "react-i18next";
import {
SectionBodyContent as ViewBodyContent,
SectionHeaderContent as ViewHeaderContent,
} from "../Profile/Section";
import { SectionHeaderContent as EditHeaderContent } from "../ProfileAction/Section";
import EditBodyContent from "../ProfileAction/Section/Body";
import Link from "@docspace/components/link";
import { Trans } from "react-i18next";
class My extends React.Component {
componentDidMount() {
const {
fetchProfile,
profile,
location,
t,
setDocumentTitle,
setLoadedProfile,
setIsLoading,
setFirstLoad,
} = this.props;
setDocumentTitle(t("Common:Profile"));
setFirstLoad(false);
const queryString = ((location && location.search) || "").slice(1);
const queryParams = queryString.split("&");
const arrayOfQueryParams = queryParams.map((queryParam) =>
queryParam.split("=")
);
const linkParams = Object.fromEntries(arrayOfQueryParams);
if (linkParams.email_change && linkParams.email_change === "success") {
toastr.success(t("ChangeEmailSuccess"));
}
if (!profile) {
setIsLoading(true);
setLoadedProfile(false);
fetchProfile("@self").finally(() => {
setIsLoading(false);
setLoadedProfile(true);
});
}
}
componentWillUnmount() {
this.props.resetProfile();
}
componentDidUpdate() {
const { tipsSubscription, t, changeEmailSubscription } = this.props;
if (location?.search !== "?unsubscribe=tips" || tipsSubscription === null)
return;
if (!tipsSubscription) {
window.history.replaceState("", "", window.location.pathname);
return;
}
changeEmailSubscription(false)
.then(() => {
window.history.replaceState("", "", window.location.pathname);
toastr.success(
<Trans t={t} i18nKey="SubscriptionTurnOffToast" ns="Profile">
You have been successfully unsubscribed from the the mailing list.
<Link
color="#5387AD"
isHovered={true}
onClick={() => {
changeEmailSubscription(true);
toastr.clear();
}}
>
Subscribe again
</Link>
</Trans>,
null,
0,
true,
true
);
})
.catch((e) => console.error(e));
}
render() {
const { tReady, location } = this.props;
const isEdit = (location && location.search === "?action=edit") || false;
//console.log("My Profile render", this.props, isEdit);
return (
<Section withBodyAutoFocus>
<Section.SectionHeader>
{isEdit ? (
<EditHeaderContent isMy={true} tReady={tReady} />
) : (
<ViewHeaderContent isMy={true} tReady={tReady} />
)}
</Section.SectionHeader>
<Section.SectionBody>
{isEdit ? (
<EditBodyContent isMy={true} tReady={tReady} />
) : (
<ViewBodyContent isMy={true} tReady={tReady} />
)}
</Section.SectionBody>
</Section>
);
}
}
My.propTypes = {
fetchProfile: PropTypes.func.isRequired,
history: PropTypes.object.isRequired,
match: PropTypes.object.isRequired,
profile: PropTypes.object,
language: PropTypes.string,
};
const MyProfile = withRouter(
inject(({ auth, peopleStore }) => ({
setDocumentTitle: auth.setDocumentTitle,
language: auth.language,
resetProfile: peopleStore.targetUserStore.resetTargetUser,
fetchProfile: peopleStore.targetUserStore.getTargetUser,
profile: peopleStore.targetUserStore.targetUser,
setLoadedProfile: peopleStore.loadingStore.setLoadedProfile,
setIsLoading: peopleStore.loadingStore.setIsLoading,
setFirstLoad: peopleStore.loadingStore.setFirstLoad,
tipsSubscription: peopleStore.targetUserStore.tipsSubscription,
changeEmailSubscription:
peopleStore.targetUserStore.changeEmailSubscription,
}))(withTranslation(["Profile", "ProfileAction"])(observer(My)))
);
const peopleStore = new PeopleStore();
export default ({ i18n, ...rest }) => {
return (
<PeopleProvider peopleStore={peopleStore}>
<I18nextProvider i18n={MyProfileI18n}>
<MyProfile {...rest} />
</I18nextProvider>
</PeopleProvider>
);
};

View File

@ -12,7 +12,6 @@ import { withTranslation } from "react-i18next";
class Profile extends React.Component {
componentDidMount() {
const {
match,
fetchProfile,
profile,
location,
@ -23,13 +22,11 @@ class Profile extends React.Component {
setIsEditTargetUser,
setLoadedProfile,
} = this.props;
let { userId } = match.params;
const userId = "@self";
setFirstLoad(false);
setIsEditTargetUser(false);
if (!userId) userId = "@self";
setDocumentTitle(t("Common:Profile"));
this.documentElement = document.getElementsByClassName("hidingHeader");
const queryString = ((location && location.search) || "").slice(1);

View File

@ -1,79 +0,0 @@
import React from "react";
import styled from "styled-components";
import equal from "fast-deep-equal/react";
import ComboBox from "@docspace/components/combobox";
import TextInput from "@docspace/components/text-input";
import IconButton from "@docspace/components/icon-button";
const Container = styled.div`
display: flex;
margin: 0 0 16px 0;
align-items: center;
.remove_icon {
padding-left: 8px;
}
`;
class ContactField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
render() {
const {
isDisabled,
comboBoxName,
comboBoxOptions,
comboBoxSelectedOption,
comboBoxOnChange,
inputName,
inputValue,
inputOnChange,
removeButtonName,
removeButtonOnChange,
} = this.props;
const setDropDownMaxHeight =
comboBoxOptions && comboBoxOptions.length > 6
? { dropDownMaxHeight: 200 }
: {};
return (
<Container>
<ComboBox
name={comboBoxName}
options={comboBoxOptions}
onSelect={comboBoxOnChange}
selectedOption={comboBoxSelectedOption}
isDisabled={isDisabled}
scaled={true}
directionY="both"
className="field-select"
scaledOptions={comboBoxOptions.length < 7}
{...setDropDownMaxHeight}
/>
<TextInput
name={inputName}
value={inputValue}
isDisabled={isDisabled}
onChange={inputOnChange}
/>
<IconButton
id={removeButtonName}
className="remove_icon"
size="16"
onClick={removeButtonOnChange}
iconName={"/static/images/catalog.trash.react.svg"}
isFill={true}
isClickable={true}
/>
</Container>
);
}
}
export default ContactField;

View File

@ -1,118 +0,0 @@
import React from "react";
import styled from "styled-components";
import equal from "fast-deep-equal/react";
import ContactField from "./ContactField";
import ComboBox from "@docspace/components/combobox";
const Container = styled.div`
width: 100%;
max-width: 450px;
.field-select {
width: 120px;
margin: 0 8px 0 0;
}
`;
const getOptions = (patterns, keyPrefix) => {
return patterns.map((item, index) => {
return {
key: keyPrefix + index,
label: item.type, //from resource
icon: item.icon,
value: item.type,
};
});
};
const renderItems = (
contacts,
pattern,
onTypeChange,
onTextChange,
onRemove,
isDisabled
) => {
const items = contacts.map((contact, index) => {
const prefix = contact.id + "_";
const itemOptions = getOptions(pattern, prefix);
const itemSelectedOption = itemOptions.filter(
(option) => option.value === contact.type
)[0];
return (
<ContactField
key={prefix + "item_" + index}
isDisabled={isDisabled}
comboBoxName={prefix + "type"}
comboBoxOptions={itemOptions}
comboBoxSelectedOption={itemSelectedOption}
comboBoxOnChange={onTypeChange}
inputName={prefix + "value"}
inputValue={contact.value}
inputOnChange={onTextChange}
removeButtonName={prefix + "remove"}
removeButtonOnChange={onRemove}
/>
);
});
return items;
};
class ContactsField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
render() {
const {
pattern,
contacts,
addItemText,
onItemAdd,
onItemTypeChange,
onItemTextChange,
onItemRemove,
isDisabled,
} = this.props;
const existItems = renderItems(
contacts,
pattern,
onItemTypeChange,
onItemTextChange,
onItemRemove,
isDisabled
);
const prefix = "null_";
const options = getOptions(pattern, prefix);
const setDropDownMaxHeight =
options && options.length > 6 ? { dropDownMaxHeight: 200 } : {};
return (
<Container>
{existItems}
<ComboBox
options={options}
onSelect={onItemAdd}
scaledOptions={options.length < 6}
selectedOption={{
key: prefix,
label: addItemText,
value: "",
default: true,
}}
isDisabled={isDisabled}
scaled={true}
className="field-select"
directionY="both"
{...setDropDownMaxHeight}
/>
</Container>
);
}
}
export default ContactsField;

View File

@ -1,56 +0,0 @@
import React from "react";
import equal from "fast-deep-equal/react";
import FieldContainer from "@docspace/components/field-container";
import DatePicker from "@docspace/components/date-picker";
class DateField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
render() {
const {
isRequired,
hasError,
labelText,
calendarHeaderContent,
inputName,
inputClassName,
inputValue,
inputIsDisabled,
inputOnChange,
inputTabIndex,
calendarMinDate,
calendarMaxDate,
locale,
maxLabelWidth,
} = this.props;
return (
<FieldContainer
isRequired={isRequired}
hasError={hasError}
labelText={labelText}
maxLabelWidth={maxLabelWidth}
>
<DatePicker
inputClassName={inputClassName}
name={inputName}
selectedDate={inputValue}
isDisabled={inputIsDisabled}
onChange={inputOnChange}
hasError={hasError}
tabIndex={inputTabIndex}
displayType="dropdown"
calendarHeaderContent={calendarHeaderContent}
minDate={calendarMinDate ? calendarMinDate : new Date("1900/01/01")}
maxDate={calendarMaxDate ? calendarMaxDate : new Date()}
locale={locale}
fixedDirection={true}
/>
</FieldContainer>
);
}
}
export default DateField;

View File

@ -1,77 +0,0 @@
import React from "react";
import equal from "fast-deep-equal/react";
import FieldContainer from "@docspace/components/field-container";
import SelectorAddButton from "@docspace/components/selector-add-button";
import SelectedItem from "@docspace/components/selected-item";
import GroupSelector from "../../../../../components/GroupSelector";
class DepartmentField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
onRemoveGroup = (e) => {
const groupId = e.currentTarget.parentElement.dataset.id;
this.props.onRemoveGroup(groupId);
};
render() {
const {
isRequired,
isDisabled,
hasError,
labelText,
showGroupSelectorButtonTitle,
onShowGroupSelector,
onCloseGroupSelector,
selectorIsVisible,
selectorSelectedOptions,
selectorOnSelectGroups,
maxLabelWidth,
} = this.props;
return (
<FieldContainer
isRequired={isRequired}
hasError={hasError}
labelText={labelText}
className="departments-field"
maxLabelWidth={maxLabelWidth}
>
<SelectorAddButton
isDisabled={isDisabled}
title={showGroupSelectorButtonTitle}
onClick={onShowGroupSelector}
className="department-add-btn"
/>
{selectorIsVisible && (
<GroupSelector
isOpen={selectorIsVisible}
isMultiSelect={true}
onSelect={selectorOnSelectGroups}
onCancel={onCloseGroupSelector}
onArrowClick={onCloseGroupSelector}
showCounter
selectedOptions={selectorSelectedOptions}
/>
)}
{selectorSelectedOptions.map((option) => (
<SelectedItem
key={`department_${option.key}`}
text={option.label}
data-id={option.key}
onClose={this.onRemoveGroup}
isInline={true}
className="department-item"
isDisabled={isDisabled}
/>
))}
</FieldContainer>
);
}
}
export default DepartmentField;

View File

@ -1,53 +0,0 @@
import React from "react";
import equal from "fast-deep-equal/react";
import FieldContainer from "@docspace/components/field-container";
import EmailInput from "@docspace/components/email-input";
class EmailField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
render() {
const {
isRequired,
hasError,
labelText,
emailSettings,
inputName,
inputValue,
inputOnChange,
inputTabIndex,
placeholder,
scale,
inputIsDisabled,
onValidateInput,
} = this.props;
return (
<FieldContainer
isRequired={isRequired}
hasError={hasError}
labelText={labelText}
>
<EmailInput
className="field-input"
name={inputName}
value={inputValue}
onChange={inputOnChange}
emailSettings={emailSettings}
tabIndex={inputTabIndex}
placeholder={placeholder}
scale={scale}
autoComplete="email"
isDisabled={inputIsDisabled}
onValidateInput={onValidateInput}
hasError={hasError}
/>
</FieldContainer>
);
}
}
export default EmailField;

View File

@ -1,54 +0,0 @@
import styled from "styled-components";
import { tablet } from "@docspace/components/utils/device";
import NoUserSelect from "@docspace/components/utils/commonStyles";
const MainContainer = styled.div`
display: flex;
flex-direction: row;
.field-input {
width: 100%;
max-width: 320px;
}
.radio-group {
line-height: 32px;
display: flex;
label:not(:first-child) {
margin-left: 33px;
}
}
.departments-field {
position: relative;
margin: 0;
max-width: 835px;
.department-add-btn {
margin: 0 8px 8px 0;
float: left;
}
.department-item {
margin: 0 8px 8px 0;
}
}
@media ${tablet} {
flex-direction: column;
}
`;
const AvatarContainer = styled.div`
margin: 0 32px 32px 0;
width: 160px;
`;
const MainFieldsContainer = styled.div`
flex-grow: 1;
${(props) => props.noSelect && NoUserSelect}
margin: ${(props) =>
`0 0 ${props.marginBottom ? props.marginBottom : "40px"} 0`};
`;
export { MainContainer, AvatarContainer, MainFieldsContainer };

View File

@ -1,35 +0,0 @@
import React from "react";
import styled from "styled-components";
import Heading from "@docspace/components/heading";
import PropTypes from "prop-types";
const Container = styled.div`
margin: ${(props) => `0 0 ${props.marginBottom} 0`};
max-width: 1024px;
`;
const StyledHeader = styled(Heading)`
margin: 0 0 24px 0;
line-height: unset;
`;
const InfoFieldContainer = React.memo((props) => {
const { headerText, children, marginBottom } = props;
return (
<Container marginBottom={marginBottom}>
<StyledHeader level={2} size="small">
{headerText}
</StyledHeader>
{children}
</Container>
);
});
InfoFieldContainer.propTypes = {
marginBottom: PropTypes.string,
};
InfoFieldContainer.defaultProps = {
marginBottom: "40px",
};
export default InfoFieldContainer;

View File

@ -1,82 +0,0 @@
import React from "react";
import equal from "fast-deep-equal/react";
import FieldContainer from "@docspace/components/field-container";
import RadioButtonGroup from "@docspace/components/radio-button-group";
import PasswordInput from "@docspace/components/password-input";
import { PasswordLimitSpecialCharacters } from "@docspace/common/constants";
class PasswordField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
render() {
const {
isRequired,
hasError,
labelText,
passwordSettings,
radioName,
radioValue,
radioOptions,
radioIsDisabled,
radioOnChange,
inputName,
emailInputName,
inputValue,
inputIsDisabled,
inputOnChange,
inputTabIndex,
copyLinkText,
copiedResourceText,
t,
} = this.props;
return (
<FieldContainer
isRequired={isRequired}
hasError={hasError}
labelText={labelText}
>
<RadioButtonGroup
name={radioName}
selected={radioValue}
options={radioOptions}
isDisabled={radioIsDisabled}
onClick={radioOnChange}
className="radio-group"
spacing="33px"
/>
<PasswordInput
inputName={inputName}
emailInputName={emailInputName}
inputValue={inputValue}
inputWidth="320px"
inputTabIndex={inputTabIndex}
onChange={inputOnChange}
clipActionResource={copyLinkText}
clipCopiedResource={copiedResourceText}
clipEmailResource={`${t("Common:Email")}: `}
clipPasswordResource={`${t("Common:Password")}: `}
tooltipPasswordTitle={`${t("Common:PasswordLimitMessage")}:`}
tooltipPasswordLength={`${t("Common:PasswordLimitLength", {
fromNumber: passwordSettings ? passwordSettings.minLength : 8,
toNumber: 30,
})}`}
tooltipPasswordDigits={`${t("Common:PasswordLimitDigits")}`}
tooltipPasswordCapital={`${t("Common:PasswordLimitUpperCase")}`}
tooltipPasswordSpecial={`${t(
"Common:PasswordLimitSpecialSymbols"
)} (${PasswordLimitSpecialCharacters})`}
generatorSpecial={PasswordLimitSpecialCharacters}
passwordSettings={passwordSettings}
isDisabled={inputIsDisabled}
/>
</FieldContainer>
);
}
}
export default PasswordField;

View File

@ -1,51 +0,0 @@
import React from "react";
import equal from "fast-deep-equal/react";
import FieldContainer from "@docspace/components/field-container";
import RadioButtonGroup from "@docspace/components/radio-button-group";
class RadioField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
render() {
const {
isRequired,
hasError,
labelText,
radioName,
radioValue,
radioOptions,
radioIsDisabled,
radioOnChange,
tooltipContent,
helpButtonHeaderContent,
maxLabelWidth,
} = this.props;
return (
<FieldContainer
isRequired={isRequired}
hasError={hasError}
labelText={labelText}
tooltipContent={tooltipContent}
helpButtonHeaderContent={helpButtonHeaderContent}
maxLabelWidth={maxLabelWidth}
>
<RadioButtonGroup
name={radioName}
selected={radioValue}
options={radioOptions}
isDisabled={radioIsDisabled}
onClick={radioOnChange}
className="radio-group"
spacing="33px"
/>
</FieldContainer>
);
}
}
export default RadioField;

View File

@ -1,73 +0,0 @@
import React from "react";
import styled from "styled-components";
import equal from "fast-deep-equal/react";
import FieldContainer from "@docspace/components/field-container";
import TextInput from "@docspace/components/text-input";
import Button from "@docspace/components/button";
const InputContainer = styled.div`
width: 100%;
max-width: 320px;
display: flex;
align-items: center;
`;
class TextChangeField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
render() {
const {
isRequired,
hasError,
labelText,
inputName,
inputValue,
inputTabIndex,
buttonText,
buttonIsDisabled,
buttonOnClick,
buttonTabIndex,
tooltipContent,
helpButtonHeaderContent,
maxLabelWidth,
} = this.props;
return (
<FieldContainer
isRequired={isRequired}
hasError={hasError}
labelText={labelText}
tooltipContent={tooltipContent}
helpButtonHeaderContent={helpButtonHeaderContent}
maxLabelWidth={maxLabelWidth}
offsetRight={100}
tooltipMaxWidth="300px"
>
<InputContainer>
<TextInput
name={inputName}
value={inputValue}
isDisabled={true}
hasError={hasError}
tabIndex={inputTabIndex}
/>
<Button
label={buttonText}
onClick={buttonOnClick}
isDisabled={buttonIsDisabled}
size="small"
style={{ marginLeft: "8px" }}
tabIndex={buttonTabIndex}
/>
</InputContainer>
</FieldContainer>
);
}
}
export default TextChangeField;

View File

@ -1,56 +0,0 @@
import React from "react";
import equal from "fast-deep-equal/react";
import FieldContainer from "@docspace/components/field-container";
import TextInput from "@docspace/components/text-input";
class TextField extends React.Component {
shouldComponentUpdate(nextProps) {
return !equal(this.props, nextProps);
}
render() {
const {
isRequired,
hasError,
labelText,
errorMessage,
inputName,
inputValue,
inputIsDisabled,
inputOnChange,
inputAutoFocussed,
inputTabIndex,
tooltipContent,
helpButtonHeaderContent,
maxLength,
maxLabelWidth,
} = this.props;
return (
<FieldContainer
isRequired={isRequired}
hasError={hasError}
errorMessage={errorMessage}
labelText={labelText}
tooltipContent={tooltipContent}
helpButtonHeaderContent={helpButtonHeaderContent}
maxLabelWidth={maxLabelWidth}
>
<TextInput
name={inputName}
value={inputValue}
isDisabled={inputIsDisabled}
onChange={inputOnChange}
hasError={hasError}
className="field-input"
isAutoFocussed={inputAutoFocussed}
tabIndex={inputTabIndex}
maxLength={maxLength}
/>
</FieldContainer>
);
}
}
export default TextField;

View File

@ -1,340 +0,0 @@
import React from "react";
import { withRouter } from "react-router";
import styled from "styled-components";
import { withTranslation } from "react-i18next";
import AvatarEditor from "@docspace/components/avatar-editor";
import Loader from "@docspace/components/loader";
import { isTablet, isMobile } from "@docspace/components/utils/device";
import {
createThumbnailsAvatar,
loadAvatar,
deleteAvatar,
} from "@docspace/common/api/people";
import toastr from "client/toastr";
import { inject, observer } from "mobx-react";
import { toEmployeeWrapper } from "../../../../helpers/people-helpers";
const dialogsDataset = {
changeEmail: "changeEmail",
changePassword: "changePassword",
changePhone: "changePhone",
};
const AvatarEditorBody = styled.div`
${isMobile() && "margin-left: -8px"}
margin-bottom: 24px;
`;
class AvatarEditorPage extends React.PureComponent {
constructor(props) {
super(props);
this.state = this.mapPropsToState(props);
}
componentDidMount() {
const { match, fetchProfile, t, profile, setDocumentTitle } = this.props;
const { avatar } = this.state;
const { userId } = match.params;
setDocumentTitle(t("ProfileAction"));
if (userId && !profile) {
fetchProfile(userId);
}
if (avatar.image === undefined) {
this.setUserPhotoToState();
}
}
componentDidUpdate(prevProps) {
const { match, fetchProfile /*, profile*/ } = this.props;
const { userId } = match.params;
const { avatar } = this.state;
const prevUserId = prevProps.match.params.userId;
if (userId !== undefined && userId !== prevUserId) {
fetchProfile(userId);
}
if (avatar.image === undefined) {
this.setUserPhotoToState();
}
}
onCancel = () => {
const { toggleAvatarEditor } = this.props;
toggleAvatarEditor(false);
};
updateUserPhotoInState = () => {
var profile = toEmployeeWrapper(this.props.profile);
this.props.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,
},
});
}
}
});
};
mapPropsToState = (props) => {
var profile = toEmployeeWrapper(props.profile);
this.props.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
? undefined
: userPhotoData.original
: undefined,
},
});
}
}
});
const newState = {
isLoading: false,
pageIsLoaded: true,
errors: {
firstName: false,
lastName: false,
},
profile: profile,
visibleAvatarEditor: false,
avatar: {
tmpFile: "",
image: null,
defaultWidth: 0,
defaultHeight: 0,
},
dialogsVisible: {
[dialogsDataset.changePassword]: false,
[dialogsDataset.changePhone]: false,
[dialogsDataset.changeEmail]: false,
currentDialog: "",
},
isMobile: isMobile || isTablet,
};
//Set unique contacts id
const now = new Date().getTime();
newState.profile.contacts.forEach((contact, index) => {
contact.id = (now + index).toString();
});
return newState;
};
onSaveAvatar = (isUpdate, result, avatar) => {
this.setState({ isLoading: true });
const { profile, toggleAvatarEditor, setAvatarMax, personal } = this.props;
if (isUpdate) {
createThumbnailsAvatar(profile.id, {
x: Math.round(result.x * avatar.defaultWidth - result.width / 2),
y: Math.round(result.y * avatar.defaultHeight - result.height / 2),
width: result.width,
height: result.height,
tmpFile: avatar.tmpFile,
})
.then((response) => {
const avatarMax =
response.max +
"?_=" +
Math.floor(Math.random() * Math.floor(10000));
let stateCopy = Object.assign({}, this.state);
setAvatarMax(avatarMax);
toastr.success(this.props.t("ChangesSavedSuccessfully"));
this.setState(stateCopy);
})
.catch((error) => {
toastr.error(error);
this.setState({ isLoading: false });
})
.then(() => {
this.props.updateProfile(this.props.profile);
})
.then(() => {
this.setState(this.mapPropsToState(this.props));
})
.then(() => !personal && this.props.fetchProfile(profile.id))
.then((res) => {
//this.props.isMe && this.props.setUser(res);
return toggleAvatarEditor(false);
});
} else {
deleteAvatar(profile.id)
.then((response) => {
let stateCopy = Object.assign({}, this.state);
setAvatarMax(response.big);
toastr.success(this.props.t("ChangesSavedSuccessfully"));
this.setState(stateCopy);
})
.catch((error) => toastr.error(error))
.then(() => this.props.updateProfile(this.props.profile))
.then(() => {
this.setState(this.mapPropsToState(this.props));
})
.then(() => !personal && this.props.fetchProfile(profile.id))
.then((res) => {
//this.props.isMe && this.props.setUser(res);
return toggleAvatarEditor(false);
});
}
};
onSaveClick = () => this.setState({ isLoading: true });
onLoadFileAvatar = (file, fileData) => {
const { profile } = this.props;
let data = new FormData();
let _this = this;
if (!file) {
_this.onSaveAvatar(false);
return;
}
data.append("file", file);
data.append("Autosave", false);
loadAvatar(profile.id, data)
.then((response) => {
if (!response.success && response.message) {
throw response.message;
}
var img = new Image();
img.onload = () => {
if (fileData) {
fileData.avatar = {
tmpFile: response.data,
image: response.data,
defaultWidth: img.width,
defaultHeight: img.height,
};
if (!fileData.existImage) {
_this.onSaveAvatar(fileData.existImage); // saving empty avatar
} else {
_this.onSaveAvatar(
fileData.existImage,
fileData.position,
fileData.avatar
);
}
}
};
img.src = response.data;
})
.catch((error) => {
toastr.error(error);
this.setState({ isLoading: false });
});
};
setUserPhotoToState = () => {
const { profile } = this.props;
if (!profile) {
this.setState({ pageIsLoaded: true });
return;
}
this.props.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,
},
});
}
}
this.setState({ pageIsLoaded: true });
});
};
render() {
const { t } = this.props;
const { pageIsLoaded } = this.state;
return pageIsLoaded ? (
<AvatarEditorBody>
<AvatarEditor
useModalDialog={false}
image={this.state.avatar.image}
visible={true}
onSave={this.onSaveClick}
onCancel={this.onCancel}
onLoadFile={this.onLoadFileAvatar}
headerLabel={t("EditPhoto")}
selectNewPhotoLabel={t("PeopleTranslations:selectNewPhotoLabel")}
orDropFileHereLabel={t("PeopleTranslations:orDropFileHereLabel")}
unknownTypeError={t("PeopleTranslations:ErrorUnknownFileImageType")}
maxSizeFileError={t("PeopleTranslations:maxSizeFileError")}
unknownError={t("Common:Error")}
saveButtonLabel={
this.state.isLoading ? t("UpdatingProcess") : t("Common:SaveButton")
}
cancelButtonLabel={t("Common:CancelButton")}
saveButtonLoading={this.state.isLoading}
maxSizeLabel={t("PeopleTranslations:MaxSizeLabel")}
/>
</AvatarEditorBody>
) : (
<Loader className="pageLoader" type="rombs" size="40px" />
);
}
}
export default withRouter(
inject(({ auth, peopleStore }) => ({
setDocumentTitle: auth.setDocumentTitle,
//setUser: auth.userStore.setUser,
toggleAvatarEditor: peopleStore.avatarEditorStore.toggleAvatarEditor,
fetchProfile: peopleStore.targetUserStore.getTargetUser,
profile: peopleStore.targetUserStore.targetUser,
//isMe: peopleStore.targetUserStore.isMe,
avatarMax: peopleStore.avatarEditorStore.avatarMax,
setAvatarMax: peopleStore.avatarEditorStore.setAvatarMax,
updateProfile: peopleStore.targetUserStore.updateProfile,
getUserPhoto: peopleStore.targetUserStore.getUserPhoto,
personal: auth.settingsStore.personal,
}))(
observer(
withTranslation(["ProfileAction", "Common", "PeopleTranslations"])(
AvatarEditorPage
)
)
)
);

View File

@ -1,305 +0,0 @@
import React from "react";
import { withRouter } from "react-router";
import styled from "styled-components";
import { withTranslation } from "react-i18next";
import AvatarEditor from "@docspace/components/avatar-editor";
import Loader from "@docspace/components/loader";
import { isTablet } from "@docspace/components/utils/device";
import {
/*createThumbnailsAvatar,*/ loadAvatar,
} from "@docspace/common/api/people";
import toastr from "client/toastr";
import { isMobile } from "react-device-detect";
import { inject, observer } from "mobx-react";
import { toEmployeeWrapper } from "../../../../helpers/people-helpers";
// const dialogsDataset = {
// changeEmail: "changeEmail",
// changePassword: "changePassword",
// changePhone: "changePhone",
// };
const AvatarEditorBody = styled.div`
margin-bottom: 24px;
`;
class CreateAvatarEditorPage extends React.PureComponent {
constructor(props) {
super(props);
this.state = this.mapPropsToState(props);
this.onLoadFileAvatar = this.onLoadFileAvatar.bind(this);
this.onSaveAvatar = this.onSaveAvatar.bind(this);
}
componentDidMount() {
const { match, fetchProfile, t, profile, setDocumentTitle } = this.props;
const { avatar } = this.state;
const { userId } = match.params;
setDocumentTitle(t("ProfileAction"));
if (userId && !profile) {
fetchProfile(userId);
}
if (avatar.image === undefined) {
this.setUserPhotoToState();
}
}
componentDidUpdate(prevProps) {
const { match, fetchProfile /*, profile*/ } = this.props;
const { userId } = match.params;
const { avatar } = this.state;
const prevUserId = prevProps.match.params.userId;
if (this.props.match.params.type !== prevProps.match.params.type) {
this.setState(this.mapPropsToState(this.props));
}
if (userId !== undefined && userId !== prevUserId) {
fetchProfile(userId);
}
if (avatar.image === undefined) {
this.setUserPhotoToState();
}
}
onCancel = () => {
const { toggleAvatarEditor } = this.props;
toggleAvatarEditor(false);
};
updateUserPhotoInState = () => {
var profile = toEmployeeWrapper(this.props.profile);
this.props.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,
},
});
}
}
});
};
mapPropsToState = (props) => {
var profile = toEmployeeWrapper({
isVisitor: props.match.params.type === "guest",
passwordType: "link",
});
return {
pageIsLoaded: true,
visibleAvatarEditor: false,
croppedAvatarImage: "",
isLoading: false,
errors: {
firstName: false,
lastName: false,
email: false,
password: false,
},
profile: profile,
avatar: {
tmpFile: "",
image: null,
defaultWidth: 0,
defaultHeight: 0,
x: 0,
y: 0,
width: 0,
height: 0,
},
isMobile: isMobile || isTablet,
};
};
setIsEdit(hasChanges) {
const { setIsEditingForm } = this.props;
setIsEditingForm(hasChanges);
}
onLoadFileAvatar(file, fileData) {
let data = new FormData();
let _this = this;
data.append("file", file);
data.append("Autosave", false);
if (!file) {
_this.onSaveAvatar(false);
return;
}
loadAvatar(0, data)
.then((response) => {
if (!response.success && response.message) {
throw response.message;
}
var img = new Image();
img.onload = function () {
if (fileData) {
fileData.avatar = {
tmpFile: response.data,
image: response.data,
defaultWidth: img.width,
defaultHeight: img.height,
};
var stateCopy = Object.assign({}, _this.state);
stateCopy.avatar = {
tmpFile: response.data,
image: response.data,
defaultWidth: img.width,
defaultHeight: img.height,
};
_this.setState(stateCopy);
if (fileData.existImage) {
_this.onSaveAvatar(
fileData.existImage,
fileData.position,
fileData.avatar,
fileData.croppedImage
);
}
}
};
img.src = response.data;
})
.catch((error) => toastr.error(error));
}
onSaveAvatar(isUpdate, result, avatar, croppedImage) {
var stateCopy = Object.assign({}, this.state);
const {
setCreatedAvatar,
toggleAvatarEditor,
setCroppedAvatar,
resetProfile,
} = this.props;
stateCopy.visibleAvatarEditor = false;
stateCopy.croppedAvatarImage = croppedImage;
if (isUpdate) {
stateCopy.avatar.x = Math.round(
result.x * avatar.defaultWidth - result.width / 2
);
stateCopy.avatar.y = Math.round(
result.y * avatar.defaultHeight - result.height / 2
);
stateCopy.avatar.width = result.width;
stateCopy.avatar.height = result.height;
setCreatedAvatar(stateCopy.avatar);
setCroppedAvatar(croppedImage);
this.setIsEdit(true);
} else {
resetProfile();
this.setIsEdit(false);
}
toggleAvatarEditor(false);
}
setUserPhotoToState = () => {
const { profile } = this.props;
if (!profile) {
this.setState({ pageIsLoaded: true });
return;
}
this.props.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,
},
});
}
}
this.setState({ pageIsLoaded: true });
});
};
render() {
const { t, createdAvatar } = this.props;
const { pageIsLoaded } = this.state;
return pageIsLoaded ? (
<AvatarEditorBody>
<AvatarEditor
useModalDialog={false}
image={createdAvatar.image}
visible={true}
onClose={this.onCloseAvatarEditor}
onSave={this.onSaveAvatar}
onCancel={this.onCancel}
onLoadFile={this.onLoadFileAvatar}
headerLabel={t("EditPhoto")}
selectNewPhotoLabel={t("PeopleTranslations:selectNewPhotoLabel")}
orDropFileHereLabel={t("PeopleTranslations:orDropFileHereLabel")}
unknownTypeError={t("PeopleTranslations:ErrorUnknownFileImageType")}
maxSizeFileError={t("PeopleTranslations:maxSizeFileError")}
unknownError={t("Common:Error")}
saveButtonLabel={
this.state.isLoading ? t("UpdatingProcess") : t("Common:SaveButton")
}
cancelButtonLabel={t("Common:CancelButton")}
saveButtonLoading={this.state.isLoading}
maxSizeLabel={t("PeopleTranslations:MaxSizeLabel")}
/>
</AvatarEditorBody>
) : (
<Loader className="pageLoader" type="rombs" size="40px" />
);
}
}
export default withRouter(
inject(({ auth, peopleStore }) => ({
setDocumentTitle: auth.setDocumentTitle,
setIsEditingForm: peopleStore.editingFormStore.setIsEditingForm,
toggleAvatarEditor: peopleStore.avatarEditorStore.toggleAvatarEditor,
resetProfile: peopleStore.targetUserStore.resetTargetUser,
fetchProfile: peopleStore.targetUserStore.getTargetUser,
profile: peopleStore.targetUserStore.targetUser,
setCreatedAvatar: peopleStore.avatarEditorStore.setCreatedAvatar,
setCroppedAvatar: peopleStore.avatarEditorStore.setCroppedAvatar,
updateProfile: peopleStore.targetUserStore.updateProfile,
updateCreatedAvatar: peopleStore.targetUserStore.updateCreatedAvatar,
getUserPhoto: peopleStore.targetUserStore.getUserPhoto,
createdAvatar: peopleStore.avatarEditorStore.createdAvatar,
avatarMax: peopleStore.avatarEditorStore.avatarMax,
croppedAvatar: peopleStore.avatarEditorStore.croppedAvatar,
}))(
observer(
withTranslation(["ProfileAction", "Common", "PeopleTranslations"])(
CreateAvatarEditorPage
)
)
)
);

View File

@ -1,758 +0,0 @@
import React from "react";
import { withRouter } from "react-router";
import Avatar from "@docspace/components/avatar";
import Button from "@docspace/components/button";
import Textarea from "@docspace/components/textarea";
import Text from "@docspace/components/text";
import AvatarEditor from "@docspace/components/avatar-editor";
import { isTablet } from "@docspace/components/utils/device";
import { withTranslation, Trans } from "react-i18next";
import {
MainContainer,
AvatarContainer,
MainFieldsContainer,
} from "./FormFields/Form";
import TextField from "./FormFields/TextField";
import PasswordField from "./FormFields/PasswordField";
import EmailField from "./FormFields/EmailField";
import DateField from "./FormFields/DateField";
import RadioField from "./FormFields/RadioField";
import DepartmentField from "./FormFields/DepartmentField";
import ContactsField from "./FormFields/ContactsField";
import InfoFieldContainer from "./FormFields/InfoFieldContainer";
import { DataLossWarningDialog } from "../../../../components/dialogs";
import {
createThumbnailsAvatar,
loadAvatar,
} from "@docspace/common/api/people";
import toastr from "client/toastr";
import { isMobile } from "react-device-detect";
import { inject, observer } from "mobx-react";
import {
toEmployeeWrapper,
getUserRole,
getUserContactsPattern,
getUserContacts,
mapGroupsToGroupSelectorOptions,
mapGroupSelectorOptionsToGroups,
filterGroupSelectorOptions,
} from "../../../../helpers/people-helpers";
import config from "PACKAGE_FILE";
import { combineUrl } from "@docspace/common/utils";
import { AppServerConfig } from "@docspace/common/constants";
class CreateUserForm extends React.Component {
constructor(props) {
super(props);
this.state = this.mapPropsToState(props);
this.mainFieldsContainerRef = React.createRef();
}
createAvatar(userId, userName) {
const { createdAvatar } = this.props;
createThumbnailsAvatar(userId, {
x: createdAvatar.x,
y: createdAvatar.y,
width: createdAvatar.width,
height: createdAvatar.height,
tmpFile: createdAvatar.tmpFile,
})
.then((res) => {
this.props.updateCreatedAvatar(res);
this.props.updateProfileInUsers();
toastr.success(this.props.t("ChangesSavedSuccessfully"));
this.props.history.push(
combineUrl(
AppServerConfig.proxyURL,
this.props.homepage,
`/accounts/view/${userName}`
)
);
})
.catch((error) => toastr.error(error));
}
openAvatarEditor = () => {
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,
});
};
openAvatarEditorPage = () => {
const { toggleAvatarEditor } = this.props;
toggleAvatarEditor(true);
};
onLoadFileAvatar = (file, fileData) => {
let data = new FormData();
let _this = this;
data.append("file", file);
data.append("Autosave", false);
if (!file) {
_this.onSaveAvatar(false);
return;
}
loadAvatar(0, data)
.then((response) => {
if (!response.success && response.message) {
throw response.message;
}
var img = new Image();
img.onload = function () {
if (fileData) {
fileData.avatar = {
tmpFile: response.data,
image: response.data,
defaultWidth: img.width,
defaultHeight: img.height,
};
var stateCopy = Object.assign({}, _this.state);
stateCopy.avatar = {
tmpFile: response.data,
image: response.data,
defaultWidth: img.width,
defaultHeight: img.height,
};
_this.setState(stateCopy);
if (fileData.existImage) {
_this.onSaveAvatar(
fileData.existImage,
fileData.position,
fileData.avatar,
fileData.croppedImage
);
}
}
};
img.src = response.data;
})
.catch((error) => toastr.error(error));
};
onSaveAvatar = (isUpdate, result, avatar, croppedImage) => {
var stateCopy = Object.assign({}, this.state);
const { setCreatedAvatar, setCroppedAvatar, resetProfile } = this.props;
stateCopy.visibleAvatarEditor = false;
stateCopy.croppedAvatarImage = croppedImage;
if (isUpdate) {
stateCopy.avatar.x = Math.round(
result.x * avatar.defaultWidth - result.width / 2
);
stateCopy.avatar.y = Math.round(
result.y * avatar.defaultHeight - result.height / 2
);
stateCopy.avatar.width = result.width;
stateCopy.avatar.height = result.height;
setCreatedAvatar(stateCopy.avatar);
setCroppedAvatar(croppedImage);
} else {
resetProfile();
}
this.setState(stateCopy);
this.setIsEdit();
};
onCloseAvatarEditor = () => {
this.setState({
visibleAvatarEditor: false,
croppedAvatarImage: "",
avatar: {
tmpFile: "",
},
});
};
componentDidUpdate(prevProps, prevState) {
if (this.props.match.params.type !== prevProps.match.params.type) {
this.setState(this.mapPropsToState(this.props));
}
const isMobileDevice = isMobile || isTablet();
if (prevState.isMobile !== isMobileDevice) {
this.setState({ isMobile: isMobileDevice });
}
}
mapPropsToState = (props) => {
var profile = toEmployeeWrapper({
isVisitor: props.match.params.type === "guest",
passwordType: "link",
});
var allOptions = mapGroupsToGroupSelectorOptions(props.groups);
var selected = mapGroupsToGroupSelectorOptions(profile.groups);
return {
visibleAvatarEditor: false,
croppedAvatarImage: "",
isLoading: false,
errors: {
firstName: false,
lastName: false,
email: false,
password: false,
},
profile: profile,
selector: {
visible: false,
allOptions: allOptions,
options: [...allOptions],
selected: selected,
},
avatar: {
tmpFile: "",
image: null,
defaultWidth: 0,
defaultHeight: 0,
x: 0,
y: 0,
width: 0,
height: 0,
},
isMobile: isMobile || isTablet,
};
};
setIsEdit() {
const { isEdit, setIsEditingForm } = this.props;
if (!isEdit) setIsEditingForm(true);
}
onInputChange = (event) => {
const { userFormValidation } = this.props;
var stateCopy = Object.assign({}, this.state);
const value = event.target.value;
const title = event.target.name;
if (!value.match(userFormValidation)) {
stateCopy.errors[title] = true;
} else {
if (this.state.errors[title]) stateCopy.errors[title] = false;
}
stateCopy.profile[title] = value;
this.setState(stateCopy);
this.setIsEdit();
};
onBirthdayDateChange = (value) => {
var stateCopy = Object.assign({}, this.state);
stateCopy.profile.birthday = value ? value.toJSON() : null;
this.setState(stateCopy);
this.setIsEdit();
};
onWorkFromDateChange = (value) => {
var stateCopy = Object.assign({}, this.state);
stateCopy.profile.workFrom = value ? value.toJSON() : null;
this.setState(stateCopy);
this.setIsEdit();
};
scrollToErrorForm = () => {
const element = this.mainFieldsContainerRef.current;
const parent = element.closest(".scroll-body");
(parent || window).scrollTo(0, element.offsetTop);
};
validate = () => {
const { profile, errors: stateErrors } = this.state;
if (stateErrors.firstName || stateErrors.lastName) {
this.scrollToErrorForm();
return;
}
const errors = {
firstName: !profile.firstName.trim(),
lastName: !profile.lastName.trim(),
email: stateErrors.email || !profile.email.trim(),
password: profile.passwordType === "temp" && !profile.password.trim(),
};
const hasError =
errors.firstName || errors.lastName || errors.email || errors.password;
if (hasError) {
this.scrollToErrorForm();
}
this.setState({ errors: errors });
return !hasError;
};
handleSubmit = () => {
if (!this.validate()) return false;
const {
setIsEditingForm,
homepage,
createProfile,
createdAvatar,
t,
history,
} = this.props;
const profile = this.state.profile;
if (!profile.birthday) profile.birthday = new Date();
this.setState({ isLoading: true });
createProfile(profile)
.then((profile) => {
if (createdAvatar.tmpFile !== "") {
this.createAvatar(profile.id, profile.userName);
} else {
toastr.success(t("ChangesSavedSuccessfully"));
history.push(
combineUrl(
AppServerConfig.proxyURL,
homepage,
`/accounts/view/${profile.userName}`
)
);
}
setIsEditingForm(false);
})
.catch((error) => {
toastr.error(error);
this.setState({ isLoading: false });
});
};
onCancelHandler = () => {
const { isEdit, setIsVisibleDataLossDialog } = this.props;
if (isEdit) {
setIsVisibleDataLossDialog(true);
} else {
this.onCancel();
}
};
onCancel = () => {
const { filter, setFilter, history } = this.props;
history.goBack();
setFilter(filter);
};
onContactsItemAdd = (item) => {
var stateCopy = Object.assign({}, this.state);
stateCopy.profile.contacts.push({
id: new Date().getTime().toString(),
type: item.value,
value: "",
});
this.setState(stateCopy);
this.setIsEdit();
};
onContactsItemTypeChange = (item) => {
const id = item.key.split("_")[0];
var stateCopy = Object.assign({}, this.state);
stateCopy.profile.contacts.forEach((element) => {
if (element.id === id) element.type = item.value;
});
this.setState(stateCopy);
this.setIsEdit();
};
onContactsItemTextChange = (event) => {
const id = event.target.name.split("_")[0];
var stateCopy = Object.assign({}, this.state);
stateCopy.profile.contacts.forEach((element) => {
if (element.id === id) element.value = event.target.value;
});
this.setState(stateCopy);
this.setIsEdit();
};
onContactsItemRemove = (event) => {
const id = event.target.closest(".remove_icon").dataset.for.split("_")[0];
var stateCopy = Object.assign({}, this.state);
const filteredArray = stateCopy.profile.contacts.filter((element) => {
return element.id !== id;
});
stateCopy.profile.contacts = filteredArray;
this.setState(stateCopy);
this.setIsEdit();
};
onShowGroupSelector = () => {
var stateCopy = Object.assign({}, this.state);
stateCopy.selector.visible = true;
this.setState(stateCopy);
};
onCloseGroupSelector = () => {
var stateCopy = Object.assign({}, this.state);
stateCopy.selector.visible = false;
this.setState(stateCopy);
};
onSearchGroups = (template) => {
var stateCopy = Object.assign({}, this.state);
stateCopy.selector.options = filterGroupSelectorOptions(
stateCopy.selector.allOptions,
template
);
this.setState(stateCopy);
};
onSelectGroups = (selected) => {
var stateCopy = Object.assign({}, this.state);
stateCopy.profile.groups = mapGroupSelectorOptionsToGroups(selected);
stateCopy.selector.selected = selected;
stateCopy.selector.visible = false;
this.setState(stateCopy);
this.setIsEdit();
};
onRemoveGroup = (id) => {
var stateCopy = Object.assign({}, this.state);
stateCopy.profile.groups = stateCopy.profile.groups.filter(
(group) => group.id !== id
);
stateCopy.selector.selected = stateCopy.selector.selected.filter(
(option) => option.key !== id
);
this.setState(stateCopy);
};
onValidateEmailField = (value) =>
this.setState({ errors: { ...this.state.errors, email: !value.isValid } });
onSaveClick = () => this.setState({ isLoading: true });
render() {
const { isLoading, errors, profile, selector, isMobile } = this.state;
const {
t,
customNames,
createdAvatar,
croppedAvatar,
passwordSettings,
language,
isTabletView,
} = this.props;
const { regDateCaption, userPostCaption, groupCaption } = customNames;
const pattern = getUserContactsPattern();
const contacts = getUserContacts(profile.contacts);
const notEmptyFirstName = Boolean(profile.firstName.trim());
const notEmptyLastName = Boolean(profile.lastName.trim());
return (
<>
<MainContainer>
<DataLossWarningDialog onContinue={this.onCancel} />
<AvatarContainer>
<Avatar
size="max"
role={getUserRole(profile)}
editing={true}
source={croppedAvatar}
editLabel={t("Common:AddButton")}
editAction={
isMobile ? this.openAvatarEditorPage : this.openAvatarEditor
}
/>
<AvatarEditor
image={createdAvatar.image}
visible={this.state.visibleAvatarEditor}
onClose={this.onCloseAvatarEditor}
onSave={this.onSaveClick}
onLoadFile={this.onLoadFileAvatar}
headerLabel={t("AddPhoto")}
selectNewPhotoLabel={t("PeopleTranslations:selectNewPhotoLabel")}
orDropFileHereLabel={t("PeopleTranslations:orDropFileHereLabel")}
unknownTypeError={t(
"PeopleTranslations:ErrorUnknownFileImageType"
)}
maxSizeFileError={t("PeopleTranslations:maxSizeFileError")}
unknownError={t("Common:Error")}
saveButtonLabel={t("Common:SaveButton")}
saveButtonLoading={this.state.isLoading}
maxSizeLabel={t("PeopleTranslations:MaxSizeLabel")}
/>
</AvatarContainer>
<MainFieldsContainer
ref={this.mainFieldsContainerRef}
{...(!isTabletView && { marginBottom: "32px" })}
>
<TextField
isRequired={true}
hasError={errors.firstName}
{...(notEmptyFirstName && {
errorMessage: t("ErrorInvalidUserFirstName"),
})}
labelText={`${t("FirstName")}:`}
inputName="firstName"
inputValue={profile.firstName}
inputIsDisabled={isLoading}
inputOnChange={this.onInputChange}
inputAutoFocussed={true}
inputTabIndex={1}
/>
<TextField
isRequired={true}
hasError={errors.lastName}
{...(notEmptyLastName && {
errorMessage: t("ErrorInvalidUserLastName"),
})}
labelText={`${t("Common:LastName")}:`}
inputName="lastName"
inputValue={profile.lastName}
inputIsDisabled={isLoading}
inputOnChange={this.onInputChange}
inputTabIndex={2}
/>
<EmailField
isRequired={true}
hasError={errors.email}
labelText={`${t("Common:Email")}:`}
inputName="email"
inputValue={profile.email}
inputIsDisabled={isLoading}
inputOnChange={this.onInputChange}
inputTabIndex={3}
helpButtonHeaderContent={t("Common:Mail")}
tooltipContent={
<Text fontSize="13px" as="div">
<Trans t={t} i18nKey="EmailPopupHelper" ns="ProfileAction">
The main e-mail is needed to restore access to the portal in
case of loss of the password and send notifications.
<p className="tooltip_email" style={{ margin: "1rem 0" }}>
You can create a new mail on the domain as the primary. In
this case, you must set a one-time password so that the
user can log in to the portal for the first time.
</p>
The main e-mail can be used as a login when logging in to
the portal.
</Trans>
</Text>
}
onValidateInput={this.onValidateEmailField}
/>
<PasswordField
isRequired={true}
hasError={errors.password}
labelText={`${t("Common:Password")}:`}
radioName="passwordType"
radioValue={profile.passwordType}
radioOptions={[
{ value: "link", label: t("ActivationLink") },
{ value: "temp", label: t("TemporaryPassword") },
]}
radioIsDisabled={isLoading}
radioOnChange={this.onInputChange}
inputName="password"
emailInputName="email"
inputValue={profile.password}
inputIsDisabled={isLoading || profile.passwordType === "link"}
inputOnChange={this.onInputChange}
copyLinkText={t("Common:CopyEmailAndPassword")}
copiedResourceText={t("CopiedResourceText")}
inputTabIndex={4}
passwordSettings={passwordSettings}
t={t}
/>
<DateField
calendarHeaderContent={`${t("CalendarSelectDate")}:`}
labelText={`${t("PeopleTranslations:Birthdate")}:`}
inputName="birthday"
inputClassName="date-picker_input-birthday"
inputValue={
profile.birthday ? new Date(profile.birthday) : undefined
}
inputIsDisabled={isLoading}
inputOnChange={this.onBirthdayDateChange}
inputTabIndex={5}
locale={language}
/>
<RadioField
labelText={`${t("PeopleTranslations:Sex")}:`}
radioName="sex"
radioValue={profile.sex}
radioOptions={[
{ value: "male", label: t("PeopleTranslations:MaleSexStatus") },
{
value: "female",
label: t("PeopleTranslations:FemaleSexStatus"),
},
]}
radioIsDisabled={isLoading}
radioOnChange={this.onInputChange}
/>
<DateField
calendarHeaderContent={`${t("CalendarSelectDate")}:`}
labelText={`${regDateCaption}:`}
inputName="workFrom"
inputClassName="date-picker_input-reg-date"
inputValue={
profile.workFrom ? new Date(profile.workFrom) : undefined
}
inputIsDisabled={isLoading}
inputOnChange={this.onWorkFromDateChange}
inputTabIndex={6}
calendarMinDate={
profile.birthday ? new Date(profile.birthday) : undefined
}
locale={language}
/>
<TextField
labelText={`${t("Common:Location")}:`}
inputName="location"
inputValue={profile.location}
inputIsDisabled={isLoading}
inputOnChange={this.onInputChange}
inputTabIndex={7}
/>
<TextField
labelText={`${userPostCaption}:`}
inputName="title"
inputValue={profile.title}
inputIsDisabled={isLoading}
inputOnChange={this.onInputChange}
inputTabIndex={8}
/>
<DepartmentField
labelText={`${groupCaption}:`}
isDisabled={isLoading}
showGroupSelectorButtonTitle={t("Common:AddButton")}
onShowGroupSelector={this.onShowGroupSelector}
onCloseGroupSelector={this.onCloseGroupSelector}
onRemoveGroup={this.onRemoveGroup}
selectorIsVisible={selector.visible}
selectorOptions={selector.options}
selectorSelectedOptions={selector.selected}
selectorSelectAllText={t("Common:SelectAll")}
selectorOnSearchGroups={this.onSearchGroups}
selectorOnSelectGroups={this.onSelectGroups}
/>
</MainFieldsContainer>
</MainContainer>
<InfoFieldContainer
headerText={t("Common:Comments")}
marginBottom={"42px"}
>
<Textarea
placeholder={t("WriteComment")}
name="notes"
value={profile.notes}
isDisabled={isLoading}
onChange={this.onInputChange}
tabIndex={9}
/>
</InfoFieldContainer>
<InfoFieldContainer
headerText={t("ContactInformation")}
marginBottom={"42px"}
>
<ContactsField
pattern={pattern.contact}
contacts={contacts.contact}
isDisabled={isLoading}
addItemText={t("AddContact")}
onItemAdd={this.onContactsItemAdd}
onItemTypeChange={this.onContactsItemTypeChange}
onItemTextChange={this.onContactsItemTextChange}
onItemRemove={this.onContactsItemRemove}
/>
</InfoFieldContainer>
<InfoFieldContainer
headerText={t("PeopleTranslations:SocialProfiles")}
{...(isTabletView && { marginBottom: "36px" })}
>
<ContactsField
pattern={pattern.social}
contacts={contacts.social}
isDisabled={isLoading}
addItemText={t("AddContact")}
onItemAdd={this.onContactsItemAdd}
onItemTypeChange={this.onContactsItemTypeChange}
onItemTextChange={this.onContactsItemTextChange}
onItemRemove={this.onContactsItemRemove}
/>
</InfoFieldContainer>
<div>
<Button
label={t("Common:SaveButton")}
onClick={this.handleSubmit}
primary
isDisabled={isLoading}
size="normal"
tabIndex={10}
className="create-user_save-btn"
/>
<Button
label={t("Common:CancelButton")}
onClick={this.onCancelHandler}
isDisabled={isLoading}
size="normal"
style={{ marginLeft: "8px" }}
tabIndex={11}
className="create-user_cancel-btn"
/>
</div>
</>
);
}
}
export default withRouter(
inject(({ auth, peopleStore }) => ({
passwordSettings: auth.settingsStore.passwordSettings,
customNames: auth.settingsStore.customNames,
language: auth.language,
homepage: config.homepage,
isEdit: peopleStore.editingFormStore.isEdit,
groups: peopleStore.groupsStore.groups,
setIsVisibleDataLossDialog:
peopleStore.editingFormStore.setIsVisibleDataLossDialog,
setIsEditingForm: peopleStore.editingFormStore.setIsEditingForm,
filter: peopleStore.filterStore.filter,
setFilter: peopleStore.filterStore.setFilterParams,
toggleAvatarEditor: peopleStore.avatarEditorStore.toggleAvatarEditor,
resetProfile: peopleStore.targetUserStore.resetTargetUser,
createProfile: peopleStore.usersStore.createUser,
createdAvatar: peopleStore.avatarEditorStore.createdAvatar,
setCreatedAvatar: peopleStore.avatarEditorStore.setCreatedAvatar,
croppedAvatar: peopleStore.avatarEditorStore.croppedAvatar,
setCroppedAvatar: peopleStore.avatarEditorStore.setCroppedAvatar,
updateProfileInUsers: peopleStore.usersStore.updateProfileInUsers,
updateCreatedAvatar: peopleStore.targetUserStore.updateCreatedAvatar,
userFormValidation: auth.settingsStore.userFormValidation,
isTabletView: auth.settingsStore.isTabletView,
}))(
observer(
withTranslation(["ProfileAction", "Common", "PeopleTranslations"])(
CreateUserForm
)
)
)
);

View File

@ -1,35 +0,0 @@
import React from "react";
import CreateAvatarEditorPage from "./createAvatarEditorPage";
import AvatarEditorPage from "./avatarEditorPage";
import CreateUserForm from "./createUserForm";
import UpdateUserForm from "./updateUserForm";
import { inject, observer } from "mobx-react";
import { withRouter } from "react-router";
import withPeopleLoader from "../../../../HOCs/withPeopleLoader";
import Loaders from "@docspace/common/components/Loaders";
const SectionUserBody = ({ avatarEditorIsOpen, match, isMy, loaded }) => {
const { type } = match.params;
return type ? (
avatarEditorIsOpen ? (
<CreateAvatarEditorPage />
) : (
<CreateUserForm />
)
) : avatarEditorIsOpen ? (
<AvatarEditorPage />
) : (
<UpdateUserForm isMy={isMy} />
);
};
export default withRouter(
inject(({ peopleStore }) => ({
avatarEditorIsOpen: peopleStore.avatarEditorStore.visible,
}))(
withPeopleLoader(observer(SectionUserBody))(
<Loaders.ProfileView isEdit={false} />
)
)
);

View File

@ -1,146 +0,0 @@
import React, { useCallback } from "react";
import styled from "styled-components";
import { withRouter } from "react-router";
import IconButton from "@docspace/components/icon-button";
import Headline from "@docspace/common/components/Headline";
import { useTranslation } from "react-i18next";
import { inject, observer } from "mobx-react";
import { isMobileOnly } from "react-device-detect";
import config from "PACKAGE_FILE";
import { combineUrl } from "@docspace/common/utils";
import { AppServerConfig } from "@docspace/common/constants";
import Loaders from "@docspace/common/components/Loaders";
import withPeopleLoader from "../../../../HOCs/withPeopleLoader";
const homepage = config.homepage;
const Wrapper = styled.div`
display: grid;
grid-template-columns: auto 1fr auto auto;
align-items: center;
.arrow-button {
@media (max-width: 1024px) {
padding: 8px 0 8px 8px;
margin-left: -8px;
}
}
.header-headline {
margin-left: 16px;
}
`;
const SectionHeaderContent = (props) => {
const {
profile,
history,
match,
customNames,
filter,
isEdit,
setFilter,
setIsVisibleDataLossDialog,
toggleAvatarEditor,
avatarEditorIsOpen,
isMy,
isEditTargetUser,
} = props;
const { userCaption, guestCaption } = customNames;
const { type } = match.params;
const { t } = useTranslation("ProfileAction");
const headerText = avatarEditorIsOpen
? t("EditPhoto")
: type
? type === "guest"
? t("CustomCreation", { user: guestCaption })
: t("CustomCreation", { user: userCaption })
: profile
? isMobileOnly
? t("Common:Editing")
: t("EditUserDialogTitle")
: "";
const onClickBackHandler = () => {
if (isEdit) {
setIsVisibleDataLossDialog(true, onClickBack);
} else {
onClickBack();
}
};
const setFilterAndReset = useCallback(
(filter) => {
props.resetProfile();
setFilter(filter);
},
[props, setFilter]
);
const goBackAndReset = useCallback(() => {
if (isMy) {
return history.goBack();
}
if (!isEditTargetUser && (!profile || !document.referrer)) {
setFilterAndReset(filter);
const urlFilter = filter.toUrlParams();
return history.push(
combineUrl(
AppServerConfig.proxyURL,
homepage,
`/accounts/filter?${urlFilter}`
)
);
}
history.push(
combineUrl(
AppServerConfig.proxyURL,
homepage,
`/accounts/view/${profile.userName}`
)
);
return props.resetProfile();
}, [history, props]);
const onClickBack = useCallback(() => {
avatarEditorIsOpen ? toggleAvatarEditor(false) : goBackAndReset();
}, [avatarEditorIsOpen, toggleAvatarEditor, profile, filter, goBackAndReset]);
return (
<Wrapper>
<IconButton
iconName="/static/images/arrow.path.react.svg"
size="17"
isFill={true}
onClick={onClickBackHandler}
className="arrow-button"
/>
<Headline className="header-headline" type="content" truncate={true}>
{headerText}
</Headline>
</Wrapper>
);
};
export default withRouter(
inject(({ auth, peopleStore }) => ({
customNames: auth.settingsStore.customNames,
isEdit: peopleStore.editingFormStore.isEdit,
setIsVisibleDataLossDialog:
peopleStore.editingFormStore.setIsVisibleDataLossDialog,
filter: peopleStore.filterStore.filter,
setFilter: peopleStore.filterStore.setFilterParams,
toggleAvatarEditor: peopleStore.avatarEditorStore.toggleAvatarEditor,
resetProfile: peopleStore.targetUserStore.resetTargetUser,
profile: peopleStore.targetUserStore.targetUser,
avatarEditorIsOpen: peopleStore.avatarEditorStore.visible,
isEditTargetUser: peopleStore.targetUserStore.isEditTargetUser,
}))(
withPeopleLoader(observer(SectionHeaderContent))(<Loaders.SectionHeader />)
)
);

View File

@ -1,5 +0,0 @@
export { default as SectionHeaderContent } from "./Header";
export { default as CreateUserForm } from "./Body/createUserForm";
export { default as UpdateUserForm } from "./Body/updateUserForm";
export { default as AvatarEditorPage } from "./Body/avatarEditorPage";
export { default as CreateAvatarEditorPage } from "./Body/createAvatarEditorPage";

View File

@ -1,142 +0,0 @@
import React from "react";
import PropTypes from "prop-types";
import Section from "@docspace/common/components/Section";
import Loaders from "@docspace/common/components/Loaders";
import toastr from "client/toastr";
import { linkOAuth } from "@docspace/common/api/people";
import { getAuthProviders } from "@docspace/common/api/settings";
import SectionUserBody from "./Section/Body/index";
import {
SectionHeaderContent,
// CreateUserForm,
// UpdateUserForm,
// AvatarEditorPage,
// CreateAvatarEditorPage,
} from "./Section";
import { withTranslation } from "react-i18next";
import { withRouter } from "react-router";
import { inject, observer } from "mobx-react";
class ProfileAction extends React.Component {
componentDidMount() {
const {
match,
fetchProfile,
isEdit,
setIsEditingForm,
t,
setDocumentTitle,
setFirstLoad,
profile,
setLoadedProfile,
} = this.props;
const { userId } = match.params;
setFirstLoad(false);
this.documentElement = document.getElementsByClassName("hidingHeader");
setDocumentTitle(t("ProfileAction"));
if (isEdit) {
setIsEditingForm(false);
}
if ((userId && !profile) || (profile && userId !== profile.userName)) {
setLoadedProfile(false);
fetchProfile(userId).finally(() => setLoadedProfile(true));
}
if (!this.loaded && this.documentElement) {
for (var i = 0; i < this.documentElement.length; i++) {
this.documentElement[i].style.transition = "none";
}
}
}
componentDidUpdate(prevProps) {
const { match, fetchProfile } = this.props;
const { userId } = match.params;
const prevUserId = prevProps.match.params.userId;
if (userId !== undefined && userId !== prevUserId) {
fetchProfile(userId);
}
if (this.loaded && this.documentElement) {
for (var i = 0; i < this.documentElement.length; i++) {
this.documentElement[i].style.transition = "";
}
}
}
componentWillUnmount() {
this.props.setIsEditTargetUser(false);
}
render() {
// console.log("ProfileAction render");
this.loaded = false;
const { profile, match, isMy, tReady, showCatalog, isAdmin } = this.props;
const { userId, type } = match.params;
if (type) {
this.loaded = true;
} else if (profile) {
this.loaded = profile.userName === userId || profile.id === userId;
}
return (
<Section>
<Section.SectionHeader>
<SectionHeaderContent tReady={tReady} loaded={this.loaded} />
</Section.SectionHeader>
<Section.SectionBody>
<SectionUserBody isMy={isMy} tReady={tReady} loaded={this.loaded} />
</Section.SectionBody>
</Section>
);
}
}
ProfileAction.propTypes = {
setDocumentTitle: PropTypes.func.isRequired,
isEdit: PropTypes.bool,
setIsEditingForm: PropTypes.func.isRequired,
fetchProfile: PropTypes.func.isRequired,
profile: PropTypes.object,
match: PropTypes.object.isRequired,
};
export default withRouter(
inject(({ auth, peopleStore }) => {
const { setDocumentTitle } = auth;
const {
usersStore,
editingFormStore,
targetUserStore,
loadingStore,
} = peopleStore;
const { setProviders } = usersStore;
const { isEdit, setIsEditingForm } = editingFormStore;
const {
getTargetUser: fetchProfile,
targetUser: profile,
setIsEditTargetUser,
} = targetUserStore;
const { setFirstLoad, setLoadedProfile } = loadingStore;
return {
setProviders,
setDocumentTitle,
isEdit,
setIsEditingForm,
fetchProfile,
profile,
setFirstLoad,
setLoadedProfile,
setIsEditTargetUser,
isAdmin: auth.isAdmin,
showCatalog: auth.settingsStore.showCatalog,
};
})(withTranslation(["ProfileAction", "Common"])(observer(ProfileAction)))
);

View File

@ -257,7 +257,6 @@ module.exports = (env, argv) => {
"./PeopleSelector": "./src/components/PeopleSelector",
"./PeopleSelector/UserTooltip":
"./src/components/PeopleSelector/sub-components/UserTooltip.js",
"./MyProfile": "./src/pages/My",
},
shared: {
...deps,