Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Z
zimbra-admin-api-js
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Public
zimbra-admin-api-js
Commits
21b45111
Commit
21b45111
authored
Feb 27, 2017
by
Juorder Gonzalez
Committed by
GitHub
Feb 27, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #287 from ZBoxApp/manager_performance
Manager performance
parents
914fed4c
a1127cde
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
169 additions
and
387 deletions
+169
-387
package.json
package.json
+1
-1
sales.jsx
src/components/sales/sales.jsx
+143
-385
client.jsx
src/utils/client.jsx
+25
-1
No files found.
package.json
View file @
21b45111
...
...
@@ -15,7 +15,7 @@
"
js-powerdns
"
:
"
ZBoxApp/js-powerdns
"
,
"
keymirror
"
:
"
0.1.1
"
,
"
lodash
"
:
"
^4.11.1
"
,
"
moment
"
:
"
^2.13.
0
"
,
"
moment
"
:
"
^2.13.
x
"
,
"
node-sass
"
:
"
^3.8.0
"
,
"
nprogress
"
:
"
^0.2.0
"
,
"
object-assign
"
:
"
4.0.1
"
,
...
...
src/components/sales/sales.jsx
View file @
21b45111
import
React
from
'react'
;
import
PageInfo
from
'../page_info.jsx'
;
import
Panel
from
'../panel.jsx'
;
import
moment
from
'moment'
;
import
currencyFormatter
from
'currency-formatter'
;
import
EventStore
from
'../../stores/event_store.jsx'
;
import
UserStore
from
'../../stores/user_store.jsx'
;
import
*
as
GlobalActions
from
'../../action_creators/global_actions.jsx'
;
import
*
as
Utils
from
'../../utils/utils.jsx'
;
import
*
as
Client
from
'../../utils/client.jsx'
;
import
ZimbraStore
from
'../../stores/zimbra_store.jsx'
;
import
sweetAlert
from
'sweetalert'
;
export
default
class
SalesForm
extends
React
.
Component
{
constructor
(
props
)
{
super
(
props
);
this
.
handleSetNumbersOfMailboxes
=
this
.
handleSetNumbersOfMailboxes
.
bind
(
this
);
this
.
getPrices
=
this
.
getPrices
.
bind
(
this
);
this
.
onlyNumber
=
this
.
onlyNumber
.
bind
(
this
);
this
.
buildPurchase
=
this
.
buildPurchase
.
bind
(
this
);
this
.
confirmShipping
=
this
.
confirmShipping
.
bind
(
this
);
this
.
getDomainInfo
=
this
.
getDomainInfo
.
bind
(
this
);
this
.
tryAgain
=
this
.
tryAgain
.
bind
(
this
);
this
.
cos
=
Utils
.
getEnabledPlansByCos
(
ZimbraStore
.
getAllCos
());
this
.
plans
=
window
.
manager_config
.
plans
;
this
.
keys
=
Object
.
keys
(
this
.
cos
);
this
.
sales
=
{};
this
.
isNAN
=
false
;
this
.
currency
=
window
.
manager_config
.
invoiceAPI
.
currency
;
const
precision
=
this
.
currency
===
'CLP'
?
0
:
2
;
this
.
currencyParams
=
{
code
:
this
.
currency
,
symbol
:
''
,
precision
};
this
.
state
=
{
loading
:
true
,
errorAjax
:
false
,
disabled
:
false
};
}
confirmShipping
(
e
)
{
e
.
preventDefault
();
const
plans
=
[];
const
{
domain
}
=
this
.
state
;
const
domainId
=
domain
.
id
;
const
companyId
=
domain
.
attrs
.
businessCategory
;
const
adminEmail
=
UserStore
.
getCurrentUser
().
name
;
const
items
=
{};
const
data
=
{
domainId
,
companyId
,
adminEmail
,
upgrade
:
false
,
currency
:
this
.
currency
const
{
name
,
attrs
}
=
UserStore
.
getCurrentUser
();
const
{
displayName
,
cn
,
sn
}
=
attrs
.
_attrs
;
const
state
=
{
disabled
:
true
,
purchase
:
{},
user
:
{
email
:
name
,
fullname
:
this
.
buildFullName
(
displayName
,
cn
,
sn
)
},
domainId
:
props
.
params
.
domainId
};
this
.
keys
.
forEach
((
plan
)
=>
{
if
(
this
.
sales
[
plan
]
&&
this
.
sales
[
plan
].
quantity
&&
this
.
sales
[
plan
].
quantity
>
0
)
{
items
[
plan
]
=
this
.
sales
[
plan
];
items
[
plan
].
type
=
'Producto'
;
plans
.
push
(
`
${
Utils
.
titleCase
(
plan
)}
: <strong>
${
this
.
sales
[
plan
].
quantity
}
</strong>`
);
}
});
if
(
plans
.
length
<
1
)
{
return
EventStore
.
emitToast
({
type
:
'error'
,
title
:
'Compra Casillas'
,
body
:
'Debe indicar cuantas casillas desea comprar.'
,
options
:
{
timeOut
:
4000
,
extendedTimeOut
:
2000
,
closeButton
:
true
}
});
}
this
.
avoidPlans
=
[
'archiving'
,
'default'
];
this
.
plans
=
window
.
manager_config
.
plans
;
this
.
messageCode
=
window
.
manager_config
.
messageCode
;
const
content
=
plans
.
join
(
', '
);
const
total
=
`
${
this
.
refs
.
total
.
value
}
${
this
.
currency
}
`
;
const
options
=
{
title
:
'Confirmación'
,
text
:
`Esta seguro de realizar la compra de
${
content
}
por un total de <strong>
${
total
}
</strong>`
,
html
:
true
,
confirmButtonText
:
'Si, compraré'
,
confirmButtonColor
:
'#4EA5EC'
,
showLoaderOnConfirm
:
true
,
closeOnConfirm
:
false
};
this
.
mailboxes
=
Object
.
keys
(
this
.
plans
).
filter
((
plan
)
=>
{
const
isValidPlan
=
!
this
.
avoidPlans
.
includes
(
plan
);
Utils
.
alertToBuy
((
isConfirmed
)
=>
{
if
(
isConfirmed
)
{
data
.
items
=
items
;
const
requestObject
=
JSON
.
stringify
(
data
);
Client
.
makeSale
(
requestObject
,
()
=>
{
Utils
.
alertToBuy
((
isConfirmed
)
=>
{
if
(
isConfirmed
)
{
Utils
.
handleLink
(
null
,
`/domains/
${
domainId
}
/mailboxes/new`
);
}
},
{
title
:
'Compra de Casillas'
,
text
:
'Su compra se ha realizado con éxito.'
,
showCancelButton
:
false
,
confirmButtonColor
:
'#4EA5EC'
,
confirmButtonText
:
'Muy bien'
,
type
:
'success'
});
},
(
error
)
=>
{
Utils
.
alertToBuy
(()
=>
{
return
null
;
},
{
title
:
'Error'
,
text
:
error
.
message
||
error
.
error
.
message
||
'Ha ocurrido un error desconocido.'
,
showCancelButton
:
false
,
confirmButtonColor
:
'#4EA5EC'
,
confirmButtonText
:
'Entiendo'
,
type
:
'error'
,
closeOnConfirm
:
true
});
});
if
(
isValidPlan
)
{
state
.
purchase
[
plan
]
=
0
;
}
},
options
);
}
getPrices
()
{
const
{
domainId
}
=
this
.
props
.
params
||
this
.
state
.
domain
.
name
||
null
;
const
attrs
=
this
.
state
.
domain
.
attrs
;
const
{
zimbraCreateTimestamp
}
=
attrs
;
const
{
businessCategory
}
=
attrs
;
const
createdDate
=
moment
(
zimbraCreateTimestamp
,
[
'YYYYDDMM'
,
'YYYY-DD-MM'
,
'DD-MM-YYYY'
,
'YYYY-MM-DD'
]);
if
(
!
createdDate
.
isValid
())
{
this
.
setState
({
disabled
:
true
,
loading
:
false
,
errorAjax
:
true
});
return
EventStore
.
emitToast
({
type
:
'error'
,
title
:
'Compras - Precios'
,
body
:
'Ha ocurrido un error al obtener su fecha de creación de dominio.'
,
options
:
{
timeOut
:
4000
,
extendedTimeOut
:
2000
,
closeButton
:
true
}
});
}
const
data
=
{
domainId
,
domainCreatedDate
:
createdDate
.
format
(
'MM/DD/Y'
),
anualRenovation
:
true
,
companyId
:
businessCategory
,
type
:
'standar'
,
currency
:
this
.
currency
};
Client
.
getPrices
(
data
,
(
success
)
=>
{
this
.
setState
({
loading
:
false
,
disabled
:
false
,
prices
:
success
.
result
.
prices
,
isAnual
:
success
.
result
.
isAnual
,
description
:
success
.
result
.
isAnual
?
success
.
result
.
description
:
null
});
},
(
error
)
=>
{
this
.
setState
({
errorAjax
:
true
,
loading
:
false
});
return
EventStore
.
emitToast
({
type
:
'error'
,
title
:
'Compras - Precios'
,
body
:
error
.
message
||
error
.
error
.
message
||
'Ha ocurrido un error al intentar obtener los precios, vuelva a intentarlo por favor.'
,
options
:
{
timeOut
:
4000
,
extendedTimeOut
:
2000
,
closeButton
:
true
}
});
return
isValidPlan
;
});
this
.
state
=
state
;
}
tryAgain
(
e
)
{
e
.
preventDefault
()
;
onKeyupInput
(
event
,
label
)
{
const
value
=
event
.
target
.
value
;
this
.
setState
({
loading
:
true
,
errorAjax
:
false
});
this
.
getPrices
();
this
.
checkAmount
(
label
,
value
);
}
getDomainInfo
(
)
{
const
{
domainId
}
=
this
.
props
.
params
;
buildFullName
(
displayName
,
cn
,
sn
)
{
const
fullname
=
displayName
&&
displayName
.
trim
()
!==
''
?
displayName
:
`
${
cn
}
${
sn
}
`
;
Client
.
getDomain
(
domainId
,
(
res
,
err
)
=>
{
if
(
err
)
{
return
Utils
.
alertToBuy
(()
=>
{
return
null
;
},
{
title
:
'Error'
,
text
:
err
.
message
||
err
.
error
.
message
||
'Ha ocurrido un error desconocido, cuando se recuperaba la información del dominio.'
,
showCancelButton
:
false
,
confirmButtonColor
:
'#4EA5EC'
,
confirmButtonText
:
'Entiendo'
,
type
:
'error'
,
closeOnConfirm
:
true
});
}
return
fullname
;
}
this
.
setState
({
domain
:
res
});
checkAmount
(
label
,
_value
)
{
const
value
=
_value
||
0
;
const
state
=
this
.
state
;
const
purchase
=
state
.
purchase
;
const
isEnabled
=
this
.
mailboxes
.
some
((
plan
)
=>
{
const
planAmount
=
plan
===
label
?
value
:
purchase
[
plan
];
return
planAmount
>
0
;
});
return
this
.
getPrices
();
this
.
setState
({
disabled
:
!
isEnabled
,
purchase
:
{...
purchase
,
[
label
]:
parseInt
(
value
,
10
)}
});
}
componentDidMount
()
{
GlobalActions
.
emitEndLoading
();
this
.
getDomainInfo
();
}
onKeydownInput
(
event
)
{
const
keycode
=
event
.
keyCode
||
event
.
which
;
const
allows
=
[
8
,
9
,
37
,
39
,
48
,
49
,
50
,
51
,
52
,
53
,
54
,
55
,
56
,
57
,
96
,
97
,
98
,
99
,
100
,
101
,
102
,
103
,
104
,
105
];
handleSetNumbersOfMailboxes
(
e
,
id
)
{
if
(
this
.
isNAN
)
{
e
.
preventDefault
();
return
null
;
if
(
allows
.
includes
(
keycode
))
{
return
true
;
}
const
amount
=
e
.
target
.
value
.
trim
();
let
totalPrice
=
0
;
let
description
=
'Nuevas Casillas '
;
this
.
keys
.
forEach
((
plan
)
=>
{
if
(
this
.
cos
[
plan
]
===
id
)
{
const
price
=
this
.
state
.
prices
[
plan
];
const
size
=
amount
.
length
>
0
?
parseInt
(
amount
,
10
)
:
0
;
const
total
=
size
?
size
*
price
:
size
;
const
totalFormatted
=
total
?
currencyFormatter
.
format
(
total
,
this
.
currencyParams
)
:
total
;
this
.
refs
[
`
${
plan
}
-total`
].
value
=
totalFormatted
;
description
+=
Utils
.
titleCase
(
plan
);
event
.
preventDefault
();
return
null
;
}
this
.
sales
[
plan
]
=
{
quantity
:
size
,
description
,
price
,
id
,
total
};
buildPurchase
(
purchase
)
{
const
plans
=
this
.
plans
;
const
content
=
[];
this
.
mailboxes
.
reduce
((
last
,
current
)
=>
{
const
quantity
=
purchase
[
current
];
if
(
quantity
>
0
)
{
const
plan
=
plans
[
current
];
const
label
=
quantity
>
1
?
'casillas'
:
'casilla'
;
last
.
push
(
`
${
quantity
}
${
label
}
${
plan
.
label
}
`
);
}
if
(
this
.
sales
[
plan
]
&&
this
.
sales
[
plan
].
total
&&
this
.
sales
[
plan
].
total
>
0
)
{
totalPrice
+=
this
.
sales
[
plan
].
total
;
}
});
const
currentTotal
=
totalPrice
?
currencyFormatter
.
format
(
totalPrice
,
this
.
currencyParams
)
:
totalPrice
;
this
.
refs
.
total
.
value
=
currentTotal
;
return
last
;
},
content
);
return
content
;
}
onlyNumber
(
e
)
{
const
key
=
e
.
keyCode
;
const
forbidden
=
[
48
,
49
,
50
,
51
,
52
,
53
,
54
,
55
,
56
,
57
,
8
,
9
,
37
,
39
];
this
.
isNAN
=
false
;
if
(
!
(
forbidden
.
indexOf
(
key
)
>
-
1
))
{
this
.
isNAN
=
true
;
e
.
preventDefault
();
return
null
;
}
transformToHTML
(
content
)
{
const
list
=
content
.
join
(
'</strong>, <strong>'
);
return
`<p><strong>
${
list
}
</strong></p>`
;
}
render
()
{
const
plans
=
this
.
cos
;
const
configPlans
=
this
.
plans
;
const
keysPlans
=
this
.
keys
;
let
form
=
null
;
let
actions
;
const
buttons
=
[];
const
{
description
,
disabled
}
=
this
.
state
;
let
descriptionText
;
if
(
description
)
{
descriptionText
=
(
<
div
key=
'desc-key'
className=
'alert alert-info margin-bottom'
>
<
span
className=
'glyphicon glyphicon glyphicon-question-sign'
aria
-
hidden=
'true'
></
span
>
<
span
className=
'sr-only'
>
Info:
</
span
>
{
description
}
</
div
>
);
}
if
(
this
.
state
.
errorAjax
)
{
form
=
(
<
div
className=
'text-center'
key=
{
'errorajax-loading'
}
>
<
i
className=
'fa fa-refresh fa-4x fa-fw pointer'
onClick=
{
this
.
tryAgain
}
>
</
i
>
<
p
>
{
'Intentarlo de nuevo'
}
</
p
>
</
div
>
);
}
confirmShipping
(
e
)
{
e
.
preventDefault
();
const
{
purchase
,
user
,
domainId
}
=
this
.
state
;
const
content
=
this
.
transformToHTML
(
this
.
buildPurchase
(
purchase
));
let
data
=
{
purchase
,
user
:
user
.
email
,
fullname
:
user
.
fullname
};
const
options
=
{
title
:
'Confirmación'
,
text
:
`Esta seguro de realizar la compra de
${
content
}
`
,
html
:
true
,
confirmButtonText
:
'Si, compraré'
,
confirmButtonColor
:
'#4EA5EC'
,
showLoaderOnConfirm
:
true
,
closeOnConfirm
:
false
};
if
(
this
.
state
.
isAnual
)
{
buttons
.
push
(
{
label
:
'Anual'
,
props
:
{
className
:
'btn btn-success btn-xs'
}
}
);
}
else
{
buttons
.
push
(
{
label
:
'Mensual'
,
props
:
{
className
:
'btn btn-info btn-xs'
Utils
.
alertToBuy
((
isConfirmed
)
=>
{
if
(
isConfirmed
)
{
Client
.
getDomain
(
domainId
,
(
domain
,
err
)
=>
{
if
(
err
)
{
return
sweetAlert
(
'Error'
,
'El Dominio no existe.'
,
'error'
);
}
}
);
}
if
(
this
.
state
.
loading
)
{
form
=
(
<
div
className=
'text-center'
key=
{
'prices-loading'
}
>
<
i
className=
'fa fa-spinner fa-spin fa-4x fa-fw'
></
i
>
<
p
>
{
'Cargando Precios...'
}
</
p
>
</
div
>
);
}
if
(
!
this
.
state
.
loading
&&
this
.
state
.
prices
)
{
const
prices
=
this
.
state
.
prices
;
const
rows
=
keysPlans
.
map
((
plan
)
=>
{
const
cosId
=
plans
[
plan
];
const
salesArray
=
configPlans
[
plan
].
sales
;
const
fields
=
salesArray
.
map
((
field
,
index
)
=>
{
const
label
=
field
.
label
||
`Casillas
${
Utils
.
titleCase
(
plan
)}
`
;
const
price
=
field
.
hasPrice
?
currencyFormatter
.
format
(
prices
[
plan
],
this
.
currencyParams
)
:
''
;
const
myref
=
field
.
ref
?
{
ref
:
`
${
plan
}
-
${
field
.
ref
}
`
}
:
{};
return
(
<
div
key=
{
`sale-input-${plan}-${index}`
}
className=
'col-xs-4'
>
<
div
className=
'form-group'
>
<
div
className=
'input-group'
>
<
div
className=
'input-group-addon'
>
{
label
}
</
div
>
<
input
type=
'text'
className=
'form-control'
disabled=
{
field
.
disabled
}
defaultValue=
{
price
}
{
...
myref
}
onKeyUp=
{
(
e
)
=>
{
this
.
handleSetNumbersOfMailboxes
(
e
,
cosId
);
}
}
onKeyDown=
{
this
.
onlyNumber
}
/>
</
div
>
</
div
>
</
div
>
);
const
{
name
}
=
domain
;
data
.
domain
=
name
;
Client
.
requestMailboxes
(
data
,
(
response
)
=>
{
const
text
=
this
.
messageCode
[
response
.
messageCode
];
sweetAlert
(
'Compra éxitosa'
,
text
,
'success'
);
},
(
error
)
=>
{
const
text
=
this
.
messageCode
[
error
.
messageCode
];
sweetAlert
(
'Error'
,
text
,
'error'
);
});
});
}
},
options
);
}
return
(
<
div
key=
{
`row-fields-${plan}`
}
className=
'row'
>
{
fields
}
</
div
>
);
});
form
=
(
<
form
key=
'form-container'
>
{
rows
}
<
div
className=
'row'
>
<
div
className=
'col-xs-4 pull-right'
>
<
div
className=
'form-group'
>
<
div
className=
'input-group'
>
<
div
className=
'input-group-addon'
>
Total
</
div
>
<
input
type=
'text'
disabled=
{
true
}
className=
'form-control'
ref=
'total'
/>
<
div
className=
'input-group-addon'
>
{
this
.
currency
}
</
div
>
</
div
>
</
div
>
</
div
>
</
div
>
</
form
>
);
actions
=
(
renderInputs
()
{
const
{
purchase
}
=
this
.
state
;
return
this
.
mailboxes
.
map
((
input
,
index
)
=>
{
const
plan
=
this
.
plans
[
input
];
const
value
=
purchase
[
input
];
return
(
<
div
className=
'row'
key=
'actions-container
'
key=
{
`sale-input-${plan.label}-${index}`
}
className=
'col-xs-4
'
>
<
div
className=
'col-xs-12 text-right'
>
<
button
className=
'btn btn-default'
>
Cancelar
</
button
>
<
button
disabled=
{
disabled
}
className=
'btn btn-info'
onClick=
{
this
.
confirmShipping
}
>
Comprar
</
button
>
<
div
className=
'form-group'
>
<
div
className=
'input-group'
>
<
div
className=
'input-group-addon'
>
{
`Casilla ${plan.label}`
}
</
div
>
<
input
type=
'text'
className=
'form-control'
defaultValue=
{
value
}
onKeyUp=
{
(
event
)
=>
this
.
onKeyupInput
(
event
,
input
)
}
onKeyDown=
{
this
.
onKeydownInput
}
/>
</
div
>
</
div
>
</
div
>
);
}
});
}
render
()
{
const
{
disabled
}
=
this
.
state
;
return
(
<
div
>
...
...
@@ -441,9 +182,26 @@ export default class SalesForm extends React.Component {
<
div
className=
'row'
>
<
div
className=
'col-md-12 central-content'
>
<
Panel
btnsHeader=
{
buttons
}
children=
{
[
descriptionText
,
form
,
actions
]
}
/>
hasHeader=
{
true
}
title=
{
'Selecciona la cantidad de casillas que deseas comprar.'
}
>
<
form
key=
'form-container'
>
<
div
className=
'row'
>
{
this
.
renderInputs
()
}
</
div
>
<
div
className=
'row'
>
<
div
className=
'col-xs-12 text-right'
>
<
button
disabled=
{
disabled
}
className=
'btn btn-info'
onClick=
{
this
.
confirmShipping
}
>
Comprar
</
button
>
</
div
>
</
div
>
</
form
>
</
Panel
>
</
div
>
</
div
>
</
div
>
...
...
src/utils/client.jsx
View file @
21b45111
...
...
@@ -75,7 +75,7 @@ function initZimbra() {
export
function
getClientConfig
(
success
,
error
)
{
return
$
.
ajax
({
url
:
'https://manager
-api.zboxapp.com
/parse/functions/getConfigManager'
,
url
:
'https://manager
.zboxapp.com/ventas_api
/parse/functions/getConfigManager'
,
//url: './config/config.json',
dataType
:
'json'
,
method
:
'POST'
,
...
...
@@ -845,6 +845,30 @@ export function getPrices(data, success, error) {
});
}
export
function
requestMailboxes
(
data
,
success
,
error
)
{
const
appId
=
window
.
manager_config
.
salesAPI
.
appId
;
const
endpoints
=
window
.
manager_config
.
salesAPI
;
const
url
=
endpoints
.
base
+
endpoints
.
requestSale
;
$
.
ajax
({
url
:
url
,
method
:
'POST'
,
data
:
data
,
contentType
:
'application/json'
,
headers
:
{
'X-Parse-Application-Id'
:
appId
,
'X-Parse-REST-API-Key'
:
'master'
},
dataType
:
'json'
,
success
:
function
onSuccess
(
response
)
{
success
(
response
);
},
error
:
function
onError
(
err
)
{
error
(
err
.
responseJSON
||
err
);
}
});
}
export
function
makeSale
(
data
,
success
,
error
)
{
const
appId
=
window
.
manager_config
.
salesAPI
.
appId
;
const
endpoints
=
window
.
manager_config
.
salesAPI
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment