web: People: Added api client with common settings for all requests

This commit is contained in:
Alexey Safronov 2019-10-08 10:59:45 +03:00
parent d941f3aeb5
commit cd63121dc7
15 changed files with 566 additions and 559 deletions

View File

@ -1,201 +1,208 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { withRouter } from 'react-router';
import React from "react";
import { connect } from "react-redux";
import PropTypes from "prop-types";
import { withRouter } from "react-router";
import {
toastr,
ModalDialog,
Link,
Checkbox,
Button,
Textarea,
Text
toastr,
ModalDialog,
Link,
Checkbox,
Button,
Textarea,
Text
} from "asc-web-components";
import { getInvitationLink, getShortenedLink } from '../../../store/profile/actions';
import { withTranslation, I18nextProvider } from 'react-i18next';
import i18n from './i18n';
import { typeGuests } from './../../../helpers/customNames';
import styled from 'styled-components'
import copy from 'copy-to-clipboard';
import { getShortenedLink } from "../../../store/services/api";
import { withTranslation, I18nextProvider } from "react-i18next";
import i18n from "./i18n";
import { typeGuests } from "./../../../helpers/customNames";
import styled from "styled-components";
import copy from "copy-to-clipboard";
const ModalDialogContainer = styled.div`
.margin-text {
margin: 12px 0;
}
.margin-text {
margin: 12px 0;
}
.margin-link {
margin-right: 12px;
}
.margin-link {
margin-right: 12px;
}
.margin-textarea {
margin-top: 12px;
}
.margin-textarea {
margin-top: 12px;
}
.flex{
display: flex;
justify-content: space-between;
}
.flex {
display: flex;
justify-content: space-between;
}
`;
const textAreaName = 'link-textarea';
const textAreaName = "link-textarea";
class PureInviteDialog extends React.Component {
constructor(props) {
super(props);
this.state = {
isGuest: false,
userInvitationLink: this.props.userInvitationLink,
guestInvitationLink: this.props.guestInvitationLink,
isLoading: false,
isLinkShort: false,
visible: false
}
}
onCopyLinkToClipboard = () => {
// console.log("COPY");
const { t } = this.props;
copy(this.state.isGuest ? this.state.guestInvitationLink : this.state.userInvitationLink);
toastr.success(t('LinkCopySuccess'));
constructor(props) {
super(props);
this.state = {
isGuest: false,
userInvitationLink: this.props.userInvitationLink,
guestInvitationLink: this.props.guestInvitationLink,
isLoading: false,
isLinkShort: false,
visible: false
};
}
onCheckedGuest = () => this.setState({ isGuest: !this.state.isGuest });
onCopyLinkToClipboard = () => {
// console.log("COPY");
const { t } = this.props;
copy(
this.state.isGuest
? this.state.guestInvitationLink
: this.state.userInvitationLink
);
toastr.success(t("LinkCopySuccess"));
};
onGetShortenedLink = () => {
this.setState({ isLoading: true });
const { getShortenedLink, userInvitationLink, guestInvitationLink } = this.props;
onCheckedGuest = () => this.setState({ isGuest: !this.state.isGuest });
getShortenedLink(userInvitationLink)
.then((res) => {
// console.log("getShortInvitationLinkuser success", res.data.response);
this.setState({ userInvitationLink: res.data.response });
})
.catch(e => {
console.error("getShortInvitationLink error", e);
this.setState({ isLoading: false });
});
onGetShortenedLink = () => {
this.setState({ isLoading: true });
const {
userInvitationLink,
guestInvitationLink
} = this.props;
getShortenedLink(guestInvitationLink)
.then((res) => {
// console.log("getShortInvitationLinkGuest success", res.data.response);
this.setState({
guestInvitationLink: res.data.response,
isLoading: false,
isLinkShort: true
});
})
.catch(e => {
console.error("getShortInvitationLink error", e);
});
getShortenedLink(userInvitationLink)
.then(link => this.setState({ userInvitationLink: link }))
.catch(e => {
console.error("getShortInvitationLink error", e);
this.setState({ isLoading: false });
});
};
getShortenedLink(guestInvitationLink)
.then(link =>
this.setState({
guestInvitationLink: link,
isLoading: false,
isLinkShort: true
})
)
.catch(e => {
console.error("getShortInvitationLink error", e);
});
};
componentDidUpdate(prevProps) {
console.log('invitelink did UPDATE')
if (this.props.visible && !prevProps.visible) {
this.onCopyLinkToClipboard();
}
componentDidUpdate(prevProps) {
console.log("invitelink did UPDATE");
if (this.props.visible && !prevProps.visible) {
this.onCopyLinkToClipboard();
}
}
onClickToCloseButton = () => this.props.onCloseButton && this.props.onCloseButton();
onClose = () => this.props.onClose && this.props.onClose();
onClickToCloseButton = () =>
this.props.onCloseButton && this.props.onCloseButton();
onClose = () => this.props.onClose && this.props.onClose();
render() {
console.log("InviteDialog render");
const { t, visible, settings } = this.props;
render() {
console.log("InviteDialog render");
const { t, visible, settings } = this.props;
return (
<ModalDialogContainer>
<ModalDialog
visible={visible}
onClose={this.onClose}
headerContent={t('InviteLinkTitle')}
bodyContent={(
<>
<Text.Body
className='margin-text'
as='p'>
{t('HelpAnswerLinkInviteSettings')}
</Text.Body>
<Text.Body
className='margin-text'
as='p'>
{t('InviteLinkValidInterval', { count: 7 })}
</Text.Body>
<div className='flex'>
<div>
<Link
className='margin-link'
type='action'
isHovered={true}
onClick={this.onCopyLinkToClipboard}
>
{t('CopyToClipboard')}
</Link>
{
settings && !this.state.isLinkShort &&
<Link type='action'
isHovered={true}
onClick={this.onGetShortenedLink}
>
{t('GetShortenLink')}
</Link>
}
</div>
<Checkbox
label={t('InviteUsersAsCollaborators', { typeGuests })}
isChecked={this.state.isGuest}
onChange={this.onCheckedGuest}
isDisabled={this.state.isLoading}
/>
</div>
<Textarea
className='margin-textarea'
isReadOnly={true}
isDisabled={this.state.isLoading}
name={textAreaName}
value={this.state.isGuest ? this.state.guestInvitationLink : this.state.userInvitationLink}
/>
</>
)}
footerContent={(
<>
<Button
key="CloseBtn"
label={this.state.isLoading ? t('LoadingProcessing') : t('CloseButton')}
size="medium"
primary={true}
onClick={this.onClickToCloseButton}
isLoading={this.state.isLoading}
/>
</>
)}
return (
<ModalDialogContainer>
<ModalDialog
visible={visible}
onClose={this.onClose}
headerContent={t("InviteLinkTitle")}
bodyContent={
<>
<Text.Body className="margin-text" as="p">
{t("HelpAnswerLinkInviteSettings")}
</Text.Body>
<Text.Body className="margin-text" as="p">
{t("InviteLinkValidInterval", { count: 7 })}
</Text.Body>
<div className="flex">
<div>
<Link
className="margin-link"
type="action"
isHovered={true}
onClick={this.onCopyLinkToClipboard}
>
{t("CopyToClipboard")}
</Link>
{settings && !this.state.isLinkShort && (
<Link
type="action"
isHovered={true}
onClick={this.onGetShortenedLink}
>
{t("GetShortenLink")}
</Link>
)}
</div>
<Checkbox
label={t("InviteUsersAsCollaborators", { typeGuests })}
isChecked={this.state.isGuest}
onChange={this.onCheckedGuest}
isDisabled={this.state.isLoading}
/>
</ModalDialogContainer>
);
};
};
const mapStateToProps = (state) => {
return {
settings: state.auth.settings.hasShortenService,
userInvitationLink: state.auth.settings.inviteLinks.userLink,
guestInvitationLink: state.auth.settings.inviteLinks.guestLink
}
</div>
<Textarea
className="margin-textarea"
isReadOnly={true}
isDisabled={this.state.isLoading}
name={textAreaName}
value={
this.state.isGuest
? this.state.guestInvitationLink
: this.state.userInvitationLink
}
/>
</>
}
footerContent={
<>
<Button
key="CloseBtn"
label={
this.state.isLoading
? t("LoadingProcessing")
: t("CloseButton")
}
size="medium"
primary={true}
onClick={this.onClickToCloseButton}
isLoading={this.state.isLoading}
/>
</>
}
/>
</ModalDialogContainer>
);
}
}
const mapStateToProps = state => {
return {
settings: state.auth.settings.hasShortenService,
userInvitationLink: state.auth.settings.inviteLinks.userLink,
guestInvitationLink: state.auth.settings.inviteLinks.guestLink
};
};
const InviteDialogContainer = withTranslation()(PureInviteDialog);
const InviteDialog = (props) => <I18nextProvider i18n={i18n}><InviteDialogContainer {...props} /></I18nextProvider>;
const InviteDialog = props => (
<I18nextProvider i18n={i18n}>
<InviteDialogContainer {...props} />
</I18nextProvider>
);
InviteDialog.propTypes = {
visible: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
onCloseButton: PropTypes.func.isRequired
visible: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired,
onCloseButton: PropTypes.func.isRequired
};
export default connect(mapStateToProps, { getInvitationLink, getShortenedLink })(withRouter(InviteDialog));
export default connect(mapStateToProps)(withRouter(InviteDialog));

View File

@ -246,7 +246,7 @@ class SectionBodyContent extends React.Component {
toastr.success(`Group '${group.name}' has been saved successfully`);
})
.catch(error => {
toastr.error(error.message);
toastr.error(error);
this.setState({ inLoading: false });
});
};

View File

@ -100,7 +100,7 @@ class SectionBodyContent extends React.PureComponent {
</Text.Body>
)
)
.catch(e => toastr.error("ERROR"))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
this.onDialogClose();
}}
@ -172,7 +172,7 @@ class SectionBodyContent extends React.PureComponent {
onLoading(true);
updateUserStatus(EmployeeStatus.Disabled, [user.id])
.then(() => toastr.success("SUCCESS Context action: Disable"))
.catch(e => toastr.error("FAILED Context action: Disable", e))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
};
@ -182,7 +182,7 @@ class SectionBodyContent extends React.PureComponent {
onLoading(true);
updateUserStatus(EmployeeStatus.Active, [user.id])
.then(() => toastr.success("SUCCESS Context action: Enable"))
.catch(e => toastr.error("FAILED Context action: Enable", e))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
};
@ -230,7 +230,7 @@ class SectionBodyContent extends React.PureComponent {
toastr.success("User has been removed successfully");
return fetchPeople(filter);
})
.catch(e => toastr.error("ERROR"))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
this.onDialogClose();
}}
@ -290,7 +290,7 @@ class SectionBodyContent extends React.PureComponent {
</Text.Body>
)
)
.catch(e => toastr.error("ERROR"))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
this.onDialogClose();
}}
@ -320,7 +320,7 @@ class SectionBodyContent extends React.PureComponent {
</Text.Body>
)
)
.catch(e => toastr.error("ERROR"))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
};
getUserContextOptions = (user, viewer) => {

View File

@ -97,7 +97,7 @@ const SectionHeaderContent = props => {
const onSentInviteAgain = useCallback(() => {
resendUserInvites(selectedUserIds)
.then(() => toastr.success("The invitation was successfully sent"))
.catch(e => toastr.error("ERROR"));
.catch(error => toastr.error(error));
}, [selectedUserIds]);
const onDelete = useCallback(() => {
@ -107,7 +107,7 @@ const SectionHeaderContent = props => {
toastr.success("Users have been removed successfully");
return fetchPeople(filter);
})
.catch(e => toastr.error("ERROR"))
.catch(error => toastr.error(error))
.finally(() => onLoading(false));
}, [selectedUserIds, onLoading, filter]);

View File

@ -200,16 +200,16 @@ class ProfileInfo extends React.PureComponent {
onSendEmailChangeInstructions = () => {
sendInstructionsToChangeEmail(this.state.profile.id, this.state.dialog.value)
.then((res) => {
res.data.error ? toastr.error(res.data.error.message) : toastr.success(res.data.response)
toastr.success(res);
})
.catch((error) => toastr.error(error.message))
.catch((error) => toastr.error(error))
.finally(this.onDialogClose);
}
onSentInviteAgain = id => {
resendUserInvites(new Array(id))
.then(() => toastr.success("The invitation was successfully sent"))
.catch(e => toastr.error("ERROR"));
.catch(error => toastr.error(error));
};

View File

@ -74,7 +74,7 @@ const SectionHeaderContent = props => {
const onInviteAgainClick = () => {
resendUserInvites(selectedUserIds)
.then(() => toastr.success("The invitation was successfully sent"))
.catch(e => toastr.error("ERROR"));
.catch(error => toastr.error(error));
};
const getUserContextOptions = (user, viewer, t) => {

View File

@ -4,7 +4,7 @@ import { connect } from 'react-redux'
import { Avatar, Button, Textarea, toastr, AvatarEditor } from 'asc-web-components'
import { withTranslation } from 'react-i18next';
import { toEmployeeWrapper, getUserRole, getUserContactsPattern, getUserContacts, mapGroupsToGroupSelectorOptions, mapGroupSelectorOptionsToGroups, filterGroupSelectorOptions } from "../../../../../store/people/selectors";
import { createProfile, loadAvatar, createThumbnailsAvatar } from '../../../../../store/profile/actions';
import { createProfile } from '../../../../../store/profile/actions';
import { MainContainer, AvatarContainer, MainFieldsContainer } from './FormFields/Form'
import TextField from './FormFields/TextField'
import PasswordField from './FormFields/PasswordField'
@ -14,6 +14,7 @@ import DepartmentField from './FormFields/DepartmentField'
import ContactsField from './FormFields/ContactsField'
import InfoFieldContainer from './FormFields/InfoFieldContainer'
import { departments, department, position, employedSinceDate } from '../../../../../helpers/customNames';
import { createThumbnailsAvatar, loadAvatar } from "../../../../../store/services/api";
class CreateUserForm extends React.Component {
@ -48,22 +49,18 @@ class CreateUserForm extends React.Component {
}
createAvatar(userId,userName){
this.props.createThumbnailsAvatar(userId, {
createThumbnailsAvatar(userId, {
x: this.state.avatar.x,
y: this.state.avatar.y,
width: this.state.avatar.width,
height: this.state.avatar.height,
tmpFile: this.state.avatar.tmpFile
})
.then((result) => {
if(result.status === 200){
.then(() => {
toastr.success("Success");
this.props.history.push(`${this.props.settings.homepage}/view/${userName}`);
}
})
.catch((error) => {
toastr.error(error.message);
});
.catch((error) => toastr.error(error));
}
openAvatarEditor(){
let avatarDefault = this.state.profile.avatarDefault ? "data:image/png;base64," + this.state.profile.avatarDefault : null;
@ -89,24 +86,23 @@ class CreateUserForm extends React.Component {
let _this = this;
data.append("file", file);
data.append("Autosave", false);
this.props.loadAvatar(0, data)
.then((result) => {
loadAvatar(0, data)
.then((response) => {
var img = new Image();
img.onload = function () {
var stateCopy = Object.assign({}, _this.state);
stateCopy.avatar = {
tmpFile: result.data.response.data,
image: result.data.response.data,
tmpFile: response.data,
image: response.data,
defaultWidth: img.width,
defaultHeight: img.height
}
_this.setState(stateCopy);
};
img.src = result.data.response.data;
img.src = response.data;
})
.catch((error) => {
toastr.error(error.message);
});
.catch((error) => toastr.error(error));
}
onSaveAvatar(isUpdate, result, file){
var stateCopy = Object.assign({}, this.state);
@ -223,7 +219,7 @@ class CreateUserForm extends React.Component {
}
})
.catch((error) => {
toastr.error(error.message)
toastr.error(error);
this.setState({ isLoading: false })
});
}
@ -475,7 +471,6 @@ class CreateUserForm extends React.Component {
);
};
}
const mapStateToProps = (state) => {
return {
settings: state.auth.settings,
@ -486,8 +481,6 @@ const mapStateToProps = (state) => {
export default connect(
mapStateToProps,
{
createProfile,
loadAvatar,
createThumbnailsAvatar
createProfile
}
)(withRouter(withTranslation()(CreateUserForm)));

View File

@ -4,7 +4,7 @@ import { connect } from 'react-redux'
import { Avatar, Button, Textarea, Text, toastr, ModalDialog, TextInput, AvatarEditor } from 'asc-web-components'
import { withTranslation } from 'react-i18next';
import { toEmployeeWrapper, getUserRole, getUserContactsPattern, getUserContacts, mapGroupsToGroupSelectorOptions, mapGroupSelectorOptionsToGroups, filterGroupSelectorOptions } from "../../../../../store/people/selectors";
import { updateProfile, loadAvatar, createThumbnailsAvatar, deleteAvatar } from '../../../../../store/profile/actions';
import { updateProfile } from '../../../../../store/profile/actions';
import { sendInstructionsToChangePassword, sendInstructionsToChangeEmail } from "../../../../../store/services/api";
import { MainContainer, AvatarContainer, MainFieldsContainer } from './FormFields/Form'
import TextField from './FormFields/TextField'
@ -15,6 +15,7 @@ import DepartmentField from './FormFields/DepartmentField'
import ContactsField from './FormFields/ContactsField'
import InfoFieldContainer from './FormFields/InfoFieldContainer'
import { departments, department, position, employedSinceDate, typeGuest, typeUser } from '../../../../../helpers/customNames';
import { createThumbnailsAvatar, loadAvatar, deleteAvatar } from "../../../../../store/services/api";
class UpdateUserForm extends React.Component {
@ -153,8 +154,8 @@ class UpdateUserForm extends React.Component {
this.props.history.push(`${this.props.settings.homepage}/view/${profile.userName}`);
})
.catch((error) => {
toastr.error(error.message)
this.setState({isLoading: false})
toastr.error(error);
this.setState({isLoading: false});
});
}
@ -201,9 +202,9 @@ class UpdateUserForm extends React.Component {
onSendEmailChangeInstructions() {
sendInstructionsToChangeEmail(this.state.profile.id, this.state.dialog.newEmail)
.then((res) => {
res.data.error ? toastr.error(res.data.error.message) : toastr.success(res.data.response)
toastr.success(res);
})
.catch((error) => toastr.error(error.message))
.catch((error) => toastr.error(error))
.finally(this.onDialogClose);
}
@ -232,9 +233,9 @@ class UpdateUserForm extends React.Component {
onSendPasswordChangeInstructions() {
sendInstructionsToChangePassword(this.state.profile.email)
.then((res) => {
res.data.error ? toastr.error(res.data.error.message) : toastr.success(res.data.response)
toastr.success(res);
})
.catch((error) => toastr.error(error.message))
.catch((error) => toastr.error(error))
.finally(this.onDialogClose);
}
@ -324,61 +325,51 @@ class UpdateUserForm extends React.Component {
let _this = this;
data.append("file", file);
data.append("Autosave", false);
this.props.loadAvatar(this.state.profile.id, data)
.then((result) => {
loadAvatar(this.state.profile.id, data)
.then((response) => {
var img = new Image();
img.onload = function () {
var stateCopy = Object.assign({}, _this.state);
stateCopy.avatar = {
tmpFile: result.data.response.data,
image: result.data.response.data,
tmpFile: response.data,
image: response.data,
defaultWidth: img.width,
defaultHeight: img.height
}
_this.setState(stateCopy);
};
img.src = result.data.response.data;
img.src = response.data;
})
.catch((error) => {
toastr.error(error.message);
});
.catch((error) => toastr.error(error));
}
onSaveAvatar(isUpdate, result) {
if(isUpdate){
this.props.createThumbnailsAvatar(this.state.profile.id, {
createThumbnailsAvatar(this.state.profile.id, {
x: Math.round(result.x*this.state.avatar.defaultWidth - result.width/2),
y: Math.round(result.y*this.state.avatar.defaultHeight - result.height/2),
width: result.width,
height: result.height,
tmpFile: this.state.avatar.tmpFile
})
.then((result) => {
if(result.status === 200){
.then((response) => {
let stateCopy = Object.assign({}, this.state);
stateCopy.visibleAvatarEditor = false;
stateCopy.avatar.tmpFile = '';
stateCopy.profile.avatarMax = result.data.response.max + '?_='+Math.floor(Math.random() * Math.floor(10000));
stateCopy.profile.avatarMax = response.max + '?_='+Math.floor(Math.random() * Math.floor(10000));
toastr.success("Success");
this.setState(stateCopy);
}
})
.catch((error) => {
toastr.error(error.message);
});
.catch((error) => toastr.error(error));
}else{
this.props.deleteAvatar(this.state.profile.id)
.then((result) => {
if(result.status === 200){
deleteAvatar(this.state.profile.id)
.then((response) => {
let stateCopy = Object.assign({}, this.state);
stateCopy.visibleAvatarEditor = false;
stateCopy.profile.avatarMax = result.data.response.big;
stateCopy.profile.avatarMax = response.big;
toastr.success("Success");
this.setState(stateCopy);
}
})
.catch((error) => {
toastr.error(error.message);
});
.catch((error) => toastr.error(error));
}
}
onCloseAvatarEditor() {
@ -626,9 +617,6 @@ const mapStateToProps = (state) => {
export default connect(
mapStateToProps,
{
updateProfile,
loadAvatar,
deleteAvatar,
createThumbnailsAvatar
updateProfile
}
)(withRouter(withTranslation()(UpdateUserForm)));

View File

@ -1,6 +0,0 @@
export function checkResponseError(res) {
if (res && res.data && res.data.error) {
console.error(res.data.error);
throw new Error(res.data.error.message);
}
}

View File

@ -1,9 +1,8 @@
import * as api from "../services/api";
import { fetchGroups, fetchPeople } from "../people/actions";
import setAuthorizationToken from "../../store/services/setAuthorizationToken";
import { setAuthorizationToken } from "../../store/services/client";
import { getFilterByLocation } from "../../helpers/converters";
import config from "../../../package.json";
import { checkResponseError } from "../../helpers/utils";
export const LOGIN_POST = "LOGIN_POST";
export const SET_CURRENT_USER = "SET_CURRENT_USER";
@ -50,8 +49,8 @@ export async function getUserInfo(dispatch) {
const { user, modules, settings } = await api.getInitInfo();
let newSettings = settings;
if (user.isAdmin) {
const inviteLinkResp = await api.getInvitationLinks();
newSettings = Object.assign(newSettings, inviteLinkResp);
const inviteLinks = await api.getInvitationLinks();
newSettings = Object.assign(newSettings, inviteLinks);
}
dispatch(setCurrentUser(user));
@ -72,20 +71,6 @@ export async function getUserInfo(dispatch) {
return dispatch(setIsLoaded(true));
}
export function login(data) {
return dispatch => {
return api
.login(data)
.then(res => {
checkResponseError(res);
const token = res.data.response.token;
setAuthorizationToken(token);
})
.then(() => getUserInfo(dispatch))
.catch((e) => console.error(e));
};
}
export function logout() {
return dispatch => {
setAuthorizationToken();

View File

@ -1,6 +1,5 @@
import * as api from "../../store/services/api";
import { setGroups, fetchPeople, fetchGroups } from "../people/actions";
import { checkResponseError } from "../../helpers/utils";
import { setGroups, fetchPeople } from "../people/actions";
import history from "../../history";
export const SET_GROUP = "SET_GROUP";
@ -21,10 +20,8 @@ export function resetGroup() {
export function fetchGroup(groupId) {
return dispatch => {
api.getGroup(groupId).then(res => {
checkResponseError(res);
dispatch(setGroup(res.data.response || null));
});
api.getGroup(groupId)
.then(group => dispatch(setGroup(group || null)));
};
}
@ -35,10 +32,8 @@ export function createGroup(groupName, groupManager, members) {
return api
.createGroup(groupName, groupManager, members)
.then(res => {
checkResponseError(res);
.then(newGroup => {
history.goBack();
const newGroup = res.data.response;
dispatch(resetGroup());
dispatch(setGroups([...groups, newGroup]));
return Promise.resolve(newGroup);
@ -53,10 +48,8 @@ export function updateGroup(id, groupName, groupManager, members) {
return api
.updateGroup(id, groupName, groupManager, members)
.then(res => {
checkResponseError(res);
.then(newGroup => {
history.goBack();
const newGroup = res.data.response;
dispatch(resetGroup());
const newGroups = groups.map(g =>
g.id === newGroup.id ? newGroup : g
@ -75,7 +68,6 @@ export function deleteGroup(id) {
return api
.deleteGroup(id)
.then(res => {
checkResponseError(res);
return dispatch(setGroups(groups.filter(g => g.id !== id)));
})
.then(() => {

View File

@ -14,7 +14,6 @@ import {
PAGE_COUNT,
EmployeeStatus
} from "../../helpers/constants";
import { checkResponseError } from "../../helpers/utils";
export const SET_GROUPS = "SET_GROUPS";
export const SET_USERS = "SET_USERS";
@ -116,7 +115,7 @@ export function setFilterUrl(filter) {
params.push(`${PAGE_COUNT}=${filter.pageCount}`);
}
params.push(`${PAGE}=${filter.page+1}`);
params.push(`${PAGE}=${filter.page + 1}`);
params.push(`${SORT_BY}=${filter.sortBy}`);
params.push(`${SORT_ORDER}=${filter.sortOrder}`);
@ -142,84 +141,57 @@ export function setSelectorUsers(users) {
export function fetchSelectorUsers() {
return dispatch => {
api
.getSelectorUserList()
.then(res => dispatch(setSelectorUsers(res.data.response)));
api.getSelectorUserList().then(data => {
const users = data.items;
return dispatch(setSelectorUsers(users));
});
};
}
export function fetchGroups(dispatchFunc = null) {
return api.getGroupList()
.then(res => {
checkResponseError(res);
return dispatchFunc
? dispatchFunc(setGroups(res.data.response))
: Promise.resolve(dispatch => dispatch(setGroups(res.data.response)));
return api.getGroupList().then(groups => {
return dispatchFunc
? dispatchFunc(setGroups(groups))
: Promise.resolve(dispatch => dispatch(setGroups(groups)));
});
}
export function fetchPeople(filter, dispatchFunc = null) {
return dispatchFunc ? fetchPeopleByFilter(dispatchFunc, filter)
: (dispatch, getState) => {
if(filter) {
return fetchPeopleByFilter(dispatch, filter);
}
else {
const {people} = getState();
const {filter} = people;
return fetchPeopleByFilter(dispatch, filter);
}
};
return dispatchFunc
? fetchPeopleByFilter(dispatchFunc, filter)
: (dispatch, getState) => {
if (filter) {
return fetchPeopleByFilter(dispatch, filter);
} else {
const { people } = getState();
const { filter } = people;
return fetchPeopleByFilter(dispatch, filter);
}
};
}
function fetchPeopleByFilter(dispatch, filter) {
let filterData = (filter && filter.clone());
let filterData = filter && filter.clone();
if(!filterData) {
if (!filterData) {
filterData = Filter.getDefault();
filterData.employeeStatus = EmployeeStatus.Active;
}
return api.getUserList(filterData).then(res => {
filterData.total = res.data.total;
return api.getUserList(filterData).then(data => {
filterData.total = data.total;
dispatch(setFilter(filterData));
dispatch({
type: SELECT_GROUP,
groupId: filterData.group
});
return dispatch(setUsers(res.data.response));
return dispatch(setUsers(data.items));
});
}
/*export async function fetchPeopleAsync(dispatch, filter = null) {
let filterData = (filter && filter.clone());
if(!filterData) {
filterData = Filter.getDefault();
filterData.employeeStatus = EmployeeStatus.Active;
}
const usersResp = await api.getUserList(filterData);
filterData.total = usersResp.data.total;
dispatch(setFilter(filterData));
dispatch({
type: SELECT_GROUP,
groupId: filterData.group
});
dispatch(setUsers(usersResp.data.response));
}*/
export function updateUserStatus(status, userIds) {
return dispatch => {
return api.updateUserStatus(status, userIds).then(res => {
if (res && res.data && res.data.error && res.data.error.message)
throw res.data.error.message;
const users = res.data.response;
return api.updateUserStatus(status, userIds).then(users => {
users.forEach(user => {
dispatch(setUser(user));
});
@ -229,12 +201,7 @@ export function updateUserStatus(status, userIds) {
export function updateUserType(type, userIds) {
return dispatch => {
return api.updateUserType(type, userIds).then(res => {
if (res && res.data && res.data.error && res.data.error.message)
throw res.data.error.message;
const users = res.data.response;
return api.updateUserType(type, userIds).then(users => {
users.forEach(user => {
dispatch(setUser(user));
});

View File

@ -3,7 +3,6 @@ import { isMe } from '../auth/selectors';
import { getUserByUserName } from '../people/selectors';
import { fetchPeople } from "../people/actions";
import { setCurrentUser } from "../auth/actions";
import { checkResponseError } from "../../helpers/utils";
export const SET_PROFILE = 'SET_PROFILE';
export const CLEAN_PROFILE = 'CLEAN_PROFILE';
@ -21,15 +20,13 @@ export function resetProfile() {
};
};
export function employeeWrapperToMemberModel(profile) {
const comment = profile.notes;
const department = profile.groups ? profile.groups.map(group => group.id) : [];
const worksFrom = profile.workFrom;
return { ...profile, comment, department, worksFrom };
}
};
export function fetchProfile(userName) {
return (dispatch, getState) => {
@ -40,16 +37,15 @@ export function fetchProfile(userName) {
} else {
const user = getUserByUserName(people.users, userName);
if (!user) {
api.getUser(userName).then(res => {
checkResponseError(res);
dispatch(setProfile(res.data.response));
api.getUser(userName).then(user => {
dispatch(setProfile(user));
});
} else {
dispatch(setProfile(user));
}
}
};
}
};
export function createProfile(profile) {
return (dispatch, getState) => {
@ -58,10 +54,9 @@ export function createProfile(profile) {
const member = employeeWrapperToMemberModel(profile);
let result;
return api.createUser(member).then(res => {
checkResponseError(res);
result = res.data.response;
return dispatch(setProfile(result));
return api.createUser(member).then(user => {
result = user;
return dispatch(setProfile(user));
}).then(() => {
return fetchPeople(filter, dispatch);
}).then(() => {
@ -77,10 +72,9 @@ export function updateProfile(profile) {
const member = employeeWrapperToMemberModel(profile);
let result;
return api.updateUser(member).then(res => {
checkResponseError(res);
result = res.data.response;
return Promise.resolve(dispatch(setProfile(result)));
return api.updateUser(member).then(user => {
result = user;
return Promise.resolve(dispatch(setProfile(user)));
}).then(() => {
return fetchPeople(filter, dispatch);
}).then(() => {
@ -91,63 +85,15 @@ export function updateProfile(profile) {
export function updateProfileCulture(id, culture) {
return (dispatch) => {
return api.updateUserCulture(id, culture).then(res => {
checkResponseError(res);
const result = res.data.response;
dispatch(setCurrentUser(result));
return dispatch(setProfile(result));
return api.updateUserCulture(id, culture).then(user => {
dispatch(setCurrentUser(user));
return dispatch(setProfile(user));
});
};
};
export function loadAvatar(profileId, data) {
return (dispatch, getState) => {
return api.loadAvatar(
profileId,
data
).then(res => {
checkResponseError(res);
return Promise.resolve(res);
});
};
};
export function createThumbnailsAvatar(profileId, data) {
return (dispatch, getState) => {
return api.createThumbnailsAvatar(
profileId,
data
).then(res => {
checkResponseError(res);
return Promise.resolve(res);
});
};
};
export function deleteAvatar(profileId) {
return (dispatch, getState) => {
return api.deleteAvatar(profileId)
.then(res => {
checkResponseError(res);
return Promise.resolve(res);
});
};
};
export function getInvitationLink(isGuest = false) {
return dispatch => {
return api.getInvitationLink(isGuest)
.then(res => {
checkResponseError(res);
return Promise.resolve(res);
});
return api.getInvitationLink(isGuest);
}
}
export function getShortenedLink(link) {
return dispatch => {
return api.getShortenedLink(link)
.then(res => {
checkResponseError(res);
return Promise.resolve(res);
});
}
}
};

View File

@ -1,62 +1,56 @@
import { request } from "./client";
import axios from "axios";
import * as fakeApi from "./fakeApi";
import Filter from "../people/filter";
import { checkResponseError } from "../../helpers/utils";
const PREFIX = "api";
const VERSION = "2.0";
const API_URL = `${window.location.origin}/${PREFIX}/${VERSION}`;
const IS_FAKE = false;
const linkTtl = 6 * 3600 * 1000;
export function login(data) {
return axios.post(`${API_URL}/authentication`, data);
}
export function getModulesList() {
return IS_FAKE
? fakeApi.getModulesList()
: axios
.get(`${API_URL}/modules`)
.then(res => {
checkResponseError(res);
const modules = res.data.response;
return axios.all(
modules.map(m => axios.get(`${window.location.origin}/${m}`))
);
})
.then(res => {
checkResponseError(res);
const response = res.map(d => d.data.response);
return Promise.resolve({ data: { response } });
});
return request({
method: "get",
url: "/modules"
}).then(modules => {
return axios.all(
modules.map(m =>
request({
method: "get",
url: `${window.location.origin}/${m}`
})
)
);
});
}
export function getSettings() {
return IS_FAKE
? fakeApi.getSettings()
: axios.get(`${API_URL}/settings.json`);
return request({
method: "get",
url: "/settings.json"
});
}
export function getPortalCultures() {
return axios.get(`${API_URL}/settings/cultures.json`);
return request({
method: "get",
url: "/settings/cultures.json"
});
}
export function getPortalPasswordSettings() {
return IS_FAKE
? fakeApi.getPortalPasswordSettings()
: axios.get(`${API_URL}/settings/security/password`);
return request({
method: "get",
url: "/settings/security/password"
});
}
export function getUser(userId) {
return IS_FAKE
? fakeApi.getUser()
: axios.get(`${API_URL}/people/${userId || "@self"}.json`);
return request({
method: "get",
url: "/people/@self.json"
});
}
export function getSelectorUserList() {
return axios.get(`${API_URL}/people/filter.json?fields=id,displayName,groups`);
return request({
method: "get",
url: "/people/filter.json?fields=id,displayName,groups"
});
}
export function getUserList(filter = Filter.getDefault()) {
@ -64,196 +58,238 @@ export function getUserList(filter = Filter.getDefault()) {
filter && filter instanceof Filter
? `/filter.json?${filter.toUrlParams()}`
: "";
return IS_FAKE ? fakeApi.getUsers() : axios.get(`${API_URL}/people${params}`);
return request({
method: "get",
url: `/people${params}`
});
}
export function getGroupList() {
return IS_FAKE ? fakeApi.getGroups() : axios.get(`${API_URL}/group`);
return request({
method: "get",
url: "/group"
});
}
export function createUser(data) {
return IS_FAKE ? fakeApi.createUser() : axios.post(`${API_URL}/people`, data);
return request({
method: "post",
url: "/people",
data
});
}
export function updateUser(data) {
return IS_FAKE
? fakeApi.updateUser()
: axios.put(`${API_URL}/people/${data.id}`, data);
return request({
method: "put",
url: `/people/${data.id}`,
data
});
}
export function updateUserCulture(id, cultureName) {
return axios.put(`${API_URL}/people/${id}/culture`, { cultureName });
return request({
method: "put",
url: `/people/${id}/culture`,
data: { cultureName }
});
}
export function loadAvatar(profileId, data) {
return IS_FAKE
? fakeApi.loadAvatar()
: axios.post(`${API_URL}/people/${profileId}/photo`, data);
return request({
method: "post",
url: `/people/${profileId}/photo`,
data
});
}
export function createThumbnailsAvatar(profileId, data) {
return IS_FAKE
? fakeApi.createThumbnailsAvatar()
: axios.post(`${API_URL}/people/${profileId}/photo/thumbnails.json`, data);
return request({
method: "post",
url: `/people/${profileId}/photo/thumbnails.json`,
data
});
}
export function deleteAvatar(profileId) {
return IS_FAKE
? fakeApi.deleteAvatar()
: axios.delete(`${API_URL}/people/${profileId}/photo`, profileId);
return request({
method: "delete",
url: `/people/${profileId}/photo`
});
}
export function getInitInfo() {
return axios.all([getUser(), getModulesList(), getSettings(), getPortalPasswordSettings(), getPortalCultures()]).then(
axios.spread(function (userResp, modulesResp, settingsResp, passwordSettingsResp, culturesResp) {
let info = {
user: userResp.data.response,
modules: modulesResp.data.response,
settings: settingsResp.data.response
};
return axios
.all([
getUser(),
getModulesList(),
getSettings(),
getPortalPasswordSettings(),
getPortalCultures()
])
.then(
axios.spread((user, modules, settings, passwordSettings, cultures) => {
const info = {
user,
modules,
settings
};
info.settings.passwordSettings = passwordSettingsResp.data.response;
info.settings.cultures = culturesResp.data.response || [];
info.settings.passwordSettings = passwordSettings;
info.settings.cultures = cultures || [];
return Promise.resolve(info);
})
);
return Promise.resolve(info);
})
);
}
export function getInvitationLinks() {
const isGuest = true;
return axios.all([getInvitationLink(), getInvitationLink(isGuest)]).then(
axios.spread(function (userInvitationLinkResp, guestInvitationLinkResp) {
let links = {
inviteLinks: {}
axios.spread((userInvitationLinkResp, guestInvitationLinkResp) => {
const links = {
inviteLinks: {
userLink: userInvitationLinkResp,
guestLink: guestInvitationLinkResp
}
};
links.inviteLinks = {
userLink: userInvitationLinkResp,
guestLink: guestInvitationLinkResp
}
return Promise.resolve(links);
})
);
}
export function updateUserStatus(status, userIds) {
return IS_FAKE
? fakeApi.updateUserStatus(status, userIds)
: axios.put(`${API_URL}/people/status/${status}`, { userIds });
return request({
method: "put",
url: `/people/status/${status}`,
data: { userIds }
});
}
export function updateUserType(type, userIds) {
return IS_FAKE
? fakeApi.updateUserType(type, userIds)
: axios.put(`${API_URL}/people/type/${type}`, { userIds });
return request({
method: "put",
url: `/people/type/${type}`,
data: { userIds }
});
}
export function resendUserInvites(userIds) {
return IS_FAKE
? fakeApi.resendUserInvites(userIds)
: axios.put(`${API_URL}/people/invite`, { userIds });
return request({
method: "put",
url: "/people/invite",
data: { userIds }
});
}
export function sendInstructionsToDelete() {
return IS_FAKE
? fakeApi.sendInstructionsToDelete()
: axios.put(`${API_URL}/people/self/delete.json`);
return request({
method: "put",
url: "/people/self/delete.json"
});
}
export function sendInstructionsToChangePassword(email) {
return IS_FAKE
? fakeApi.sendInstructionsToChangePassword()
: axios.post(`${API_URL}/people/password.json`, { email });
return request({
method: "post",
url: "/people/password.json",
data: { email }
});
}
export function sendInstructionsToChangeEmail(userId, email) {
return IS_FAKE
? fakeApi.sendInstructionsToChangeEmail()
: axios.post(`${API_URL}/people/email.json`, { userId, email });
return request({
method: "post",
url: "/people/email.json",
data: { userId, email }
});
}
export function deleteUser(userId) {
return IS_FAKE
? fakeApi.deleteUser(userId)
: axios.delete(`${API_URL}/people/${userId}.json`);
return request({
method: "delete",
url: `/people/${userId}.json`
});
}
export function deleteUsers(userIds) {
return IS_FAKE
? fakeApi.deleteUsers(userIds)
: axios
.put(`${API_URL}/people/delete.json`, { userIds })
.then(CheckError);
return request({
method: "put",
url: "/people/delete.json",
data: { userIds }
});
}
export function getGroup(groupId) {
return IS_FAKE
? fakeApi.getGroup(groupId)
: axios.get(`${API_URL}/group/${groupId}.json`);
return request({
method: "get",
url: `/group/${groupId}.json`
});
}
const GUEST_INVITE_LINK = "guestInvitationLink";
const USER_INVITE_LINK = "userInvitationLink";
const INVITE_LINK_TTL = "localStorageLinkTtl";
const LINKS_TTL = 6 * 3600 * 1000;
export function getInvitationLink(isGuest) {
let localStorageLinkTtl = localStorage.getItem('localStorageLinkTtl');
const curLinksTtl = localStorage.getItem(INVITE_LINK_TTL);
const now = +new Date();
if (localStorageLinkTtl === null) {
localStorage.setItem('localStorageLinkTtl', +new Date());
}
else if (+new Date() - localStorageLinkTtl > linkTtl) {
localStorage.clear();
localStorage.setItem('localStorageLinkTtl', +new Date());
if (!curLinksTtl) {
localStorage.setItem(INVITE_LINK_TTL, now);
} else if (now - curLinksTtl > LINKS_TTL) {
localStorage.removeItem(GUEST_INVITE_LINK);
localStorage.removeItem(USER_INVITE_LINK);
localStorage.setItem(INVITE_LINK_TTL, now);
}
if (IS_FAKE) {
return fakeApi.getInvitationLink(isGuest);
}
else
if (isGuest) {
const guestInvitationLink = localStorage.getItem('guestInvitationLink');
return guestInvitationLink
? guestInvitationLink
: axios.get(`${API_URL}/portal/users/invite/2.json`)
.then(res => {
localStorage.setItem('guestInvitationLink', res.data.response);
return Promise.resolve(res.data.response);
})
}
else {
const userInvitationLink = localStorage.getItem('userInvitationLink');
return userInvitationLink
? userInvitationLink
: axios.get(`${API_URL}/portal/users/invite/1.json`)
.then(res => {
localStorage.setItem('userInvitationLink', res.data.response);
return Promise.resolve(res.data.response);
})
}
const link = localStorage.getItem(
isGuest ? GUEST_INVITE_LINK : USER_INVITE_LINK
);
return link
? Promise.resolve(link)
: request({
method: "get",
url: `/portal/users/invite/${isGuest ? 2 : 1}.json`
}).then(link => {
localStorage.setItem(
isGuest ? GUEST_INVITE_LINK : USER_INVITE_LINK,
link
);
return Promise.resolve(link);
});
}
export function getShortenedLink(link) {
return IS_FAKE
? fakeApi.getShortenedLink(link)
: axios.put(`${API_URL}/portal/getshortenlink.json`, link);
}
function CheckError(res) {
if (res.data && res.data.error) {
const error = res.data.error.message || "Unknown error has happened";
console.trace(error);
throw error;
}
return Promise.resolve(res);
return request({
method: "put",
url: "/portal/getshortenlink.json",
data: link
});
}
export function createGroup(groupName, groupManager, members) {
const group = { groupName, groupManager, members };
return axios.post(`${API_URL}/group.json`, group);
const data = { groupName, groupManager, members };
return request({
method: "post",
url: "/group.json",
data
});
}
export function updateGroup(id, groupName, groupManager, members) {
const group = { groupId: id, groupName, groupManager, members };
return axios.put(`${API_URL}/group/${id}.json`, group);
const data = { groupId: id, groupName, groupManager, members };
return request({
method: "put",
url: `/group/${id}.json`,
data
});
}
export function deleteGroup(id) {
return axios.delete(`${API_URL}/group/${id}.json`);
return request({
method: "delete",
url: `/group/${id}.json`
});
}

View File

@ -0,0 +1,99 @@
import axios from "axios";
import Cookies from "universal-cookie";
import history from "../../history";
import { AUTH_KEY } from "../../helpers/constants.js";
const PREFIX = "api";
const VERSION = "2.0";
const baseURL = `${window.location.origin}/${PREFIX}/${VERSION}`;
/**
* @description axios instance for ajax requests
*/
const client = axios.create({
baseURL: baseURL,
responseType: "json",
timeout: 30000 // default is `0` (no timeout)
});
setAuthorizationToken(localStorage.getItem(AUTH_KEY));
client.interceptors.response.use(
response => {
return response;
},
error => {
if (error.response.status === 401) {
//place your reentry code
history.push("/login/error=unauthorized");
}
if (error.response.status === 502) {
//toastr.error(error.response);
history.push(`/error/${error.response.status}`);
}
return error;
}
);
export function setAuthorizationToken(token) {
const cookies = new Cookies();
if (token) {
client.defaults.headers.common["Authorization"] = token;
localStorage.setItem(AUTH_KEY, token);
const current = new Date();
const nextYear = new Date();
nextYear.setFullYear(current.getFullYear() + 1);
cookies.set(AUTH_KEY, token, {
path: "/",
expires: nextYear
});
} else {
localStorage.clear();
delete client.defaults.headers.common["Authorization"];
cookies.remove(AUTH_KEY, {
path: "/"
});
}
}
const checkResponseError = res => {
if (res && res.data && res.data.error) {
console.error(res.data.error);
throw new Error(res.data.error.message);
}
};
/**
* @description wrapper for making ajax requests
* @param {object} object with method,url,data etc.
*/
export const request = function(options) {
const onSuccess = function(response) {
checkResponseError(response);
return response.data && response.data.hasOwnProperty("total")
? { total: +response.data.total, items: response.data.response }
: response.data.response;
};
const onError = function(error) {
console.error("Request Failed:", error.config);
if (error.response) {
console.error("Status:", error.response.status);
console.error("Data:", error.response.data);
console.error("Headers:", error.response.headers);
} else {
console.error("Error Message:", error.message);
}
return Promise.reject(error.response || error.message);
};
return client(options)
.then(onSuccess)
.catch(onError);
};