Commit c68b517c authored by Elias Nahum's avatar Elias Nahum

Calculo de tipos de cuenta utilizando getAllCos y maxAccountsByCos

parent b1bd98c2
......@@ -14,5 +14,9 @@
{
"id": "76424135-5",
"name": "Test Company"
},
{
"id": "1233667482",
"name": "Parnasa"
}
]
......@@ -5,10 +5,12 @@ import $ from 'jquery';
import React from 'react';
import Promise from 'bluebird';
import MessageBar from '../message_bar.jsx';
import PageInfo from '../page_info.jsx';
import Panel from '../panel.jsx';
import CompaniesStore from '../../stores/company_store.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx';
import * as Client from '../../utils/client.jsx';
import * as Utils from '../../utils/utils.jsx';
......@@ -27,7 +29,6 @@ export default class Companies extends React.Component {
this.getCompanies = this.getCompanies.bind(this);
this.getDomains = this.getDomains.bind(this);
this.getPlans = this.getPlans.bind(this);
this.getAdmins = this.getAdmins.bind(this);
this.gotoCompany = this.gotoCompany.bind(this);
}
......@@ -47,8 +48,8 @@ export default class Companies extends React.Component {
}
return Client.getAllCompanies().then((data) => {
const domains = data.map((d) => {
return self.getDomains(d);
const domains = data.map((company) => {
return self.getDomains(company);
});
return Promise.all(domains).then((comps) => {
......@@ -80,13 +81,17 @@ export default class Companies extends React.Component {
},
(data) => {
const domains = data.domain;
Promise.all([self.getPlans(domains), self.getAdmins(domains)]).
then(() => {
company.domains = domains;
if (domains) {
self.getPlans(domains).then(() => {
company.domains = domains;
resolve(company);
}).catch((error) => {
reject(error);
});
} else {
company.domains = [];
resolve(company);
}).catch((error) => {
reject(error);
});
}
},
(error) => {
reject(error);
......@@ -94,31 +99,6 @@ export default class Companies extends React.Component {
});
}
getAdmins(domains) {
return new Promise((resolve, reject) => {
const promises = domains.map((d) => {
return new Promise((solve, rej) => {
return d.getAdmins((err, admins) => {
if (err) {
return rej(err);
}
d.admins = admins.account;
return solve(d);
});
});
});
Promise.all(promises).
then((doms) => {
resolve(doms);
}).
catch((error) => {
reject(error);
});
});
}
getPlans(domains) {
const names = domains.map((d) => {
return d.name;
......@@ -155,6 +135,7 @@ export default class Companies extends React.Component {
}
let panelBody;
let noLimitError;
if (this.state.companies.length === 0) {
panelBody = (
<div className='center-block text-center'>
......@@ -168,17 +149,43 @@ export default class Companies extends React.Component {
);
} else {
const rows = this.state.companies.map((c) => {
const plans = Utils.getPlansFromDomains(c.domains);
const cos = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
const plansString = [];
const totalBought = Object.keys(plans).reduce((prev, current) => {
const limit = plans[current].limit;
const domains = c.domains;
const planKeys = Object.keys(cos).map((cosKey) => {
return cos[cosKey];
});
const plans = {};
plansString.push(`${limit} ${Utils.titleCase(current.slice(0, 3))}`); //eslint-disable-line no-undefined
planKeys.forEach((key) => {
plans[key] = 0;
});
if (plans[prev]) {
return plans[prev].limit + limit;
domains.forEach((d) => {
const domainCos = d.maxAccountsByCos();
if (domainCos) {
Object.keys(domainCos).forEach((id) => {
const limit = domainCos[id];
plans[cos[id]] += limit;
});
} else if (!noLimitError) {
noLimitError = (
<MessageBar
message='Existen dominios sin límites asignados'
type='WARNING'
autoclose={true}
/>
);
}
return limit;
});
let totalBought = 0;
planKeys.forEach((key) => {
const limit = plans[key];
plansString.push(`${limit} ${Utils.titleCase(key.slice(0, 3))}`); //eslint-disable-line no-undefined
totalBought += limit;
});
return (
<tr key={c.id}>
......@@ -203,6 +210,7 @@ export default class Companies extends React.Component {
</tr>
);
});
panelBody = (
<div className='table-responsive'>
<div className='table-responsive'>
......@@ -232,6 +240,7 @@ export default class Companies extends React.Component {
titlePage='Empresas'
descriptionPage='Las empresas son los que pagan el servicio'
/>
{noLimitError}
<div className='content animate-panel'>
<div className='row'>
<div className='col-md-12 central-content'>
......
......@@ -3,10 +3,13 @@
import React from 'react';
import _ from 'lodash';
import Promise from 'bluebird';
import Panel from '../panel.jsx';
import StatusLabel from '../status_label.jsx';
import CompanyStore from '../../stores/company_store.jsx';
import * as Utils from '../../utils/utils.jsx';
export default class CompanyAdmins extends React.Component {
......@@ -14,107 +17,173 @@ export default class CompanyAdmins extends React.Component {
super(props);
this.getCompanyAdmins = this.getCompanyAdmins.bind(this);
this.getAdmins = this.getAdmins.bind(this);
this.state = this.getCompanyAdmins();
this.state = {};
}
getAdmins(domains) {
return new Promise((resolve, reject) => {
const promises = domains.map((d) => {
return new Promise((solve, rej) => {
return d.getAdmins((err, admins) => {
if (err) {
return rej(err);
}
d.admins = admins.account;
return solve(d);
});
});
});
return Promise.all(promises).
then((doms) => {
return resolve(doms);
}).
catch((error) => {
return reject(error);
});
});
}
getCompanyAdmins() {
const domains = this.props.company.domains;
const company = this.props.company;
const domains = company.domains;
const admins = [];
const domainsArray = [];
if (domains) {
domains.forEach((d) => {
if (d.admins) {
Reflect.apply(Array.prototype.push, admins, d.admins);
} else {
domainsArray.push(d);
}
});
}
return {
if (domainsArray.length > 0) {
return this.getAdmins(domainsArray).
then((doms) => {
doms.forEach((d) => {
if (!d.admins) {
d.admins = [];
}
CompanyStore.addDomainAdmins(company.id, d);
Reflect.apply(Array.prototype.push, admins, d.admins);
});
return this.setState({
admins: _.uniqBy(admins, 'id')
});
}).
catch(() => {
return this.setState({
error: {
message: 'No pudimos obtener los admins de los dominios',
type: 'ERROR'
}
});
});
}
return this.setState({
admins: _.uniqBy(admins, 'id')
};
});
}
componentDidMount() {
this.getCompanyAdmins();
}
render() {
const admins = this.state.admins;
const error = this.state.error;
let panelBody;
if (admins.length > 0) {
const rows = admins.map((a) => {
let globalAdmin = a.attrs.zimbraIsAdminAccount === 'TRUE';
let adminClass = '';
if (globalAdmin) {
adminClass = 'btn btn-xs btn-danger';
globalAdmin = 'global admin';
} else {
adminClass = 'btn btn-xs btn-info';
globalAdmin = 'domain admin';
}
if (admins || error) {
let panelBody;
if (!error && admins.length > 0) {
const rows = admins.map((a) => {
let globalAdmin = a.attrs.zimbraIsAdminAccount === 'TRUE';
let adminClass = '';
if (globalAdmin) {
adminClass = 'btn btn-xs btn-danger';
globalAdmin = 'global admin';
} else {
adminClass = 'btn btn-xs btn-info';
globalAdmin = 'domain admin';
}
return (
<tr
key={`admin-${a.id}`}
className='user-row'
>
<td className='user-email'>
{a.name}
</td>
<td className='user-name text-center'>
{a.attrs.cn} {a.attrs.sn}
</td>
<td className='user-type text-center'>
<StatusLabel
classes={adminClass}
children={globalAdmin}
/>
</td>
<td className='user-actions text-center'>
<a
className='btn btn-default btn-xs'
href='#'
onClick={(e) => Utils.handleLink(e, `/mailboxes/${a.id}/edit`, this.props.location)}
>
{'Editar'}
</a>
</td>
</tr>
);
});
panelBody = (
<div className='table-responsive'>
<table
cellPadding='1'
cellSpacing='1'
className='table table-condensed table-striped vertical-align'
>
<thead>
<tr>
<th>{'email'}</th>
<th className='td-mbxs text-center'>{'Nombre'}</th>
<th className='text-center'>{'Perfil'}</th>
<th className='text-center'>{'Acciones'}</th>
return (
<tr
key={`admin-${a.id}`}
className='user-row'
>
<td className='user-email'>
{a.name}
</td>
<td className='user-name text-center'>
{a.attrs.cn} {a.attrs.sn}
</td>
<td className='user-type text-center'>
<StatusLabel
classes={adminClass}
children={globalAdmin}
/>
</td>
<td className='user-actions text-center'>
<a
className='btn btn-default btn-xs'
href='#'
onClick={(e) => Utils.handleLink(e, `/mailboxes/${a.id}/edit`, this.props.location)}
>
{'Editar'}
</a>
</td>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
);
} else {
panelBody = (
<div className='empty-message text-danger'>
<h4>
{'Esta empresa no tiene administradores de dominio registrados.'}
</h4>
</div>
);
});
panelBody = (
<div className='table-responsive'>
<table
cellPadding='1'
cellSpacing='1'
className='table table-condensed table-striped vertical-align'
>
<thead>
<tr>
<th>{'email'}</th>
<th className='td-mbxs text-center'>{'Nombre'}</th>
<th className='text-center'>{'Perfil'}</th>
<th className='text-center'>{'Acciones'}</th>
</tr>
</thead>
<tbody>
{rows}
</tbody>
</table>
</div>
);
} else {
panelBody = (
<div className='empty-message text-danger'>
<h4>
{'Esta empresa no tiene administradores de dominio registrados.'}
</h4>
</div>
);
}
return (
<Panel
hasHeader={false}
children={panelBody}
/>
);
}
return (
<Panel
hasHeader={false}
children={panelBody}
/>
);
return <div/>;
}
}
......
......@@ -32,7 +32,6 @@ export default class CompaniesDetails extends React.Component {
this.getCompany = this.getCompany.bind(this);
this.getDomains = this.getDomains.bind(this);
this.getAdmins = this.getAdmins.bind(this);
this.getPlans = this.getPlans.bind(this);
}
......@@ -76,7 +75,7 @@ export default class CompaniesDetails extends React.Component {
},
(data) => {
const domains = data.domain;
Promise.all([self.getPlans(domains), self.getAdmins(domains)]).
self.getPlans(domains).
then(() => {
company.domains = domains;
resolve(company);
......@@ -90,30 +89,6 @@ export default class CompaniesDetails extends React.Component {
});
}
getAdmins(domains) {
return new Promise((resolve, reject) => {
const promises = domains.map((d) => {
return new Promise((solve, rej) => {
return d.getAdmins((err, admins) => {
if (err) {
return rej(err);
}
d.admins = admins.account;
return solve(d);
});
});
});
Promise.all(promises).
then((doms) => {
resolve(doms);
}).
catch((error) => {
reject(error);
});
});
}
getPlans(domains) {
const names = domains.map((d) => {
return d.name;
......
......@@ -4,6 +4,7 @@
import React from 'react';
import UserStore from '../../stores/user_store.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx';
import Panel from '../panel.jsx';
import StatusLabel from '../status_label.jsx';
......@@ -21,7 +22,7 @@ export default class CompanyDomains extends React.Component {
label: 'Agregar Dominio',
props: {
className: 'btn btn-default btn-xs',
onClick: (e) => Utils.handleLink(e, '/domains/new', this.props.location)
onClick: (e) => Utils.handleLink(e, `/companies/${this.props.company.id}/domains/new`, this.props.location)
}
}];
}
......@@ -47,15 +48,30 @@ export default class CompanyDomains extends React.Component {
}
let totalAccounts = 0;
const plans = Utils.getPlansFromDomain(d);
const cos = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
const planKeys = Object.keys(cos).map((cosKey) => {
return cos[cosKey];
});
const plans = {};
planKeys.forEach((key) => {
plans[key] = 0;
});
const domainCos = d.maxAccountsByCos();
if (domainCos) {
Object.keys(domainCos).forEach((id) => {
const limit = domainCos[id];
plans[cos[id]] += limit;
});
}
const plansArray = Object.keys(plans).map((p) => {
const limit = plans[p].limit;
const plansArray = planKeys.map((key) => {
const limit = plans[key];
totalAccounts += limit;
return (
<li key={`domain-${d.id}-${p}`}>
{limit} {Utils.titleCase(p.slice(0, 3))}
<li key={`domain-${d.id}-${key}`}>
{limit} {Utils.titleCase(key.slice(0, 3))}
</li>
);
});
......
......@@ -3,8 +3,11 @@
import React from 'react';
import MessageBar from '../message_bar.jsx';
import Panel from '../panel.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx';
import * as Utils from '../../utils/utils.jsx';
export default class CompanyMailboxPlans extends React.Component {
......@@ -29,8 +32,55 @@ export default class CompanyMailboxPlans extends React.Component {
];
const mailboxPlans = [];
const cos = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
const planKeys = Object.keys(cos).map((c) => {
return cos[c];
});
const domains = company.domains;
const plans = Utils.getPlansFromDomains(domains);
const plans = {};
let noLimitError;
planKeys.forEach((key) => {
plans[key] = {
limit: 0,
used: 0,
free: 0,
noLimit: false
};
});
domains.forEach((d) => {
const domainCos = d.maxAccountsByCos();
const domainPlans = Utils.getPlansFromDomain(d);
let used = 0;
if (domainCos) {
Object.keys(domainCos).forEach((id) => {
const limit = domainCos[id];
used = domainPlans[cos[id]].used;
plans[cos[id]].limit += limit;
plans[cos[id]].used += used;
plans[cos[id]].free += (limit - used);
});
} else {
if (!noLimitError) {
noLimitError = (
<MessageBar
message='Existen dominios sin límites asignados'
type='WARNING'
autoclose={true}
/>
);
}
Object.keys(domainPlans).forEach((id) => {
used = domainPlans[id].used;
plans[id].noLimit = true;
plans[id].used += used;
});
}
});
for (const key in plans) {
if (plans.hasOwnProperty(key)) {
......@@ -42,12 +92,12 @@ export default class CompanyMailboxPlans extends React.Component {
const plan = plans[key];
limit = plan.limit;
used = plan.used;
if (limit) {
free = limit - used;
percent = Math.round((used * 100) / limit);
} else {
if (plan.noLimit) {
limit = free = '\u221e';
percent = 100;
} else {
free = limit - used;
percent = Math.round((used * 100) / limit);
}
if (percent <= 10) {
......@@ -112,6 +162,7 @@ export default class CompanyMailboxPlans extends React.Component {
<Panel
title='Casillas'
btnsHeader={headerButtons}
error={noLimitError}
children={panelBody}
/>
);
......
This diff is collapsed.
......@@ -3,8 +3,11 @@
import React from 'react';
import MessageBar from '../message_bar.jsx';
import Panel from '../panel.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx';
import * as Utils from '../../utils/utils.jsx';
export default class DomainMailboxPlans extends React.Component {
......@@ -61,15 +64,56 @@ export default class DomainMailboxPlans extends React.Component {
];
const mailboxPlans = [];
const plans = this.state.plans;
const configPlans = global.window.manager_config.plans;
const cos = Utils.getEnabledPlansByCosId(ZimbraStore.getAllCos());
const planKeys = Object.keys(cos).map((c) => {
return cos[c];
});
const domain = this.props.domain;
const domainCos = domain.maxAccountsByCos();
const domainPlans = Utils.getPlansFromDomain(domain);
const plans = {};
let noLimitError;
let totalUsed = 0;
let totalLimit = 0;
planKeys.forEach((key) => {
plans[key] = {
limit: 0,
used: 0
};
});
let used = 0;
if (domainCos) {
Object.keys(domainCos).forEach((id) => {
const limit = domainCos[id];
used = domainPlans[cos[id]].used;
plans[cos[id]].limit += limit;
plans[cos[id]].used += used;
});
}
for (const key in plans) {
if (plans.hasOwnProperty(key) && configPlans[key]) {
if (plans.hasOwnProperty(key)) {
const plan = plans[key];
totalUsed += plan.used;
totalLimit += plan.limit || 0;
if (plan.limit === 0) {
totalLimit = '\u221e';
if (!noLimitError) {
noLimitError = (
<MessageBar
message='Existen dominios sin límites asignados'
type='WARNING'
autoclose={true}
/>
);
}
} else {
totalLimit += plan.limit;
}
mailboxPlans.push(
<tr key={`plan-${key}`}>
<td className='mbx-plan'
......@@ -105,7 +149,7 @@ export default class DomainMailboxPlans extends React.Component {
className='text-center'
style={{borderTop: 0}}
>
<strong>{totalLimit || '\u221e'}</strong>
<strong>{totalLimit}</strong>
</td>
<td
className='text-center'
......@@ -141,6 +185,7 @@ export default class DomainMailboxPlans extends React.Component {
<Panel
title='Casillas'
btnsHeader={headerButtons}
error={noLimitError}
children={panelBody}
/>
);
......
......@@ -3,6 +3,7 @@
import $ from 'jquery';
import React from 'react';
import Promise from 'bluebird';
import MessageBar from '../message_bar.jsx';
import PageInfo from '../page_info.jsx';
......@@ -42,42 +43,51 @@ export default class Domains extends React.Component {
},
(data) => {
const domains = data.domain;
const plans = domains.map((d) => {
return self.getPlans(d);
this.getPlans(domains).
then(() => {
self.setState({
data
});
}).
catch(() => {
this.setState({
error: {
message: 'No se obtuvieron los planes de las cuentas',
type: messageType.ERROR
}
});
}).
finally(() => {
GlobalActions.emitEndLoading();
});
Promise.all(plans).then(
() => {
self.setState({
data
});
GlobalActions.emitEndLoading();
},
() => {
this.setState({
error: 'No se obtuvieron los planes de las cuentas'
});
GlobalActions.emitEndLoading();
}
);
},
(error) => {
this.setState({
error: error.message
error: {
message: error.message,
type: messageType.ERROR
}
});
GlobalActions.emitEndLoading();
}
);
}
getPlans(domain) {
getPlans(domains) {
const names = domains.map((d) => {
return d.name;
});
return new Promise((resolve, reject) => {
Client.countAccounts(domain.name,
(info) => {
domain.plans = info;
resolve();
return Client.batchCountAccount(
names,
(data) => {
domains.forEach((d, i) => {
d.plans = data[i];
});
resolve(domains);
},
() => {
reject();
(error) => {
reject(error);
}
);
});
......@@ -105,12 +115,13 @@ export default class Domains extends React.Component {
}
render() {
const error = this.state.error;
let message;
if (this.state.error) {
if (error) {
message = (
<MessageBar
message={this.state.error}
type={messageType.WARNING}
message={error.message}
type={error.type}
autoclose={true}
/>
);
......
......@@ -6,6 +6,8 @@ import React from 'react';
import {browserHistory} from 'react-router';
import UserStore from '../../stores/user_store.jsx';
import ZimbraStore from '../../stores/zimbra_store.jsx';
import Constants from '../../utils/constants.jsx';
import * as Client from '../../utils/client.jsx';
......@@ -66,7 +68,12 @@ export default class Login extends React.Component {
Client.login(email, password,
() => {
browserHistory.push('/companies');
return Client.getAllCos(
(cosData) => {
ZimbraStore.setAllCos(cosData);
browserHistory.push('/companies');
}
);
},
(err) => {
this.setState({loginError: err.message});
......
......@@ -103,7 +103,7 @@ export default class MessageBar extends React.Component {
MessageBar.defaultProps = {
message: null,
type: 'error',
type: 'ERROR',
position: 'relative',
canClose: true,
autoclose: false,
......
......@@ -77,7 +77,17 @@ function onPreLoggedIn(nextState, replace, callback) {
global.window.Zimbra = ZimbraStore.getCurrent();
}
return callback();
const cos = ZimbraStore.getAllCos();
if (cos) {
return callback();
}
return Client.getAllCos(
(cosData) => {
ZimbraStore.setAllCos(cosData);
return callback();
}
);
},
(err) => {
let query;
......@@ -145,6 +155,10 @@ function renderRootComponent() {
path='companies/:id'
component={Company}
/>
<Route
path='companies/:id/domains/new'
component={CreateDomains}
/>
<Route
path='mailboxes'
......
......@@ -51,6 +51,66 @@ class CompanyStoreClass {
setCurrent(company) {
this.current = company;
}
addDomain(companyId, domain) {
const currentCompany = this.getCurrent();
const company = this.getCompanyById(companyId);
if (currentCompany && currentCompany.id === companyId) {
currentCompany.domains.push(domain);
if (company) {
this.companies[companyId] = currentCompany;
}
} else if (company) {
company.domains.push(domain);
}
}
addDomainAdmins(companyId, domain) {
function findDomain(company) {
const domains = company.domains;
let index = -1;
if (domains) {
domains.forEach((d, i) => {
if (d.id === domain.id) {
index = i;
return false;
}
return true;
});
}
return index;
}
function replaceDomain(company, index) {
if (index >= 0) {
company.domains[index] = domain;
} else {
company.domains.push(domain);
}
}
const currentCompany = this.getCurrent();
const company = this.getCompanyById(companyId);
let index = -1;
if (currentCompany && currentCompany.id === companyId) {
index = findDomain(currentCompany);
replaceDomain(currentCompany, index);
if (company) {
this.companies[companyId] = currentCompany;
}
} else if (company) {
index = findDomain(company);
replaceDomain(company, index);
}
}
}
const CompanyStore = new CompanyStoreClass();
......
......@@ -4,6 +4,7 @@
class ZimbraStoreClass {
constructor() {
this.zimbra = null;
this.cos = null;
}
getCurrent() {
......@@ -13,6 +14,14 @@ class ZimbraStoreClass {
setCurrent(zimbra) {
this.zimbra = zimbra;
}
setAllCos(cos) {
this.cos = cos;
}
getAllCos() {
return this.cos;
}
}
var ZimbraStore = new ZimbraStoreClass();
......
......@@ -228,6 +228,25 @@ export function getDomain(id, success, error) {
);
}
export function createDomain(domain, success, error) {
initZimbra().then(
(zimbra) => {
zimbra.createDomain(domain.name, domain.attrs, (err, data) => {
if (err) {
const e = handleError('createDomain', err);
return error(e);
}
return success(data);
});
},
(err) => {
const e = handleError('createDomain', err);
return error(e);
}
);
}
export function addDistributionList(name, attrs, success, error) {
initZimbra().then(
(zimbra) => {
......@@ -500,7 +519,9 @@ export function getAllCos(success, error) {
zimbra.getAllCos((err, data) => {
if (err) {
const e = handleError('getAllCos', err);
return error(e);
if (error) {
return error(e);
}
}
return success(data);
......@@ -508,7 +529,11 @@ export function getAllCos(success, error) {
},
(err) => {
const e = handleError('getAllCos', err);
return error(e);
if (error) {
return error(e);
}
return null;
}
);
}
......@@ -3,7 +3,9 @@
import {browserHistory} from 'react-router';
import * as GlobalActions from '../action_creators/global_actions.jsx';
import CONSTANTS from './constants.jsx';
import Constants from './constants.jsx';
const messageType = Constants.MessageType;
export function setCookie(cname, cvalue) {
localStorage.setItem(cname, cvalue);
......@@ -178,7 +180,7 @@ export function validateInputRequired(refs) {
}
const Error = {
message,
typeError: 'warning',
typeError: messageType.ERROR,
node: refs[ref]
};
......@@ -210,7 +212,7 @@ export function dateFormatted(dateString, isShortDate, separator) {
const year = date.substr(0, 4);
const month = (isShortDate) ? date.substr(4, 2) : parseInt(date.substr(4, 2), 10);
const day = date.substr(6, 2);
let dateFormattedString = `${day} de ${CONSTANTS.MONTHS[month - 1]} de ${year}`;
let dateFormattedString = `${day} de ${Constants.MONTHS[month - 1]} de ${year}`;
if (isShortDate) {
dateFormattedString = `${day}${separator}${month}${separator}${year}`;
......@@ -295,3 +297,17 @@ export function getEnabledPlansByCos(cosArray) {
return plans;
}
export function getEnabledPlansByCosId(cosArray) {
const configPlans = global.window.manager_config.plans;
const plans = {};
cosArray.forEach((cos) => {
const key = cos.name;
if (configPlans.hasOwnProperty(key) && configPlans[key]) {
plans[cos.id] = key;
}
});
return plans;
}
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