diff --git a/www/index.html b/www/index.html index 3e5ece0..31d0eb6 100644 --- a/www/index.html +++ b/www/index.html @@ -80,6 +80,7 @@ + diff --git a/www/js/app.js b/www/js/app.js index aff1ea0..eb6b79a 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -18,6 +18,7 @@ angular.module('TagApp', [ 'eventTypes.controller', 'oldFiles.controller', 'teams.controller', + 'supportTickets.controller', 'recorder.service', 'cameraMovement.service', 'recorderControll.service', @@ -172,6 +173,24 @@ angular.module('TagApp', [ } } + }).state('app.support_tickets', { + url: '/support_tickets', + views: { + 'menuContent': { + templateUrl: 'templates/support_tickets.html', + controller: 'SupportTicketsCtrl' + } + } + + }).state('app.view_ticket', { + url: '/view_ticket/{id}', + views: { + 'menuContent': { + templateUrl: 'templates/view_ticket.html', + controller: 'ViewTicketCtrl' + } + } + }); // if none of the above states are matched, use this as the fallback $urlRouterProvider.otherwise('/login'); diff --git a/www/js/controllers/support_tickets.js b/www/js/controllers/support_tickets.js new file mode 100644 index 0000000..52bf10a --- /dev/null +++ b/www/js/controllers/support_tickets.js @@ -0,0 +1,199 @@ +angular.module('supportTickets.controller', []) + +.controller('SupportTicketsCtrl', function($scope, $rootScope, $ionicPopup, $state) { + $scope.$on("$ionicView.beforeEnter", function() { + if (!$rootScope.isUser()) { + $state.go('login'); + } + $scope.loadTickets(); + }); + + $scope.tickets = []; + $scope.statusFilter = 'all'; + + $scope.loadTickets = function() { + if (localStorage.support_tickets) { + $scope.tickets = JSON.parse(localStorage.support_tickets); + } else { + $scope.tickets = []; + } + }; + + $scope.saveTickets = function() { + localStorage.support_tickets = JSON.stringify($scope.tickets); + }; + + $scope.filteredTickets = function() { + if ($scope.statusFilter === 'all') return $scope.tickets; + return $scope.tickets.filter(function(t) { return t.status === $scope.statusFilter; }); + }; + + $scope.setFilter = function(status) { + $scope.statusFilter = status; + }; + + $scope.priorityClass = function(priority) { + return { low: 'energized', medium: 'assertive', high: 'assertive' }[priority] || ''; + }; + + $scope.statusLabel = function(status) { + var labels = { open: 'Open', in_progress: 'In Progress', resolved: 'Resolved', closed: 'Closed' }; + return labels[status] || status; + }; + + $scope.openNewTicketPopup = function() { + $scope.newTicket = { priority: 'medium', category: 'technical' }; + + var template = + '
' + + '' + + '' + + '
' + + 'Priority' + + '' + + '
' + + '
' + + 'Category' + + '' + + '
' + + '
'; + + $ionicPopup.show({ + template: template, + title: 'New Support Ticket', + scope: $scope, + buttons: [ + { text: 'Cancel' }, + { + text: 'Submit', + type: 'button-positive', + onTap: function(e) { + if (!$scope.newTicket.title) { + e.preventDefault(); + } else { + return $scope.newTicket; + } + } + } + ] + }).then(function(ticket) { + if (!ticket) return; + var now = new Date().toISOString(); + $scope.tickets.unshift({ + id: Date.now().toString(), + title: ticket.title, + description: ticket.description || '', + priority: ticket.priority, + category: ticket.category, + status: 'open', + created_at: now, + updated_at: now, + comments: [] + }); + $scope.saveTickets(); + }); + }; + + $scope.deleteTicket = function(index) { + $ionicPopup.confirm({ + title: 'Delete Ticket', + template: 'Are you sure you want to delete this ticket?' + }).then(function(confirmed) { + if (confirmed) { + $scope.tickets.splice(index, 1); + $scope.saveTickets(); + } + }); + }; + + $scope.viewTicket = function(ticket) { + $state.go('app.view_ticket', { id: ticket.id }); + }; +}) + +.controller('ViewTicketCtrl', function($scope, $rootScope, $ionicPopup, $state, $stateParams, $ionicHistory) { + $scope.$on("$ionicView.beforeEnter", function() { + if (!$rootScope.isUser()) { + $state.go('login'); + } + $scope.loadTicket(); + }); + + $scope.ticket = null; + $scope.newComment = ''; + + $scope.loadTicket = function() { + var tickets = localStorage.support_tickets ? JSON.parse(localStorage.support_tickets) : []; + $scope.ticket = tickets.filter(function(t) { return t.id === $stateParams.id; })[0] || null; + $scope.ticketIndex = tickets.indexOf($scope.ticket); + }; + + $scope.saveTickets = function(tickets) { + localStorage.support_tickets = JSON.stringify(tickets); + }; + + $scope.updateTicket = function() { + var tickets = localStorage.support_tickets ? JSON.parse(localStorage.support_tickets) : []; + var idx = tickets.findIndex(function(t) { return t.id === $scope.ticket.id; }); + if (idx !== -1) { + $scope.ticket.updated_at = new Date().toISOString(); + tickets[idx] = $scope.ticket; + $scope.saveTickets(tickets); + } + }; + + $scope.setStatus = function(status) { + if (!$scope.ticket) return; + $scope.ticket.status = status; + $scope.updateTicket(); + }; + + $scope.addComment = function() { + if (!$scope.newComment || !$scope.newComment.trim()) return; + $scope.ticket.comments.push({ + id: Date.now().toString(), + text: $scope.newComment.trim(), + created_at: new Date().toISOString() + }); + $scope.newComment = ''; + $scope.updateTicket(); + }; + + $scope.deleteComment = function(index) { + $scope.ticket.comments.splice(index, 1); + $scope.updateTicket(); + }; + + $scope.priorityClass = function(priority) { + var map = { low: 'balanced', medium: 'energized', high: 'assertive' }; + return map[priority] || 'stable'; + }; + + $scope.statusClass = function(status) { + var map = { open: 'positive', in_progress: 'energized', resolved: 'balanced', closed: 'stable' }; + return map[status] || 'stable'; + }; + + $scope.formatDate = function(iso) { + if (!iso) return ''; + var d = new Date(iso); + return d.toLocaleDateString() + ' ' + d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' }); + }; + + $scope.goBack = function() { + $ionicHistory.goBack(); + }; +}); diff --git a/www/templates/menu.html b/www/templates/menu.html index 2abd050..7c1a32f 100644 --- a/www/templates/menu.html +++ b/www/templates/menu.html @@ -33,6 +33,9 @@

Team Setup + + Support Tickets + diff --git a/www/templates/support_tickets.html b/www/templates/support_tickets.html new file mode 100644 index 0000000..a31722d --- /dev/null +++ b/www/templates/support_tickets.html @@ -0,0 +1,82 @@ + + + +
+ + + + + +
+ + +
+ +

No tickets found.

+

Try changing the filter above.

+
+ + + + + + + + {{ticket.priority}} + + +

{{ticket.title}}

+

+ + {{statusLabel(ticket.status)}} + +  {{ticket.category | uppercase}} + • {{ticket.comments.length}} comment{{ticket.comments.length !== 1 ? 's' : ''}} +

+

+ {{ticket.created_at | date:'mediumDate'}} +

+ + + + + + +
+
+
+ + + + +
diff --git a/www/templates/view_ticket.html b/www/templates/view_ticket.html new file mode 100644 index 0000000..787a38d --- /dev/null +++ b/www/templates/view_ticket.html @@ -0,0 +1,99 @@ + + + + +
+
+ + {{ticket.priority}} priority + + {{ticket.title}} +
+
+

{{ticket.description}}

+
+
+ Category: {{ticket.category | uppercase}} +  •  + Created: {{formatDate(ticket.created_at)}} +
+
+ + +
+
Status
+
+
+ + + + +
+
+
+ + +
+
+ Comments ({{ticket.comments.length}}) +
+ +
+ No comments yet. +
+ +
+

{{comment.text}}

+
+ {{formatDate(comment.created_at)}} + +
+
+
+ + +
+
Add Comment
+
+ +
+
+ +
+
+ +
+
+ + + +
+ +

Ticket not found.

+ +
+
+