{"version":3,"file":"common.js","mappings":"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","names":["UniqueCouponCampaignService","constructor","httpClient","deserializeService","this","index","params","get","environment","pipe","mergeMap","response","uniqueCouponCampaigns","a","deserialize","Response","meta","show","id","d","create","post","update","ucc","put","addCoupons","checkCsvProgress","campaignCsv","updateCoupon","coupon","i0","factory","Base","StoreBranding","RegistrationParamsService","storeService","storageService","RegistrationParams","BehaviorSubject","registration","registrationSource","next","saveParams","getObservable","asObservable","getParams","fromStore","fromLocal","JSON","parse","getItem","storageServiceName","error","console","brandScrapingData","data","branding","getSource","value","headerFont","template","getValue","cleanRegistration","removeItem","updatedAt","Date","createdAt","setItem","stringify","canUseCarts","canUseRecoModule","set","key","snakeToCamel","camelKey","SubTemplate","str","replace","g","toUpperCase","ctx_r5","oxw","ctx_r7","OnsiteAbandonmentSendPreviewModalComponent","activeModal","userService","emailService","errorService","senderEmailService","ngOnInit","store","user","getSenderEmails","send","form","submittedForm","isProd","m","controls","recaptcha","_a","valid","sendPreview","email","formatEmailParam","subscribe","close","sent","resp","errors","extractErrorMessages","cancel","dismiss","loading","senderEmails","filter","senderEmail","verifiedAt","userSenderEmail","find","push","SenderEmail","selectedSenderEmails","map","join","addEmail","se","indexOf","removeEmail","selectedEmails","splice","selectors","ctx","PreviewModal","sanitizer","sanitizedHtml","bypassSecurityTrustHtml","previewHtml","options","setAvailableAttributesFrom","compactSubscriptions","weekly","hasWeeklySubscription","userDataArray","userData","User","firstName","undefined","lastName","phone1","Object","entries","springbotEmailSubscriptions","item","e","some","emailTypeString","enabled"],"sourceRoot":"webpack:///","sources":["./src/app/automations/services/unique_coupon_campaign.service.ts","./src/app/shared/models/store_branding.ts","./src/app/shared/registration_params.ts","./src/app/brand_scraping/services/RegistrationParamsService.ts","./src/app/content_editor/models/editor_email_model.ts","./src/app/shared/components/onsite_abandonment_send_preview_modal/onsite_abandonment_send_preview_modal.component.html","./src/app/shared/components/onsite_abandonment_send_preview_modal/onsite_abandonment_send_preview_modal.component.ts","./src/app/shared/components/preview_modal/preview_modal.ts","./src/app/shared/components/preview_modal/preview_modal.html","./src/app/shared/models/user.ts"],"sourcesContent":["import { HttpClient } from \"@angular/common/http\";\nimport { Injectable } from \"@angular/core\";\nimport { CampaignCsv } from \"@models/unique_coupon_campaigns/campaign_csv\";\nimport { Coupon } from \"@models/unique_coupon_campaigns/coupon\";\nimport { UniqueCouponCampaign } from \"@models/unique_coupon_campaigns/unique_coupon_campaign\";\n\nimport { Response } from \"@models/response\";\nimport { DeserializeService } from \"@app/shared/services/deserialize.service\";\nimport { Observable } from \"rxjs\";\nimport { mergeMap } from \"rxjs/operators\";\nimport { environment } from \"@environments/environment\";\n\n@Injectable({\n providedIn: \"root\",\n})\nexport class UniqueCouponCampaignService {\n constructor(\n private httpClient: HttpClient,\n private deserializeService: DeserializeService,\n ) {}\n\n index(params?: any): Observable> {\n return this.httpClient.get(`${environment.apiUrl}/v2/unique_coupon_campaigns`, { params })\n .pipe(mergeMap(async (response: any) => {\n const uniqueCouponCampaigns = this.deserializeService.deserialize(response) as UniqueCouponCampaign[];\n return new Response(uniqueCouponCampaigns, response.meta);\n }));\n }\n\n show(id: string, params?: any): Observable {\n return this.httpClient.get(`${environment.apiUrl}/v2/unique_coupon_campaigns/${id}`, { params })\n .pipe(mergeMap(async (response) => {\n const uniqueCouponCampaign = this.deserializeService.deserialize(response) as UniqueCouponCampaign;\n return uniqueCouponCampaign;\n }));\n }\n\n create(params?: any): Observable {\n return this.httpClient.post(`${environment.apiUrl}/v2/unique_coupon_campaigns`, params)\n .pipe(mergeMap(async (response) => {\n const uniqueCouponCampaign = this.deserializeService.deserialize(response) as CampaignCsv;\n return uniqueCouponCampaign;\n }));\n }\n\n update(ucc: UniqueCouponCampaign): Observable {\n return this.httpClient.put(`${environment.apiUrl}/v2/unique_coupon_campaigns/${ucc.id}`, ucc)\n .pipe(mergeMap(async (response) => {\n const uniqueCouponCampaign = this.deserializeService.deserialize(response) as UniqueCouponCampaign;\n return uniqueCouponCampaign;\n }));\n }\n\n addCoupons(ucc: UniqueCouponCampaign, params?: any): Observable {\n return this.httpClient.put(`${environment.apiUrl}/v2/unique_coupon_campaigns/${ucc.id}/add_coupons`, params)\n .pipe(mergeMap(async (response) => {\n const uniqueCouponCampaign = this.deserializeService.deserialize(response) as CampaignCsv;\n return uniqueCouponCampaign;\n }));\n }\n\n checkCsvProgress(campaignCsv: CampaignCsv): Observable {\n return this.httpClient.get(`${environment.apiUrl}/v2/unique_coupon_campaign_csvs/${campaignCsv.id}`)\n .pipe(mergeMap(async (response) => {\n const csvStatus = this.deserializeService.deserialize(response);\n return csvStatus;\n }));\n }\n\n updateCoupon(coupon: Coupon) {\n return this.httpClient.put(`${environment.apiUrl}/v2/unique_coupons/${coupon.id}`, coupon);\n }\n}\n","import { Base } from \"@models/base\";\n\n// no related back-end model, represents a json field object contained in StoreBranding model\nexport interface CustomSocialIcon {\n name: string;\n url: string;\n imageUrl: string;\n}\n\nexport class StoreBranding extends Base {\n logoUrl: string | null;\n bannerUrl: string | null;\n bannerName: string | null;\n logoName: string | null;\n state: string | null;\n fontFamily: string | null;\n buttonBorderStyle: string | null;\n headerColor: string | null;\n bodyColor: string | null;\n linkColor: string | null;\n textColor: string | null;\n primaryColor: string | null;\n buttonColor: string | null;\n buttonTextColor: string | null;\n buttonBorderColor: string | null;\n socialIconSize: number | null;\n socialIconBorderRadius: number | null;\n socialIconBaseUrl: string | null;\n facebookIconBackgroundColor: string | null;\n facebookIconCustomUrl: string | null;\n instagramIconBackgroundColor: string | null;\n instagramIconCustomUrl: string | null;\n linkedinIconBackgroundColor: string | null;\n linkedinIconCustomUrl: string | null;\n pinterestIconBackgroundColor: string | null;\n pinterestIconCustomUrl: string | null;\n twitterIconBackgroundColor: string | null;\n twitterIconCustomUrl: string | null;\n navlinks: { text: string; url: string }[] | null;\n youtubeIconBackgroundColor: string | null;\n youtubeIconCustomUrl: string | null;\n customSocialIcons: CustomSocialIcon[] | null;\n // defaults stores the default values from the back-end for fallback if no data has been set\n // the typing of the field is recursive,\n // due to it having the exact same \"shape\" as it's parent class\n defaults: StoreBranding;\n}\n","import { StoreBranding } from \"@models/store_branding\";\n\nexport class RegistrationParams extends StoreBranding {\n headerFont: string = \"Arial, Helvetica, sans-serif\"\n template: string = \"one\";\n}\n","import { Injectable } from \"@angular/core\";\nimport { BehaviorSubject } from \"rxjs\";\nimport { RegistrationParams } from \"@app/shared/registration_params\";\nimport { StoreService } from \"@app/shared/services/store.service\";\nimport {StorageService} from \"@app/shared/services/storage.service\";\n@Injectable({\n providedIn: \"root\",\n})\n\nexport class RegistrationParamsService {\n public registration = new RegistrationParams();\n private registrationSource = new BehaviorSubject(this.registration);\n private storageServiceName: string = \"brandScrapingData\";\n\n constructor(\n private storeService: StoreService,\n private storageService: StorageService,\n ){}\n\n update(registration: RegistrationParams) {\n this.registrationSource.next(registration);\n this.saveParams();\n }\n\n getObservable() {\n return this.registrationSource.asObservable();\n }\n\n getParams(fromStore: boolean = false) {\n let fromLocal: any = undefined;\n\n try {\n fromLocal = JSON.parse(this.storageService.getItem(this.storageServiceName));\n } catch (error) {\n console.error('Invalid JSON:', error);\n }\n\n let brandScrapingData = { data: null };\n const branding = this.storeService.getSource().value.branding;\n if (branding && fromStore) {\n brandScrapingData.data = branding;\n } else if (fromLocal) {\n brandScrapingData = fromLocal;\n } else {\n brandScrapingData.data = new RegistrationParams();\n }\n\n if (fromLocal) {\n brandScrapingData.data.headerFont = fromLocal.data.headerFont || \"'Arial',Helvetica,sans-serif\";\n brandScrapingData.data.template = fromLocal.data.template || \"one\";\n } else {\n brandScrapingData.data.headerFont = \"'Arial',Helvetica,sans-serif\";\n brandScrapingData.data.template = \"one\";\n }\n\n this.registrationSource.next(brandScrapingData.data);\n return this.registrationSource.getValue();\n }\n\n cleanRegistration() {\n this.registrationSource.next(new RegistrationParams());\n this.storageService.removeItem(this.storageServiceName);\n }\n\n private saveParams() {\n let brandScrapingData = JSON.parse(this.storageService.getItem(this.storageServiceName));\n if (brandScrapingData) {\n brandScrapingData.data = this.registrationSource.getValue();\n brandScrapingData.updatedAt = new Date();\n } else {\n brandScrapingData = {\n createdAt: new Date(),\n updatedAt: new Date(),\n data: this.registrationSource.getValue()\n }\n }\n\n this.storageService.setItem(this.storageServiceName, JSON.stringify(brandScrapingData));\n }\n}\n","// core interface that is required for model to be used in the EmailEditor\nimport { Base } from \"@models/base\";\nimport { SubTemplate } from \"@models/email_templates/sub_template\";\nimport { UniqueCouponCampaign } from \"@models/unique_coupon_campaigns/unique_coupon_campaign\";\n\nexport interface EditorEmailModelInterface {\n mjmlContent?: string;\n content?: string;\n cartTemplate?: SubTemplate;\n purchasedCartTemplate?: SubTemplate;\n productRecommendationTemplate?: SubTemplate;\n couponCampaign?: UniqueCouponCampaign;\n uniqueCouponCampaignId?: string;\n masterTemplateRequiresUpgrade?: boolean;\n brandingUpdateRequired?: boolean; // TODO verify sent from backend\n canUseCarts(): boolean;\n canUseRecoModule(): boolean;\n set(key: string, value: any): void;\n get(key: string): any;\n snakeToCamel(str: string): string;\n}\n\n// NOTE: this class is not to be used directly, but to be inherited from by all classes\n// that can de used within the email editor\nexport class EditorEmailModel extends Base implements EditorEmailModelInterface {\n mjmlContent?: string;\n content?: string;\n cartTemplate?: SubTemplate;\n purchasedCartTemplate?: SubTemplate;\n productRecommendationTemplate?: SubTemplate;\n couponCampaign?: UniqueCouponCampaign;\n uniqueCouponCampaignId?: string;\n masterTemplateRequiresUpgrade = false;\n\n // stub method to handle email models that do not utilize Recos\n canUseCarts(): boolean {\n return false;\n }\n\n // stub method to handle email models that do not utilize Recos\n canUseRecoModule(): boolean {\n return false;\n }\n\n set(key: string, value: any): void {\n this[this.snakeToCamel(key)] = value;\n }\n\n get(key: string): any {\n const camelKey = this.snakeToCamel(key);\n switch (camelKey) {\n case \"productRecommendationsTemplate\":\n return this.canUseRecoModule() ? new SubTemplate(this[camelKey]) : null;\n case \"cartTemplate\":\n case \"purchasedCartTemplate\":\n return this.canUseCarts() ? new SubTemplate(this[camelKey]) : null;\n default:\n return this[camelKey];\n }\n }\n\n // Because the editor is upgraded from angular.js and uses snake_case everywhere.\n // TODO: remove the need for this method globally\n snakeToCamel(str: string): string {\n return str.replace(/([-_]\\w)/g, (g) => g[1].toUpperCase());\n }\n}\n","
\n
\n

\n \n

\n

\n Send Preview Email\n

\n
\n\n
\n
\n
\n Select the email you wish to send the preview to.
For security reasons, you can only send to verified sender emails.\n
\n
\n
0\" class=\"form-group send-preview-emails\">\n \n \n
\n\n
\n \n
\n \n reCAPTCHA is required\n \n
\n
\n\n
\n
\n\n
\n {{ error }}\n
\n\n\n","import { Component, OnInit } from \"@angular/core\";\nimport { OnsiteAbandonmentEmailService } from \"@app/shared/services/onsite_abandonment_email.service\";\nimport { StoreService } from \"@app/shared/services/store.service\";\nimport { OnsiteAbandonmentEmail } from \"@models/onsite_abandonment_email\";\nimport { Store } from \"@models/store\";\nimport { NgbActiveModal } from \"@ng-bootstrap/ng-bootstrap\";\nimport { environment } from \"@environments/environment\";\nimport { UniversalErrorService } from \"@app/shared/services/universal_error_service\";\nimport { SenderEmail } from \"@models/sender_email\";\nimport { SenderEmailsService } from \"@app/shared/services/sender_emails.service\";\nimport { UserService } from \"@app/shared/services/user.service\";\nimport { User } from \"@bugsnag/js\";\n\n@Component({\n selector: \"onsite-abandonment-send-preview-modal\",\n styleUrls: [\"./onsite_abandonment_send_preview_modal.component.scss\"],\n templateUrl: \"./onsite_abandonment_send_preview_modal.component.html\",\n})\nexport class OnsiteAbandonmentSendPreviewModalComponent implements OnInit {\n store: Store;\n user: User;\n email: OnsiteAbandonmentEmail;\n submittedForm: boolean = false;\n errors: string[];\n isProd = environment.production;\n recaptcha = null;\n senderEmails: SenderEmail[];\n selectedSenderEmails: SenderEmail[] = [];\n loading = false;\n\n constructor(\n private activeModal: NgbActiveModal,\n private storeService: StoreService,\n private userService: UserService,\n private emailService: OnsiteAbandonmentEmailService,\n private errorService: UniversalErrorService,\n private senderEmailService: SenderEmailsService,\n ) {}\n\n ngOnInit() {\n this.store = this.storeService.getSource().getValue();\n this.user = this.userService.getSource().value;\n this.getSenderEmails();\n }\n\n send(form) {\n this.submittedForm = true;\n if (!this.isProd || form.form.controls.recaptcha?.valid) {\n this.emailService.sendPreview(this.email.id, this.formatEmailParam()).subscribe(\n (response) => {\n this.activeModal.close({ sent: true });\n },\n (resp) => {\n this.errors = this.errorService.extractErrorMessages(resp);\n }\n );\n }\n }\n\n cancel() {\n this.activeModal.dismiss();\n }\n\n getSenderEmails() {\n this.loading = true;\n this.senderEmailService\n .index({})\n .subscribe((response) => {\n this.loading = false;\n this.senderEmails = response.data.filter((senderEmail) => !!senderEmail.verifiedAt || senderEmail.email === this.user.email);\n const userSenderEmail = this.senderEmails.find((senderEmail) => senderEmail.email === this.user.email);\n if (!userSenderEmail) {\n this.senderEmails.push(new SenderEmail({ email: this.user.email, verifiedAt: new Date() }));\n }\n this.selectedSenderEmails = this.senderEmails.filter((senderEmail) => senderEmail.email === this.user.email);\n }, () => {\n this.loading = false;\n this.senderEmails = [];\n });\n }\n\n formatEmailParam(): string {\n return this.selectedSenderEmails.map((senderEmail) => senderEmail.email).join(\",\");\n }\n\n addEmail(senderEmail: SenderEmail): void {\n const selectedEmails = this.selectedSenderEmails.map((se) => se.email);\n const index = selectedEmails.indexOf(senderEmail.email);\n\n if (index < 0) {\n this.selectedSenderEmails.push(senderEmail);\n }\n }\n\n removeEmail(senderEmail: SenderEmail): void {\n const selectedEmails = this.selectedSenderEmails.map((se) => se.email);\n const index = selectedEmails.indexOf(senderEmail.email);\n\n if (index >= 0 ) {\n this.selectedSenderEmails.splice(index, 1);\n }\n }\n}\n","import { Component, Input } from \"@angular/core\";\nimport { DomSanitizer } from \"@angular/platform-browser\";\nimport { Modal } from \"@models/modal_info\";\nimport { NgbActiveModal } from \"@ng-bootstrap/ng-bootstrap\";\n\n@Component({\n selector: \"preview-modal-content\",\n templateUrl: \"./preview_modal.html\",\n})\nexport class PreviewModal {\n @Input()\n previewHtml: string;\n\n sanitizedHtml;\n\n constructor(private sanitizer: DomSanitizer) {}\n\n ngOnInit() {\n this.sanitizedHtml = this.sanitizer.bypassSecurityTrustHtml(\n this.previewHtml\n );\n }\n}\n","
\n","import { SpringbotEmailSubscription } from \"@models/springbot_email_subscription\";\nimport { Store } from \"@models/store\";\nimport { Role } from \"./role\";\n\n// nightly and weekly are front-end generated attributes\n//\n\n// IMPORTANT!: Do NOT use the User model directly as an interface/type check.\n// Instead, use UserOptions as the interface and instantiate the User from an object literal\n// thus not part of interface\nexport interface UserOptions {\n id?: string;\n firstName: string;\n lastName: string;\n email: string;\n phone1: string;\n springbotEmailSubscriptions?: SpringbotEmailSubscription[];\n currentStore?: Store;\n currentStoreId?: string;\n}\n\n// ex: (userData: UserOptions) => new User(userData);\nexport class User {\n static createUsersArray(userDataArray: UserOptions[]): User[] {\n return userDataArray.map((userData) => new User(userData));\n }\n\n static blankUser(): User {\n return new User({\n firstName: undefined,\n lastName: undefined,\n email: undefined,\n phone1: undefined, // generates blank user with the minimal data required\n });\n }\n\n id: string;\n firstName: string;\n lastName: string;\n admin: boolean;\n email: string;\n phone1: string; // not required in all cases\n currentStore: Store;\n currentStoreId: number;\n currentRole: Role;\n storeRole: string;\n stores: any;\n springbotEmailSubscriptions: SpringbotEmailSubscription[] = [];\n weekly: boolean;\n trueUserId: number;\n trueUserAdmin: boolean;\n oldPassword?: string;\n newPassword?: string;\n apiToken?: string;\n lastSignInAt: Date;\n signInCount: number;\n confirmed: boolean;\n\n constructor(options: UserOptions) {\n this.setAvailableAttributesFrom(options);\n this.compactSubscriptions();\n this.weekly = this.hasWeeklySubscription();\n }\n\n // sets any values for attributes passed in via the options object\n private setAvailableAttributesFrom(options: UserOptions): void {\n Object.entries(options).map(([key, value]) => (this[key] = value));\n }\n\n // strips erroneous nulls from the array\n private compactSubscriptions(): void {\n this.springbotEmailSubscriptions = this.springbotEmailSubscriptions.filter(\n (item) => item !== null\n );\n }\n\n private hasWeeklySubscription(): boolean {\n return this.springbotEmailSubscriptions?.some(\n ({ emailTypeString, enabled }) => emailTypeString === \"weekly\" && enabled\n );\n }\n}\n"]}