// // "quote" is the quote process module and is loaded into the main angular application (budget). Each of the files in this //var quoteScripts = ['selection', 'personal', 'home', 'car', 'bundles','portable']; // directory contains a controller or controllers that are loaded into the quote angular module (which is defined in this file). //this loads all the quote steps. Note that each of them lists quote.js (THIS FILE) as a dependency so they will //be loaded after the quote module is initialized. var stepControllers = [ 'Selection', 'Personal', 'Home', 'Building', 'Car', 'Motorcycle', 'RegularDriver', 'Portable', 'PortableItems', 'Bundles', 'FinalSummary', 'AcceptHouseholdMember', 'AcceptPortable', 'AcceptClaimsAndLosses', 'AcceptClaimsAndLossesHome', 'AcceptClaimsAndLossesPerson', 'AcceptClaimsAndLossesWatercraft', 'Payment', 'TermsAndConditions', 'ReferToManager', 'UnacceptableRisk', 'Onboarding', 'Register', 'LinkAccounts', 'BackNext', 'Trailer', 'Watercraft', 'Caravan', 'GolfCart', 'ResumeQuote', 'QuickQuote', 'QuickQuoteSummary' ] //ask requirejs to load quote scripts. the array must be the same as above with quote/ in front and case change requirejs([ 'quote/personal', 'quote/home', 'quote/building', 'quote/car', 'quote/motorcycle', 'quote/regulardriver', 'quote/portable', 'quote/portableItems', 'quote/bundles', 'quote/finalsummary', 'quote/accepthouseholdmember', 'quote/acceptPortable', 'quote/acceptclaimsandlosses', 'quote/payment', 'quote/termsandconditions', 'quote/refertomanager', 'quote/unacceptablerisk', 'quote/register', 'quote/onboarding', 'quote/linkaccounts', 'quote/backnext', 'quote/trailer', 'quote/watercraft', 'quote/caravan', 'quote/golfcart', 'quote/resumequote', 'quote/quickquote', 'quote/quickquotesummary' ]); define(['lib/fingerprint', 'autocomplete', 'lib/json-formatter', 'lib/angular-route', 'callmebackblock', 'utilities', 'validators', 'quotestarter'], function (fingerprint) { var rootScopeHelper = {}; return angular.module('quote', ['utilities', 'validators', 'callmebackblock', 'autocomplete', 'jsonFormatter', 'ngRoute', 'ngIdle', 'quotestarter']) .config(["$routeProvider", function ($routeProvider) { //helper function that will route each step by name function route(step) { function routeOptions(step) { //note: this function returns a function function templateUrl(step) { return function (parameters) { if (rootScopeHelper.$rootScope && rootScopeHelper.$rootScope.ReferenceNumber) { var referenceNumber = rootScopeHelper.$rootScope && rootScopeHelper.$rootScope.ReferenceNumber.match(/^[^\|]+/)[0]; var typeString = ""; var quoteType = rootScopeHelper.$rootScope && rootScopeHelper.$rootScope.QuoteType; if (quoteType) typeString = '/' + quoteType; if (referenceNumber) { return '/Quote/' + encodeURIComponent(referenceNumber) + typeString + '/' + encodeURIComponent(step) } else { return '/Quote/' + encodeURIComponent(step); } } else { return '/Quote/' + encodeURIComponent(step); } } } return { controller: step, templateUrl: templateUrl(step) }; } //register the route for step $routeProvider.when('/' + step.toLowerCase(), routeOptions(step)); //new angular seems to always call quote.js, the following step always add #/selection if its not a quote page if (window.location.href && window.location.href.indexOf("#/") > -1) { $routeProvider.otherwise('/selection'); } } stepControllers.forEach(route); }]) .controller('Quote', ['$scope', '$http', '$q', "$rootScope", '$anchorScroll', 'VehicleHelpers', 'PersonHelpers', '$templateCache', '$location', function ($scope, $http, $q, $rootScope, $anchorScroll, VehicleHelpers, PersonHelpers, $templateCache, $location) { //allows us to get the root scope later prop(rootScopeHelper, "$rootScope", function () { return $rootScope; }); $rootScope.IsBroker = false; if (typeof _IsBroker != "undefined" && _IsBroker) $rootScope.IsBroker = true; //this method will initialize the quote state scope variable in its own special way function InitializeQuoteState(quote) { if (!quote) quote = {}; //If we are doing an amendment hide the default message. We could have different headers for different amendments as they are loading here if so desired if (quote.Type && quote.Type == "Amendment") { quoteStepHeader = { 'MainHTMLHeader': '', 'SubTextHeader': '', 'ShowLoader': false, 'isFinalSummary': false } } else { quoteStepHeader = { 'MainHTMLHeader': '

Your quote is just a couple of steps away

', 'SubTextHeader': '', 'ShowLoader': false, 'isFinalSummary': false } } VehicleHelpers.init(quote); PersonHelpers.init(quote); //creates a property on $scope called "Quote" that can not be written without throwing prop($scope, "Quote", function () { return quote; }, function (newValue) { throw "Quote may only be initialized by InitializeQuoteState"; }); prop($scope, "QuoteStepHeader", function () { return quoteStepHeader; }, function (newValue) { throw "QuoteStepHeader may only be initialized by InitializeQuoteState"; }); //a hiddenprop will not be serialized. Here we add a property called "PolicyHolder" on quote //which get's the policy holder, but it cannot be set or serialized as JSON hiddenprop(quote, "PolicyHolder", function () { if (!quote.Persons) quote.Persons = []; var ph = quote.Persons.filter(function (p) { return p.IsPolicyHolder; })[0]; if (!ph) { ph = { IsPolicyHolder: true }; quote.Persons.push(ph); } return ph; }); //When we are on the first step of a quote we will want to navigate to where the user was when het clicks back $scope.NavPreviousULR = document.referrer; } $scope.GoHomeButtonText = "Go to homepage"; if ($rootScope.IsBroker) { $scope.GoHomeButtonText = "Broker Dashboard"; } $scope.goToHome = function () { if ($rootScope.IsBroker) window.location = "/brokers/dashboard"; else window.location = '/'; } $rootScope.InitializeQuoteState = InitializeQuoteState; $rootScope.NavigationInProgress = false; //from ~/Views/Quote/Index.cshtml:4 InitializeQuoteState(GetQuoteState()); function PostQuoteState(url, paramObj) { if (!$rootScope.NavigationInProgress) { $rootScope.NavigationInProgress = true; $scope.loadingNext = true; var deferred = $q.defer(); //patch the url up if needed if (!url.match(/\//)) { if ($scope.ReferenceNumber) { var typeString = ""; var quoteType = rootScopeHelper.$rootScope && rootScopeHelper.$rootScope.QuoteType; if (quoteType) typeString = '/' + quoteType; url = "/Quote/" + encodeURIComponent($scope.ReferenceNumber.match(/^[^\|]+/)[0]) + typeString + '/' + url + "/Submit"; } else { url = "/Quote/" + url + "/Submit"; } } //Goes through and adds additional parameters to the url if (paramObj) { url += "?"; var count = 0; for (var x in paramObj) { if (count++ > 0) url += "&"; url += encodeURIComponent(x) + "=" + encodeURIComponent(paramObj[x]) } } //do the http call $http({ method: 'POST', url: url, data: $scope.Quote, headers: { 'RequestVerificationToken': $scope.Quote.antiForgeryToken } }).then(function success(data, status, headers, config) { data = data && data.data; var referenceNumber = data && data.ReferenceNumber; if (referenceNumber) $rootScope.ReferenceNumber = referenceNumber; else return window.location = '/login'; //must we redirect? if (data && data.MustRedirect && data.RedirectUrl) { //do the redirect if (data.IsBroker && data.CurrentStepName.toLowerCase() === "onboarding" && data.Type.toLowerCase() === "amendment") window.location = "/brokers/client" + data.RedirectUrl; else window.location = data.RedirectUrl; //and don't resolve } else { //otherwise, start setting the qoute $rootScope._quoteToLoad = data; $rootScope._resolve = function () { deferred.resolve(data); }; var previousHash = window.location.hash; var naviageHash = '#/' + encodeURIComponent(data.CurrentStepName.toLowerCase()); window.location.hash = naviageHash; previousHash = (previousHash.indexOf('?') > -1) ? previousHash.substr(0, previousHash.indexOf('?')) : previousHash; if (previousHash == naviageHash) { //I do not like using this, but the routeChangeSuccess was not being called, thus not updating the quote state. $rootScope.$broadcast('$routeChangeSuccess', null); } } }, function failure() { $rootScope.NavigationInProgress = false; deferred.reject.apply(this, arguments); }); return deferred.promise; } } $scope.MVDinit = function () { if ($scope.Quote.ReferenceNumberDisplay && !$scope.Quote.DiscountDetails) { $http({ method: 'POST', url: '/MVD/GetMVDDetails', data: { referenceNumber: $scope.Quote.ReferenceNumberDisplay } }).then( function (data) { $scope.Quote.DiscountDetails = data.data.DiscountAmount; } ); } }(); if ($scope.Quote && !$scope.Quote.Hash) { $scope.Quote.Hash = fingerprint.md5hash; } $scope.removeFromArray = function (array, index) { array.splice(index, 1); } //Set the header in the red title block $scope.SetStepHeader = function (newMainHTMLHeader, newSubTextHeader) { if (typeof newMainHTMLHeader === 'string') { $scope.QuoteStepHeader.MainHTMLHeader = newMainHTMLHeader; } if (typeof newSubTextHeader === 'string') { $scope.QuoteStepHeader.SubTextHeader = newSubTextHeader; } } $scope.SetIsFinalSummary = function (value) { $scope.QuoteStepHeader.isFinalSummary = value; } //Control when to show the header loading functionality $scope.SetStepLoading = function () { $scope.QuoteStepHeader.ShowLoader = true; } $scope.SetStepLoaded = function () { $scope.QuoteStepHeader.ShowLoader = false; } $scope.$on('$viewContentLoaded', function () { $rootScope.NavigationInProgress = false; $scope.loadingNext = false; }); $scope.PostQuoteState = PostQuoteState; $scope.AddRiskItem = function (quoteStep) { $http({ method: 'POST', url: '/Quote/Bundles/AddRiskItem', data: { quoteState: $scope.Quote, riskItem: quoteStep } }).then(function (data, status, headers, config, statusText) { data = data.data || data; InitializeQuoteState(data); }, function (error) { console.error('Error: ', error); }); }; $scope.EditRiskItem = function (riskItem, sequenceNumber) { $http({ method: 'POST', url: '/Quote/FinalSummary/EditRiskItem', data: { quoteState: $scope.Quote, riskItem: riskItem, sequenceNumber: sequenceNumber } }).then(function (data, status, headers, config) { data = data.data || data; InitializeQuoteState(data); }, function (error) { console.error('Error: ', error); }); }; //set the root scope reference number $scope.$watch('Quote.ReferenceNumber', function (referenceNumber) { $rootScope.ReferenceNumber = referenceNumber; }) //set the root scope reference number $scope.$watch('Quote.TypeDisplay', function (type) { $rootScope.QuoteType = type; }) //watch current step name and navigate $scope.$watch('Quote.CurrentStepName', function (step) { var naviageHash = encodeURIComponent(step.toLowerCase()); //navigate $location.path(naviageHash).replace(); }); // generic previous function $scope.NavPrevious = function () { var qs = $scope.Quote; var amIOnTheFirstStep = qs.QuoteNavigation[0] == qs.CurrentStep || (qs.QuoteNavigation && qs.QuoteNavigation.length == 0); if (amIOnTheFirstStep) { if ($scope.NavPreviousULR) { window.location.href = $scope.NavPreviousULR; } else { window.history.back(); } } else { return PostQuoteState('/Quote/Quote/Previous'); } } // generic next function: you should probably not be using this, unless your page has no validation/tape work $scope.NavNext = function () { return PostQuoteState('/Quote/Quote/Next'); }; //personal $scope.PersonalSubmit = function () { $scope.Quote.CurrentStep = "Personal"; return PostQuoteState('Personal'); }; //selection $scope.SelectionSubmit = function () { $scope.Quote.CurrentStep = "Selection"; return PostQuoteState('Selection'); }; //building $scope.BuildingSubmit = function () { $scope.Quote.CurrentStep = "Building"; return PostQuoteState('Building'); }; //home $scope.HomeSubmit = function () { $scope.Quote.CurrentStep = "Home"; return PostQuoteState('Home'); }; $scope.TrailerSubmit = function () { $scope.Quote.CurrentStep = "Trailer"; return PostQuoteState('Trailer'); }; $scope.CarSubmit = function () { $scope.Quote.CurrentStep = "Car"; return PostQuoteState('Car'); }; $scope.MotorcycleSubmit = function () { $scope.Quote.CurrentStep = "Motorcycle"; return PostQuoteState('Motorcycle'); }; $scope.RegularDriverSubmit = function () { $scope.Quote.CurrentStep = "RegularDriver"; return PostQuoteState('RegularDriver'); }; $scope.PortableSubmit = function () { $scope.Quote.CurrentStep = "Portable"; return PostQuoteState('Portable'); }; $scope.PortableItemsSubmit = function () { $scope.Quote.CurrentStep = "PortableItems"; return PostQuoteState('PortableItems'); }; $scope.BundlesSubmit = function () { $scope.Quote.CurrentStep = "Bundles"; return PostQuoteState('Bundles'); }; $scope.FinalSummarySubmit = function () { $scope.Quote.CurrentStep = "FinalSummary"; return PostQuoteState('FinalSummary'); }; $scope.AcceptHouseholdMemberSubmit = function () { $scope.Quote.CurrentStep = "AcceptHouseholdMember"; return PostQuoteState('AcceptHouseholdMember'); }; $scope.AcceptClaimsAndLossesSubmit = function () { $scope.Quote.CurrentStep = "AcceptClaimsAndLosses"; return PostQuoteState('AcceptClaimsAndLosses'); }; $scope.PaymentSubmit = function () { $scope.Quote.CurrentStep = "Payment"; return PostQuoteState('Payment'); }; $scope.TermsAndConditionsSubmit = function () { $scope.Quote.CurrentStep = "TermsAndConditions"; return PostQuoteState('TermsAndConditions'); }; $scope.AcceptPortableSubmit = function () { $scope.Quote.CurrentStep = "AcceptPortable"; return PostQuoteState('AcceptPortable'); }; $scope.SubmitLinkAccounts = function () { $scope.Quote.CurrentStep = "LinkAccounts"; return PostQuoteState('LinkAccounts'); }; $scope.Trailer = function () { $scope.Quote.CurrentStep = "Trailer"; return PostQuoteState('Trailer'); }; $scope.CaravanSubmit = function () { $scope.Quote.CurrentStep = "Caravan"; return PostQuoteState('Caravan'); }; $scope.GolfCartSubmit = function () { $scope.Quote.CurrentStep = "GolfCart"; return PostQuoteState('GolfCart'); }; $scope.SubmitWatercraft = function () { $scope.Quote.CurrentStep = "Watercraft"; return PostQuoteState('Watercraft'); }; $scope.QuickQuoteSubmit = function () { $scope.Quote.CurrentStep = "QuickQuote"; return PostQuoteState('QuickQuote'); }; $scope.QuickQuoteSummarySubmit = function () { ; $scope.Quote.CurrentStep = "QuickQuoteSummary"; return PostQuoteState('QuickQuoteSummary'); }; $scope.RegisterSubmit = function (paramObj) { $scope.Quote.CurrentStep = "Register" return PostQuoteState('Register', paramObj); }; $scope.CheckPortablesWhenDeletingHome = function () { $http({ method: 'POST', url: '/Quote/FinalSummary/RefreshAndCheckPortables', data: { quoteState: $scope.Quote } }).then(function (data, status, headers, config) { InitializeQuoteState(data); }, function (error) { console.error('Error: ', error); }); }; $scope.ActivateAddHousehold = function () { $http({ method: 'POST', url: '/quote/AcceptPortable/ActivateAddHousehold', data: { quoteState: $scope.Quote } }).then(function (data, status, headers, config) { data = data.data || data; InitializeQuoteState(data); }, function (error) { console.error('Error: ', error); }); }; $scope.$on('$routeChangeSuccess', function (event, next, current) { $scope.isBundles = next && (next.$$route.controller.toLowerCase() === 'bundles' && $scope.Quote && $scope.Quote.Type !== 'Amendment'); $scope.fullWidthContainer = next && ( next.$$route.controller.toLowerCase() === 'finalsummary' || next.$$route.controller.toLowerCase() === 'onboarding' || next.$$route.controller.toLowerCase() === 'termsandconditions' || next.$$route.controller.toLowerCase() === 'refertomanager' || next.$$route.controller.toLowerCase() === 'unacceptablerisk' || ($scope.isBundles) ); }); //Goolge $scope.showMap = true; var iconcolours = { 'red': "//maps.google.com/mapfiles/ms/icons/red-dot.png" }; var marker = new google.maps.Marker(); $scope.mapOptions = { center: new google.maps.LatLng(-26, 27), zoom: 6, disableDefaultUI: true, zoomControl: true }; function makeMarker(lat, lon, colour, infoObj) { var content = "" + (infoObj.title || infoObj.FullAddress) + ""; content += (infoObj.Address1) ? "
" + infoObj.Address1 + "," : ""; content += (infoObj.Address2) ? "
" + infoObj.Address2 + "," : ""; content += (infoObj.Address3) ? "
" + infoObj.Address3 : ""; if (infoObj.AddressLattitude && infoObj.AddressLongitude) { content += "
Latitude: " + infoObj.AddressLattitude; content += "
Longitude: " + infoObj.AddressLongitude; } var myLatlng = new google.maps.LatLng(lat, lon); var mapMarker = new google.maps.Marker({ position: myLatlng, map: map, icon: iconcolours[colour], title: infoObj.title || infoObj.FullAddress }); var infowindow = new google.maps.InfoWindow({ content: content }); mapMarker.addListener('click', function () { infowindow.open(map, mapMarker); }); return mapMarker; } function pantoaddress(locationMarker) { map.setZoom(17); map.panTo(locationMarker.position); } $scope.SearchLocation = function (locationdata) { marker.setMap(null); marker = makeMarker(locationdata.AddressLattitude, locationdata.AddressLongitude, "red", locationdata); pantoaddress(marker); }; $scope.placeMarker = function (location, pan) { $scope.loading = true; marker.setMap(null); marker = new google.maps.Marker({ position: location, map: map, icon: iconcolours['red'] }); reverseGeocodePoint(location); if (pan) { pantoaddress(marker); $scope.isActive = true; } else $scope.isActive = false; } function reverseGeocodePoint(latlng) { var geocoder = new google.maps.Geocoder(); geocoder.geocode( { 'latLng': latlng }, function (results, status) { if (status == google.maps.GeocoderStatus.OK) { if (results[0]) { $scope.Quote.RiskAddress = populateAddressModel(results[0]); $scope.loading = false; } } } ) } function tryGetSuburb(addrComp, typeString) { // Order to check if (!typeString || typeString == "") typeString = "sublocality"; else if (typeString == "sublocality") typeString = "administrative_area_level_3"; else if (typeString == "administrative_area_level_3") typeString = "locality"; else return ""; for (var compIdx = 0; compIdx < addrComp.length; compIdx++) { for (var typeIdx = 0; typeIdx < addrComp[compIdx].types.length; typeIdx++) { if (addrComp[compIdx].types[typeIdx] == typeString) { return addrComp[compIdx].short_name; } } } return tryGetSuburb(addrComp, typeString); } function populateAddressModel(address) { var riskAddress = {}; riskAddress.AddressLattitude = address.geometry.location.lat(); riskAddress.AddressLongitude = address.geometry.location.lng(); //Street nr should be added to street if (address.address_components[0].types[0] == 'street_number') { riskAddress.Address1 = address.address_components[0].short_name + ' ' + address.address_components[1].short_name; riskAddress.Address2 = address.address_components[2].short_name; riskAddress.Address3 = address.address_components[3].short_name; riskAddress.SuburbName = tryGetSuburb(address.address_components); } else if (address.address_components[1].types[0] == 'street_number') { riskAddress.Address1 = address.address_components[1].short_name + ' ' + address.address_components[2].short_name; riskAddress.Address2 = address.address_components[3].short_name; riskAddress.Address3 = address.address_components[4].short_name; riskAddress.SuburbName = tryGetSuburb(address.address_components); } else if (address.address_components.length > 2) { riskAddress.Address1 = address.address_components[0].short_name; riskAddress.Address2 = address.address_components[1].short_name; riskAddress.Address3 = address.address_components[2].short_name; riskAddress.SuburbName = tryGetSuburb(address.address_components); } else { riskAddress.Address1 = address.address_components[0].short_name; riskAddress.Address2 = address.address_components[1].short_name; riskAddress.SuburbName = tryGetSuburb(address.address_components); } for (var i = 0; i < address.address_components.length; i++) { var addressType = address.address_components[i].types[0]; if (addressType == 'postal_code') { riskAddress.PostCode = address.address_components[i].short_name; } } return riskAddress; } $scope.showHideMap = function () { $scope.showMap = !$scope.showMap; } //Current Location $scope.getLocation = function () { $scope.isActive = false; if (navigator.geolocation) navigator.geolocation.getCurrentPosition(successCallback); function successCallback(position) { if (position.timestamp > new Date(Date.now() - 1 * 60 * 60 * 1000)) { var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); $scope.placeMarker(latlng, true); } }; } //Current Suburb Location $scope.getSuburbLocation = function () { navigator.geolocation.getCurrentPosition(successCallback, errorCallback, { maximumAge: Infinity, timeout: 5000 }); function successCallback(position) { // By setting the 'maximumAge' to Infinity, the position // object is guaranteed to be a cached one. // By using a 'timeout' of 0 milliseconds, if there is // no cached position available at all, the user agent // will immediately invoke the error callback with code // TIMEOUT and will not initiate a new position // acquisition process. if (position.timestamp > new Date(Date.now() - 1 * 60 * 60 * 1000)) { var geocoder; geocoder = new google.maps.Geocoder(); var latlng = new google.maps.LatLng(position.coords.latitude, position.coords.longitude); geocoder.geocode( { 'latLng': latlng }, function (results, status) { if (status == google.maps.GeocoderStatus.OK) { if (results[0]) { var add = results[0].formatted_address; var value = add.split(","); var count = value.length; var suburb = value[count - 4]; if (suburb.charAt(0) === ' ') { suburb = suburb.substr(1); } $http({ method: 'POST', url: '/quote/personal/GetSuburbExact', data: { suburbName: suburb, postalCode: value[count - 2] } }).success(function (data, status, headers, config) { $rootScope.currentLocationSub = data; $rootScope.enablecurrentlocation = true; }).error(function (data, status, headers, config) { $rootScope.enablecurrentlocation = true; }); } } } ) } else { doFallback(); } } function errorCallback(error) { doFallback(); } function doFallback() { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(function (position) { var latitude = position.coords.latitude; var longitude = position.coords.longitude; var geocoder; geocoder = new google.maps.Geocoder(); var latlng = new google.maps.LatLng(latitude, longitude); geocoder.geocode( { 'latLng': latlng }, function (results, status) { if (status == google.maps.GeocoderStatus.OK) { if (results[0]) { var add = results[0].formatted_address; var value = add.split(","); var count = value.length; var suburb = value[count - 4]; if (suburb.charAt(0) === ' ') { suburb = suburb.substr(1); } $http({ method: 'POST', url: '/quote/personal/GetSuburbExact', data: { suburbName: suburb, postalCode: value[count - 2] } }).success(function (data, status, headers, config) { $rootScope.currentLocationSub = data; $rootScope.enablecurrentlocation = true; }).error(function (data, status, headers, config) { $rootScope.enablecurrentlocation = true; }); } } } ) }); } } } }]) .run(['$rootScope', '$templateCache', '$anchorScroll', function ($rootScope, $templateCache, $anchorScroll) { $rootScope.$on('$routeChangeStart', function (event, next, current) { if (typeof (current) !== 'undefined') { $templateCache.remove(current.loadedTemplateUrl); } $rootScope.NavigationInProgress = true; }); $rootScope.$on('$routeChangeSuccess', function (event, next, current) { // route loaded if ($rootScope._quoteToLoad) { $rootScope.InitializeQuoteState($rootScope._quoteToLoad); $rootScope._resolve($rootScope._quoteToLoad); delete $rootScope._resolve; delete $rootScope._quoteToLoad; } $rootScope.NavigationInProgress = false; $anchorScroll(); }); }]); });