Computools Review

My company has paid Computools over $45,000 for 5 webpages that still don’t work and suffered over $150,000 in losses due to Computools incompetence.

 

I hired a backend Java coder employed by Computools over two years ago. He has done a good job.

 

So, when I had a new project that related to the server, I hired Computools to write the custom code for a few WIX pages.

 

I provided Computools with the Wix pages with the UI already done and explicit instructions on how the pages should work.

 

The concept was not that hard, and the coding should have taken about 2 months to complete and another month to polish. It is now 7 months later, and 3 of the 5 web pages still have catastrophic bugs.

 

The code Computools wrote was done so unprofessionally with not a single line of comment or documentation that even after 6 and a half months none of the primary pages have ever worked properly. Months and months of time was spent chasing bugs only to have the fix cause more bugs.

 

Computools repeatedly mislead me to believe the problems were problems on the WIX site.

 

After 6 and a half months Computools fired me as a client effectively leaving me with a website that did not work and code that was incomprehensible. I hired 4 professional coders to work a total of 24 hours a day to try and at least temporarily fix the website enough to have at least basic functionality working in time for the new year’s resolution fitness resolution buying time. They worked on it for 14 days straight and could not fix all the bugs with three of the 5 pages still not performing basic functionality. I paid Computools $45,000 so far for these pages, plus another $10,000 to the professionals I hired to try and temporarily fix the site, and put in at least a 1000 hours of my own time bug testing and Skype chatting with the programmers and project manager to try and get the project done on time.

 

It is now Dec 31 and we will miss the biggest days to market fitness products. I will have to start completely over and rewrite the website from scratch. My losses from Computools incompetence have caused losses to my company in excess of $150,000.

 

Here are the reviews written by the programmers I hired along with samples of the code they wrote.

Hi Brad,

I started working on lets-sync (Wix), in my 7.5 years of experience I have never seen this type of code quality.

Following are the standards which are not maintained

1. Comments on Code: I can see in code that there is no Single Comment, it is hard to understand for other developer if we won’t provide comment, Please see below code there is no Single comment and it is complex too.

Lets-sync_codingstandard 1.jpg

2. Written Complex Code and not provided any documentation

Lets-sync_codingstandard 2.jpg

3. There are some Dead code and commented code:

4. There are lots of Bug. If we click on 1 button and click on other button 1st button it stops working

5. There are no Spinner when data loading

Following Code Guide line should be followed:

  • • Coding Standard should be maintain

  • • Proper comment on each block

  • • Code should not be complex

  • • Proper documents should be maintain

  • • Code should be Bug Free

 

Thanks,

Ankit Jain,

Tech Lead

Lets-sync_codingstandard  3.jpg
Computools code review by  Junaid_Page_7
Computools code review by  Junaid_Page_1
Computools code review by  Junaid_Page_2
Computools code review by  Junaid_Page_3
Computools code review by  Junaid_Page_4
Computools code review by  Junaid_Page_6
Computools code review by  Junaid_Page_5

To Whom It May Concern:

     I was hired by Brad to help him fix some issues he was having with his site lets-sync.com. The first page I had to work on was the class build page under Yoga menu. I noticed that the coders did not name the buttons. There was button#1 - # 6. It almost seemed as if that did not want to name the buttons to confuse the person that they were building the site for. Could this have been a way to keep the customer a customer? All good coders know that you name things which make sense on what they do, so that when the next person comes along it easier to know what the button does or the purpose the function. When coder do this, it is just being lazy, or it is to keep the customer in the dark. I am a freelancer and even though it would be great to keep a customer a customer all the time it is wrong to do so. I feel like this can give other freelancers a bad rep and it is already hard enough to make it is on your own. Please consider refunding Brad his money.

Thank you

Dustin Cox

Full Stack Engineer

Dustin Cox Resume2020_Page_1.png
Dustin Cox Resume2020_Page_2.png
Dustin Cox Resume2020_Page_3.png

This is an example of the code written by Computools. Please note that there are no comments, buttons are not named, in this code, there is abandon code that was not even commented out. There are many dependencies, so fixing one thing causes several other things to break. Before I could use the website most of the code Computools wrote had to be completely rewritten.

import wixData from 'wix-data';

import wixUsers from 'wix-users';

import wixWindow from 'wix-window';

 

let members = [];

let currentPage = 0;

let totalPages = 0;

let exercises = [];

let totalExercises = 0;

let currentPageExercises = 0;

let nextExercises = [];

let transitions = [];

let currontExercise = null

const exerciseStyleCollection = 'ExerciseStyle';

 

const levelsName = ['Beginner', 'Intermediate', 'Advanced'];

 

$w.onReady(async () => {

const user = wixUsers.currentUser;

getTeacherOptions();

getExercisesStyles().then(styles => {

$w("#exerciseStyle").options = transformStylesToDisplay(styles);

})

$w('#repeater1').data = [];

$w('#asanaRecord').collapse();

$w('#asanaList').collapse();

$w('#asanaList').data = [];

 

wixData.query("Exercises")

.count()

.then((num) => {

totalExercises = num;

})

.catch( (error) => {

console.log(error, 'ERROR');

} );

 

wixData.query("Exercises")

.eq('beginnerRef', 1)

.limit(1)

.find()

.then((res) => {

currontExercise = res.items[0];

})

.catch( (error) => {

console.log(error, 'ERROR');

} );

 

user.getRoles()

.then(roles => {

let isAdmin = roles.map(function(e) { return e.name; }).indexOf('Admin');

let isUpload = roles.map(function(e) { return e.name; }).indexOf('Upload_admin');

if (isAdmin >= 0 || isUpload >= 0) {

$w('#addTeacher').expand();

} else {

$w('#addTeacher').collapse();

user.getEmail()

// .then( (email) => {

// $w('#teacher').value = email;

// } );

}

})

 

$w('#repeater1').onItemReady(async ($item, itemData, index) => {

$item('#ref').value = itemData.number;

$item('#asanaName').value = itemData.title;

$item('#audioName').value = itemData.audioTitle ? itemData.audioTitle : null;

$item('#audioName').resetValidityIndication();

if (itemData.audio) {

$item('#audioAsana').src = itemData.audio;

$item('#audioAsana').show();

} else {

if ($item('#audioAsana').src) {

$item('#audioAsana').src = '';

}

$item('#audioAsana').hide();

let isHidden = $w("#audioAsana").hidden

console.log('audioAsana hide', isHidden);

}

 

$item('#uploadButton').on('uploadedFile', async (event) => {

let data = event.detail.data;

if (data.url) {

$item('#audioName').value = data.name;

let toSave;

if (itemData.custom) {

toSave = {...itemData.custom, audio: data.url, audioTitle: data.name, convertedLink: data.changedUrl, duration: data.duration};

} else {

toSave = {

userEmail: $w('#teacher').value,

rootExercise: itemData.exercises,

exerciseLevel: itemData._id,

audio: data.url,

audioTitle: data.name,

exerciseStyleId: $w('#exerciseStyle').value,

convertedLink: data.changedUrl,

duration: data.duration,

}

}

let element = await saveData('CustomExercises', toSave);

let levels = $w('#repeater1').data;

levels[index] = {...itemData, custom: element, audio: data.url, audioTitle: data.name};

$w('#repeater1').data = [];

$w('#repeater1').data = levels;

}

})

});

 

$w('#asanaList').onItemReady(async ($item, itemData, index) => {

let isChecked = false;

if (nextExercises.length > 0) {

isChecked = nextExercises.find(element => element.exerciseNextId === itemData._id);

}

let transition = null;

if (transitions.length > 0) {

transition = transitions.find(element => (element.startAsana === currontExercise._id && element.endAsana._id === itemData._id));

}

 

$item('#exerciseName').text = itemData.title;

$item('#checkbox1').checked = isChecked ? true : false;

// $item('#refNumbers').text = itemData.levels[0].number+' - '+itemData.levels[itemData.levels.length - 1].number

let startStr = String(itemData.beginnerRef);

let endStr = String(itemData.advancedRef);

$item('#refNumbers').text = (startStr.length <= 2 ? (startStr.length < 2 ? '00'+startStr : '0'+startStr) : startStr)+' - '+(endStr.length <= 2 ? (endStr.length < 2 ? '00'+endStr : '0'+endStr) : endStr);

if ($item('#checkbox1').checked) {

$item('#uploadTransition').show();

$item('#transitionLink').show();

$item('#transitionRecord').show();

$item('#fullRecord').show();

$item('#transitionLink').value = transition ? transition.audioName : '';

if (transition && transition.audioUrl) {

$item('#audioTransation').src = transition.audioUrl;

$item('#audioTransation').show();

$item('#removeTransition').show();

$item('#star').show();

} else {

$item('#removeTransition').hide();

$item('#audioTransation').hide();

$item('#star').hide();

}

} else {

$item('#uploadTransition').hide();

$item('#transitionLink').hide();

$item('#audioTransation').hide();

$item('#removeTransition').hide();

$item('#star').hide();

$item('#transitionRecord').hide();

$item('#fullRecord').hide();

}

 

$item('#goTo').onClick(event => {

currontExercise = itemData;

exerciseDataset_currentIndexChanged();

// goToExercises(itemData.levels);

});

 

$item('#checkbox1').onChange(async (event) => {

$item('#checkbox1').disable();

await updateRecommendedAsanas($item('#checkbox1').checked, currontExercise._id, itemData._id).then((value) => {

$item('#checkbox1').enable();

 

if ($item('#checkbox1').checked) {

$item('#uploadTransition').show();

$item('#transitionLink').show();

$item('#transitionRecord').show();

$item('#fullRecord').show();

$item('#transitionLink').value = transition ? transition.audioName : '';

if (transition && transition.audioUrl) {

$item('#audioTransation').src = transition.audioUrl;

$item('#audioTransation').show();

$item('#removeTransition').show();

$item('#star').show();

} else {

$item('#removeTransition').hide();

$item('#audioTransation').hide();

$item('#star').hide();

}

} else {

$item('#uploadTransition').hide();

$item('#transitionLink').hide();

$item('#audioTransation').hide();

$item('#removeTransition').hide();

$item('#star').hide();

$item('#transitionRecord').hide();

$item('#fullRecord').hide();

}

});

});

 

$item('#removeTransition').onClick(async (event) => {

let rmTransition = await getTransition(currontExercise._id, itemData._id);

if (rmTransition) {

wixData.remove('exerciseTransitions', rmTransition._id)

.then( (results) => {

$item('#transitionLink').value = '';

$item('#removeTransition').hide();

$item('#audioTransation').hide();

$item('#star').hide();

} )

.catch( (err) => {

let errorMsg = err;

} );

}

})

 

$item('#uploadTransition').on('uploadedFile', async (event) => {

let data = event.detail.data;

if (data.url) {

$item('#transitionLink').value = data.name;

let toSave;

let upTransition = await getTransition(currontExercise._id, itemData._id);

if (upTransition) {

toSave = {...upTransition, audioUrl: data.url, audioName: data.name, duration: data.duration, convertedLink: data.changedUrl};

} else {

toSave = {

userEmail: $w('#teacher').value,

exerciseStyleId: $w('#exerciseStyle').value,

startAsana: currontExercise._id,

endAsana: itemData._id,

audioUrl: data.url,

audioName: data.name,

duration: data.duration,

convertedLink: data.changedUrl

}

}

let element = await saveData('exerciseTransitions', toSave);

$item('#transitionLink').value = data.name;

$item('#audioTransation').src = data.url;

$item('#audioTransation').show();

$item('#removeTransition').show();

$item('#star').show();

}

});

 

$item('#transitionRecord').onClick(async event => {

$item('#transitionRecord').disable();

let files = [];

transition = await getTransition(currontExercise._id, itemData._id);

let link = null;

if (transition) {

link = transition.audioUrl;

}

files.push({

name: getRenderTransitionName(currontExercise.beginnerRef, currontExercise.title, itemData.beginnerRef, itemData.title),

link

});

$w("#recordFiles").postMessage({files});

})

 

$item('#fullRecord').onClick(async event => {

$item('#fullRecord').disable();

let files = [];

let nextCustoms = await getCustomExercises(itemData._id);

// let asanas = $w('#repeater1').data;

 

// asanas.map((item, i) => {

// files.push({

// name: getRenderAsanaName(item.number, currontExercise.title, levelsName[i]),

// link: item.audio ? item.audio : false

// });

// })

if (nextCustoms) {

wixData.query("ExercisesByLevel")

.ascending('number')

.eq('exercises', itemData._id)

.limit(3)

.find()

.then((results) => {

let levels = results.items;

if (levels && levels.length > 0) {

levels.forEach((item, i) => {

let custom = [];

if (nextCustoms && nextCustoms.length > 0) {

custom = nextCustoms.filter(el => el.exerciseLevel === item._id);

}

files.push({name: getRenderAsanaName(item.number, itemData.title, levelsName[i]), link: custom.length > 0 ? custom[0].audio: false});

})

}

 

files.push({name: getRenderTransitionName(currontExercise.beginnerRef, currontExercise.title, itemData.beginnerRef, itemData.title), link: false});

$w("#recordFiles").postMessage({files});

})

} else {

files.push({name: getRenderAsanaName(itemData.beginnerRef, itemData.title, 'Beginner'), link: false});

files.push({name: getRenderAsanaName(itemData.intermediateRef, itemData.title, 'Intermediate'), link: false});

files.push({name: getRenderAsanaName(itemData.advancedRef, itemData.title, 'Advanced'), link: false});

 

files.push({name: getRenderTransitionName(currontExercise.beginnerRef, currontExercise.title, itemData.beginnerRef, itemData.title), link: false});

$w("#recordFiles").postMessage({files});

}

})

})

 

$w("#recordFiles").onMessage((event) => {

if (event.data.finished) {

$w('#asanaRecord').enable();

$w('#transitionRecord').enable();

$w('#fullRecord').enable();

}

});

});

 

export async function getExercisesSelector (page) {

return new Promise((resolve, reject) => {

const exLimit = 1000;

wixData.query('Exercises')

.ascending('title')

.skip(page * exLimit)

.limit(exLimit)

.find()

.then( async (results) => {

let items = results.items;

for (let index = 0; index < items.length; index++) {

let element = items[index];

 

exercises.push({...element});

$w('#asanaList').data = exercises;

if ($w('#asanaList').collapsed) {

$w('#asanaList').expand();

}

}

resolve(true);

})

.catch( (err) => {

reject(err);

});

});

}

 

function getExerciseLevels (id) {

return new Promise((resolve, reject) => {

wixData.query('ExercisesByLevel')

.ascending('number')

.eq('exercises', id)

.limit(3)

.find()

.then( async (results) => {

resolve(results.items);

})

.catch( (err) => {

reject(err);

});

});

}

 

export function getTeacherOptions () {

$w("#teacherDataset").onReady( () => {

getUserEmail('teacherDataset', 0);

} );

// $w("#members").onReady( () => {

// getUserEmail('members', 0);

// } );

}

 

function getUserEmail (dataset, start, value = false) {

$w("#"+dataset).getItems(start, 1000)

.then( (result) => {

let items = result.items;

let totalCount = result.totalCount;

items.forEach(item => {

if (!members.find(element => {return element.value === item.loginEmail})) {

let label = (item.firstName || item.lastName) ? item.firstName + ' ' + item.lastName : item.title

if (!label || label === ' ') {

label = item.loginEmail;

}

members.push({label: label, value: item.loginEmail})

}

});

if (totalCount > start+1000) {

getUserEmail(dataset, start+1000);

} else {

$w('#teacher').options = members;

}

} )

.catch( (err) => {

let errMsg = err.message;

let errCode = err.code;

} );

}

 

async function saveData(collection, toSave) {

return new Promise((resolve, reject) => {

wixData.save(collection, toSave)

.then((element) => {

resolve(element);

}).catch((err) => {

console.log("UPLOAD ERROR", JSON.stringify(err));

resolve(false);

})

});

}

 

export function addTeacher_click(event) {

wixWindow.openLightbox("addExerciseTeacher")

.then(data => {

if(data && data.name && data.loginEmail) {

members.push({label: data.name, value: data.loginEmail});

$w('#teacher').options = members;

$w('#teacher').value = data.loginEmail;

}

})

}

 

export async function exerciseDataset_currentIndexChanged() {

beforeUpdateAsana();

 

if ($w('#teacher').value !== '' && $w('#exerciseStyle').value !== '') {

$w('#repeater1').data = [];

wixData.query("ExercisesByLevel")

.ascending('number')

.eq('exercises', currontExercise._id)

.limit(3)

.find()

.then(async (results) => {

let levels = results.items;

if (levels && levels.length > 0) {

let customs = await getCustomExercises(currontExercise._id);

let repeterData = [];

let custom = [];

levels.forEach(item => {

custom = [];

if (customs && customs.length > 0) {

custom = customs.filter(el => el.exerciseLevel === item._id);

if (custom && custom.length > 0) {

repeterData.push({...item, custom: custom[0], audio: custom[0].audio, audioTitle: custom[0].audioTitle});

} else {

repeterData.push({...item});

}

} else {

repeterData.push({...item});

}

})

$w('#repeater1').data = repeterData;

$w('#asanaRecord').expand();

nextExercises = await getRecommendedAsanas(currontExercise._id);

transitions = await getTransitions(currontExercise._id);

if ($w('#asanaList').data.length === 0) {

await getExercisesSelector(currentPageExercises).then(() => {

$w('#button2').show();

})

} else {

asanaListUpdate();

$w('#asanaList').expand();

}

}

 

checkNavigateButtons();

})

}

}

 

function asanaListUpdate () {

$w('#asanaList').forEachItem(($item, itemData, index) => {

setTimeout(function() {

let isChecked = nextExercises.find(element => element.exerciseNextId === itemData._id);

let transition = transitions.find(element => (element.startAsana === currontExercise._id && element.endAsana._id === itemData._id));

if ($item('#checkbox1').checked !== !!isChecked) {

$item('#checkbox1').checked = isChecked ? true : false;

}

if ($item('#checkbox1').checked) {

$item('#uploadTransition').show();

$item('#transitionLink').show();

$item('#transitionLink').value = transition ? transition.audioName : '';

$item('#transitionRecord').show();

$item('#fullRecord').show();

if (transition && transition.audioUrl) {

$item('#audioTransation').src = transition.audioUrl;

$item('#audioTransation').show();

$item('#removeTransition').show();

$item('#star').show();

} else {

$item('#removeTransition').hide();

$item('#audioTransation').hide();

$item('#star').hide();

}

} else {

$item('#uploadTransition').hide();

$item('#transitionLink').hide();

$item('#audioTransation').hide();

$item('#removeTransition').hide();

$item('#star').hide();

$item('#transitionRecord').hide();

$item('#fullRecord').hide();

}

}, 100)

 

});

}

 

async function getCustomExercises (id) {

return new Promise((resolve, reject) => {

wixData.query('CustomExercises')

.eq('rootExercise', id)

.eq('exerciseStyleId', $w('#exerciseStyle').value)

.eq('userEmail', $w('#teacher').value)

.find()

.then((result) => {

resolve(result.items);

})

 

});

}

 

export function nextAsana_click(event) {

wixData.query("Exercises")

.ascending('advancedRef')

.gt('advancedRef', currontExercise.advancedRef)

.limit(1)

.find()

.then((res) => {

console.log(res,'next')

if (res.items.length > 0) {

currontExercise = res.items[0];

exerciseDataset_currentIndexChanged();

} else {

$w('#nextAsana').disable();

}

})

.catch( (error) => {

console.log(error, 'ERROR');

} );

 

}

 

export function prevAsana_click(event) {

wixData.query("Exercises")

.descending('beginnerRef')

.lt('beginnerRef', currontExercise.beginnerRef)

.limit(1)

.find()

.then((res) => {

console.log(res,'prevAsana_click')

if (res.items.length > 0) {

currontExercise = res.items[0];

exerciseDataset_currentIndexChanged();

}

})

.catch( (error) => {

console.log(error, 'ERROR');

} );

}

 

async function getRecommendedAsanas (id) {

return new Promise((resolve, reject) => {

// wixData.queryReferenced('Exercises', id, 'nextExercises')

// .then( (results) => {

// if(results.items.length > 0) {

// resolve(results.items);

// } else {

// resolve([]);

// }

// } )

// .catch( (err) => {

// let errorMsg = err;

// } );

wixData.query('RecommendNextExercises')

.eq('exerciseId', id)

.limit(1000)

.find()

.then((results) => {

if(results.items.length > 0) {

resolve(results.items);

} else {

resolve([]);

}

})

.catch((err) => {

let errorMsg = err;

});

});

}

 

async function updateRecommendedAsanas (isChecked, exID, nextId) {

return new Promise((resolve, reject) => {

if (exID && nextId) {

if (isChecked) {

//insert

wixData.insert('RecommendNextExercises', {exerciseId: exID, exerciseNextId: nextId})

.then((result) => {

nextExercises.push(result);

resolve(true);

})

.catch(error => {

reject(error);

});

}else{

//remove

let recomendate = nextExercises.find(element => element.exerciseNextId === nextId);

let filtered = nextExercises.filter((element) => {

return element.exerciseNextId !== recomendate._id;

});

wixData.remove('RecommendNextExercises', recomendate._id)

.then(() => {

nextExercises = filtered;

resolve(true);

})

.catch(error => {

reject(error);

});

}

}

});

}

 

async function getTransitions (id) {

return new Promise((resolve, reject) => {

wixData.query('exerciseTransitions')

.eq('startAsana', id)

.eq('exerciseStyleId', $w('#exerciseStyle').value)

.eq('userEmail', $w('#teacher').value)

.include('endAsana')

.find()

.then( (results) => {

if(results.items.length > 0) {

resolve(results.items);

} else {

resolve([]);

}

} )

.catch( (err) => {

let errorMsg = err;

} );

});

}

 

async function getTransition (startId, endId) {

return new Promise((resolve, reject) => {

wixData.query('exerciseTransitions')

.eq('startAsana', startId)

.eq('endAsana', endId)

.eq('exerciseStyleId', $w('#exerciseStyle').value)

.eq('userEmail', $w('#teacher').value)

.limit(1)

.find()

.then( (results) => {

if(results.items.length > 0) {

resolve(results.items[0]);

} else {

resolve(false);

}

} )

.catch( (err) => {

let errorMsg = err;

} );

});

}

 

function beforeUpdateAsana () {

$w('#teacher').updateValidityIndication();

$w('#exerciseStyle').updateValidityIndication();

$w('#prevAsana').disable();

$w('#nextAsana').disable();

$w('#asanaList').collapse();

$w('#button2').hide();

}

 

function checkNavigateButtons() {

$w('#prevAsana').expand();

$w('#nextAsana').expand();

 

if (exercises.length === totalExercises) {

$w('#button2').hide();

} else {

$w('#button2').show();

}

 

if(currontExercise.beginnerRef !== 1) {

$w('#prevAsana').enable();

}

// if(currentPage !== (totalPages-1)) {

$w('#nextAsana').enable();

// }

}


 

export async function button2_click(event) {

currentPageExercises++;

$w('#button2').disable();

await getExercisesSelector(currentPageExercises).then(() => {

$w('#button2').enable();

if (exercises.length === totalExercises) {

$w('#button2').hide();

}

});

}

 

export function asanaRecord_click(event) {

$w('#asanaRecord').disable();

let files = [];

let asanas = $w('#repeater1').data;

asanas.map((item, i) => {

files.push({

name: getRenderAsanaName(item.number, currontExercise.title, levelsName[i]),

link: item.audio ? item.audio : false

});

})

 

$w("#recordFiles").postMessage({files});

}

 

function getRenderAsanaName(ref, title, level){

let asanaName = getRenderStartName(ref, title, 'A');

return asanaName+'-'+level+'-'+getRenderEndtName()+'.wav';

}

 

function getRenderTransitionName(ref1, title1, ref2, title2,){

let fromAsana = getRenderStartName(ref1, title1, 'T');

let toAsana = getRenderStartName(ref2, title2);

return fromAsana+'-'+toAsana+'-'+getRenderEndtName()+'.wav';

}

 

function getRenderStartName(ref, title, prefix = null){

let refNumber = String(ref);

title = title.replace(/ /g,"_")

refNumber = (refNumber.length <= 2 ? (refNumber.length < 2 ? '00'+refNumber : '0'+refNumber) : refNumber);

return prefix ? prefix+'-'+refNumber+'-'+title : refNumber+'-'+title;

}

function getRenderEndtName(ref, title){

let teachers = $w('#teacher').options;

let teacher = teachers.filter(el => el.value === $w('#teacher').value)[0].label;

let styleName = $w('#exerciseStyle').options.find(styleObj => styleObj.value === $w('#exerciseStyle').value).label;

teacher = teacher.replace(/ /g,"_")

styleName = styleName.replace(/ /g,"_")

 

return teacher+'-'+styleName;

}

 

function getExercisesStyles() {

return new Promise((resolve, reject) => {

wixData.query(exerciseStyleCollection).limit(1000).find().then(data => {

return resolve(data.items);

})

.catch(err => {

reject(err);

})

})

}

 

function transformStylesToDisplay(styles) {

if (Array.isArray(styles)) {

return styles.map(style => {

return {label: style.title, value: style._id}

})

}

return [];

}