158158 }
159159 }
160160 } ] )
161+ . factory ( 'DefaultInfo' , [ 'LAYOUTS' , function ( LAYOUTS ) {
162+ return {
163+ content : {
164+ carouselImages : [ ] ,
165+ description : '<p> <br></p>' ,
166+ addressTitle : '' ,
167+ address : {
168+ type :'' ,
169+ location :'' ,
170+ location_coordinates : [ ] ,
171+ } ,
172+ links : [ ] ,
173+ showMap : false
174+ } ,
175+ design : {
176+ listLayout : LAYOUTS . listLayouts [ 0 ] . name ,
177+ backgroundImage : ''
178+ }
179+ }
180+ } ] )
181+ . factory ( 'AIStateSeeder' , [ 'DefaultInfo' , 'DataStore' , 'TAG_NAMES' , '$rootScope' , function ( DefaultInfo , DataStore , TAG_NAMES , $rootScope ) {
182+ let stateSeederInstance ;
183+ let ContactInfo = DefaultInfo ;
184+ const jsonTemplate = {
185+ imagesURLs : [ ] ,
186+ description : '' ,
187+ phoneNumber : '' ,
188+ email : '' ,
189+ location : '' ,
190+ }
191+
192+ const getAddress = function ( location ) {
193+ return new Promise ( ( resolve ) => {
194+ if ( location ) {
195+ const geocoder = new google . maps . Geocoder ( ) ;
196+ geocoder . geocode ( { 'address' : location } , function ( result , status ) {
197+ if ( status == google . maps . GeocoderStatus . OK ) {
198+ resolve (
199+ {
200+ type : 'Location' ,
201+ location : result [ 0 ] . formatted_address || location ,
202+ location_coordinates : [ result [ 0 ] . geometry . location . lng ( ) , result [ 0 ] . geometry . location . lat ( ) ]
203+ } ) ;
204+ } else {
205+ resolve ( {
206+ type : 'Location' ,
207+ location : location ,
208+ location_coordinates : [ ]
209+ } ) ;
210+ } ;
211+ } ) ;
212+ } else {
213+ resolve ( null ) ;
214+ } ;
215+ } ) ;
216+ } ;
217+
218+ const parseImageURL = function ( url ) {
219+ const optimizedURL = url . replace ( '1080x720' , '100x100' ) ;
220+ return new Promise ( ( resolve ) => {
221+ if ( url . includes ( "http" ) ) {
222+ const xhr = new XMLHttpRequest ( ) ;
223+ xhr . open ( "GET" , optimizedURL ) ;
224+ xhr . onerror = ( error ) => {
225+ console . warn ( 'provided URL is not a valid image' , error ) ;
226+ resolve ( '' ) ;
227+ }
228+ xhr . onload = ( ) => {
229+ if ( xhr . responseURL . includes ( 'source-404' ) || xhr . status == 404 ) {
230+ return resolve ( '' ) ;
231+ } else {
232+ return resolve ( xhr . responseURL . replace ( 'h=100' , 'h=720' ) . replace ( 'w=100' , 'w=1080' ) ) ;
233+ }
234+ } ;
235+ xhr . send ( ) ;
236+ } else resolve ( '' ) ;
237+ } ) ;
238+ }
239+
240+ const getCurrentUser = function ( ) {
241+ return new Promise ( ( resolve , reject ) => {
242+ buildfire . auth . getCurrentUser ( ( err , currentUser ) => {
243+ if ( err ) reject ( err ) ;
244+ resolve ( currentUser ) ;
245+ } ) ;
246+ } ) ;
247+ }
248+
249+ const _applyDefaults = function ( data ) {
250+ // create HTML div element for the description, to avoid breaking the WYSIWYG
251+ const descriptionElement = document . createElement ( 'div' ) ;
252+ descriptionElement . innerHTML = data . description || '' ;
253+ // default address in case there was no address provided
254+ let address = {
255+ type : 'Location' ,
256+ location : '501 Pacific Hwy, San Diego, CA 92101, USA' ,
257+ location_coordinates : [ - 117.17096400000003 , 32.7100444 ]
258+ }
259+ if ( data . address ) {
260+ address = data . address ;
261+ }
262+ if ( data . imagesURLs && data . imagesURLs . length ) {
263+ for ( let i = 0 ; i < data . imagesURLs . length ; i ++ ) {
264+ data . imagesURLs [ i ] = {
265+ action : 'noAction' ,
266+ iconUrl : data . imagesURLs [ i ] ,
267+ title : 'image'
268+ }
269+ }
270+ } else {
271+ data . imagesURLs = [ ] ;
272+ }
273+
274+ // add links based on the contact info provided
275+ let links = [ ] ;
276+ const emailRegex = / ^ [ A - Z a - z 0 - 9 . _ % + - ] + @ [ A - Z a - z 0 - 9 . - ] + \. [ A - Z a - z ] { 2 , } $ / ;
277+ if ( data . email && data . email . match ( emailRegex ) ) {
278+ links . push ( {
279+ title : 'Email' ,
280+ action :'sendEmail' ,
281+ email : data . email ,
282+ subject : 'Contact US' ,
283+ } ) ;
284+ }
285+ if ( data . phoneNumber ) {
286+ links . push ( {
287+ title :'Call' ,
288+ action :'callNumber' ,
289+ phoneNumber : data . phoneNumber
290+ } ) ;
291+ }
292+ return {
293+ showMap : true ,
294+ carouselImages : data . imagesURLs ,
295+ description : descriptionElement . outerHTML ,
296+ addressTitle : 'Navigate to Location' ,
297+ address : address ,
298+ links : links ,
299+ }
300+ }
301+
302+ const handleAIReq = function ( err , response ) {
303+ if (
304+ err ||
305+ ! response ||
306+ typeof response !== 'object' ||
307+ ! Object . keys ( response ) . length || ! response . data
308+ ) {
309+ return buildfire . dialog . toast ( {
310+ message : 'Bad AI request, please try changing your request.' ,
311+ type : 'danger' ,
312+ } ) ;
313+ }
314+
315+ let optimizedURLs = [ ] ;
316+ let promises = response . data . imagesURLs . map ( url => {
317+ return parseImageURL ( url )
318+ } ) ;
319+
320+ Promise . allSettled ( promises ) . then ( parsingResults => {
321+ parsingResults . forEach ( parsingResult => {
322+ if ( parsingResult . status == 'fulfilled' && parsingResult . value ) {
323+ optimizedURLs . push ( parsingResult . value ) ;
324+ }
325+ } )
326+ response . data . imagesURLs = optimizedURLs ;
327+ DataStore . get ( TAG_NAMES . CONTACT_INFO ) . then ( info => {
328+ if ( info && info . data && Object . keys ( info . data ) . length ) {
329+ ContactInfo = info . data ;
330+ }
331+ getAddress ( response . data . location ) . then ( locationResult => {
332+ response . data . address = locationResult ;
333+ ContactInfo . content = _applyDefaults ( response . data ) ;
334+ DataStore . save ( ContactInfo , TAG_NAMES . CONTACT_INFO ) . then ( ( ) => {
335+ stateSeederInstance ?. requestResult ?. complete ( ) ;
336+ $rootScope . initContentHome ( ) ;
337+ } ) . catch ( err => {
338+ stateSeederInstance ?. requestResult ?. complete ( ) ;
339+ console . warn ( 'error saving data to datastore' , err ) ;
340+ return buildfire . dialog . toast ( {
341+ message : 'Something went wrong, try again later.' ,
342+ type : 'danger' ,
343+ } ) ;
344+ } ) ;
345+ } ) ;
346+ } ) . catch ( err => {
347+ stateSeederInstance ?. requestResult ?. complete ( ) ;
348+ console . warn ( 'error getting data from datastore' , err ) ;
349+ return buildfire . dialog . toast ( {
350+ message : 'Something went wrong, try again later.' ,
351+ type : 'danger' ,
352+ } ) ;
353+ } ) ;
354+ } ) ;
355+ } ;
356+
357+ return {
358+ initStateSeeder : function ( ) {
359+ getCurrentUser ( ) . then ( user => {
360+ stateSeederInstance = new buildfire . components . aiStateSeeder ( {
361+ generateOptions : {
362+ userMessage : `Generate a contact us information related to [business-type] located in [target-region].\nFor phone number use [+1 555 555-1234].\nFor email use [${ user ?. email || '' } ].` ,
363+ maxRecords : 5 ,
364+ systemMessage :
365+ 'images are two 1080x720 images URLs related to location, use source.unsplash.com for images, URL should not have premium_photo or source.unsplash.com/random. return description as HTML' ,
366+ jsonTemplate : jsonTemplate ,
367+ callback : handleAIReq . bind ( this ) ,
368+ hintText : 'Replace values between brackets to match your requirements.' ,
369+ } ,
370+ } ) . smartShowEmptyState ( ) ;
371+ } ) ;
372+ return true ;
373+ } ,
374+ }
375+ } ] )
161376} ) ( window . angular , window . buildfire ) ;
0 commit comments