import { Component, OnInit, ViewChild, HostListener } from '@angular/core'; import { FormControl } from '@angular/forms'; import { CommonfunctionService } from '../../services/commonfunction.service'; import { ItemService } from '../../services/item.service'; import { ItemVariantService } from '../../services/item.variant.service'; import { BsModalRef, BsModalService } from 'ngx-bootstrap'; import { AuthenticationService } from '../../services/authentication.service'; import { MessengerService } from '../../services/messenger.service'; import { SignUpModalComponent } from '../../views/custom-portal-pages/header-components/sign-up-modal/sign-up-modal.component'; import { LoginModalComponent } from '../../views/custom-portal-pages/header-components/login-modal/login-modal.component'; import { MatSidenav } from '@angular/material/sidenav/sidenav'; import { AlertModalComponent } from '../../views/common/alert-modal/alert-modal.component'; import { Router } from '@angular/router'; import { NGXLogger } from 'ngx-logger'; import { CartService } from '../../services/cart.service'; import { ToastrService } from 'ngx-toastr'; type memVarJson = { categories: any[], promoandKeyItems: any[], sliders: any[], locations: any[], has_notification: boolean, notification: string, location_id: number, taxSlabs: any[], taxGroups: any[] } @Component({ selector: 'app-customer-portal', templateUrl: './customer-portal-layout.component.html', styleUrls: ['./customer-portal-layout.component.css'] }) export class CustomerPortalLayoutComponent implements OnInit { @ViewChild('sidenav', { static: false }) sidemenu: MatSidenav; @ViewChild('cartContainer', { static: false }) cartContainer; bsModalRef: BsModalRef; userLoggedIn: boolean = false; walletDisplayed: boolean = false; walletValue: number; isAdmin: false; hide; title = 'espl-cp'; transparentBgJson: { "background-color": string, 'border-top': string, 'border-left': string, 'border-right': string, color: string }; //loadedCache is for checking availability of promoandKey items for displaying the homepage loadedCache: boolean; contentDisplayed: boolean = true; cartDisplayed: boolean = false; locationDropdown: FormControl; locationsArray = []; categories = []; isNotificationExists: boolean; userLocation: any; notificationMessage: any; //allItemsloaded is used to display search , which is loaded only when all the customer items are available allItemsloaded: boolean = false; userSSO: number; allItems: any; promoandKeyItems: any; itemsInCart: any[]; env: any; cartItemsCount: number; constructor(private cartService: CartService, private messengerService: MessengerService, private commonFunction: CommonfunctionService, private logger: NGXLogger, private router: Router, private itemService: ItemService, private itemVariantService: ItemVariantService, private auth: AuthenticationService, private modalService: BsModalService, private toastr: ToastrService) { this.transparentBgJson = { "background-color": 'transparent', 'border-top': "none", 'border-left': 'none', 'border-right': 'none', color: 'white' } this.locationDropdown = new FormControl(); } async ngOnInit(): Promise { window.addEventListener('storage', (event) => { if (event.storageArea == localStorage) { if(event.key === 'promoOrKeyItems') { this.allItems = []; this.allItemsloaded = false; this.loadedCache = false; } else if ( event.key === 'nonKeyOrPromoItems') { this.allItems = []; this.allItemsloaded = false; } let userDetails = JSON.parse(localStorage.getItem('user')); if( this.userLoggedIn ) { if (!userDetails || userDetails.token == undefined) { this.router.navigate(['/home']); this.userLoggedIn = false; console.debug("Logged out from other tab"); this.logout(); } else if(event.key == 'user') { this.auth.setUser(userDetails); } } else { if (userDetails && userDetails.token) { console.debug("Logged In from other tab"); this.auth.setUser(userDetails); this.userLoggedIn = true; } } if(event.key === 'cartItems') { let cartItems = JSON.parse(localStorage.getItem('cartItems')) || []; this.itemsInCart = cartItems; this.cartItemsCount = this.cartService.getSum(this.itemsInCart, "numItems"); this.cartService.setItemsInCart(JSON.stringify(this.itemsInCart)); } else if ( event.key === "promoOrKeyItems") { let config = JSON.parse(localStorage.getItem('config')); this.promoandKeyItems = JSON.parse(localStorage.getItem('promoOrKeyItems')) ; let nonKeyPromoItems = JSON.parse(localStorage.getItem('nonKeyOrPromoItems')); this.allItems = [...this.promoandKeyItems, ...nonKeyPromoItems]; this.allItemsloaded = true; let memVarUpdateData : memVarJson = { categories: JSON.parse(localStorage.getItem('categories')), promoandKeyItems: this.promoandKeyItems, sliders: JSON.parse(localStorage.getItem('sliders')), locations: JSON.parse(localStorage.getItem('locations')), has_notification: config.has_notification, notification: config.notification, location_id: config.location_id, taxSlabs: JSON.parse(localStorage.getItem('taxslabs')), taxGroups: JSON.parse(localStorage.getItem('taxgroups')) } this.updateMemVarandSendMsgServiceWithHomePageData(memVarUpdateData); } else if( event.key === 'config') { let config = JSON.parse(localStorage.getItem('config')); this.locationDropdown.patchValue(config.location_id); } if(event.key === 'nonKeyOrPromoItems' ) { let nonKeyPromoItems = JSON.parse(localStorage.getItem('nonKeyOrPromoItems')); this.allItems = [...this.promoandKeyItems, ...nonKeyPromoItems]; this.allItemsloaded = true; this.messengerService.nonPromoAndKeyDatafn(nonKeyPromoItems); } } }); this.cartService.getItemsInCart().subscribe(result => { this.itemsInCart = JSON.parse(result) || []; this.cartItemsCount = this.cartService.getSum(this.itemsInCart, "numItems"); }); // let categoryLookup = {}; this.isNotificationExists = true; if (typeof (Storage) !== 'undefined' ) { let userDetails = localStorage.getItem('user'); // Check if local storage key does not exist and add the cached item. if (userDetails) { let user = JSON.parse(userDetails); this.userLoggedIn = true; if (user.location) { this.userLocation = user.location; } else { if (this.locationsArray && this.locationsArray.length > 0) { this.userLocation = this.locationsArray.find(location => { return location.is_default; }).location_id; } else { let locations = JSON.parse(localStorage.getItem('locations')); if(locations){ this.userLocation = locations.find(location => { return location.is_default; }).location_id; } } } //this.walletValue = user.wallet; this.isAdmin = user.isAdmin; this.userSSO = user.username; this.hide = false; } else { this.userLoggedIn = false; } if (localStorage.customerItemsLastUpdatedDate == null) { await this.updateLocalStorageForHomePageData(); this.updateLocalStorageWithNonKeyPromoItems(); } else { await this.verifyLastUpdatedAndCacheUpdate(); } } else { // If local storage is not supported then directly data will be feteched from server. this.logger.debug('localstorage is not supported so reading directly from server.'); } } /* updates non key and non promo items to local storage */ updateLocalStorageWithNonKeyPromoItems() { if(localStorage.getItem('config')) { let config = JSON.parse(localStorage.getItem('config')); this.itemService.getNonkeyandpromoitems(config.location_id).subscribe((itemsData: { status: string, message: string, data }) => { if (itemsData.data) { this.setAllItemsandUpdateCart(itemsData.data.items); localStorage.nonKeyOrPromoItems = JSON.stringify(itemsData.data.items); } }); } } private async setAllItemsandUpdateCart(nonKeyPromoItems){ // Already promo key(pk) must have got updated in flow as it is synchronous calls. and non pk 's updation is not required localstorage has latest non pk data. this.allItems = [...this.promoandKeyItems, ...nonKeyPromoItems]; let cartItems = JSON.parse(localStorage.getItem('cartItems')) || []; //If we are entering here, already homePage items musthave got updated. //TODO: using ISO string. need to check with different timezones. localStorage.customerItemsLastUpdatedDate = new Date().toISOString(); //TODO: have flags to check whether Pk itms got updated or npk items got updated. Based on that update only those items in cart. --performance this.itemsInCart = cartItems.filter(item => { let foundItemInCart = this.allItems.find(custItem => {return custItem.item_id === item.item_id}); if(foundItemInCart && foundItemInCart.is_available) { let foundVariantInCart = foundItemInCart.variants.find((custVariant) => { return custVariant.variant_id === item.variant_id}); if( foundVariantInCart && foundVariantInCart.is_available ) { item.discount_price = foundVariantInCart.discount_price ; item.sales_price = foundVariantInCart.sales_price; item.variant = foundVariantInCart.variant; item.variant_unit = foundVariantInCart.variant_unit; item.cost_price = foundVariantInCart.cost_price; item.taxable = foundVariantInCart.taxable; item.interTaxSlab = foundVariantInCart.inter_state_tax; item.intraTaxGroup = foundVariantInCart.intra_state_tax; item.discount_percent = Number((100 - ((100 * foundVariantInCart.discount_price) / foundVariantInCart.sales_price)).toFixed(0)); item.totalDiscountPrice = foundVariantInCart.discount_price * item.numItems; item.totalSalesPrice = foundVariantInCart.sales_price * item.numItems; return item; } } }); localStorage.cartItems= JSON.stringify(this.itemsInCart); this.cartService.setItemsInCart(JSON.stringify(this.itemsInCart)); this.messengerService.nonPromoAndKeyDatafn(nonKeyPromoItems); this.allItemsloaded = true; } // Check if local storage key exists and cache timestamp item is different. // If timestamp is same then wont update the localstorage key otherwise update it with latest data. private async verifyLastUpdatedAndCacheUpdate() { const lastUpdatedDateObj = await this.itemService.getCustomerItemsLastUpdatedDates(); const cacheLastUpdatedDate = new Date(localStorage.customerItemsLastUpdatedDate); let getHomePageItems = localStorage.promoOrKeyItems == null || localStorage.locations == null || localStorage.sliders == null || localStorage.categories == null || localStorage.config == null; if (new Date(lastUpdatedDateObj['data']['lastUpdatedDate']) > cacheLastUpdatedDate || getHomePageItems) { if (new Date(lastUpdatedDateObj['data']['itemImageUpdatedDate']) > cacheLastUpdatedDate) { await this.updateLocalStorageForHomePageData(); this.updateLocalStorageWithNonKeyPromoItems(); } else { if ((new Date(lastUpdatedDateObj['data']['genericKeyPromoUpdatedDate']) > cacheLastUpdatedDate) || getHomePageItems) { this.logger.debug('Cache Timestamp lastUpdatedDate key is behind. so, updating localStorage.'); await this.updateLocalStorageForHomePageData(); } else { const configuration = JSON.parse(localStorage.getItem('config')); const memVarUpdateData: memVarJson = { categories : JSON.parse(localStorage.getItem('categories')), promoandKeyItems: JSON.parse(localStorage.getItem('promoOrKeyItems')), sliders: JSON.parse(localStorage.getItem('sliders')), locations : JSON.parse(localStorage.getItem('locations')), has_notification: configuration.has_notification, notification: configuration.notification, location_id: configuration.location_id, taxSlabs: JSON.parse(localStorage.getItem('taxslabs')), taxGroups : JSON.parse(localStorage.getItem('taxgroups')) } await this.updateMemVarandSendMsgServiceWithHomePageData(memVarUpdateData); } if (new Date(lastUpdatedDateObj['data']['nonKeyPromoUpdatedDate']) > cacheLastUpdatedDate || localStorage.nonKeyOrPromoItems == null) { this.logger.debug('Cache Timestamp lastUpdatedDate key is behind. so, updating localStorage.'); this.updateLocalStorageWithNonKeyPromoItems(); } else { this.setAllItemsandUpdateCart(JSON.parse(localStorage.getItem('nonKeyOrPromoItems'))); } } } else { this.logger.debug('Cache Timestamp is same so not updating localStorage key'); const configuration = JSON.parse(localStorage.getItem('config')); const fallBackImageUpdatedDate = new Date(configuration.fallback_image_timestamp); const categoryImageUpdatedDate = new Date(configuration.category_image_timestamp); let configUpdated = false; if (new Date(lastUpdatedDateObj['data']['fallbackImageUpdatedDate']) > fallBackImageUpdatedDate) { configuration.fallback_image_timestamp = lastUpdatedDateObj['data']['fallbackImageUpdatedDate']; configUpdated = true; } if (new Date(lastUpdatedDateObj['data']['categoryImageUpdatedDate']) > categoryImageUpdatedDate) { configuration.category_image_timestamp = lastUpdatedDateObj['data']['categoryImageUpdatedDate']; configUpdated= true; } if(configUpdated) { localStorage.config = JSON.stringify(configuration); } const memVarUpdateData: memVarJson = { categories : JSON.parse(localStorage.getItem('categories')), promoandKeyItems: JSON.parse(localStorage.getItem('promoOrKeyItems')), sliders: JSON.parse(localStorage.getItem('sliders')), locations : JSON.parse(localStorage.getItem('locations')), has_notification: configuration.has_notification, notification: configuration.notification, location_id: configuration.location_id, taxSlabs: JSON.parse(localStorage.getItem('taxslabs')), taxGroups : JSON.parse(localStorage.getItem('taxgroups')) } await this.updateMemVarandSendMsgServiceWithHomePageData(memVarUpdateData); this.setAllItemsandUpdateCart(JSON.parse(localStorage.getItem('nonKeyOrPromoItems'))); } } /* @usage: updates promoOrKeyItems and nonKeyOrPromoItems variables of local storage with server cache data, when location gets changes @purpose: called when there is a change in location*/ locationChanged(selectedLocationObj) { if(localStorage.config && JSON.parse(localStorage.config)){ let config = JSON.parse(localStorage.config); if(config.location_id !== selectedLocationObj.location_id){ this.router.navigate(['/home']); this.itemVariantService.getLocationBasedVariants(selectedLocationObj.location_id).subscribe((items: { status, message, data }) => { this.locationDropdown.setValue(selectedLocationObj.location_id); localStorage.promoOrKeyItems = JSON.stringify(items.data.keyorpromoitems); localStorage.nonKeyOrPromoItems = JSON.stringify(items.data.nonkeyorpromoitems); this.allItems = [...items.data.keyorpromoitems, ...items.data.nonkeyorpromoitems]; this.allItemsloaded = true; let config = JSON.parse(localStorage.config); config.location_id = selectedLocationObj.location_id; localStorage.config = JSON.stringify(config); this.messengerService.promoKeyDatafn(items.data.keyorpromoitems); this.messengerService.nonPromoAndKeyDatafn(items.data.nonkeyorpromoitems); this.itemsInCart = []; localStorage.cartItems = JSON.stringify(this.itemsInCart); this.cartService.setItemsInCart(JSON.stringify(this.itemsInCart)) }); } } } /* @purpose: updated all the member variables related to homePage load and sends messages to subscribed event about availability of home page data. */ private async updateMemVarandSendMsgServiceWithHomePageData(homePageData: memVarJson) : Promise { let sortedCategories = homePageData.categories.sort(this.commonFunction.sortByProperty('display_order')); this.categories = sortedCategories; this.locationsArray = homePageData.locations; this.locationDropdown.setValue(homePageData.location_id); this.promoandKeyItems = homePageData.promoandKeyItems; this.isNotificationExists = homePageData.has_notification; this.notificationMessage = homePageData.notification; this.messengerService.promoKeyDatafn(this.promoandKeyItems); this.messengerService.categoryDatafn(sortedCategories); this.messengerService.sliderDatafn(homePageData.sliders); this.cartService.taxGroupDatafn(homePageData.taxGroups); this.cartService.taxSlabDatafn(homePageData.taxSlabs); //all the information needed for loading homepage is available. this.loadedCache = true; } /* @usage: adds/ updates local storage variables based on default/user's location with lastest data available on server cache. @purpose: called when any of the local storage variable need is missing. Is called only when the page is refreshed*/ private async updateLocalStorageForHomePageData(): Promise { //this.router.navigate(['/home']); if(localStorage.config) { const configuration = JSON.parse(localStorage.getItem('config')); if(configuration.location_id) { this.userLocation = configuration.location_id; } } let homePageData = await this.itemService.getHomePageItems(this.userLoggedIn, this.userLocation); if(homePageData['data']){ this.userLocation = this.userLocation ? this.userLocation : homePageData['data']['locations'].find(location => location.is_default).location_id; const memVarUpdateData : memVarJson = { categories : homePageData['data']['categories'], promoandKeyItems: homePageData['data']['items'], sliders: homePageData['data']['sliders'], locations : homePageData['data']['locations'], has_notification: homePageData['data']['configurations'].has_notification, notification: homePageData['data']['configurations'].notification, location_id : this.userLocation, taxSlabs: homePageData['data']['taxgroups'], taxGroups : homePageData['data']['taxslabs'] } await this.updateMemVarandSendMsgServiceWithHomePageData(memVarUpdateData); this.logger.debug("updating Local Storage for generic data") localStorage.promoOrKeyItems = JSON.stringify(homePageData['data']['items']); localStorage.categories = JSON.stringify(homePageData['data']['categories']); localStorage.locations = JSON.stringify(homePageData['data']['locations']); localStorage.sliders = JSON.stringify(homePageData['data']['sliders']); homePageData['data']['configurations'].location_id = this.userLocation; localStorage.config = JSON.stringify(homePageData['data']['configurations']); if(!localStorage.org){ localStorage.org = JSON.stringify(homePageData['data']['org']); } localStorage.taxgroups = JSON.stringify(homePageData['data']['taxgroups']); localStorage.taxslabs = JSON.stringify(homePageData['data']['taxslabs']); this.loadedCache = true; this.cartService.taxGroupDatafn(homePageData['data']['taxgroups']); this.cartService.taxSlabDatafn(homePageData['data']['taxslabs']); } } /* @usage: called click on login button @purpose:To open the login Dialog. */ login() { this.sidemenu.close(); this.bsModalRef = this.modalService.show(LoginModalComponent, { initialState: { title: 'Login', } }); this.bsModalRef.content.event.subscribe(modelResult => { if (modelResult) { this.assignUserDetails(); } }); } assignUserDetails(){ if (localStorage.getItem('user')) { this.userLoggedIn = true; let user = JSON.parse(localStorage.getItem('user')); if(user.location){ this.userLocation = user.location; }else{ let locations = JSON.parse(localStorage.getItem('locations')); this.userLocation = locations.find(location => { return location.is_default; }).location_id; } //this.walletValue = user.wallet; this.isAdmin = user.isAdmin; this.userSSO = user.username; // this.locationDropdown.setValue(user.location); let locationObject = { location_id: this.userLocation } this.locationChanged(locationObject); } } /* @purpose: To open the modal to sign up */ signUpPopup() { this.sidemenu.close(); this.bsModalRef = this.modalService.show(SignUpModalComponent, { initialState: { title: 'Sign Up', } }); this.bsModalRef.content.event.subscribe(modelResult => { if (modelResult) { this.assignUserDetails(); } }); } //Set User Logged In status, when user logged in/out from My account dropdown setUserLoggedInStatus(userLoggedInStatus){ if(userLoggedInStatus) { this.assignUserDetails(); } else { this.logout(); } } //To logout the current user logout() { this.sidemenu.close(); this.userLoggedIn = false; this.auth.logout(); this.itemsInCart = []; localStorage.cartItems = JSON.stringify(this.itemsInCart); this.cartService.setItemsInCart(JSON.stringify(this.itemsInCart)); this.toastr.success('Successfully logged out!'); } openMyOrders() { this.sidemenu.close(); this.router.navigate(['/home/myOrders']); } openMyaddresses(){ this.sidemenu.close(); this.router.navigate(['/home/myAddresses']); } displayPopUp(){ this.bsModalRef = this.modalService.show(AlertModalComponent, { backdrop: 'static', keyboard: false, animated: true, ignoreBackdropClick: true, initialState: { data: 'Please download App to refer.', infoPopup: true } }); } viewWalletValue(){ this.auth.getWalletValue(this.userSSO).subscribe((result: { status: string, message: string, data })=>{ if (result.status === 'success') { this.walletDisplayed = true; this.walletValue = result.data; if(localStorage.getItem('user')){ let user = JSON.parse(localStorage.getItem('user')); user.wallet = this.walletValue; localStorage.user = JSON.stringify(user); } } }, (error) => { this.toastr.error('Something went wrong! Please try again'); } ); } toggleSideNav(){ if(this.walletDisplayed){ this.walletDisplayed = false; this.walletValue = undefined; } } hideSideNav(event: any){ event.toggle(); this.toggleSideNav(); } showCart() { this.cartDisplayed = true; window.scroll({ top: 0, left: 0, behavior: 'smooth' }); var width = (window.innerWidth > 0) ? window.innerWidth : screen.width; const selector: HTMLElement = window.document.querySelector( 'app-customer-portal' ); if (width > 768) // Items images will be displayed when device width is more than 768px { this.contentDisplayed = true; selector.removeAttribute("style"); } } reloadCache(cartItems){ if (typeof (Storage) !== 'undefined') { if(localStorage.getItem('config')){ let config = JSON.parse(localStorage.getItem('config')), itemsInCart; this.itemVariantService.getLocationBasedVariants(config.location_id).subscribe((items: { status, message, data }) => { this.router.navigate(['/home']); localStorage.promoOrKeyItems = JSON.stringify(items.data.keyorpromoitems); localStorage.nonKeyOrPromoItems = JSON.stringify(items.data.nonkeyorpromoitems); this.allItemsloaded = true; this.allItems = [...items.data.keyorpromoitems, ...items.data.nonkeyorpromoitems]; this.messengerService.promoKeyDatafn(items.data.keyorpromoitems); this.messengerService.nonPromoAndKeyDatafn(items.data.nonkeyorpromoitems); localStorage.customerItemsLastUpdatedDate = new Date().toISOString(); if(cartItems && cartItems.length > 0){ itemsInCart = this.allItems.filter(item => { let foundItemInCart = cartItems.find(cartItem => { return cartItem['item_id'] === item.item_id && item.is_available && item.variants.find(variant => { if(variant.variant_id === cartItem['variant_id'] && variant.is_available) return true; }); }); if( foundItemInCart ) { item.numberOfCartItems = foundItemInCart['numItems']; item.selectedConstituents = foundItemInCart['constituent_name']; item.variant_id = foundItemInCart['variant_id']; return item; } }); if(itemsInCart && itemsInCart.length > 0){ var index = 0, cartItemsLength = itemsInCart.length, cartItem, variant, newItem = []; for(index; index < cartItemsLength; index++){ cartItem = itemsInCart[index]; variant = cartItem.variants.find(variant => {if(variant.variant_id === cartItem['variant_id']) return variant;}); newItem.push({ item_name: cartItem.item_name, item_id: cartItem.item_id, isInventory: cartItem.is_inventory, variant_id: variant.variant_id, discount_percent: Number((100 - ((100 * variant.discount_price) / variant.sales_price)).toFixed(0)), discount_price: variant.discount_price, sales_price: variant.sales_price, variant: variant.variant, variant_unit: variant.variant_unit, numItems: cartItem.numberOfCartItems, totalDiscountPrice: variant.discount_price * cartItem.numberOfCartItems, totalSalesPrice: variant.sales_price * cartItem.numberOfCartItems, cost_price: variant.cost_price, taxable:variant.taxable, interTaxSlab: variant.inter_state_tax, intraTaxGroup: variant.intra_state_tax, constituent_name: cartItem.selectedConstituents, is_available: variant.is_available }); } } } this.itemsInCart = newItem ? newItem : []; localStorage.cartItems = JSON.stringify(this.itemsInCart); this.cartService.setItemsInCart(JSON.stringify(this.itemsInCart)); }); } } } /* Hide cart if click outside of cart area */ @HostListener('document:mouseup', ['$event']) clickout(event) { if (event && event.target && event.target.id === "btn-close-espl-cart" || this.cartContainer && this.cartContainer.esplcart && !this.cartContainer.esplcart.nativeElement.contains(event.target)) { this.cartDisplayed = false; this.contentDisplayed = true; const selector: HTMLElement = window.document.querySelector( 'app-customer-portal' ); selector.removeAttribute("style"); } } @HostListener('window:resize', ['$event']) onResize(event) { if (event.target.innerWidth > 959) { this.sidemenu.close(); } } }