Skip to content

Commit 7ba008e

Browse files
authored
Merge pull request #93 from BuildFire/ai-seeder
feat: Init AI state seeder
2 parents bd8bcb2 + 62adff1 commit 7ba008e

9 files changed

Lines changed: 283 additions & 33 deletions

File tree

control/content/app.services.js

Lines changed: 205 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,5 +247,209 @@
247247
buildfire.analytics.unregisterEvent('coupon_item_view_' + key);
248248
}
249249
};
250-
}]);;
250+
}]).factory('StateSeeder', ['TAG_NAMES', 'DataStore', 'RankOfLastItem', '$rootScope', '$timeout' ,function(TAG_NAMES, DataStore, RankOfLastItem, $rootScope, $timeout) {
251+
let itemsList;
252+
let stateSeederInstance;
253+
$rootScope.oldCouponsIds = [];
254+
let jsonTemplate = {
255+
items: [
256+
{
257+
title: "",
258+
summary: "",
259+
listImage: "",
260+
},
261+
],
262+
};
263+
let handleAIReq = function(isImport, err, data) {
264+
if (
265+
err ||
266+
!data ||
267+
typeof data !== "object" ||
268+
!Object.keys(data).length || !data.data || !data.data.items || !data.data.items.length
269+
) {
270+
return buildfire.dialog.toast({
271+
message: "Bad AI request, please try changing your request.",
272+
type: "danger",
273+
});
274+
}
275+
itemsList = data.data.items;
276+
//Check image URLs
277+
let coupons = itemsList.map(item => {
278+
return new Promise((resolve, reject) => {
279+
checkNotFoundImages(item.listImage ?? "", isImport).then(res => {
280+
if (res.isValid) {
281+
item.listImage = res.newURL;
282+
resolve(item);
283+
} else {
284+
reject('image URL not valid');
285+
}
286+
})
287+
})
288+
})
289+
290+
// Check image URLs
291+
Promise.allSettled(coupons).then(results => {
292+
itemsList = [];
293+
results.forEach(res => {
294+
if(res.status == 'fulfilled') {
295+
const coupon = res.value;
296+
if (coupon) {
297+
itemsList.push(coupon);
298+
}
299+
}
300+
})
301+
if (!itemsList.length) {
302+
stateSeederInstance?.requestResult?.complete();
303+
return buildfire.dialog.toast({
304+
message: "Bad AI request, please try changing your request.",
305+
type: "danger",
306+
});
307+
}
308+
309+
// reset old data
310+
checkOldData().then(() => {
311+
// save new data
312+
buildfire.messaging.sendMessageToWidget({ type: "ImportCSV", importing: true });
313+
let promises = itemsList.map((item, i) => {
314+
return new Promise((resolve, reject) => {
315+
itemsList[i] = _applyDefaults(itemsList[i]);
316+
RankOfLastItem.setRank(itemsList[i].rank);
317+
DataStore.insert(itemsList[i], TAG_NAMES.COUPON_ITEMS).then((res)=> {
318+
if (res) {
319+
$rootScope.oldCouponsIds.push(res.id);
320+
itemsList[i].deepLinkId = res.id,
321+
itemsList[i].deepLinkUrl = buildfire.deeplink.createLink({ id: res.id })
322+
new Deeplink({
323+
deeplinkId: res.id,
324+
name: res.data.title,
325+
imageUrl: res.data.listImage ? res.data.listImage : null,
326+
deeplinkData: {
327+
id: res.id,
328+
}
329+
}).save((err, deepLinkData) => {
330+
itemsList[i].deepLinkId = deepLinkData.deeplinkId;
331+
DataStore.update(res.id, itemsList[i], TAG_NAMES.COUPON_ITEMS).then(() => {
332+
})
333+
resolve();
334+
});
335+
}
336+
})
337+
338+
});
339+
})
340+
Promise.allSettled(promises).then(() => {
341+
$timeout(()=> {
342+
buildfire.messaging.sendMessageToWidget({ type: "ImportCSV", importing: false });
343+
$rootScope.reloadCoupons = true;
344+
})
345+
$rootScope.reloadCoupons = true;
346+
}).catch(err => console.warn('error while saving data: ', err))
347+
348+
})
349+
stateSeederInstance?.requestResult?.complete();
350+
})
351+
}
352+
353+
// UTILITIES
354+
let _applyDefaults = function(item) {
355+
if (item.title) {
356+
return {
357+
title: item.title,
358+
summary: item.summary || "",
359+
listImage: item.listImage || "",
360+
startOn: Date.now(),
361+
expiresOn: Math.trunc(Date.now() + Math.random() * 8640000000),
362+
links: [],
363+
preRedemptionText: "Redeem Now",
364+
postRedemptionText: "Coupon Redeemed",
365+
carouselImages: item.listImage ? [
366+
{
367+
"action": "noAction",
368+
"iconUrl": item.listImage,
369+
"title": "image"
370+
}
371+
] : [],
372+
rank: RankOfLastItem.getRank() ? RankOfLastItem.getRank() + 10: 10,
373+
addressTitle: "",
374+
location: {
375+
addressTitle: "",
376+
coordinates: {
377+
lat: "",
378+
lng: ""
379+
}
380+
},
381+
Categories: [],
382+
reuseAfterInMinutes: -1,
383+
dateCreated: Date.now(),
384+
deepLinkUrl: '', // must have an id from datatore
385+
deepLinkId: '', //same as item id
386+
SelectedCategories: [],
387+
}
388+
}
389+
return null
390+
}
391+
392+
let checkNotFoundImages = function(url, isImport) {
393+
const optimisedURL = url.replace('1080x720', '100x100');
394+
return new Promise((resolve) => {
395+
if (url.includes("http")){
396+
const xhr = new XMLHttpRequest();
397+
xhr.open("GET", optimisedURL);
398+
xhr.onerror = (error) => {
399+
console.warn('provided URL is not a valid image', error);
400+
resolve({isValid: true, newURL: isImport ? null : 'https://dummyimage.com/300x300/d7dbde/ffffff.png'});
401+
}
402+
xhr.onload = () => {
403+
if (xhr.responseURL.includes('source-404') || xhr.status == 404) {
404+
return resolve({isValid: true ,newURL: isImport ? null : 'https://dummyimage.com/300x300/d7dbde/ffffff.png'});
405+
} else {
406+
return resolve({isValid: true, newURL: xhr.responseURL.replace('h=100', 'h=720').replace('w=100', 'w=1080') });
407+
}
408+
};
409+
xhr.send();
410+
} else resolve({isValid: true ,newURL: isImport ? null : 'https://dummyimage.com/300x300/d7dbde/ffffff.png'});
411+
});
412+
};``
413+
414+
let checkOldData = function() {
415+
return new Promise(resolve => {
416+
if (stateSeederInstance.requestResult.resetData){
417+
$rootScope.oldCouponsIds.forEach(id => {
418+
Deeplink.deleteById(id);
419+
})
420+
$rootScope.oldCouponsIds = [];
421+
DataStore.save([], TAG_NAMES.COUPON_ITEMS).then(() => {
422+
resolve();
423+
})
424+
} else {
425+
resolve();
426+
}
427+
})
428+
}
429+
430+
return {
431+
initStateSeeder: function() {
432+
stateSeederInstance = new buildfire.components.aiStateSeeder({
433+
generateOptions: {
434+
userMessage: `List sample coupons for a new [Optics Shop]`,
435+
maxRecords: 5,
436+
systemMessage:
437+
"listImage is an 1080x720 image URL related to title and the list type, use source.unsplash.com for images, URL should not have premium_photo or source.unsplash.com/random.",
438+
jsonTemplate: jsonTemplate,
439+
callback: handleAIReq.bind(this, false),
440+
hintText: 'Replace values between brackets to match your requirements.',
441+
},
442+
importOptions: {
443+
jsonTemplate: jsonTemplate,
444+
sampleCSV: "Save 20% on Flights, Get 20% off on flight bookings with this exclusive coupon, https://source.unsplash.com/1080x720/?travel\n50% Off Hotel Bookings, Enjoy a 50% discount on hotel reservations using this limited-time coupon, https://source.unsplash.com/1080x720/?hotel\nCar Rental Special Offer, Rent a car for 7 days and pay for only 5 days with this coupon code, https://source.unsplash.com/1080x720/?car\nAdventure Tour Promo, Book an adventure tour and receive a free equipment rental worth $50 using this coupon, https://source.unsplash.com/1080x720/?adventure",
445+
maxRecords: 5,
446+
hintText: 'Each row should start with a Coupon title, Summary, and Image URL',
447+
systemMessage: 'listImage is an image URL, summary and listImage are optional',
448+
callback: handleAIReq.bind(this, true),
449+
},
450+
}).smartShowEmptyState();
451+
return true;
452+
},
453+
}
454+
}])
251455
})(window.angular, window.buildfire);

control/content/assets/css/jquery-ui.css

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1273,5 +1273,6 @@ body .ui-tooltip {
12731273
}
12741274

12751275
.draggable-list-view.wide-list{
1276-
overflow: visible !important;
1276+
/* overflow: visible !important; */
1277+
overflow-y: scroll;
12771278
}

control/content/assets/css/sortable.css

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
.draggable-list-view .d-item.square-icon .media-holder{
1111
margin-right: .5rem;
1212
object-fit: cover;
13-
}
14-
.draggable-list-view .d-item.square-icon .media-holder {
15-
object-fit: cover;
13+
min-width: 50px;
1614
}
1715
.draggable-list-view.no-media .d-item .copy{
1816
display: flex;
@@ -91,6 +89,7 @@ html[buildfire] .d-item .btn-edit-icon:hover::after{
9189

9290
.media-holder.pull-left > img {
9391
object-fit: cover !important;
92+
min-width: 50px;
9493
}
9594

9695
.draggable-list-view.carousel-items .d-item span.title {
@@ -103,6 +102,13 @@ html[buildfire] .d-item .btn-edit-icon:hover::after{
103102
top: 3px
104103
}
105104

105+
.draggable-list-view .d-item.double-line .copy .delete-icon-cont {
106+
display: flex;
107+
}
108+
.draggable-list-view .d-item.double-line .overflow-hidden {
109+
overflow: hidden;
110+
}
111+
106112
a.text-primary.text {
107113
top: -15px !important
108114
}

control/content/controllers/content.home.controller.js

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
(function (angular, buildfire) {
44
angular
55
.module('couponPluginContent')
6-
.controller('ContentHomeCtrl', ['$scope', '$timeout', 'TAG_NAMES', 'SORT', 'SORT_FILTER', 'STATUS_CODE', 'DataStore', 'LAYOUTS', 'Buildfire', 'Modals', 'RankOfLastFilter', 'RankOfLastItem', '$csv', 'Utils', '$rootScope', 'PluginEvents',
7-
function ($scope, $timeout, TAG_NAMES, SORT, SORT_FILTER, STATUS_CODE, DataStore, LAYOUTS, Buildfire, Modals, RankOfLastFilter, RankOfLastItem, $csv, Utils, $rootScope, PluginEvents) {
8-
6+
.controller('ContentHomeCtrl', ['$scope', '$timeout', 'TAG_NAMES', 'SORT', 'SORT_FILTER', 'STATUS_CODE', 'DataStore', 'LAYOUTS', 'Buildfire', 'Modals', 'RankOfLastFilter', 'RankOfLastItem', '$csv', 'Utils', '$rootScope', 'PluginEvents', 'StateSeeder', '$filter',
7+
function ($scope, $timeout, TAG_NAMES, SORT, SORT_FILTER, STATUS_CODE, DataStore, LAYOUTS, Buildfire, Modals, RankOfLastFilter, RankOfLastItem, $csv, Utils, $rootScope, PluginEvents, StateSeeder, $filter) {
98
var ContentHome = this;
9+
let stateSeeder;
10+
$rootScope.$watch('showEmptyState', function(newValue, oldValue) {
11+
if ((typeof newValue === 'undefined' || newValue == true) && !stateSeeder) {
12+
stateSeeder = StateSeeder.initStateSeeder();
13+
}
14+
})
1015
ContentHome.searchValue = "";
1116
ContentHome.filter = null;
1217
ContentHome.isBusy = true;
@@ -799,9 +804,34 @@
799804
"limit": "50"
800805
};
801806

802-
ContentHome.loadMoreItems = function (str) {
803-
console.log("------------------>>>>>>>>>>>>>>>>>>>>", str)
807+
ContentHome.reloadCoupons = function () {
808+
ContentHome.isBusy = true;
809+
Buildfire.datastore.search(ContentHome.searchOptionsForItems, TAG_NAMES.COUPON_ITEMS, function (err, result) {
810+
if (err) {
811+
Buildfire.spinner.hide();
812+
return console.error('-----------err in getting list-------------', err);
813+
}
814+
if (result.length <= SORT._limit) {// to indicate there are more
815+
ContentHome.noMore = true;
816+
Buildfire.spinner.hide();
817+
} else {
818+
result.pop();
819+
ContentHome.searchOptionsForItems.skip = ContentHome.searchOptionsForItems.skip + SORT._limit;
820+
ContentHome.noMore = false;
821+
}
822+
ContentHome.items = result;
823+
ContentHome.isBusy = false;
824+
$rootScope.reloadCoupons = false;
825+
$scope.$digest();
826+
if (!ContentHome.items.length) {
827+
$rootScope.showEmptyState = true;
828+
} else {
829+
$rootScope.showEmptyState = false;
830+
}
831+
})
832+
}
804833

834+
ContentHome.loadMoreItems = function (str) {
805835
Buildfire.spinner.show();
806836
if (ContentHome.busy) {
807837
return;
@@ -845,7 +875,11 @@
845875

846876
ContentHome.items = ContentHome.items ? ContentHome.items.concat(result) : result;
847877
Buildfire.datastore.search(searchOptionsFilterForItemList, TAG_NAMES.COUPON_CATEGORIES, function (err, resultFilter) {
848-
878+
if (!ContentHome.items.length) {
879+
$rootScope.showEmptyState = true;
880+
} else {
881+
$rootScope.showEmptyState = false;
882+
}
849883
if (err) {
850884
Buildfire.spinner.hide();
851885
return console.error('-----------err in getting list-------------', err);
@@ -1323,6 +1357,7 @@
13231357
* Go pull any previously saved data
13241358
* */
13251359
var init = function () {
1360+
console.log('$scope ====================>', $scope)
13261361
var success = function (result) {
13271362
console.info('Init success result:', result);
13281363
ContentHome.data = result.data;
@@ -1387,6 +1422,11 @@
13871422
return ContentHome.filter;
13881423
}, updateItemsWithDelay, true);
13891424

1390-
1425+
$rootScope.$watch('reloadCoupons', function(newValue, oldValue) {
1426+
if (newValue) {
1427+
ContentHome.reloadCoupons();
1428+
}
1429+
})
13911430
}]);
1431+
13921432
})(window.angular, window.buildfire);

control/content/controllers/content.item.controller.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,8 +495,9 @@
495495

496496
}
497497
//#
498+
$rootScope.showEmptyState = false;
498499
buildfire.messaging.sendMessageToWidget({});
499-
Location.goToHome();
500+
$location.path('home');
500501
};
501502
ContentItem.setLocation = function (data) {
502503
console.log(

control/content/index.html

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,10 @@
1010
<!-- endbuild -->
1111

1212
<!-- JS -->
13+
<script src="../../../../scripts/buildfire.min.js"></script>
14+
<script src="../../../../scripts/buildfire/components/aiStateSeeder/aiStateSeeder.js"></script>
1315
<script src="../../../../scripts/jquery/jquery-1.11.2.min.js"></script>
1416
<script src="../../../../scripts/jquery/jquery-ui.min.js"></script>
15-
<script src="../../../../scripts/buildfire.js"></script>
1617
<script src="../../../../scripts/sortable.min.js"></script>
1718
<script src="../../../../scripts/buildfire/components/carousel/carousel.js"></script>
1819
<script src="../../../../scripts/buildfire/components/actionItems/sortableList.js"></script>

0 commit comments

Comments
 (0)