Initial implementation of a simple week view.
authoranuko <support@anuko.com>
Tue, 26 Dec 2017 19:22:56 +0000 (19:22 +0000)
committeranuko <support@anuko.com>
Tue, 26 Dec 2017 19:22:56 +0000 (19:22 +0000)
WEB-INF/lib/ttTimeHelper.class.php
WEB-INF/templates/footer.tpl
WEB-INF/templates/time.tpl
WEB-INF/templates/week.tpl
table_test.php
week.php

index d186696..ff3399c 100644 (file)
@@ -766,31 +766,57 @@ class ttTimeHelper {
     return $groupedRecords;
   }
 
-  /* This is work in progress, not working properly.
-  static function getDurationsForWeek($user_id, $start_date, $end_date) {
+  // getDataForWeekView - builds an array to render a table of durations for week view.
+  static function getDataForWeekView($user_id, $start_date, $end_date) {
     // Start by obtaining all records in interval.
-    // Then, iterate through them to build an array.
     $records = ttTimeHelper::getRecordsForInterval($user_id, $start_date, $end_date);
-    $durations_with_labels = array();
 
+    $dataArray = array();
+
+    // Iterate through records and build $dataArray cell by cell.
     foreach ($records as $record) {
+      // Create record id without suffix.
       $record_id_no_suffix = ttTimeHelper::makeRecordIdentifier($record);
       // Handle potential multiple records with the same attributes by using a numerical suffix.
       $suffix = 0;
       $record_id = $record_id_no_suffix.'_'.$suffix;
-      while (!empty($durations_with_labels[$record_id][$record['date']])) {
+      $day_header = substr($record['date'], 8); // Day number in month.
+      while (ttTimeHelper::cellExists($record_id, $day_header, $dataArray)) {
         $suffix++;
         $record_id = $record_id_no_suffix.'_'.$suffix;
       }
-      $groupedRecords[$record_identifier][$record['date']] = array('id'=>$record['id'], 'duration'=>$record['duration']);
-      $groupedRecords[$record_identifier]['client'] = $record['client'];
-      $groupedRecords[$record_identifier]['cf_1_value'] = $record['cf_1_value'];
-      $groupedRecords[$record_identifier]['project'] = $record['project'];
-      $groupedRecords[$record_identifier]['task'] = $record['task'];
-      $groupedRecords[$record_identifier]['billable'] = $record['billable'];
+      // Find row.
+      $pos = ttTimeHelper::findRow($record_id, $dataArray);
+      if ($pos < 0) {
+        $dataArray[] = array('id' => $record_id,'label' => ttTimeHelper::makeRecordLabel($record)); // Insert row.
+        $pos = ttTimeHelper::findRow($record_id, $dataArray);
+      }
+      // Insert cell data from $record.
+      $dataArray[$pos][$day_header] = array('id' => $record['id'],'duration' => $record['duration']);
     }
+    return $dataArray;
+  }
+
+  // cellExists is a helper function for getDataForWeekView() to see if a cell with a given label
+  // and a day header already exists.
+  static function cellExists($record_id, $day_header, $dataArray) {
+    foreach($dataArray as $row) {
+      if ($row['id'] == $record_id && !empty($row[$day_header]['duration']))
+        return true;
+    }
+    return false;
+  }
+
+  // findRow returns an existing row position in $dataArray, -1 otherwise.
+  static function findRow($record_id, $dataArray) {
+    $pos = 0; // Row position in array.
+    foreach($dataArray as $row) {
+      if ($row['id'] == $record_id)
+        return $pos;
+      $pos++; // Increment for search.
+    }
+    return -1; // Row not found.
   }
-  */
 
   // makeRecordIdentifier - builds a string identifying a record for a grouped display (such as a week view).
   // For example:
@@ -820,6 +846,39 @@ class ttTimeHelper {
     return $record_identifier;
   }
 
+  // makeRecordLabel - builds a human readable label for a row in week view,
+  // which is a combination ot record properties.
+  // Client - Project - Task - Custom field 1.
+  // Note that billable property is not part of the label. Instead, we intend to
+  // identify such records with a different color in week view.
+  static function makeRecordLabel($record) {
+    // TODO: debug this function.
+    global $user;
+    // Start with client.
+    if ($user->isPluginEnabled('cl'))
+      $label = $record['client'];
+
+    // Add project.
+    $project = $record['project'] ? $record['project'] : '';
+    if (!empty($label)) $label .= ' - ';
+    $label .= $project;
+
+    // Add task.
+    $task = $record['task'] ? $record['task'] : '';
+    if (!empty($label)) $label .= ' - ';
+    $label .= $task;
+
+    // Add custom field 1.
+    if ($user->isPluginEnabled('cf')) {
+      if ($record['cf_1_value']) {
+        if (!empty($label)) $label .= ' - ';
+        $label .= $record['cf_1_value'];
+      }
+    }
+
+    return $label;
+  }
+
   // getGroupedRecordsTotals - returns day totals for grouped records.
   static function getGroupedRecordsTotals($groupedRecords) {
     $groupedRecordsTotals = array();
@@ -843,7 +902,7 @@ class ttTimeHelper {
   static function getDayHeadersForWeek($start_date) {
     $dayHeaders = array();
     $objDate = new DateAndTime(DB_DATEFORMAT, $start_date);
-    $dayHeaders['day_header_0'] = $objDate->getDate();
+    $dayHeaders['day_header_0'] = (string)$objDate->getDate(); // It returns an int on first call. Why?
     $objDate->incDay();
     $dayHeaders['day_header_1'] = $objDate->getDate();
     $objDate->incDay();
@@ -859,4 +918,28 @@ class ttTimeHelper {
     unset($objDate);
     return $dayHeaders;
   }
+
+  // getDayTotals calculates total durations for each day from the existing data in $dataArray.
+  static function getDayTotals($dataArray, $dayHeaders) {
+    $dayTotals = array();
+
+    // Insert label.
+    global $i18n;
+    $dayTotals['label'] = $i18n->getKey('label.total');
+
+    foreach ($dataArray as $row) {
+      foreach($dayHeaders as $dayHeader) {
+        if (array_key_exists($dayHeader, $row)) {
+          $minutes = ttTimeHelper::toMinutes($row[$dayHeader]['duration']);
+          $dayTotals[$dayHeader] += $minutes;
+        }
+      }
+    }
+    // Convert minutes to hh:mm for display.
+    foreach($dayHeaders as $dayHeader) {
+      $dayTotals[$dayHeader] = ttTimeHelper::toAbsDuration($dayTotals[$dayHeader]);
+    }
+    return $dayTotals;
+  }
 }
+
index d94d662..aafa107 100644 (file)
@@ -12,7 +12,7 @@
       <br>
       <table cellspacing="0" cellpadding="4" width="100%" border="0">
         <tr>
-          <td align="center">&nbsp;Anuko Time Tracker 1.12.3.3693 | Copyright &copy; <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
+          <td align="center">&nbsp;Anuko Time Tracker 1.13.3.3694 | Copyright &copy; <a href="https://www.anuko.com/lp/tt_3.htm" target="_blank">Anuko</a> |
             <a href="https://www.anuko.com/lp/tt_4.htm" target="_blank">{$i18n.footer.credits}</a> |
             <a href="https://www.anuko.com/lp/tt_5.htm" target="_blank">{$i18n.footer.license}</a> |
             <a href="https://www.anuko.com/lp/tt_7.htm" target="_blank">{$i18n.footer.improve}</a>
index d5db36a..182f012 100644 (file)
@@ -8,13 +8,11 @@
 
 {$forms.timeRecordForm.open}
 <table cellspacing="4" cellpadding="0" border="0">
-{if defined(WEEK_VIEW_DEBUG)}
   <tr>
     <td align="center" colspan=2">
       <a href="time.php?date={$selected_date->toString()}">{$i18n.label.day_view}</a>&nbsp;/&nbsp;<a href="week.php?date={$selected_date->toString()}">{$i18n.label.week_view}</a>
     </td>
   </tr>
-{/if}
   <tr>
     <td valign="top">
       <table>
index 0d279ec..4abfa37 100644 (file)
     <td>{$forms.weekTimeForm.week_durations.control}</td>
   </tr>
 </table>
-
-<table width="720">
-<tr>
-  <td valign="top">
-{if $grouped_records}
-      <table border="0" cellpadding="3" cellspacing="1" width="100%">
-      <tr>
-  {if ($user->isPluginEnabled('cl') || ($smarty.const.MODE_PROJECTS == $user->tracking_mode || $smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode))}
-        <td class="tableHeader"></td>
-  {/if}
-  {if ($user->isPluginEnabled('cf') || $smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode)}
-        <td class="tableHeader"></td>
-  {/if}
-        <td class="tableHeader">{$day_header_0}</td>
-        <td class="tableHeader">{$day_header_1}</td>
-        <td class="tableHeader">{$day_header_2}</td>
-        <td class="tableHeader">{$day_header_3}</td>
-        <td class="tableHeader">{$day_header_4}</td>
-        <td class="tableHeader">{$day_header_5}</td>
-        <td class="tableHeader">{$day_header_6}</td>
-      </tr>
-  {foreach $grouped_records as $record}
-      <tr bgcolor="{cycle values="#f5f5f5,#ffffff"}" {if !$record.billable} class="not_billable" {/if}>
-    {if ($user->isPluginEnabled('cl') || ($smarty.const.MODE_PROJECTS == $user->tracking_mode || $smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode))}
-        <td valign="top">{$record.project|escape}<p>{$record.client|escape}</td>
-    {/if}
-    {if ($user->isPluginEnabled('cf') || $smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode)}
-        <td valign="top">{$record.task|escape}<p>{$record.cf_1_value|escape}</td>
-    {/if}
-        <td valign="top">{$record.$date_0.duration}</td>
-        <td valign="top">{$record.$date_1.duration}</td>
-        <td valign="top">{$record.$date_2.duration}</td>
-        <td valign="top">{$record.$date_3.duration}</td>
-        <td valign="top">{$record.$date_4.duration}</td>
-        <td valign="top">{$record.$date_5.duration}</td>
-        <td valign="top">{$record.$date_6.duration}</td>
-      </tr>
-  {/foreach}
-      <tr>
-  {if ($user->isPluginEnabled('cl') || ($smarty.const.MODE_PROJECTS == $user->tracking_mode || $smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode))}
-        <td class="tableHeader"></td>
-  {/if}
-  {if ($user->isPluginEnabled('cf') || $smarty.const.MODE_PROJECTS_AND_TASKS == $user->tracking_mode)}
-        <td class="tableHeader"></td>
-  {/if}
-        <td class="tableHeader">{$grouped_records_totals.$date_0}</td>
-        <td class="tableHeader">{$grouped_records_totals.$date_1}</td>
-        <td class="tableHeader">{$grouped_records_totals.$date_2}</td>
-        <td class="tableHeader">{$grouped_records_totals.$date_3}</td>
-        <td class="tableHeader">{$grouped_records_totals.$date_4}</td>
-        <td class="tableHeader">{$grouped_records_totals.$date_5}</td>
-        <td class="tableHeader">{$grouped_records_totals.$date_6}</td>
-      </tr>
-    </table>
-{/if}
-  </td>
-</tr>
-</table>
 <!--
-{if $time_records}
-<table cellpadding="3" cellspacing="1" width="720">
-  <tr>
-    <td align="left">{$i18n.label.week_total}: {$week_total}</td>
-    <td align="right">{$i18n.label.day_total}: {$day_total}</td>
-  </tr>
-  {if $user->isPluginEnabled('mq')}
-  <tr>
-    <td align="left">{$i18n.label.month_total}: {$month_total}</td>
-    {if $over_quota}
-    <td align="right">{$i18n.form.time.over_quota}: <span style="color: green;">{$quota_remaining}</span></td>
-    {else}
-    <td align="right">{$i18n.form.time.remaining_quota}: <span style="color: red;">{$quota_remaining}</span></td>
-    {/if}
-  </tr>
-  {/if}
-</table>
-{/if}
--->
 <table>
   <tr>
     <td align="center" colspan="2">{$forms.weekTimeForm.btn_submit.control}</td>
   </tr>
 </table>
+-->
 {$forms.weekTimeForm.close}
index d4b21c7..f8b4c72 100644 (file)
@@ -73,7 +73,7 @@ class LabelCellRenderer extends DefaultCellRenderer {
 // Define rendering class for a single cell for time entry in week view table.
 class TimeCellRenderer extends DefaultCellRenderer {
   function render(&$table, $value, $row, $column, $selected = false) {
-    $field_name = $table->getValueAtName($row,$column)['id']; // Our text field names (and ids) are like x_y (row_column).
+    $field_name = $table->getValueAt($row,$column)['id']; // Our text field names (and ids) are like x_y (row_column).
     $field = new TextField($field_name);
     $field->setFormName($table->getFormName());
     $field->setSize(2);
index 9e1d518..a3f30cb 100644 (file)
--- a/week.php
+++ b/week.php
@@ -65,8 +65,64 @@ $endDate = new DateAndTime();
 $endDate->setTimestamp(mktime(0,0,0,$t_arr[4]+1,$t_arr[3]-$t_arr[6]+6+$startWeekBias,$t_arr[5]));
 // The above is needed to set date range (timestring) in page title.
 
+// Use custom fields plugin if it is enabled.
+if ($user->isPluginEnabled('cf')) {
+  require_once('plugins/CustomFields.class.php');
+  $custom_fields = new CustomFields($user->team_id);
+  $smarty->assign('custom_fields', $custom_fields);
+}
+
+// TODO: how is this plugin supposed to work for week view?
+if ($user->isPluginEnabled('mq')){
+  require_once('plugins/MonthlyQuota.class.php');
+  $quota = new MonthlyQuota();
+  $month_quota = $quota->get($selected_date->mYear, $selected_date->mMonth);
+  $month_total = ttTimeHelper::getTimeForMonth($user->getActiveUser(), $selected_date);
+  $minutes_left = ttTimeHelper::toMinutes($month_quota) - ttTimeHelper::toMinutes($month_total);
+
+  $smarty->assign('month_total', $month_total);
+  $smarty->assign('over_quota', $minutes_left < 0);
+  $smarty->assign('quota_remaining', ttTimeHelper::toAbsDuration($minutes_left));
+}
+
+// Initialize variables.
+// Custom field.
+$cl_cf_1 = trim($request->getParameter('cf_1', ($request->getMethod()=='POST'? null : @$_SESSION['cf_1'])));
+$_SESSION['cf_1'] = $cl_cf_1;
+$cl_billable = 1;
+if ($user->isPluginEnabled('iv')) {
+  if ($request->isPost()) {
+    $cl_billable = $request->getParameter('billable');
+    $_SESSION['billable'] = (int) $cl_billable;
+  } else
+    if (isset($_SESSION['billable']))
+      $cl_billable = $_SESSION['billable'];
+}
+$on_behalf_id = $request->getParameter('onBehalfUser', (isset($_SESSION['behalf_id'])? $_SESSION['behalf_id'] : $user->id));
+$cl_client = $request->getParameter('client', ($request->getMethod()=='POST'? null : @$_SESSION['client']));
+$_SESSION['client'] = $cl_client;
+$cl_project = $request->getParameter('project', ($request->getMethod()=='POST'? null : @$_SESSION['project']));
+$_SESSION['project'] = $cl_project;
+$cl_task = $request->getParameter('task', ($request->getMethod()=='POST'? null : @$_SESSION['task']));
+$_SESSION['task'] = $cl_task;
+
+
+
+
+
+
+
+
+
+
+
+
 // Get column headers.
 $dayHeaders = ttTimeHelper::getDayHeadersForWeek($startDate->toString(DB_DATEFORMAT));
+// Build data array for the table.
+$dataArray = ttTimeHelper::getDataForWeekView($user->getActiveUser(), $startDate->toString(DB_DATEFORMAT), $endDate->toString(DB_DATEFORMAT));
+// Build day totals.
+$dayTotals = ttTimeHelper::getDayTotals($dataArray, $dayHeaders);
 
 // TODO: replace these two sample arrays with real data.
 $durations_with_labels = array(
@@ -120,67 +176,17 @@ class TimeCellRenderer extends DefaultCellRenderer {
   }
 }
 
-
-
-
-
-
 //$durations = ttTimeHelper::getDurationsForWeek($user->getActiveUser(), $startDate->toString(DB_DATEFORMAT), $endDate->toString(DB_DATEFORMAT));
 
 
 
-$groupedRecords = ttTimeHelper::getGroupedRecordsForInterval($user->getActiveUser(), $startDate->toString(DB_DATEFORMAT), $endDate->toString(DB_DATEFORMAT));
-
+//$groupedRecords = ttTimeHelper::getGroupedRecordsForInterval($user->getActiveUser(), $startDate->toString(DB_DATEFORMAT), $endDate->toString(DB_DATEFORMAT));
+//$dayTotals = ttTimeHelper::getGroupedRecordsTotals($groupedRecords);
 
 
 
 
-$dayTotals = ttTimeHelper::getGroupedRecordsTotals($groupedRecords);
 
-// Use custom fields plugin if it is enabled.
-if ($user->isPluginEnabled('cf')) {
-  require_once('plugins/CustomFields.class.php');
-  $custom_fields = new CustomFields($user->team_id);
-  $smarty->assign('custom_fields', $custom_fields);
-}
-
-// TODO: how is this plugin supposed to work for week view?
-if ($user->isPluginEnabled('mq')){
-  require_once('plugins/MonthlyQuota.class.php');
-  $quota = new MonthlyQuota();
-  $month_quota = $quota->get($selected_date->mYear, $selected_date->mMonth);
-  $month_total = ttTimeHelper::getTimeForMonth($user->getActiveUser(), $selected_date);
-  $minutes_left = ttTimeHelper::toMinutes($month_quota) - ttTimeHelper::toMinutes($month_total);
-
-  $smarty->assign('month_total', $month_total);
-  $smarty->assign('over_quota', $minutes_left < 0);
-  $smarty->assign('quota_remaining', ttTimeHelper::toAbsDuration($minutes_left));
-}
-
-// Initialize variables.
-$cl_start = trim($request->getParameter('start'));
-$cl_finish = trim($request->getParameter('finish'));
-$cl_duration = trim($request->getParameter('duration'));
-$cl_note = trim($request->getParameter('note'));
-// Custom field.
-$cl_cf_1 = trim($request->getParameter('cf_1', ($request->getMethod()=='POST'? null : @$_SESSION['cf_1'])));
-$_SESSION['cf_1'] = $cl_cf_1;
-$cl_billable = 1;
-if ($user->isPluginEnabled('iv')) {
-  if ($request->isPost()) {
-    $cl_billable = $request->getParameter('billable');
-    $_SESSION['billable'] = (int) $cl_billable;
-  } else
-    if (isset($_SESSION['billable']))
-      $cl_billable = $_SESSION['billable'];
-}
-$on_behalf_id = $request->getParameter('onBehalfUser', (isset($_SESSION['behalf_id'])? $_SESSION['behalf_id'] : $user->id));
-$cl_client = $request->getParameter('client', ($request->getMethod()=='POST'? null : @$_SESSION['client']));
-$_SESSION['client'] = $cl_client;
-$cl_project = $request->getParameter('project', ($request->getMethod()=='POST'? null : @$_SESSION['project']));
-$_SESSION['project'] = $cl_project;
-$cl_task = $request->getParameter('task', ($request->getMethod()=='POST'? null : @$_SESSION['task']));
-$_SESSION['task'] = $cl_task;
 
 // Elements of weekTimeForm.
 $form = new Form('weekTimeForm');
@@ -204,16 +210,16 @@ $table = new Table('week_durations');
 // $table->setIAScript('markModified'); // TODO: write a script to mark table or particular cells as modified.
 $table->setTableOptions(array('width'=>'100%','cellspacing'=>'1','cellpadding'=>'3','border'=>'0'));
 $table->setRowOptions(array('valign'=>'top','class'=>'tableHeader'));
-$table->setData($durations_with_labels);
+$table->setData($dataArray); // $durations_with_labels);
 // Add columns to table.
-$table->addColumn(new TableColumn('label', '', new LabelCellRenderer(), $totals['label']));
-$table->addColumn(new TableColumn('day_0', $dayHeaders['day_header_0'], new TimeCellRenderer(), $totals['day_0']));
-$table->addColumn(new TableColumn('day_1', $dayHeaders['day_header_1'], new TimeCellRenderer(), $totals['day_1']));
-$table->addColumn(new TableColumn('day_2', $dayHeaders['day_header_2'], new TimeCellRenderer(), $totals['day_2']));
-$table->addColumn(new TableColumn('day_3', $dayHeaders['day_header_3'], new TimeCellRenderer(), $totals['day_3']));
-$table->addColumn(new TableColumn('day_4', $dayHeaders['day_header_4'], new TimeCellRenderer(), $totals['day_4']));
-$table->addColumn(new TableColumn('day_5', $dayHeaders['day_header_5'], new TimeCellRenderer()));
-$table->addColumn(new TableColumn('day_6', $dayHeaders['day_header_6'], new TimeCellRenderer()));
+$table->addColumn(new TableColumn('label', '', new LabelCellRenderer(), $dayTotals['label']));
+$table->addColumn(new TableColumn($dayHeaders['day_header_0'], $dayHeaders['day_header_0'], new TimeCellRenderer(), $dayTotals[$dayHeaders['day_header_0']]));
+$table->addColumn(new TableColumn($dayHeaders['day_header_1'], $dayHeaders['day_header_1'], new TimeCellRenderer(), $dayTotals[$dayHeaders['day_header_1']]));
+$table->addColumn(new TableColumn($dayHeaders['day_header_2'], $dayHeaders['day_header_2'], new TimeCellRenderer(), $dayTotals[$dayHeaders['day_header_2']]));
+$table->addColumn(new TableColumn($dayHeaders['day_header_3'], $dayHeaders['day_header_3'], new TimeCellRenderer(), $dayTotals[$dayHeaders['day_header_3']]));
+$table->addColumn(new TableColumn($dayHeaders['day_header_4'], $dayHeaders['day_header_4'], new TimeCellRenderer(), $dayTotals[$dayHeaders['day_header_4']]));
+$table->addColumn(new TableColumn($dayHeaders['day_header_5'], $dayHeaders['day_header_5'], new TimeCellRenderer(), $dayTotals[$dayHeaders['day_header_5']]));
+$table->addColumn(new TableColumn($dayHeaders['day_header_6'], $dayHeaders['day_header_6'], new TimeCellRenderer(), $dayTotals[$dayHeaders['day_header_6']]));
 $table->setInteractive(false);
 $form->addInputElement($table);
 
@@ -464,8 +470,8 @@ $smarty->assign('selected_date', $selected_date);
 $smarty->assign('week_total', $week_total);
 $smarty->assign('day_total', ttTimeHelper::getTimeForDay($user->getActiveUser(), $cl_date));
 //$groupedRecords = ttTimeHelper::getGroupedRecordsForInterval($user->getActiveUser(), $startDate->toString(DB_DATEFORMAT), $endDate->toString(DB_DATEFORMAT));
-$smarty->assign('grouped_records', $groupedRecords);
-$smarty->assign('grouped_records_totals', ttTimeHelper::getGroupedRecordsTotals($groupedRecords));
+//$smarty->assign('grouped_records', $groupedRecords);
+//$smarty->assign('grouped_records_totals', ttTimeHelper::getGroupedRecordsTotals($groupedRecords));
 
 $smarty->assign('client_list', $client_list);
 $smarty->assign('project_list', $project_list);