From 32ed65d3493807525e74f8e015656da8489eec00 Mon Sep 17 00:00:00 2001
From: Peter Rotich <peter@osticket.com>
Date: Mon, 9 Apr 2012 11:07:27 -0400
Subject: [PATCH] Advanced search initial changes

---
 include/ajax.config.php       |   2 +-
 include/ajax.tickets.php      |  51 +++++++++++-
 include/staff/tickets.inc.php | 112 +++++++++++++++++++++++--
 scp/ajax.php                  |   7 +-
 scp/css/scp.css               | 153 ++++++++++++++++++++++++++++++++++
 scp/images/ajax-loader.gif    | Bin 0 -> 1849 bytes
 scp/js/scp.js                 |  84 ++++++++++++++++++-
 7 files changed, 395 insertions(+), 14 deletions(-)
 create mode 100644 scp/images/ajax-loader.gif

diff --git a/include/ajax.config.php b/include/ajax.config.php
index 7dcfd9972..fc9fb2c3f 100644
--- a/include/ajax.config.php
+++ b/include/ajax.config.php
@@ -19,7 +19,7 @@ if(!defined('INCLUDE_DIR')) die('!');
 class ConfigAjaxAPI extends AjaxController {
 
     //config info UI might need.
-    function ui() {
+    function scp_ui() {
         global $thisstaff, $cfg;
 
         $config=array('ticket_lock_time'=>($cfg->getLockTime()*3600),
diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php
index 458e430ea..648edc825 100644
--- a/include/ajax.tickets.php
+++ b/include/ajax.tickets.php
@@ -20,11 +20,11 @@ include_once(INCLUDE_DIR.'class.ticket.php');
 
 class TicketsAjaxAPI extends AjaxController {
    
-    function search() {
+    function lookup() {
         global $thisstaff;
 
         if(!is_numeric($_REQUEST['q']))
-            return self::searchByEmail();
+            return self::lookupByEmail();
 
 
         $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
@@ -53,7 +53,7 @@ class TicketsAjaxAPI extends AjaxController {
         return $this->json_encode($tickets);
     }
 
-    function searchByEmail() {
+    function lookupByEmail() {
         global $thisstaff;
 
 
@@ -84,6 +84,51 @@ class TicketsAjaxAPI extends AjaxController {
         return $this->json_encode($tickets);
     }
 
+    function search() {
+        global $thisstaff;
+          
+        $result=array();
+        $sql='SELECT count(ticket_id) as tickets '
+            .' FROM '.TICKET_TABLE
+            .' WHERE 1 ';
+
+        //Access control.
+        $sql.=' AND ( staff_id='.db_input($thisstaff->getId());
+
+        if(($teams=$thisstaff->getTeams()) && count(array_filter($teams)))
+            $sql.=' OR team_id IN('.implode(',', array_filter($teams)).')';
+
+        if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts()))
+            $sql.=' OR dept_id IN ('.implode(',', $depts).')';
+
+        $sql.=' ) ';
+
+        //Department
+        if($_REQUEST['deptId'])
+            $sql.=' AND dept_id='.db_input($_REQUEST['deptId']);
+
+        //Status
+        switch(strtolower($_REQUEST['status'])) {
+            case 'open';
+                $sql.=' AND status="open" ';
+                break;
+            case 'overdue':
+                $sql.=' AND status="open" and isoverdue=1 ';
+                break;
+            case 'closed':
+                $sql.=' AND status="closed" ';
+                break;
+        }
+        
+        if(($tickets=db_result(db_query($sql)))) {
+            $result['success'] ="Search criteria matched  $tickets tickets - view";
+        } else {
+            $result['fail']='No tickets found matching your search criteria.'.$tickets;
+        }
+            
+        return $this->json_encode($result);
+    }
+
     function acquireLock($tid) {
         global $cfg,$thisstaff;
         
diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php
index 67d270c3f..c60bdc750 100644
--- a/include/staff/tickets.inc.php
+++ b/include/staff/tickets.inc.php
@@ -97,9 +97,6 @@ $deep_search=false;
 if($search):
     $qstr.='&a='.urlencode($_REQUEST['a']);
     $qstr.='&t='.urlencode($_REQUEST['t']);
-    if(isset($_REQUEST['advance_search'])){ //advance search box!
-        $qstr.='&advance_search=Search';
-    }
 
     //query
     if($searchTerm){
@@ -250,12 +247,10 @@ if(!$results_type) {
 }
 $negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting..
 
-$basic_display=!isset($_REQUEST['advance_search'])?true:false;
-
 //YOU BREAK IT YOU FIX IT.
 ?>
 <!-- SEARCH FORM START -->
-<div id='basic' style="display:<?php echo $basic_display?'block':'none'; ?>">
+<div id='basic_search'>
     <form action="tickets.php" method="get">
     <input type="hidden" name="a" value="search">
     <table>
@@ -263,6 +258,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false;
             <td><input type="text" id="basic-ticket-search" name="query" size=30 value="<?php echo Format::htmlchars($_REQUEST['query']); ?>"
                 autocomplete="off" autocorrect="off" autocapitalize="off"></td>
             <td><input type="submit" name="basic_search" class="button" value="Search"></td>
+            <td>&nbsp;&nbsp;<a href="" id="go-advanced">[advanced]</a></td>
         </tr>
     </table>
     </form>
@@ -449,3 +445,107 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false;
     } ?>
     </form>
 </div>
+<div id="overlay"></div>
+<div style="display:none;" id="advanced-search">
+    <h3>Advanced Ticket Search</h3>
+    <a class="close" href="">&times;</a>
+    <form action="tickets.php" method="post" id="search" name="search">
+        <input type="hidden" name="a" value="search">
+        <fieldset class="query">
+            <label for="query">Keyword:</label>
+            <input type="input" id="query" name="query" size="20"> <em>Optional</em>
+        </fieldset>
+        <fieldset>
+            <label for="status">Status:</label>
+            <select id="status" name="status">
+                <option value="">&mdash; Any Status &mdash;</option>
+                <option value="open">Open</option>
+                <option value="overdue">Overdue</option>
+                <option value="closed">Closed</option>
+            </select>
+            <label for="deptId">Dept:</label>
+            <select id="deptId" name="deptId">
+                <option value="">&mdash; All Departments &mdash;</option>
+                <?php
+                if(($mydepts = $thisstaff->getDepts()) && ($depts=Dept::getDepartments())) {
+                    foreach($depts as $id =>$name) {
+                        if(!in_array($id, $mydepts)) continue; 
+                        echo sprintf('<option value="%d">%s</option>', $id, $name);
+                    }
+                }
+                ?>
+            </select>
+        </fieldset>
+        <fieldset class="owner">
+            <label for="assigneeId">Assigned To:</label>
+            <select id="assigneeId" name="assigneeId">
+                <option value="0">&mdash; Anyone &mdash;</option>
+                <?php
+                if(($users=Staff::getStaffMembers())) {
+                    echo '<OPTGROUP label="Staff Members ('.count($users).')">';
+                    foreach($users as $id => $name) {
+                        $k="s$id";
+                        echo sprintf('<option value="%s">%s</option>', $k, $name);
+                    }
+                    echo '</OPTGROUP>';
+                }
+                
+                if(($teams=Team::getTeams())) {
+                    echo '<OPTGROUP label="Teams ('.count($teams).')">';
+                    foreach($teams as $id => $name) {
+                        $k="t$id";
+                        echo sprintf('<option value="%s">%s</option>', $k, $name);
+                    }
+                    echo '</OPTGROUP>';
+                }
+                ?>
+            </select>
+            <label for="staffId">Closed By:</label>
+            <select id="staffId" name="staffId">
+                <option value="0">&mdash; Anyone &mdash;</option>
+                <?php
+                if(($users=Staff::getStaffMembers())) {
+                    foreach($users as $id => $name) {
+                        $k="s$id";
+                        echo sprintf('<option value="%s">%s</option>', $k, $name);
+                    }
+                }
+                ?>
+            </select>
+        </fieldset>
+        <fieldset class="date_range">
+            <label>Date Range:</label>
+            <input class="dp" type="input" size="20" name="startDate"><i></i>
+            <span>TO</span>
+            <input class="dp" type="input" size="20" name="endDate"><i></i>
+        </fieldset>
+        <fieldset class="sorting">
+            <label>Sorting:</label>
+            <select name="sort">
+                <option value="date">Create Date</option>
+            </select>
+            <select name="order">
+                <option value="desc">Descending</option>
+                <option value="asc">Ascending</option>
+            </select>
+            <select name="limit">
+                <option value="25">25 records/page</option>
+                <option value="50" selected="selected">50 records/page</option>
+                <option value="75">75 records/page</option>
+                <option value="100">100 records/page</option>
+            </select>
+        </fieldset>
+        <p>
+            <span class="buttons">
+                <input type="submit" value="Search">
+                <input type="reset" value="Reset">
+                <input type="button" value="Cancel" class="close">
+            </span>
+            <span class="spinner">
+                <img src="./images/ajax-loader.gif" width="16" height="16">
+            </span>
+        </p>
+    </form>
+    <div id="result-count">
+    </div>
+</div>
diff --git a/scp/ajax.php b/scp/ajax.php
index 471e9c710..2b08168ad 100644
--- a/scp/ajax.php
+++ b/scp/ajax.php
@@ -43,10 +43,13 @@ $dispatcher = patterns('',
         url_get('^ticket_variables', 'ticket_variables')
     )),
     url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI',
-        url_get('^ui', 'ui')
+        url_get('^ui', 'scp_ui')
     )),
     url_get('^/users$', array('ajax.users.php:UsersAjaxAPI', 'search')),
-    url_get('^/tickets$', array('ajax.tickets.php:TicketsAjaxAPI', 'search')),
+    url('^/tickets', patterns('ajax.tickets.php:TicketsAjaxAPI',
+        url_get('^/lookup', 'lookup'),
+        url_get('^$', 'search')
+    )),
     url('^/ticket/', patterns('ajax.tickets.php:TicketsAjaxAPI',
         url_get('^(?P<tid>\d+)/preview', 'previewTicket'),
         url_get('^(?P<tid>\d+)/lock', 'acquireLock'),
diff --git a/scp/css/scp.css b/scp/css/scp.css
index 5ccdbe543..de333413a 100644
--- a/scp/css/scp.css
+++ b/scp/css/scp.css
@@ -1060,3 +1060,156 @@ h2 .reload {
   padding-left: 24px;
   background: url('../images/icons/page.png') 0 50% no-repeat;
 }
+
+
+/* Advanced Ticket Search */
+
+#overlay {
+    background:#000;
+    position:absolute;
+    display:none;
+    z-index:1000;
+}
+
+#advanced-search, #advanced-search * {
+    box-sizing: border-box;
+    -moz-box-sizing: border-box;
+    -webkit-box-sizing: border-box;
+}
+
+#advanced-search {
+    position:absolute;
+    padding:1em;
+    width:640px;
+    height:400px;
+    background:#fff;
+    border:1px solid #2a67ac;
+    display:none;
+    z-index:1200;
+}
+
+#advanced-search h3 {
+    color:#2a67ac;
+    font-size:20px;
+    margin:0;
+    padding:0;
+    display:inline-block;
+}
+
+#advanced-search a.close {
+    display:inline-block;
+    float:right;
+    font-size:16px;
+    color:#777;
+}
+
+#advanced-search form {
+    clear:both;
+    padding:2em 0 1em 0;
+    width:100%;
+}
+
+#advanced-search div.closed_by, #advanced-search span.spinner {
+    display:none;
+}
+
+#advanced-search fieldset {
+    margin:0;
+    padding:0.25em 0;
+    border:none;
+    overflow:hidden;
+}
+
+#advanced-search label {
+    width:100px;
+    display:inline-block;
+    text-align:right;
+    padding:10px;
+}
+
+#advanced-search fieldset input {
+    border:1px solid #ccc;
+    background:#fff;
+}
+
+#advanced-search fieldset select {
+    width:170px;
+    display:inline-block;
+}
+
+#advanced-search fieldset span {
+    width:50px;
+    display:inline-block;
+    text-align:center;
+    color:#777;
+    font-size:0.75em;
+}
+
+#advanced-search .query input {
+    width:350px;
+}
+
+#advanced-search .date_range input {
+    width:175px;
+}
+
+#advanced-search .date_range i {
+    display:inline-block;
+    margin-left:3px;
+    position:relative;
+    top:5px;
+    width:16px;
+    height:16px;
+    background:url(../images/cal.png) bottom left no-repeat;
+}
+
+#advanced-search fieldset.sorting select {
+    width:130px;
+}
+
+#advanced-search p {
+    text-align:center;
+}
+
+#advanced-search input[type="submit"],
+#advanced-search input[type="reset"],
+#advanced-search input[type="button"]
+{
+    display:inline-block;
+    margin:0;
+    height:24px;
+    line-height:24px;
+    font-weight:bold;
+    border:1px solid #666666;
+    padding:0 10px;
+    background: url('../images/grey_btn_bg.png?1312910883') top left repeat-x;
+    color: #333;
+}
+
+#advanced-search input[type="reset"], #advanced-search input[type="button"] {
+    opacity:0.7;
+}
+
+#advanced-search input[type=submit]:hover, #advanced-search input[type=submit]:active,
+#advanced-search input[type=reset]:hover, #advanced-search input[type=reset]:active {
+    background-position:bottom left;
+}
+
+#result-count div {
+    padding:5px 10px;
+    text-align:left;
+    font-weight:bold;
+    width:100%;
+    margin:0 auto;
+}
+
+#result-count .success {
+    background:#e3ffd8;
+    border:1px solid #0a0;
+}
+
+#result-count .fail {
+    background:#ffd8d8;
+    border:1px solid #a00;
+}
+
diff --git a/scp/images/ajax-loader.gif b/scp/images/ajax-loader.gif
new file mode 100644
index 0000000000000000000000000000000000000000..d42f72c723644bbf8cf8d6e1b7ff0bea7ddd305a
GIT binary patch
literal 1849
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

literal 0
HcmV?d00001

diff --git a/scp/js/scp.js b/scp/js/scp.js
index 7a9e0e218..37389d34b 100644
--- a/scp/js/scp.js
+++ b/scp/js/scp.js
@@ -198,11 +198,11 @@ $(document).ready(function(){
         }
     }
 
-    /* Typeahead init */
+    /* Typeahead tickets lookup */
     $('#basic-ticket-search').typeahead({
         source: function (typeahead, query) {
             $.ajax({
-                url: "ajax.php/tickets?q="+query,
+                url: "ajax.php/tickets/lookup?q="+query,
                 dataType: 'json',
                 success: function (data) {
                     typeahead.process(data);
@@ -215,6 +215,7 @@ $(document).ready(function(){
         property: "value"
     });
 
+    /* Typeahead user lookup */
     $('#email.typeahead').typeahead({
         source: function (typeahead, query) {
             if(query.length > 2) {
@@ -235,5 +236,84 @@ $(document).ready(function(){
         property: "email"
     });
 
+    /* advanced search */
+    $("#overlay").css({
+        opacity : 0.3,
+        top     : 0,
+        left    : 0,
+        width   : $(window).width(),
+        height  : $(window).height()
+    });
+
+    $("#advanced-search").css({
+        top  : ($(window).height() / 6),
+        left : ($(window).width() / 2 - 300)
+    });
+
+    $('#go-advanced').click(function(e) {
+        e.preventDefault();
+        $('#result-count').html('');
+        $('#overlay').show();
+        $('#advanced-search').show();
+    });
+
+    $('#advanced-search').delegate('a.close, input.close', 'click', function(e) {
+        e.preventDefault();
+        $('#advanced-search').hide()
+        $('#overlay').hide();
+    }).delegate('#status', 'change', function() {
+        switch($(this).val()) {
+            case 'closed':
+                $('select#assigneeId').find('option:first').attr('selected', 'selected').parent('select');
+                $('select#assigneeId').attr('disabled','disabled');
+                $('select#staffId').removeAttr('disabled');
+                break;
+            case 'open':
+            case 'overdue':
+                $('select#staffId').find('option:first').attr('selected', 'selected').parent('select');
+                $('select#staffId').attr('disabled','disabled');
+                $('select#assigneeId').removeAttr('disabled');
+                break;
+            default:
+                $('select#staffId').removeAttr('disabled');
+                $('select#assigneeId').removeAttr('disabled');
+        }
+    });
+
+    $('#advanced-search form#search').submit(function(e) { 
+        e.preventDefault();
+        var fObj = $(this);
+        var elem = $('#advanced-search');
+        $('#result-count').html('');
+        $.ajax({
+                url: "ajax.php/tickets",
+                data: fObj.serialize(),
+                dataType: 'json',
+                beforeSend: function ( xhr ) {
+                   $('.buttons', elem).hide();
+                   $('.spinner', elem).show();
+                   return true;
+                },
+                success: function (resp) {
+                        
+                    if(resp.success) {
+                        $('#result-count').html('<div class="success">' + resp.success +'</div>');
+                    } else if (resp.fail) {
+                        $('#result-count').html('<div class="fail">' + resp.fail +'</div>');
+                    } else {
+                        $('#result-count').html('<div class="fail">Unknown error</div>');
+                    }
+                }
+            })
+            .done( function () {
+             })
+            .fail( function () {
+                $('#result-count').html('<div class="fail">Advanced search failed - try again!</div>');
+            })
+            .always( function () {
+                $('.spinner', elem).hide();
+                $('.buttons', elem).show();
+             });
+    });
 
 });
-- 
GitLab