{"version":3,"sources":["wwwroot/js/app/controllers/survey/Survey.Dashboard.Controller.js","wwwroot/js/app/controllers/survey/Survey.Details.Controller.js","wwwroot/js/app/controllers/survey/Survey.List.Controller.js","wwwroot/js/app/controllers/survey/Survey.Response.List.Controller.js","wwwroot/js/app/controllers/survey/Survey.Response.List.Directive.js","wwwroot/js/app/controllers/survey/Survey.View.Controller.js","wwwroot/js/app/controllers/survey/Survey.View.Directive.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AC9ZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AChTA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACrFA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACjBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;ACjEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"survey.min.js","sourcesContent":["'use strict';\n\nangular\n .module('App.v1.Controllers')\n .controller(\"App.v1.Survey.Dashboard.Controller\",\n [\"$scope\", \"$q\", \"$log\", \"$interval\", \"App.v1.Services.Survey\", \"App.v1.Services.Odata.Snap\", \"App.v1.Services.Response\", \"$document\",\n function ($scope, $q, $log, $interval, surveyService, snapQueryService, responseService, $document) {\n\n $scope.vm = {\n liveUpdates: false,\n liveUpdatesConnecting: false,\n surveys: [],\n responses: [],\n skip: 0,\n take: 50,\n toggleAllValue: true,\n showNewOnly:false,\n snapFilterLimit: 1,\n replyActive: false,\n focus: null\n };\n\n $scope.pendingReply = [];\n\n $scope.surveysById = {};\n\n //assume that the majority of the responses came from the surveys they most recently created\n function loadSurveys() {\n var deferred = $q.defer();\n \n snapQueryService.query(\n {\n \"$orderby\": 'lastResponseDate desc',\n \"$top\": 30\n }, function(results) {\n _.forEach(results, updateSurveyDetails);\n \n $scope.vm.surveys = results;\n $scope.surveysById = _.keyBy(results, \"id\");\n\n deferred.resolve(); // Resolve the promise when the query completes\n });\n \n return deferred.promise;\n }\n\n\n this.$onInit = function () {\n loadSurveys().then(function() {\n $scope.getPage();\n connectToLiveUpdates();\n });\n }\n\n //every 30 seconds go update the labels on the 'updated X minutes ago' text\n $interval(function () { updateRecency($scope.vm.responses); }, 30000);\n\n $scope.getPage = function () {\n responseService.list({\n \"includeAll\": true,\n \"skip\": $scope.vm.skip,\n \"take\": $scope.vm.take\n })\n .$promise\n .then(function (page) {\n $scope.vm.responses = page.items;\n $scope.vm.take = page.take;\n $scope.vm.skip = page.skip;\n $scope.vm.total = page.total;\n\n $scope.vm.currentPage = ($scope.vm.skip / $scope.vm.take) + 1;\n $scope.vm.totalPages = Math.ceil($scope.vm.total / $scope.vm.take);\n\n updateSurveyCounts();\n\n //we want to use a proper for loop here so that we only have one \n //thread going at once\n for (var i = 0; i < page.items.length; i++) {\n var response = page.items[i];\n\n //we pulled down a response for survey that we don't know about. grab it and add it\n if (!$scope.surveysById[response.snapID]) {\n\n //make a placeholder object so that the if won't get hit again\n $scope.surveysById[response.snapID] = {\n \"name\": \"Loading...\"\n };\n\n surveyService.get({ 'id': response.snapID }, function (surveyGetResponse) {\n updateSurveyDetails(surveyGetResponse);\n $scope.vm.surveys.push(surveyGetResponse);\n $scope.surveysById[surveyGetResponse.id] = surveyGetResponse;\n });\n }\n }\n\n updateRecency(page.items);\n });\n }\n\n\n $scope.showOnlyNew = function () {\n $scope.vm.showNewOnly = true;\n }\n\n $scope.showAll = function () {\n $scope.vm.showNewOnly = false;\n }\n\n /** Snap Visibility Control */\n $scope.showAllSnaps = function () {\n return $scope.vm.snapFilterLimit = 0;\n }\n\n $scope.showActiveSnaps = function () {\n return $scope.vm.snapFilterLimit = 1\n }\n\n $scope.snapFilter = function (survey) {\n return survey.newCount >= $scope.vm.snapFilterLimit;\n }\n\n $scope.responseFilter = function (response) {\n if($scope.vm.snapFilterLimit == 0)\n {\n return true;\n }\n else\n {\n return response.isNew ? true : false;\n }\n }\n\n /**\n * Toggle Open/Done state of a Snap Response\n * @param {any} response Response Instance\n */\n $scope.toggleRead = function (response)\n {\n response.isNew = !response.isNew;\n //Resoved should be the opposite of isNew. If it's new, it's not resolved. etc\n response.IsResolved = !response.isNew;\n updateSurveyStatus(response);\n updateSurveyCounts();\n \n }\n\n\n $scope.enableNotifications = function (e) {\n e.preventDefault();\n\n self.Notification.requestPermission().then(res => console.log(res))\n };\n\n /**\n * Toggle the reply UI for a response\n * @param {object} response \n */\n $scope.toggleReply = function (response) {\n response.replyActive = !response.replyActive;\n }\n\n /**\n * Send a reply to a conversation\n * @param {object} response \n */\n $scope.sendReply = function (response) {\n\n var message = $scope.pendingReply[response.id];\n\n responseService.reply(\n { id: response.id },\n { message: message }\n ).$promise\n .then(function (conversationEntry) {\n response.replyActive = false;\n $scope.pendingReply[response.id] = '';\n var existingResponse = _.find($scope.vm.responses, { id: response.id });\n if (existingResponse) {\n existingResponse.conversations = existingResponse.conversations || [];\n existingResponse.conversations.push(conversationEntry);\n }\n })\n .catch(function (error) {\n $log.error(error);\n });\n }\n\n /**\n * Focus on a single snap in the dashboard list\n */\n $scope.focusSnapVisibility = function(snap)\n {\n if($scope.vm.focus != snap)\n {\n $scope.vm.focus = snap;\n _.forEach($scope.vm.surveys, function (s) {\n s._show = s.id === snap.id;\n });\n }\n else\n {\n $scope.vm.focus = null;\n $scope.toggleAllVisibility(true);\n }\n }\n\n $scope.toggleSnapVisbility = function(snap)\n {\n snap._show = !snap._show;\n $scope.vm.focus = null;\n }\n\n /**\n * toggle the visibility of all surveys\n * @param {boolean} value value to set them to\n */\n $scope.toggleAllVisibility = function (value) {\n _.forEach($scope.vm.surveys, function (s) {\n s._show = value;\n });\n }\n\n /**\n * given a survey object\n * * create a dictionary of it's options for easy access\n * * default the display value to true\n * * get a count of the number of unread messages\n * @param {object} survey\n */\n function updateSurveyDetails(survey) {\n if (survey) {\n survey.optionsById = _.keyBy(survey.options, \"id\");\n survey._show = true;\n survey.newCount = survey.newCount || 0;\n }\n }\n\n function updateRecency(responses) {\n _.forEach(responses, function (response) {\n response.recency = Math.ceil((Date.now() - new Date(response.createdDate)) / 1000);\n });\n }\n\n /**\n * Update the count of new responses for each survey\n * Also update the title\n */\n function updateSurveyCounts()\n {\n var surveyCounts = {};\n $scope.vm.responses.forEach(function(response) {\n if(response.isNew)\n {\n surveyCounts[response.snapID] = (surveyCounts[response.snapID] || 0) + 1;\n }\n });\n\n var newResponseCountTotal = _.sumBy($scope.vm.responses, function(response) {\n return response.isNew ? 1 : 0;\n });\n changeTitle(newResponseCountTotal);\n\n \n\n _.forEach($scope.surveysById, function (survey) {\n survey.newCount = surveyCounts[survey.id] || 0;\n });\n }\n\n // Function to change the document title\n function changeTitle(newCount) {\n if(newCount > 0)\n {\n $document[0].title = 'Dashboard 🛎️ (' + newCount + ') - SnapDesk';\n }\n else\n {\n $document[0].title = 'Dashboard - SnapDesk';\n }\n };\n\n //Update the status of a survey response (new/not new)\n function updateSurveyStatus(response)\n {\n\n var deferred = $q.defer();\n \n responseService.update(\n { id: response.id },\n response,\n function () {\n deferred.resolve(); // Resolve the promise when the query completes\n\n }\n );\n\n return deferred.promise;\n }\n\n function connectToLiveUpdates() {\n\n $scope.vm.liveUpdatesConnecting = true;\n\n var connection = new signalR.HubConnectionBuilder()\n .withUrl(\"/notify\")\n .build();\n\n // Create a new web worker\n // var notificationWorker = new Worker('/dist/js/notificationWorker.min.js');\n // notificationWorker.onmessage = (e) => {\n // console.log(\"Message received from worker\");\n // console.log(e.data);\n // var url = `/snap/details/${e.data.snapID}`;\n // window.location.href = url;\n // };\n\n connection.on(\"SurveyResponse\", function (response) {\n response.recency = 0;\n $scope.vm.responses.splice(0, 0, response);\n\n if (angular.isDefined($scope.surveysById[response.snapID])) {\n //$scope.surveysById[response.snapID].newCount++;\n updateSurveyCounts();\n }\n else {\n surveyService.get({ 'id': response.snapID }, function (surveyGetResponse) {\n updateSurveyDetails(surveyGetResponse);\n $scope.vm.surveys.push(surveyGetResponse);\n $scope.surveysById[surveyGetResponse.id] = surveyGetResponse;\n });\n }\n\n // Send the response to the web worker for notification\n // notificationWorker.postMessage(response);\n\n $scope.$apply();\n });\n\n /**\n * Add a new conversation event to the UI\n */\n connection.on(\"ConversationEvent\", function (conversationEntry) {\n\n //Get the response object either from the UI, or load it.\n var existingResponse = _.find($scope.vm.responses, { id: conversationEntry.responseId });\n //create a waitable promise\n var deferred = $q.defer();\n\n if(existingResponse)\n {\n //resolve the promise successfully\n deferred.resolve(existingResponse);\n \n } \n else\n {\n responseService.get({ id: conversationEntry.responseId }, function (response) {\n deferred.resolve(response);\n });\n \n }\n\n //Handle updating the Response Object\n deferred.promise.then(function (response) {\n\n response.conversations = response.conversations || [];\n\n //Check if the converation entry is already there\n var existingConversation = _.find(response.conversations, { id: conversationEntry.id });\n if(!existingConversation)\n {\n response.conversations.push(conversationEntry);\n }\n\n //How many should we add to the \"new\" count on the survey?\n\n //Upsert response to the $scope.vm.responses list, matching by id\n var existingResponseIndex = _.findIndex($scope.vm.responses, { id: response.id });\n if (existingResponseIndex !== -1) {\n $scope.vm.responses[existingResponseIndex] = response;\n } else {\n $scope.vm.responses.push(response);\n }\n\n //Check if survey is there or not\n if (angular.isDefined($scope.surveysById[response.snapID])) {\n updateSurveyCounts();\n //$scope.surveysById[response.snapID].newCount = _.filter($scope.vm.responses, { snapID: response.snapID, isNew: true }).length;\n }\n else \n {\n surveyService.get({ 'id': response.snapID }, function (surveyGetResponse) {\n updateSurveyDetails(surveyGetResponse);\n $scope.vm.surveys.push(surveyGetResponse);\n $scope.surveysById[surveyGetResponse.id] = surveyGetResponse;\n $scope.$apply;\n });\n }\n \n });\n\n\n });\n\n connection.start().then(function () {\n $scope.vm.liveUpdatesConnecting = false;\n $scope.vm.liveUpdates = true;\n }).catch(function (err) {\n $scope.vm.liveUpdatesConnecting = true;\n $scope.vm.liveUpdates = false;\n return $log.error(err.toString());\n });\n }\n }]);","'use strict';\n\nangular\n .module('App.v1.Controllers')\n .value('viewmodel', ViewBag)\n .filter('urlEncode', [\"$window\",\n function ($window) {\n return function (input) {\n if (input) {\n return $window.encodeURIComponent(input);\n }\n return \"\";\n }\n }\n ])\n .controller(\"App.v1.Survey.Details.Controller\",\n [\"$scope\", \"$window\", \"$timeout\", \"App.v1.Services.Survey\", \"App.v1.Services.ServiceMenu\", \"viewmodel\",\n function ($scope, $window, $timeout, surveyService, serviceMenuService, viewmodel) {\n\n serviceMenuService.list({ \"take\": 100 }).$promise\n .then(function (page) {\n $scope.serviceMenus = page.items;\n });\n\n $scope.surveyComplete = false;\n\n //alternative URL to use when generating a QR/url to reduce the amount of\n //data that needs to be encoded\n $scope.shortUrl = viewmodel.qrUrlDomain;\n\n\n $scope.model = {\n zazzleProdId: \"256035703841143983\",\n qrLevels: [\n // At current GUID size, L is irrelevant\n //{\n // level: 'L',\n // name: \"Level L – up to 7% damage\",\n // moduleCount: 00\n //},\n {\n level: 'M',\n name: \"Level M – up to 15% damage\",\n moduleCount:33\n },\n {\n level: 'Q',\n name: \"Level Q – up to 25% damage\",\n moduleCount: 37\n },\n {\n level: 'H',\n name: \"Level H – up to 30% damage\",\n moduleCount: 41\n }],\n displayTypes: [\n {\n id: 0,\n name: \"Hidden\"\n },\n {\n id: 1,\n name: \"Optional\"\n },\n {\n id: 2,\n name: \"Required\"\n }]\n };\n\n //Set Default QR Config\n $scope.model.qrConfig = {\n _min: 1,\n _max: 200,\n\n scale: 50,\n colorDark: \"#000000\",\n colorLight: \"#ffffff\",\n /*\n * Level L – up to 7% damage\n * Level M – up to 15% damage\n * Level Q – up to 25% damage\n * Level H – up to 30% damage\n */\n correctLevel: $scope.model.qrLevels[0]\n };\n\n if (viewmodel.Id && viewmodel.Id != \"\") {\n $scope.surveyInstance = surveyService.get({ id: viewmodel.Id }, createQrCode);\n }\n else {\n $scope.surveyInstance = {\n options: [],\n isDisabled: false,\n labelSubmit: \"Submit\",\n labelOther: \"Other\",\n contactName: 0, // 0 == Hidden\n contactEmail: 0, // 0 == Hidden\n contactPhone: 0 // 0 == Hidden\n };\n }\n\n $scope.mockSurveyComplete = function () {\n $scope.surveyComplete = !$scope.surveyComplete;\n };\n\n\n\n /*\n * Save Handler\n * Creates a new survey or updates existing\n */\n $scope.save = function () {\n if ($scope.surveyInstance.id && $scope.surveyInstance.id != \"\") {\n $scope.surveyInstance = surveyService.update({ id: $scope.surveyInstance.id }, $scope.surveyInstance,\n function () {\n $scope.saved = true;\n $scope.model.error = \"\";\n\n $timeout(function () { $scope.saved = false; }, 2000);\n }, toError);\n }\n else {\n surveyService.create($scope.surveyInstance,\n function (results) {\n $window.location.href = '/snap/details/' + results.id;\n }, toError);\n }\n };\n\n function toError(error) {\n if (angular.isDefined(error.data.errors) && error.data.length > 0) {\n $scope.model.error = _.join(_.flatMap(error.data.errors, (f) => _.flatten(f)), \", \");\n }\n else if(angular.isDefined(error.data.title) && angular.isDefined(error.data.detail)) \n {\n $scope.model.error = error.data.title + \": \" + error.data.detail;\n }\n else \n {\n $scope.model.error = error.data;\n }\n }\n\n $scope.getSelectedServiceMenu = function () {\n\n if ($scope.surveyInstance.serviceMenuID && $scope.surveyInstance.serviceMenuID != null) {\n var serviceMenu = _.find($scope.serviceMenus, { 'id': $scope.surveyInstance.serviceMenuID });\n return serviceMenu;\n } else {\n var serviceMenu = _.first($scope.serviceMenus);\n return serviceMenu;\n }\n };\n\n //Methods ====================================================================\n\n /**\n * Add Option to Option List\n */\n $scope.addOption = function (option) {\n if (option) {\n $scope.surveyInstance.options.push(\n {\n text: option,\n weight: $scope.surveyInstance.options.length,\n isDisabled: false\n }\n );\n\n $scope.newOption = \"\";\n }\n };\n\n /**\n * Move Option Up in Option List\n */\n $scope.moveOption = function (option, step) {\n let sortedOptions = _.sortBy($scope.surveyInstance.options, ['weight']);\n let currentIndex = _.indexOf(sortedOptions, option);\n\n let current = sortedOptions[currentIndex];\n let other = sortedOptions[currentIndex + step];\n if (other) {\n if (current.weight == other.weight) {\n current.weight += step;\n }\n else {\n let temp = current.weight;\n current.weight = other.weight;\n other.weight = temp;\n }\n }\n };\n\n /**\n * Remove option from Option List\n */\n $scope.removeOption = function (option) {\n if (!option.id) {\n $scope.surveyInstance.options.splice($scope.surveyInstance.options.indexOf(option), 1);\n }\n option.isDisabled = true;\n };\n\n /**\n * Remove option from Option List\n */\n $scope.enableOption = function (option) {\n option.isDisabled = false;\n };\n\n /**\n * re-render the QR code using the user's input\n */\n $scope.updateQrCode = function () {\n if ($scope.qr_form.$valid) {\n $scope.model.qrConfig.scale = $scope.userQrSize;\n\n $timeout(function () {\n createQrCode();\n });\n }\n };\n\n function createQrCode() {\n\n //Raw URL\n let url = $scope.shortUrl + \"/-/\" + $scope.surveyInstance.id;\n $scope.viewUrl = url;\n\n //Render QR Code\n\n let qrUrl = getQrCodeUrl(\"png\");\n $scope.model.qrRenderLink = qrUrl;\n }\n\n /**\n * Get QR Code Graphic URL\n * Format: png, pdf, svg\n */\n function getQrCodeUrl(format) {\n return viewmodel.qrToolsHostname + \"/api/alert/\" + $scope.surveyInstance.id\n + \"/image.\" + format\n + \"?quality=\" + $scope.model.qrConfig.correctLevel.level\n + \"&scale=\" + $scope.model.qrConfig.scale\n + \"&color=\" + $window.encodeURIComponent($scope.model.qrConfig.colorDark)\n + \"&background=\" + $window.encodeURIComponent($scope.model.qrConfig.colorLight)\n + \"&name=\" + $window.encodeURIComponent($scope.surveyInstance.name)\n + \"&cb=\" + Date.now();\n }\n\n /**\n * Trigger download of PNG file\n */\n $scope.downloadPng = function () {\n\n let renderUrl = getQrCodeUrl(\"png\");\n $scope.model.qrPng = renderUrl;\n\n //we have to wait for the digest cycle to bind the url to the link\n $timeout(function () {\n document.getElementById(\"downloadPngLink\").click();\n }, 10)\n }\n\n /**\n * Trigger download of SVG file\n */\n $scope.downloadSvg = function () {\n\n let renderUrl = getQrCodeUrl(\"svg\");\n $scope.model.qrSvg = renderUrl;\n\n //we have to wait for the digest cycle to bind the url to the link\n $timeout(function () {\n document.getElementById(\"downloadSvgLink\").click();\n }, 10)\n }\n\n /**\n * Trigger download of PDF file\n */\n $scope.downloadPdf = function () {\n\n let renderUrl = getQrCodeUrl(\"pdf\");\n $scope.model.qrPdf = renderUrl;\n\n //we have to wait for the digest cycle to bind the url to the link\n $timeout(function () {\n document.getElementById(\"downloadPdfLink\").click();\n }, 10)\n }\n\n /**\n * Trigger an Order from Zazzle\n */\n $scope.orderFromZazzle = function () {\n\n //we have to wait for the digest cycle to bind the url to the link\n $timeout(function () {\n document.getElementById(\"orderFromZazzle\").click();\n }, 10)\n }\n }]);","'use strict';\n\nangular\n .module('App.v1.Controllers')\n .controller(\"App.v1.Survey.Index.Controller\",\n [\"$scope\", \"App.v1.Services.Survey\",\n function ($scope, surveyService) {\n $scope.vm = {\n skip: 0,\n take: 100,\n type: \"\",\n surveys: [],\n error: null\n };\n\n /* Keyword Search */\n $scope.searchSurveys = function () {\n $scope.vm.skip = 0;\n $scope.getPage();\n }\n\n $scope.getPage = function () {\n surveyService.list({\n \"skip\": $scope.vm.skip,\n \"take\": $scope.vm.take,\n \"keyword\": $scope.vm.searchKeyword\n })\n .$promise\n .then(function (page) {\n $scope.vm.surveys = page.items;\n\n $scope.vm.take = page.take;\n $scope.vm.skip = page.skip;\n $scope.vm.total = page.total;\n\n $scope.vm.currentPage = ($scope.vm.skip / $scope.vm.take) + 1;\n $scope.vm.totalPages = Math.ceil($scope.vm.total / $scope.vm.take);\n });\n }\n\n $scope.getPage();\n\n $scope.copySurvey = function (surveyInstance) {\n surveyService.get({ id: surveyInstance.id }, function (getFullDetails) {\n\n //blank out the ID so that when we post it duplicates it\n getFullDetails.id = null;\n getFullDetails.name = \"Copy of \" + getFullDetails.name;\n\n _.forEach(getFullDetails.options, function (o) {\n o.id = null;\n });\n\n surveyService.create({}, getFullDetails, function (result) {\n $scope.vm.surveys.push(result);\n $scope.vm.error = null;\n },\n toError);\n });\n }\n\n $scope.deleteSurvey = function (surveyInstance) {\n if (confirm(\"Are you sure you want to delete this Snap and all responses?\")) {\n\n surveyService.delete({ id: surveyInstance.id }, function () {\n _.remove($scope.vm.surveys, { 'id': surveyInstance.id });\n $scope.vm.error = null;\n },\n toError);\n }\n }\n\n function toError(error) {\n if (angular.isDefined(error.data.errors) && error.data.length > 0) {\n $scope.vm.error = _.join(_.flatMap(error.data.errors, (f) => _.flatten(f)), \", \");\n }\n else if(angular.isDefined(error.data.title) && angular.isDefined(error.data.detail)) \n {\n $scope.vm.error = error.data.title + \": \" + error.data.detail;\n }\n else \n {\n $scope.vm.error = error.data;\n }\n }\n }]);","'use strict';\n\nangular\n .module('App.v1.Controllers')\n .value('viewmodel', ViewBag)\n .controller(\"App.v1.Survey.Response.List.Controller\",\n [\"$scope\", \"App.v1.Services.Survey\", \"App.v1.Services.Response\", \"viewmodel\",\n function ($scope, surveyService, responseService, viewmodel) {\n //expose lodash to the UI\n $scope._ = _;\n\n $scope.vm = {\n take: 10,\n skip: 0\n };\n\n $scope.surveyOptions = {};\n $scope.surveyInstance = $scope.data;\n\n this.$onInit = function () {\n //wait for the promise to resolve then try to load it\n if ($scope.data.$promise) {\n $scope.data.$promise.then(function (results) {\n if (results && results.id) {\n $scope.id = results.id;\n\n $scope.getPage();\n $scope.surveyOptions = _.keyBy(results.options, \"id\");\n }\n });\n }\n //load from a survey\n else if ($scope.surveyInstance.Id && $scope.surveyInstance.Id) {\n $scope.id = $scope.surveyInstance.Id;\n\n $scope.getPage();\n $scope.surveyOptions = _.keyBy($scope.surveyResponses.options, \"id\");\n }\n //survey hasn't been created yet\n else { }\n }\n\n $scope.getPage = function() {\n surveyService.listResponses({\n id: $scope.id,\n take: $scope.vm.take,\n skip: $scope.vm.skip\n }).$promise\n .then(function (page) {\n $scope.surveyResponses = page.items;\n\n $scope.vm.take = page.take;\n $scope.vm.skip = page.skip;\n $scope.vm.total = page.total;\n\n $scope.vm.currentPage = ($scope.vm.skip / $scope.vm.take) + 1;\n $scope.vm.totalPages = Math.ceil($scope.vm.total / $scope.vm.take);\n });\n }\n\n /**\n * save an admin's updates\n * @param {any} response\n */\n $scope.saveResponse = function (response) {\n if (response._hasChanges === true) {\n responseService.update({ id: response.id }, response);\n\n response._hasChanges = false;\n response._edit = false;\n }\n }\n\n /**\n * it's a bit brute force but it'll work for now\n */\n $scope.saveAll = function () {\n\n var changed = _.filter($scope.surveyResponses, function (value, index) {\n return value._hasChanges\n });\n\n\n _.forEach(changed, $scope.saveResponse);\n }\n }]);","(function () {\n 'use strict';\n\n angular.module('App.v1.Directives')\n .directive('surveyResponseList', function () {\n return {\n scope: {},\n restrict: 'E',\n controller: \"App.v1.Survey.Response.List.Controller\",\n templateUrl: \"/js/app/controllers/survey/Survey.Response.List.Template.html\",\n scope: {\n data: \"=survey\",\n onSubmit: \"<\",\n showConfirm: \"=\"\n }\n }\n });\n}());","'use strict';\n\nangular\n .module('App.v1.Controllers')\n .value('viewmodel', ViewBag)\n .controller(\"App.v1.Survey.View.Controller\",\n [\"$scope\", \"$log\", \"App.v1.Services.Survey\", \"App.v1.Services.Response\", \"viewmodel\", \"$sce\",\n function ($scope, $log, surveyService, responseService, viewmodel, $sce) {\n\n let markdownLinkPattern = /\\[(.+)\\]\\((.+)\\)/;\n let markdownReplacement = \"$1\";\n $scope.isLoading = true;\n\n if (viewmodel && viewmodel.Id) {\n surveyService.get({ id: viewmodel.Id, includeDesign: true })\n .$promise\n .then(function (response) { \n $scope.surveyInstance = response;\n $scope.surveyInstance.design = $scope.surveyInstance.serviceMenu.design;\n })\n .catch(function (error) {\n $log.error(\"Failed to load survey\", error);\n $scope.errorMsg = \"Unable to load data. Please try again.\";\n })\n .finally(function () {\n $scope.isLoading = false;\n });\n }\n\n $scope.trustAsHtml = function (markdown) {\n let html = markdown.replace(markdownLinkPattern, markdownReplacement);\n\n return $sce.trustAsHtml(html);\n }\n\n /**\n * UI Flag. Indicates whether survey buttons or confirmation should be shown\n */\n $scope.surveyComplete = false;\n\n /**\n * Handle Submit action\n * @param {object} userInput - Form Data\n */\n $scope.submit = function (userInput) {\n let options = _.keys(_.pickBy(userInput.selections, function (v, k) { return v; }));\n\n if (options.length > 0 || userInput.otherText) {\n return responseService.create(\n {\n snapId: viewmodel.Id,\n options: options,\n comment: userInput.comment,\n otherText: userInput.otherText,\n contactName: userInput.contactName,\n contactEmail: userInput.contactEmail,\n contactPhone: userInput.contactPhone\n }, function () {\n $scope.surveyComplete = true;\n $scope.error = null;\n }, function (error) {\n $scope.error = error.data;\n });\n }\n }\n }]);","(function () {\n 'use strict';\n\n angular.module('App.v1.Directives')\n .directive('surveyView', function () {\n return {\n restrict: 'E',\n controller: surveyViewController,\n templateUrl: \"/js/app/controllers/survey/Survey.View.Template.html\",\n scope: {\n design: \"<\",\n serviceMenu: \"<\",\n data: \"=survey\",\n onSubmit: \"<\",\n showConfirm: \"=\"\n }\n }\n\n\n function surveyViewController($scope, $sce) {\n let markdownLinkPattern = /\\[(.+)\\]\\((.+)\\)/;\n let markdownReplacement = \"$1\";\n\n $scope.input = {\n selections: {}\n };\n\n //We bind the view to these instead of directly to the inputs so that we\n // can use cascading assignment if necessary\n $scope.vm = {\n design: null,\n serviceMenu: null,\n };\n\n $scope.showCommentField = false;\n\n $scope.trustAsHtml = function (markdown) {\n if (markdown) {\n let html = markdown.replace(markdownLinkPattern, markdownReplacement);\n\n return $sce.trustAsHtml(html);\n }\n else {\n return markdown;\n }\n }\n\n this.$onInit = function () {\n rebindInputs();\n\n $scope.$watchGroup(['serviceMenu', 'design', 'data'], function () {\n rebindInputs();\n });\n }\n\n /**\n * triggered when the user selects an option (not 'other') and if multi-select\n * is disabled then will toggle all other options to 'off'\n * @param {any} selection what was selected\n */\n $scope.select = function (selection) {\n \n //Show Notes Field (or hide)\n $scope.showCommentField = _.some($scope.input.selections, function (v, k) { return v; });\n\n //if it's not multiselect then unselect everything else when a new one is selected\n if (!$scope.vm.serviceMenu.allowMultiSelect) {\n let isSelected = $scope.input.selections[selection.id];\n\n //Select Action\n if (isSelected) {\n $scope.showCommentField = true;\n _.forEach($scope.input.selections, function (value, key) {\n if (key != selection.id) {\n $scope.input.selections[key] = false;\n }\n });\n\n $scope.input.otherSelected = false;\n }\n }\n }\n\n /**\n * triggered when the 'other' option is selected and if multi-select\n * is disabled then will toggle all other options to 'off'\n */\n $scope.selectOther = function () {\n if (!$scope.vm.serviceMenu.allowMultiSelect) {\n $scope.showCommentField = false;\n\n _.forEach($scope.input.selections, function (value, key) {\n $scope.input.selections[key] = false;\n });\n }\n }\n\n /**\n * @returns {boolean} returns true if the other option is selected and populated\n * or if any of the selections are set to true\n */\n $scope.submitAllowed = function () {\n return ($scope.input.otherSelected && $scope.input.otherText)\n || _.some($scope.input.selections, function (v, k) { return v; });\n }\n\n /**\n * submit the survey using the method defined by the directive\n */\n $scope.submit = function () {\n if (!$scope.submitPending) {\n $scope.submitPending = true;\n\n if (angular.isFunction($scope.onSubmit)) {\n let promise = $scope.onSubmit($scope.input);\n\n if (promise && promise.$promise) {\n promise.$promise\n .catch(angular.noop)\n .finally(function () {\n $scope.submitPending = false;\n });\n }\n else {\n $scope.submitPending = false;\n }\n }\n\n }\n }\n\n function rebindInputs()\n {\n //i need to do something when the serviceMenu, design, or data is loaded and promises fulfilled\n Promise.all([\n $scope.serviceMenu && $scope.serviceMenu.$promise,\n $scope.design && $scope.design.$promise,\n $scope.data && $scope.data.$promise\n ]).then(function () {\n $scope.vm.design = $scope.design || ($scope.serviceMenu ? $scope.serviceMenu.design : null) || ($scope.data && $scope.data.serviceMenu ? $scope.data.serviceMenu.design : null);\n $scope.vm.serviceMenu = $scope.serviceMenu || ($scope.data ? $scope.data.serviceMenu : null);\n\n $scope.$apply();\n\n }).catch(function (error) {\n console.error('Error in loading promises', error);\n });\n }\n }\n\n });\n\n}());"]}