Commit 87385a56 authored by Juorder Antonio's avatar Juorder Antonio

add massive deleting, add error detalis view, get config from parse server, add custom error view

parent 54dece61
1467994135
\ No newline at end of file
1468357419
\ No newline at end of file
module.exports = {"main":{"js":"/907311bundle.js"}}
\ No newline at end of file
module.exports = {"main":{"js":"/451280bundle.js"}}
\ No newline at end of file
import React from 'react';
import * as Utils from '../../utils/utils.jsx';
export default class NotFound404 extends React.Component {
render() {
const clouds = [];
const totalClouds = Utils.randomRange(30, 20);
const screenHeight = window.innerHeight;
const screenWidth = window.innerWidth;
for (let i = 0; i < totalClouds; i++) {
const topStyle = Utils.randomRange(screenHeight, 80);
const sizeCloud = Utils.randomRange(1, 5);
const leftStyle = Utils.randomRange(screenWidth + 300, screenWidth);
//const scale = Utils.randomRange(1, 0.1);
clouds.push(
(
<i
key={`cloud-${i}`}
style={{top: topStyle + 'px', left: leftStyle + 'px'}}
className={`fa fa-cloud fa-${sizeCloud}x`}
></i>
)
);
}
return (
<div className='wrapper-error'>
<div className='zboxPlain'>
<i className='fa fa-paper-plane'></i>
<i className='fa fa-paper-plane-o underPlain'></i>
</div>
{clouds}
</div>
);
}
}
import React from 'react';
import Panel from './panel.jsx';
import PageInfo from './page_info.jsx';
import * as GlobalActions from '../action_creators/global_actions.jsx';
import ErrorStore from '../stores/error_store.jsx';
export default class ErrorDetails extends React.Component {
constructor(props) {
super(props);
this.getDetails = this.getDetails.bind(this);
this.state = {
errors: null
};
}
getDetails() {
const errors = ErrorStore.getErrors();
this.setState({
errors
});
}
componentDidMount() {
GlobalActions.emitEndLoading();
this.getDetails();
}
componentWillUnmount() {
ErrorStore.destroy();
}
render() {
const {errors} = this.state;
let bodyError = null;
let title;
let message;
if (!errors) {
bodyError = (
<div className='text-center'>
<h3 className='page-header'>
Por suerte no tenemos errores para mostrar <small><i className='fa fa-smile-o fa-3x color-smile'></i></small>
</h3>
</div>
);
}
if (errors) {
title = errors.title;
message = errors.message;
const elements = [];
const keys = Object.keys(errors.data || []);
keys.forEach((key) => {
errors.data[key].forEach((error, i) => {
elements.push(
(
<li key={`error-${i}`}>
{`${error.item} : ${error.error}`}
</li>
)
);
});
});
bodyError = (
<div className='alert alert-danger'>
<ul className='list-errors list-unstyled'>
{elements}
</ul>
</div>
);
}
return (
<div>
<PageInfo
titlePage={title || 'No hay errores que mostrar'}
descriptionPage={message || ''}
/>
<div className='content animate-panel'>
<div className='row'>
<div className='col-md-12 central-content'>
<Panel
children={bodyError}
hasHeader={false}
/>
</div>
</div>
</div>
</div>
);
}
}
......@@ -148,7 +148,7 @@ export default class ImportMassiveModal extends React.Component {
}
extractCols(data, flagDefault) {
let splitConditio = /\r\n|\r|\n/g;
let splitConditio = /\r\n|\r|\n/gi;
let hasError = false;
const dataArray = data.split(splitConditio);
......
import React from 'react';
import * as Client from '../../utils/client.jsx';
import * as GlobalActions from '../../action_creators/global_actions.jsx';
import * as Utils from '../../utils/utils.jsx';
import ErrorStore from '../../stores/error_store.jsx';
import PageInfo from '../page_info.jsx';
import Panel from '../panel.jsx';
export default class MassiveDelete extends React.Component {
constructor(props) {
super(props);
this.handleDelete = this.handleDelete.bind(this);
this.handleCommands = this.handleCommands.bind(this);
this.removeMassiveAccounts = this.removeMassiveAccounts.bind(this);
this.isExecuting = false;
}
getDetails(e, errors) {
ErrorStore.saveErrors(errors);
Utils.handleLink(e, '/errorsFromAction');
}
handleCommands(e) {
if (!e) {
return null;
}
const enter = 13;
const keyCode = e.keyCode || e.which;
const isCtrlPressed = e.ctrlKey;
if (keyCode === enter && isCtrlPressed) {
e.preventDefault();
this.handleDelete();
}
}
componentDidMount() {
this.handleCommands();
}
handleDelete(e) {
if (e) {
e.preventDefault();
}
const consoleText = this.refs.console.value.trim();
if (consoleText === '' && consoleText.length < 1 || this.isExecuting) {
return null;
}
const preMailboxes = consoleText.split(/\r?\n/gi);
const getAccountByBatch = [];
const deleteAccountByBatch = [];
const wrongEmails = [];
const emailsNotFound = [];
preMailboxes.forEach((email) => {
const pattern = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
const cleanEmail = email.trim();
const condition = pattern.test(cleanEmail) && cleanEmail !== '';
if (condition) {
getAccountByBatch.push(Client.getAccountByBatch(cleanEmail));
return condition;
}
if (cleanEmail !== '') {
wrongEmails.push(cleanEmail);
}
return condition;
});
GlobalActions.emitStartTask({
origin: 'Borrado Masivo',
action: 'Borrando Casillas.',
id: 'deleteMassive'
});
this.isExecuting = true;
Client.batchRequest(getAccountByBatch, (found) => {
if (found.Fault) {
found.Fault.forEach((object) => {
const parts = object.Reason.Text.split(':');
const message = parts.length > 1 ? parts.pop() : object.Reason.Text;
emailsNotFound.push({
item: message.trim(),
error: 'Este email no existe.'
});
});
if (!found.GetAccountResponse) {
return GlobalActions.emitEndTask({
id: 'deleteMassive',
toast: {
message: 'Las casillas indicadas, no existen, verifique por favor',
title: 'Borrado Masivo',
type: 'error'
}
});
}
}
if (found.GetAccountResponse) {
found.GetAccountResponse.forEach((object) => {
const id = object.account[0].id;
deleteAccountByBatch.push(Client.removeAccountByBatch(id));
});
}
if (deleteAccountByBatch.length > 0) {
const response = {
title: 'Borrado Masivo',
message: 'Ha ocurrido los siguientes errores, cuando se intentaba borrar casillas masivamente.',
data: {
onValid: emailsNotFound
}
};
this.removeMassiveAccounts(deleteAccountByBatch, response);
}
}, (err) => {
this.isExecuting = false;
return GlobalActions.emitEndTask({
id: 'deleteMassive',
toast: {
message: err.message || 'Ocurrió un error desconocido.',
title: 'Borrado Masivo',
type: 'error'
}
});
});
}
removeMassiveAccounts(accountsId, response) {
const accountsInstances = accountsId || null;
const resp = response || null;
let control;
if (!accountsInstances) {
return;
}
if (accountsInstances.length > 0) {
Client.batchRequest(accountsInstances, (done) => {
this.isExecuting = false;
if (done.Fault) {
done.Fault.forEach((object) => {
const parts = object.Reason.Text.split(':');
const message = parts.length > 1 ? parts.pop() : object.Reason.Text;
if (resp.data.onRemove) {
resp.data.onRemove = [...resp.data.onRemove, {
item: message.trim(),
error: object.Reason.Text
}];
} else {
resp.data.onRemove = [{
item: message.trim(),
error: object.Reason.Text
}];
}
});
if (!done.DeleteAccountResponse) {
control = (
<div>
<p>
{'Ha ocurrido un error, para mas detalles haga '}
<a
onClick={(e) => {
this.getDetails(e, resp);
}}
className='link-error'
>
Click Aqui
</a>
</p>
</div>
);
return GlobalActions.emitEndTask({
id: 'deleteMassive',
toast: {
message: control,
title: 'Borrado Masivo',
type: 'error'
}
});
}
}
const total = done.DeleteAccountResponse.length;
const totalDeleted = total > 1 ? `${total} casillas` : `${total} casilla`;
if (this.refs && this.refs.console) {
this.refs.console.value = '';
}
const hasDetails = resp.data.onValid.length > 0 || (resp.data.onRemove && resp.data.onRemove.length > 0) ? true : null;
control = (
<div>
<p>
{`Se han borrado ${totalDeleted}, éxitosamente, pero hubo algunos errores en otras, para mas detalle haga `}
<a
onClick={(e) => {
this.getDetails(e, resp);
}}
className='link-error'
>
click aqui
</a>
</p>
</div>
);
if (!hasDetails) {
control = `Se han borrado ${totalDeleted}, éxitosamente.`;
}
return GlobalActions.emitEndTask({
id: 'deleteMassive',
toast: {
message: control,
title: 'Borrado Masivo',
type: 'success'
}
});
}, (err) => {
this.isExecuting = false;
return GlobalActions.emitEndTask({
id: 'deleteMassive',
toast: {
message: err.message || 'Ocurrió un error desconocido, al intentar de borrar las casillas.',
title: 'Borrado Masivo',
type: 'error'
}
});
});
}
}
render() {
const consoleText = (
<div
className='row'
key='deleteConsole'
>
<div className='col-xs-12'>
<blockquote className='custom-blockquote'>
<p>
<i>
{'Escribir el nombre de las casillas a la cual se quiere eliminar, cada casilla debe ser separada por un salto de linea (Tecla Enter).'}
</i>
</p>
</blockquote>
</div>
<div className='col-xs-12 wrapper-console'>
<textarea
className='form-control consoleText'
ref='console'
onKeyDown={this.handleCommands}
>
</textarea>
<span className='tooltip-console'>
<code>
{'CTRL + ENTER'}
</code>
{'PARA EJECUTAR'}
</span>
</div>
</div>
);
const buttons = (
<div
key={'btn-actions'}
className='row'
>
<div className='col-xs-12 text-right'>
<button
className='btn btn-danger'
onClick={this.handleDelete}
>
{'Borrar Casillas'}
</button>
</div>
</div>
);
return (
<div>
<PageInfo
titlePage='Borrado Masivo de Casillas'
descriptionPage='Herramienta para borrar masivamente'
/>
<div className='content animate-panel'>
<div className='row'>
<div className='col-md-12 central-content'>
<Panel
children={[consoleText, buttons]}
hasHeader={false}
/>
</div>
</div>
</div>
</div>
);
}
}
......@@ -24,6 +24,9 @@ import DistributionLists from './components/distribution/distribution_lists.jsx'
import EditDistributionList from './components/distribution/edit_distribution_lists.jsx';
import SearchView from './components/search/search.jsx';
import SalesForm from './components/sales/sales.jsx';
import deleteMassive from './components/massive/masive_delete.jsx';
import ErrorsFromActions from './components/errors_from_action.jsx';
import Template404 from './components/404/404.jsx';
import * as Client from './utils/client.jsx';
import * as Utils from './utils/utils.jsx';
......@@ -46,13 +49,15 @@ const notFoundParams = {
function preRenderSetup(callwhendone) {
const d1 = Client.getClientConfig(
(data) => {
if (!data) {
const config = data.result;
if (!config) {
return;
}
global.window.manager_config = data;
global.window.manager_config = config;
if (data.debug) {
if (config.debug) {
global.window.Client = Client;
global.window.Utils = Utils;
}
......@@ -119,7 +124,7 @@ function renderRootComponent() {
>
<Route
path='error'
component={ErrorPage}
component={ErrorPage || Template404}
/>
<Route
component={LoggedIn}
......@@ -213,6 +218,16 @@ function renderRootComponent() {
path='sales/:domainId/mailboxes'
component={SalesForm}
/>
<Route
path='massive'
component={deleteMassive}
/>
<Route
path='errorsFromAction'
component={ErrorsFromActions}
/>
</Route>
<Route component={NotLoggedIn}>
<IndexRedirect to='login'/>
......
......@@ -1686,3 +1686,118 @@ label {
right: 0;
}
}
.wrapper-console {
margin-bottom: 15px;
overflow: hidden;
position: relative;
.consoleText {
background: $black;
color: $color-console;
font-weight: 500;
max-height: 600px;
min-height: 300px;
overflow: auto;
resize: none;
&:focus + .tooltip-console {
top: 4px;
}
}
.tooltip-console {
border: 1px solid $color-console;
color: $white;
font-size: 10px;
opacity: .6;
padding: 5px;
position: absolute;
right: 18px;
top: -50%;
transition: top .5s;
&:hover {
opacity: .9;
}
code {
margin-right: 5px;
}
}
}
// scss-lint:disable all
.custom-blockquote {
border-color: $border-color-ok;
i {
font-size: 14px;
}
}
.color-smile {
color: $border-color-ok;
vertical-align: middle;
}
.link-error {
color: $border-color-ok;
text-decoration: underline;
}
.list-errors {
list-style: none;
li {
&::before {
content: '\274C';
margin-right: 10px;
}
}
}
.wrapper-error {
background: #6BB9F0;
.zboxPlain {
display: inline-block;
font-size: 80px;
left: 500px;
position: relative;
top: 220px;
-webkit-animation: flying 3s infinite;
transform: rotate(50deg);
i {
color: $white;
left: 0;
position: absolute;
top: 0;
&.underPlain {
color: grey;
}
}
}
i[class*='cloud'] {
color: $white;
position: absolute;
//animation: wind 27s infinite;
//-webkit-animation: wind 27s infinite;
&:nth-child(2n + 1) {
//animation: windSlow 17s infinite;
//-webkit-animation: windSlow 17s infinite;
}
&:nth-child(3n + 1) {
//animation: windSlower 25s infinite;
//-webkit-animation: windSlower 25s infinite;
}
}
}
// scss-lint:enable all
@charset 'UTF-8';
// scss-lint:disable all
@keyframes wind {
0% {
margin-left: 110%;
}
100% {
margin-left: -10%;
}
}
@-webkit-keyframes windSlow {
0% {
margin-left: 150%;
}
100% {
margin-left: -20%;
}
}
@-webkit-keyframes windSlower {
0% {
margin-left: 180%;
}
100% {
margin-left: -70%;
}
}
@-webkit-keyframes flying {
0%, 100% {
top: 5px;
}
50% {
top: 30px;
}
}
// scss-lint:enable all
......@@ -130,3 +130,7 @@ $bg-beta: #ee8e4a;
// tags mailbox style
$border-color-tag: #e2e2e2;
// console color letters
$color-console: #0f0;
class ErrorStore {
constructor() {
this.errors = null;
}
saveErrors(error) {
this.errors = error;
}
getErrors() {
if (this.errors) {
return this.errors;
}
}
destroy() {
this.errors = null;
}
}
const erroStore = new ErrorStore();
export {erroStore as default};
......@@ -75,8 +75,13 @@ function initZimbra() {
export function getClientConfig(success, error) {
return $.ajax({
url: '/config/config.json',
url: 'https://ventasparse-ventas.hub.zboxapp.com/parse/functions/getConfigManager',
dataType: 'json',
method: 'POST',
headers: {
'X-Parse-Application-Id': 'salesZboxManagerApp'
},
data: {target: 'manager'},
success,
error: function onError(xhr, status, err) {
var e = handleError('getClientConfig', err);
......@@ -385,6 +390,14 @@ export function getAllAccountsByBatch(attrs) {
return ZimbraStore.getCurrent().getAllAccounts(attrs);
}
export function getAccountByBatch(id) {
return ZimbraStore.getCurrent().getAccount(id);
}
export function removeAccountByBatch(id) {
return ZimbraStore.getCurrent().removeAccount(id);
}
export function getAccount(id, success, error) {
initZimbra().then(
(zimbra) => {
......
......@@ -842,3 +842,7 @@ export function getDaysFromDate2Date(dateFrom, dateTo) {
var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24));
return diffDays;
}
export function randomRange(max, min) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment