summaryrefslogtreecommitdiff
path: root/demos/time-tracker
diff options
context:
space:
mode:
Diffstat (limited to 'demos/time-tracker')
-rw-r--r--demos/time-tracker/protected/App_Code/CategoryDao.php5
-rw-r--r--demos/time-tracker/protected/App_Code/ProjectDao.php11
-rw-r--r--demos/time-tracker/protected/App_Data/time_tracker.dbbin16384 -> 17408 bytes
-rw-r--r--demos/time-tracker/protected/application.xml2
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/CategoryDataList.php94
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/CategoryDataList.tpl152
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/LogTimeEntry.page77
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/LogTimeEntry.php107
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.page70
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.php160
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/ProjectList.page40
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/ProjectList.php34
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/ReportProject.page15
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl2
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/TimeEntry.page4
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/TimeEntryList.php89
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/TimeEntryList.tpl66
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/UserList.page33
-rw-r--r--demos/time-tracker/protected/pages/TimeTracker/config.xml2
-rw-r--r--demos/time-tracker/themes/TimeTracker/project.css96
-rw-r--r--demos/time-tracker/themes/TimeTracker/site.css7
-rw-r--r--demos/time-tracker/themes/TimeTracker/time-entry.css46
22 files changed, 1059 insertions, 53 deletions
diff --git a/demos/time-tracker/protected/App_Code/CategoryDao.php b/demos/time-tracker/protected/App_Code/CategoryDao.php
index f0149f0b..cb1b6399 100644
--- a/demos/time-tracker/protected/App_Code/CategoryDao.php
+++ b/demos/time-tracker/protected/App_Code/CategoryDao.php
@@ -5,7 +5,10 @@ class CategoryDao extends BaseDao
function addNewCategory($category)
{
$sqlmap = $this->getConnection();
- $sqlmap->insert('AddNewCategory', $category);
+ $exists = $this->getCategoryByNameInProject(
+ $category->Name, $category->ProjectID);
+ if(!$exists)
+ $sqlmap->insert('AddNewCategory', $category);
}
function getCategoryByID($categoryID)
diff --git a/demos/time-tracker/protected/App_Code/ProjectDao.php b/demos/time-tracker/protected/App_Code/ProjectDao.php
index 416c6540..0a0771e3 100644
--- a/demos/time-tracker/protected/App_Code/ProjectDao.php
+++ b/demos/time-tracker/protected/App_Code/ProjectDao.php
@@ -62,10 +62,17 @@ class ProjectDao extends BaseDao
return $sqlmap->queryForList('GetProjectMembers', $projectID);
}
- public function getAllProjects()
+ public function getAllProjects($sort='', $order='ASC')
{
$sqlmap = $this->getConnection();
- return $sqlmap->queryForList('GetAllProjects');
+ if($sort === '')
+ return $sqlmap->queryForList('GetAllProjects');
+ else
+ {
+ $param['sort'] = $sort;
+ $param['order'] = $order;
+ return $sqlmap->queryForList('GetAllProjectsOrdered', $param);
+ }
}
public function getProjectsByManagerName($manager)
diff --git a/demos/time-tracker/protected/App_Data/time_tracker.db b/demos/time-tracker/protected/App_Data/time_tracker.db
index 03fe9156..e7adaec3 100644
--- a/demos/time-tracker/protected/App_Data/time_tracker.db
+++ b/demos/time-tracker/protected/App_Data/time_tracker.db
Binary files differ
diff --git a/demos/time-tracker/protected/application.xml b/demos/time-tracker/protected/application.xml
index e7d3b330..02be327b 100644
--- a/demos/time-tracker/protected/application.xml
+++ b/demos/time-tracker/protected/application.xml
@@ -21,6 +21,6 @@
</module>
</modules>
<services>
- <service id="page" class="TPageService" DefaultPage="TimeTracker.TimeEntry"/>
+ <service id="page" class="TPageService" DefaultPage="TimeTracker.LogTimeEntry"/>
</services>
</application> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/CategoryDataList.php b/demos/time-tracker/protected/pages/TimeTracker/CategoryDataList.php
new file mode 100644
index 00000000..d2772067
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/CategoryDataList.php
@@ -0,0 +1,94 @@
+<?php
+
+class CategoryDataList extends TTemplateControl
+{
+ public function setProjectID($value)
+ {
+ $this->setViewState('ProjectID', $value, '');
+ }
+
+ public function getProjectID()
+ {
+ return $this->getViewState('ProjectID', '');
+ }
+
+ public function getCategories()
+ {
+ $this->ensureChildControls();
+ return $this->getRegisteredObject('categories');
+ }
+
+ protected function getCategoryDao()
+ {
+ return $this->Application->Modules['daos']->getDao('CategoryDao');
+ }
+
+ public function showCategories()
+ {
+ $categoryDao = $this->getCategoryDao();
+ $list = $categoryDao->getCategoriesByProjectID($this->getProjectID());
+ $this->categories->DataSource = $list;
+ $this->categories->dataBind();
+ }
+
+ public function deleteCategoryItem($sender, $param)
+ {
+ $id = $this->categories->DataKeys[$param->Item->ItemIndex];
+ $this->getCategoryDao()->deleteCategory($id);
+ $this->refreshCategoryList($sender, $param);
+ }
+
+ public function editCategoryItem($sender, $param)
+ {
+ $this->categories->EditItemIndex=$param->Item->ItemIndex;
+ $this->showCategories();
+ }
+
+ public function refreshCategoryList($sender, $param)
+ {
+ $this->categories->EditItemIndex=-1;
+ $this->showCategories();
+ }
+
+ public function updateCategoryItem($sender, $param)
+ {
+ if(!$this->Page->IsValid)
+ return;
+
+ $item = $param->Item;
+
+ $id = $this->categories->DataKeys[$param->Item->ItemIndex];
+ $category = new Category;
+ $category->ID = $id;
+ $category->Name = $item->name->Text;
+ $category->Abbreviation = $item->abbrev->Text;
+ $category->EstimateDuration = floatval($item->duration->Text);
+ $category->ProjectID = $this->getProjectID();
+
+ $this->getCategoryDao()->updateCategory($category);
+
+ $this->refreshCategoryList($sender, $param);
+ }
+
+ public function addCategory_clicked($sender, $param)
+ {
+ if(!$this->Page->IsValid)
+ return;
+
+ $newCategory = new Category;
+ $newCategory->Name = $this->categoryName->Text;
+ $newCategory->Abbreviation = $this->abbrev->Text;
+ $newCategory->EstimateDuration = floatval($this->duration->Text);
+ $newCategory->ProjectID = $this->getProjectID();
+
+ $this->getCategoryDao()->addNewCategory($newCategory);
+
+ $this->categoryName->Text = '';
+ $this->abbrev->Text = '';
+ $this->duration->Text = '';
+
+ $this->showCategories();
+ }
+}
+
+?> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/CategoryDataList.tpl b/demos/time-tracker/protected/pages/TimeTracker/CategoryDataList.tpl
new file mode 100644
index 00000000..7a19dadb
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/CategoryDataList.tpl
@@ -0,0 +1,152 @@
+
+<table class="categorylist">
+ <tr>
+ <th>Category Name</th>
+ <th>Abbreviation</th>
+ <th>Estimate Duration</th>
+ <th></th>
+ </tr>
+<com:TDataList ID="categories"
+ RepeatLayout="Raw"
+ DataKeyField="ID"
+ OnEditCommand="editCategoryItem"
+ OnCancelCommand="refreshCategoryList"
+ OnUpdateCommand="updateCategoryItem"
+ OnDeleteCommand="deleteCategoryItem">
+
+ <prop:ItemTemplate>
+ <tr>
+ <td class="categoryName"><%# $this->DataItem->Name %></td>
+ <td class="abbrev"><%# $this->DataItem->Abbreviation %></td>
+ <td class="duration"><%# $this->DataItem->EstimateDuration %></td>
+ <td class="edit">
+ <com:TButton Text="Edit" CommandName="edit"/>
+ <com:TButton Text="Delete" CommandName="delete"
+ Attributes.onclick="if(!confirm('Are you sure?')) return false;" />
+ </td>
+ </tr>
+ </prop:ItemTemplate>
+
+ <prop:EditItemTemplate>
+ <tr>
+ <td class="categoryName">
+ <com:TTextBox ID="name" Text=<%# $this->DataItem->Name %> />
+ <span class="required">*</span>
+ <com:TRequiredFieldValidator
+ ControlToValidate="name"
+ Display="None"
+ CssClass="validator"
+ ControlCssClass="required-input"
+ ValidationGroup="category-update"
+ ErrorMessage="Please enter the category name." />
+ </td>
+ <td class="abbrev">
+ <com:TTextBox ID="abbrev" Text=<%# $this->DataItem->Abbreviation %> />
+ <span class="required">*</span>
+ <com:TRequiredFieldValidator
+ ControlToValidate="abbrev"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="category-update"
+ ControlCssClass="required-input"
+ ErrorMessage="Please enter an abbreviation." />
+ <com:TRegularExpressionValidator
+ ControlToValidate="abbrev"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="category-update"
+ ControlCssClass="required-input1"
+ RegularExpression="[a-zA-Z0-9]*"
+ ErrorMessage="Abbreviation must be alphanumeric." />
+ </td>
+ <td class="duration">
+ <com:TTextBox ID="duration" Text=<%# $this->DataItem->EstimateDuration %> />
+ <span class="required">*</span>
+ <com:TRequiredFieldValidator
+ ControlToValidate="duration"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="category-update"
+ ControlCssClass="required-input"
+ ErrorMessage="Please enter a duration." />
+ <com:TRangeValidator
+ ControlToValidate="duration"
+ DataType="Float"
+ MinValue="0"
+ MaxValue="9999"
+ CssClass="validator"
+ Display="None"
+ ValidationGroup="category-update"
+ ControlCssClass="required-input1"
+ ErrorMessage="Duration must be between 0 and 9999." />
+ </td>
+ <td class="edit">
+ <com:TButton Text="Save" CommandName="update" ValidationGroup="category-update"/>
+ <com:TButton Text="Cancel" CommandName="cancel" />
+ </td>
+ </tr>
+ </prop:EditItemTemplate>
+
+</com:TDataList>
+ <tr>
+ <td class="categoryName">
+ <com:TTextBox ID="categoryName" />
+ <com:TRequiredFieldValidator
+ ControlToValidate="categoryName"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="category-add"
+ ControlCssClass="required-input"
+ ErrorMessage="Please enter the category name." />
+ </td>
+
+ <td class="abbrev">
+ <com:TTextBox ID="abbrev" />
+ <com:TRequiredFieldValidator
+ ControlToValidate="abbrev"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="category-add"
+ ControlCssClass="required-input"
+ ErrorMessage="Please enter an abbreviation." />
+ <com:TRegularExpressionValidator
+ ControlToValidate="abbrev"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="category-add"
+ RegularExpression="[a-zA-Z0-9]*"
+ ControlCssClass="required-input1"
+ ErrorMessage="Abbreviation must be alphanumeric." />
+ </td>
+
+ <td class="duration">
+ <com:TTextBox ID="duration" />
+ <com:TRequiredFieldValidator
+ ControlToValidate="duration"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="category-add"
+ ControlCssClass="required-input"
+ ErrorMessage="Please enter a duration." />
+ <com:TRangeValidator
+ ControlToValidate="duration"
+ DataType="Float"
+ MinValue="0"
+ MaxValue="9999"
+ CssClass="validator"
+ Display="None"
+ ValidationGroup="category-add"
+ ControlCssClass="required-input1"
+ ErrorMessage="Duration must be between 0 and 9999." />
+ </td>
+ <td class="edit">
+ <com:TButton Text="Add Category" OnClick="addCategory_clicked" ValidationGroup="category-add" />
+ </td>
+ </tr>
+</table>
+<com:TValidationSummary
+ AutoUpdate="false"
+ ValidationGroup="category-add" />
+<com:TValidationSummary
+ AutoUpdate="false"
+ ValidationGroup="category-update" />
diff --git a/demos/time-tracker/protected/pages/TimeTracker/LogTimeEntry.page b/demos/time-tracker/protected/pages/TimeTracker/LogTimeEntry.page
new file mode 100644
index 00000000..ca5797e4
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/LogTimeEntry.page
@@ -0,0 +1,77 @@
+<com:TContent ID="Main">
+<h2>Time Entry</h2>
+
+<div class="loghours">
+
+<fieldset>
+<legend>Log your hours</legend>
+<div class="project">
+<com:TLabel ForControl="projects" Text="Project:" />
+<span class="required">*</span><br />
+<com:TDropDownList ID="projects" AutoPostBack="true" OnSelectedIndexChanged="projects_Changed" />
+</div>
+
+<div class="category">
+<com:TLabel ForControl="category" Text="Category:" />
+<span class="required">*</span><br />
+<com:TDropDownList ID="category" />
+</div>
+
+<div class="day">
+<com:TLabel ForControl="day" Text="Day:" />
+<span class="required">*</span><br />
+<com:TDatePicker ID="day" InputMode="DropDownList" />
+</div>
+
+<div class="hours">
+<com:TLabel ForControl="hours" Text="Hours:" />
+<span class="required">*</span><br />
+<com:TTextBox ID="hours" />
+ <com:TRequiredFieldValidator
+ ControlToValidate="hours"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="hours-add"
+ ControlCssClass="required-input"
+ ErrorMessage="Please enter your work hours." />
+ <com:TRangeValidator
+ ControlToValidate="hours"
+ DataType="Float"
+ MinValue="0"
+ MaxValue="9999"
+ CssClass="validator"
+ Display="None"
+ ValidationGroup="hours-add"
+ ControlCssClass="required-input1"
+ ErrorMessage="Hours must be between 0 and 9999" />
+ </div>
+
+<div class="description">
+<com:TLabel ForControl="description" Text="Description:" /><br/>
+<com:TTextBox ID="description" TextMode="MultiLine" />
+</div>
+
+<div class="addEntry">
+
+<com:TValidationSummary AutoUpdate="false" ValidationGroup="hours-add" />
+
+<com:TButton Text="Add Entry" ValidationGroup="hours-add" OnClick="AddNewEntry" />
+</div>
+
+</fieldset>
+
+</div>
+
+<div class="timesheet">
+<fieldset>
+<legend>Time Sheet For:
+<com:TDropDownList ID="projectMembers" CssClass="sheetfor"
+ AutoPostBack="True" OnSelectedIndexChanged="showTimeSheet" />
+</legend>
+
+<com:Application.pages.TimeTracker.TimeEntryList ID="entryList" />
+
+</fieldset>
+
+</div>
+</com:TContent> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/LogTimeEntry.php b/demos/time-tracker/protected/pages/TimeTracker/LogTimeEntry.php
new file mode 100644
index 00000000..cc27c93c
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/LogTimeEntry.php
@@ -0,0 +1,107 @@
+<?php
+
+class LogTimeEntry extends TPage
+{
+
+ protected function getProjectDao()
+ {
+ return $this->Application->Modules['daos']->getDao('ProjectDao');
+ }
+
+ protected function getCategoryDao()
+ {
+ return $this->Application->Modules['daos']->getDao('CategoryDao');
+ }
+
+ protected function getTimeEntryDao()
+ {
+ return $this->Application->Modules['daos']->getDao('TimeEntryDao');
+ }
+
+ public function onLoad($param)
+ {
+ if(!$this->IsPostBack)
+ {
+ $projects = $this->getProjects();
+ $this->projects->DataSource = $projects;
+ $this->projects->dataBind();
+ $this->showCategories(key($projects));
+ }
+ }
+
+ protected function showCategories($projectID)
+ {
+ $categories = array();
+ foreach($this->getCategoryDao()->getCategoriesByProjectID($projectID) as $cat)
+ {
+ $categories[$cat->ID] = $cat->Name;
+ }
+ $this->category->DataSource = $categories;
+ $this->category->dataBind();
+ $this->showProjectUsers($projectID);
+ }
+
+ protected function showProjectUsers($projectID)
+ {
+ if($this->User->isInRole('manager'))
+ $users = $this->getProjectDao()->getProjectMembers($projectID);
+ else
+ $users = array($this->User->Name);
+ $this->projectMembers->DataSource = $users;
+ $this->projectMembers->dataBind();
+ if(is_int($index = array_search($this->User->Name, $users)))
+ $this->projectMembers->SelectedIndex = $index;
+ $this->showTimeSheet();
+ }
+
+ public function showTimeSheet()
+ {
+ $user = $this->projectMembers->SelectedItem->Text;
+ $project = $this->projects->SelectedValue;
+ $this->entryList->setProjectEntry($user,$project);
+ $this->entryList->refreshEntryList();
+ }
+
+ protected function getProjects()
+ {
+ $projects = array();
+ if($this->User->isInRole('admin'))
+ $list = $this->getProjectDao()->getAllProjects();
+ else if($this->User->isInRole('manager'))
+ $list = $this->getProjectDao()->getProjectsByManagerName($this->User->Name);
+ else
+ $list = $this->getProjectDao()->getProjectsByUserName($this->User->Name);
+ foreach($list as $project)
+ $projects[$project->ID] = $project->Name;
+ return $projects;
+ }
+
+ public function projects_Changed($sender, $param)
+ {
+ $this->showCategories($sender->SelectedValue);
+ }
+
+ public function AddNewEntry($sender, $param)
+ {
+ if(!$this->IsValid)
+ return;
+
+ $entry = new TimeEntry;
+ $entry->CreatorUserName = $this->User->Name;
+ $category = new Category;
+ $category->ID = $this->category->SelectedValue;
+ $entry->Category = $category;
+ $entry->Description = $this->description->Text;
+ $entry->Duration = floatval($this->hours->Text);
+ $entry->ReportDate = $this->day->TimeStamp;
+ $entry->Username = $this->projectMembers->SelectedItem->Text;
+
+ $this->hours->Text = '';
+ $this->description->Text = '';
+
+ $this->getTimeEntryDao()->addNewTimeEntry($entry);
+ $this->showTimeSheet();
+ }
+}
+
+?> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.page b/demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.page
index 2a7cb6dd..ea384452 100644
--- a/demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.page
+++ b/demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.page
@@ -1,5 +1,5 @@
<com:TContent ID="Main">
-<h1>Create New Project</h1>
+<h2>Project Details</h2>
<fieldset class="project"><legend>Project Configuration</legend>
<p>Define the project and specify which users will be part of the project.
@@ -10,22 +10,51 @@
<h2>Project Information</h2>
<div class="projectName">
<com:TLabel ForControl="projectName" Text="Project Name"/>
+ <span class="required">*</span><br />
<com:TTextBox ID="projectName" />
+ <com:TRequiredFieldValidator
+ ControlToValidate="projectName"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="project-edit"
+ ControlCssClass="required-input"
+ ErrorMessage="Please enter a project name."/>
+
</div>
<div class="manager">
<com:TLabel ForControl="manager" Text="Project Manager" />
+ <span class="required">*</span><br />
<com:TDropDownList ID="manager" />
</div>
<div class="completionDate">
<com:TLabel ForControl="completionDate" Text="Estimated complete date:"/>
+ <span class="required">*</span><br />
<com:TDatePicker ID="completionDate" InputMode="DropDownList" />
</div>
<div class="estimateHours">
<com:TLabel ForControl="estimateHours" Text="Estimated Duration (in hours):"/>
+ <span class="required">*</span><br />
<com:TTextBox ID="estimateHours" />
+ <com:TRequiredFieldValidator
+ ControlToValidate="estimateHours"
+ Display="None"
+ CssClass="validator"
+ ValidationGroup="project-edit"
+ ControlCssClass="required-input"
+ ErrorMessage="Please enter the project duration." />
+ <com:TRangeValidator
+ ControlToValidate="estimateHours"
+ DataType="Float"
+ MinValue="0"
+ MaxValue="9999"
+ CssClass="validator"
+ Display="None"
+ ValidationGroup="project-edit"
+ ControlCssClass="required-input1"
+ ErrorMessage="Duration must be between 0 and 9999" />
</div>
<div class="description">
- <com:TLabel ForControl="description" Text="Description:" />
+ <com:TLabel ForControl="description" Text="Description:" /><br />
<com:TTextBox ID="description" TextMode="MultiLine" />
</div>
</div>
@@ -36,10 +65,39 @@
<com:TListBox ID="members" SelectionMode="Multiple" />
</div>
- <div class="actionButtons">
- <com:TButton Text="Save" />
- <com:TButton Text="Cancel" />
- <com:TButton Text="Delete" />
+ <com:TPanel CssClass="projectCategory" ID="projectCategoryColumn">
+ <h2>Define Project Categories for Project Management</h2>
+
+ <p>Categories can be added in two ways. You can <strong>ADD</strong> a category
+ by specifying name, abbreviation, and duration -
+ the amount of hours that may be charged under the category. Or,
+ You can <strong>COPY</strong> categories that already have been defined in
+ another project to this project. </p>
+
+ <com:Application.pages.TimeTracker.CategoryDataList ID="categories" />
+
+ <div class="fromProject">
+ <com:TLabel ForControl="projectList" Text="Add categories from another project:" />
+ <com:TDropDownList ID="projectList" />
+ <com:TButton Text="Copy" OnClick="copyButton_clicked" />
+ </div>
+
+ </com:TPanel>
+
+ <div class="actions">
+
+ <com:TValidationSummary AutoUpdate="false" ValidationGroup="project-edit" />
+ <p>Press the <tt>SAVE</tt> button for your configuration to take effect.
+ <com:TPlaceHolder Visible=<%= $this->deleteButton->Visible %>>
+ Press the <tt>DELETE</tt> button to delete the current project.
+ </com:TPlaceHolder>
+ </p>
+ <div class="buttons">
+ <com:TButton Text="Save" CssClass="save"
+ OnClick="saveButton_clicked" ValidationGroup="project-edit"/>
+ <com:TButton ID="deleteButton" Text="Delete" OnClick="deleteButton_clicked"
+ Attributes.onclick="if(!confirm('Are you sure?')) return false;" />
+ </div>
</div>
</fieldset>
diff --git a/demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.php b/demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.php
index 16c10e6f..767e259c 100644
--- a/demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.php
+++ b/demos/time-tracker/protected/pages/TimeTracker/ProjectDetails.php
@@ -2,7 +2,30 @@
class ProjectDetails extends TPage
{
- private $allUsers = null;
+ private $allUsers;
+
+ private $currentProject;
+
+ protected function getCurrentProject()
+ {
+ if(!$this->currentProject)
+ {
+ $id = intval($this->Request['ProjectID']);
+ if($id > 0)
+ $this->currentProject = $this->getProjectDao()->getProjectByID($id);
+ }
+ return $this->currentProject;
+ }
+
+ protected function getProjectDao()
+ {
+ return $this->Application->Modules['daos']->getDao('ProjectDao');
+ }
+
+ protected function getCategoryDao()
+ {
+ return $this->Application->Modules['daos']->getDao('CategoryDao');
+ }
public function onLoad($param)
{
@@ -12,7 +35,53 @@ class ProjectDetails extends TPage
$this->manager->dataBind();
$this->members->DataSource = $this->getUsersWithRole('consultant');
$this->members->dataBind();
+
+ $project = $this->getCurrentProject();
+
+ if($project !== null)
+ {
+ $this->projectName->Text = $project->Name;
+ $this->completionDate->TimeStamp = $project->CompletionDate;
+ $this->description->Text = $project->Description;
+ $this->estimateHours->Text = $project->EstimateDuration;
+ $this->manager->SelectedValue = $project->ManagerUserName;
+
+ $this->selectProjectMembers($project->ID);
+
+ $this->projectCategoryColumn->Visible = true;
+ $this->categories->ProjectID = $project->ID;
+ $this->categories->showCategories();
+
+ $this->deleteButton->Visible = true;
+
+ $this->projectList->DataSource = $this->getProjects();
+ $this->projectList->dataBind();
+
+ }
+ else
+ {
+ $this->projectCategoryColumn->Visible = false;
+ $this->deleteButton->Visible = false;
+ }
+
+ }
+ }
+
+ protected function getProjects()
+ {
+ $projects = array();
+ foreach($this->getProjectDao()->getAllProjects() as $project)
+ {
+ if($project->Name != $this->currentProject->Name)
+ $projects[$project->ID] = $project->Name;
}
+ return $projects;
+ }
+
+ protected function selectProjectMembers($projectID)
+ {
+ $members = $this->getProjectDao()->getProjectMembers($projectID);
+ $this->members->SelectedValues = $members;
}
protected function getUsersWithRole($role)
@@ -26,10 +95,97 @@ class ProjectDetails extends TPage
foreach($this->allUsers as $user)
{
if($user->isInRole($role))
- $users[] = $user->Name;
+ $users[$user->Name] = $user->Name;
}
return $users;
}
+
+ public function onPreRender($param)
+ {
+ $ids = array();
+ foreach($this->members->Items as $item)
+ {
+ if($item->Selected)
+ $ids[] = $item->Value;
+ }
+ $this->setViewState('ActiveConsultants', $ids);
+ }
+
+ public function saveButton_clicked($sender, $param)
+ {
+ if(!$this->Page->IsValid)
+ return;
+
+ $newProject = new Project;
+
+ $projectDao = $this->getProjectDao();
+
+ if($project = $this->getCurrentProject())
+ $newProject = $projectDao->getProjectByID($project->ID);
+ else
+ $newProject->CreatorUserName = $this->User->Name;
+
+ $newProject->Name = $this->projectName->Text;
+ $newProject->CompletionDate = $this->completionDate->TimeStamp;
+ $newProject->Description = $this->description->Text;
+ $newProject->EstimateDuration = floatval($this->estimateHours->Text);
+ $newProject->ManagerUserName = $this->manager->SelectedValue;
+
+ if($this->currentProject)
+ $projectDao->updateProject($newProject);
+ else
+ $projectDao->addNewProject($newProject);
+
+ $this->updateProjectMembers($newProject->ID);
+
+ $url = $this->Service->constructUrl('TimeTracker.ProjectDetails',
+ array('ProjectID'=> $newProject->ID));
+
+ $this->Response->redirect($url);
+ }
+
+ protected function updateProjectMembers($projectID)
+ {
+ $active = $this->getViewState('ActiveConsultants');
+ $projectDao = $this->getProjectDao();
+ foreach($this->members->Items as $item)
+ {
+ if($item->Selected)
+ {
+ if(!in_array($item->Value, $active))
+ $projectDao->addUserToProject($projectID, $item->Value);
+ }
+ else
+ {
+ if(in_array($item->Value, $active))
+ $projectDao->removeUserFromProject($projectID, $item->Value);
+ }
+ }
+ }
+
+ public function deleteButton_clicked($sender, $param)
+ {
+ if($project = $this->getCurrentProject())
+ {
+ $this->getProjectDao()->deleteProject($project->ID);
+ $url = $this->Service->constructUrl('TimeTracker.ProjectList');
+ $this->Response->redirect($url);
+ }
+ }
+
+ public function copyButton_clicked($sender, $param)
+ {
+ $project = $this->projectList->SelectedValue;
+ $categoryDao = $this->getCategoryDao();
+ $categories = $categoryDao->getCategoriesByProjectID($project);
+ $currentProject = $this->getCurrentProject();
+ foreach($categories as $cat)
+ {
+ $cat->ProjectID = $currentProject->ID;
+ $categoryDao->addNewCategory($cat);
+ }
+ $this->categories->showCategories();
+ }
}
?> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/ProjectList.page b/demos/time-tracker/protected/pages/TimeTracker/ProjectList.page
index 1bc50a4b..f55360c4 100644
--- a/demos/time-tracker/protected/pages/TimeTracker/ProjectList.page
+++ b/demos/time-tracker/protected/pages/TimeTracker/ProjectList.page
@@ -1,4 +1,42 @@
<com:TContent ID="Main">
-<h1>Projects</h1>
+<h2>Projects</h2>
+
+<fieldset class="project-list">
+<legend>Project List</legend>
+<com:TDataGrid
+ ID="projectList"
+ AllowSorting="true"
+ OnSortCommand="sortProjects"
+ AutoGenerateColumns="false">
+ <com:THyperLinkColumn
+ HeaderText="Project Name"
+ DataTextField="Name"
+ DataNavigateUrlField="ID"
+ SortExpression="Name"
+ DataNavigateUrlFormatString="?page=TimeTracker.ProjectDetails&ProjectID=%d" />
+ <com:TBoundColumn
+ SortExpression="ManagerUserName"
+ HeaderText="Project Manager"
+ DataField="ManagerUserName" />
+ <com:TBoundColumn
+ SortExpression="Description"
+ HeaderText="Description"
+ DataField="Description" />
+ <com:TTemplateColumn HeaderText="Completion" SortExpression="CompletionDate">
+ <prop:ItemTemplate>
+ <com:System.I18N.TDateFormat
+ Pattern="dd/MM/yyyy"
+ Value=<%# $this->NamingContainer->DataItem->CompletionDate %> />
+ </prop:ItemTemplate>
+ </com:TTemplateColumn>
+ <com:TBoundColumn
+ SortExpression="EstimateDuration"
+ HeaderText="Estimate Duration"
+ DataField="EstimateDuration" />
+</com:TDataGrid>
+<div style="padding:1em">
+ <a href="?page=TimeTracker.ProjectDetails">Create New Project</a>
+</div>
+</fieldset>
</com:TContent> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/ProjectList.php b/demos/time-tracker/protected/pages/TimeTracker/ProjectList.php
new file mode 100644
index 00000000..eb92dcb7
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/ProjectList.php
@@ -0,0 +1,34 @@
+<?php
+
+class ProjectList extends TPage
+{
+ protected function showProjects($sort='', $order='')
+ {
+ $dao = $this->Application->Modules['daos']->getDao('ProjectDao');
+ $this->projectList->DataSource = $dao->getAllProjects($sort, $order);
+ $this->projectList->dataBind();
+ }
+
+ protected function getSortOrder($sort)
+ {
+ $ordering = $this->getViewState('SortOrder', array());
+ $order = isset($ordering[$sort]) ? $ordering[$sort] : 'DESC';
+ $ordering[$sort] = $order == 'DESC' ? 'ASC' : 'DESC';
+ $this->setViewState('SortOrder', $ordering);
+ return $ordering[$sort];
+ }
+
+ protected function sortProjects($sender, $param)
+ {
+ $sort = $param->SortExpression;
+ $this->showProjects($sort, $this->getSortOrder($sort));
+ }
+
+ public function onLoad($param)
+ {
+ if(!$this->IsPostBack)
+ $this->showProjects();
+ }
+}
+
+?> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/ReportProject.page b/demos/time-tracker/protected/pages/TimeTracker/ReportProject.page
index 699c2544..065b6b17 100644
--- a/demos/time-tracker/protected/pages/TimeTracker/ReportProject.page
+++ b/demos/time-tracker/protected/pages/TimeTracker/ReportProject.page
@@ -1,4 +1,17 @@
<com:TContent ID="Main">
-<h1>Project Reports</h1>
+<h2>Project Reports</h2>
+
+<fieldset>
+ <legend>Project Report</legend>
+<com:TMultiView ID="views" ActiveViewIndex="0">
+ <com:TView>
+ <com:TLabel ForControl="projects"
+ Text="Select a project. Use ctrl+click to select multiple resources at once: "/>
+ <com:TListBox ID="projects" CssClass="projects" />
+ <com:TButton Text="Generate Report" />
+ </com:TView>
+</com:TMultiView>
+
+</fieldset>
</com:TContent> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl b/demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl
index 808c233b..5bea2811 100644
--- a/demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl
+++ b/demos/time-tracker/protected/pages/TimeTracker/SiteMap.tpl
@@ -1,7 +1,7 @@
<com:TPanel CssClass="sitemap" Visible="true">
<ul class="level1">
<li class="<com:TPlaceHolder ID="LogMenu" />">
- <a class="menuitem" href="?page=TimeTracker.TimeEntry">Log</a>
+ <a class="menuitem" href="?page=TimeTracker.LogTimeEntry">Log</a>
</li>
<com:TPlaceHolder Visible=<%= $this->User->isInRole('manager') %> >
<li class="<com:TPlaceHolder ID="ReportMenu" />">
diff --git a/demos/time-tracker/protected/pages/TimeTracker/TimeEntry.page b/demos/time-tracker/protected/pages/TimeTracker/TimeEntry.page
deleted file mode 100644
index f934ca02..00000000
--- a/demos/time-tracker/protected/pages/TimeTracker/TimeEntry.page
+++ /dev/null
@@ -1,4 +0,0 @@
-<com:TContent ID="Main">
-<h1>Time Entry</h1>
-
-</com:TContent> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/TimeEntryList.php b/demos/time-tracker/protected/pages/TimeTracker/TimeEntryList.php
new file mode 100644
index 00000000..2b5f7a0f
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/TimeEntryList.php
@@ -0,0 +1,89 @@
+<?php
+
+class TimeEntryList extends TTemplateControl
+{
+ protected function getTimeEntryDao()
+ {
+ return $this->Application->Modules['daos']->getDao('TimeEntryDao');
+ }
+
+ protected function getCategoryDao()
+ {
+ return $this->Application->Modules['daos']->getDao('CategoryDao');
+ }
+
+ public function setProjectEntry($userID,$projectID)
+ {
+ $this->setViewState('ProjectEntry', array($userID,$projectID));
+ }
+
+ protected function getCategories()
+ {
+ $project = $this->getViewState('ProjectEntry');
+ foreach($this->getCategoryDao()->getCategoriesByProjectID($project[1]) as $cat)
+ {
+ $categories[$cat->ID] = $cat->Name;
+ }
+ return $categories;
+ }
+
+ protected function showEntryList()
+ {
+ $project = $this->getViewState('ProjectEntry');
+ $list = $this->getTimeEntryDao()->getTimeEntriesInProject($project[0], $project[1]);
+ $this->entries->DataSource = $list;
+ $this->entries->dataBind();
+ }
+
+ public function refreshEntryList()
+ {
+ $this->entries->EditItemIndex=-1;
+ $this->showEntryList();
+ }
+
+ public function editEntryItem($sender, $param)
+ {
+ $this->entries->EditItemIndex=$param->Item->ItemIndex;
+ $this->showEntryList();
+ }
+
+ public function deleteEntryItem($sender, $param)
+ {
+ $id = $this->entries->DataKeys[$param->Item->ItemIndex];
+ $this->getTimeEntryDao()->deleteTimeEntry($id);
+ $this->refreshEntryList();
+ }
+
+ public function updateEntryItem($sender, $param)
+ {
+ if(!$this->Page->IsValid)
+ return;
+
+ $item = $param->Item;
+
+ $id = $this->entries->DataKeys[$param->Item->ItemIndex];
+
+ $entry = $this->getTimeEntryDao()->getTimeEntryByID($id);
+ $category = new Category;
+ $category->ID = $param->Item->category->SelectedValue;
+ $entry->Category = $category;
+ $entry->Description = $param->Item->description->Text;
+ $entry->Duration = floatval($param->Item->hours->Text);
+ $entry->ReportDate = $param->Item->day->TimeStamp;
+
+ $this->getTimeEntryDao()->updateTimeEntry($entry);
+ $this->refreshEntryList();
+ }
+
+ public function EntryItemCreated($sender, $param)
+ {
+ if($param->Item->ItemType == 'EditItem' && $param->Item->DataItem)
+ {
+ $param->Item->category->DataSource = $this->getCategories();
+ $param->Item->category->dataBind();
+ $param->Item->category->SelectedValue = $param->Item->DataItem->Category->ID;
+ }
+ }
+}
+
+?> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/TimeEntryList.tpl b/demos/time-tracker/protected/pages/TimeTracker/TimeEntryList.tpl
new file mode 100644
index 00000000..ace8a95b
--- /dev/null
+++ b/demos/time-tracker/protected/pages/TimeTracker/TimeEntryList.tpl
@@ -0,0 +1,66 @@
+<com:TDataList ID="entries"
+ RepeatLayout="Raw"
+ DataKeyField="ID"
+ OnEditCommand="editEntryItem"
+ OnCancelCommand="refreshEntryList"
+ OnUpdateCommand="updateEntryItem"
+ OnDeleteCommand="deleteEntryItem"
+ OnItemCreated="EntryItemCreated" >
+ <prop:EmptyTemplate>
+ There are no time entries for this user.
+ </prop:EmptyTemplate>
+ <prop:HeaderTemplate>
+ <table class="time-entries">
+ <tr>
+ <th>Category Name</th>
+ <th>Description</th>
+ <th>Duration</th>
+ <th>Reported Date</th>
+ <th>Edit/Delete</th>
+ </tr>
+ </prop:HeaderTemplate>
+
+ <prop:FooterTemplate>
+ </table>
+ </prop:FooterTemplate>
+ <prop:ItemTemplate>
+ <tr>
+ <td class="categoryName"><%# $this->DataItem->Category->Name %></td>
+ <td class="description"><%# $this->DataItem->Description %></td>
+ <td class="duration"><%# $this->DataItem->Duration %></td>
+ <td class="date">
+ <com:System.I18N.TDateFormat
+ Pattern="dd/MM/yyyy"
+ Value=<%# $this->DataItem->ReportDate %> />
+ </td>
+ <td class="edit">
+ <com:TButton Text="Edit" CommandName="edit"/>
+ <com:TButton Text="Delete" CommandName="delete"
+ Attributes.onclick="if(!confirm('Are you sure?')) return false;" />
+ </td>
+ </tr>
+ </prop:ItemTemplate>
+
+ <prop:EditItemTemplate>
+ <tr>
+ <td class="categoryName">
+ <com:TDropDownList ID="category" />
+ </td>
+ <td class="description">
+ <com:TTextBox ID="description" Text=<%# $this->DataItem->Description %> />
+ </td>
+ <td class="duration">
+ <com:TTextBox ID="hours" Text=<%# $this->DataItem->Duration %> />
+ </td>
+ <td class="date">
+ <com:TDatePicker InputMode="DropDownList" ID="day"
+ TimeStamp=<%# $this->DataItem->ReportDate %> />
+ </td>
+ <td class="edit">
+ <com:TButton Text="Save" CommandName="update" ValidationGroup="entry-update"/>
+ <com:TButton Text="Cancel" CommandName="cancel" />
+ </td>
+ </tr>
+ </prop:EditItemTemplate>
+
+</com:TDataList> \ No newline at end of file
diff --git a/demos/time-tracker/protected/pages/TimeTracker/UserList.page b/demos/time-tracker/protected/pages/TimeTracker/UserList.page
index f0c88112..3696e1db 100644
--- a/demos/time-tracker/protected/pages/TimeTracker/UserList.page
+++ b/demos/time-tracker/protected/pages/TimeTracker/UserList.page
@@ -1,31 +1,20 @@
<com:TContent ID="Main">
-<h1>List Users</h1>
+<h2>Users</h2>
<fieldset>
<legend>User List</legend>
<com:TRepeater ID="list" EnableViewState="false">
- <prop:HeaderTemplate>
- <table cellpadding="2">
- <tr class="header">
- <th>User Name</th>
- <th>E-Mail Address</th>
- </tr>
- </prop:HeaderTemplate>
- <prop:ItemTemplate>
- <tr class="row0">
- <td><%#$this->DataItem->Name %></td>
- <td><%#$this->DataItem->EmailAddress %></td>
- </tr>
- </prop:ItemTemplate>
- <prop:AlternatingItemTemplate>
- <tr class="row1">
- <td><%#$this->DataItem->Name %></td>
+ <prop:HeaderTemplate>
+ <table cellpadding="2">
+ <tr class="header">
+ <th>User Name</th>
+ <th>E-Mail Address</th>
+ </tr>
+ </prop:HeaderTemplate>
+ <prop:ItemTemplate>
+ <tr class="row0"> <td><%#$this->DataItem->Name %></td> <td><%#$this->DataItem->EmailAddress %></td> </tr> </prop:ItemTemplate> <prop:AlternatingItemTemplate> <tr class="row1"> <td><%#$this->DataItem->Name %></td>
<td><%#$this->DataItem->EmailAddress %></td>
- </tr>
- </prop:AlternatingItemTemplate>
- <prop:FooterTemplate>
- </table>
- </prop:FooterTemplate>
+ </tr> </prop:AlternatingItemTemplate> <prop:FooterTemplate> </table> </prop:FooterTemplate>
</com:TRepeater>
<div style="padding:1em">
<a href="?page=TimeTracker.UserCreate">Create New User</a>
diff --git a/demos/time-tracker/protected/pages/TimeTracker/config.xml b/demos/time-tracker/protected/pages/TimeTracker/config.xml
index 4497d9e3..b086f8a0 100644
--- a/demos/time-tracker/protected/pages/TimeTracker/config.xml
+++ b/demos/time-tracker/protected/pages/TimeTracker/config.xml
@@ -13,7 +13,7 @@
<authorization>
<allow roles="admin" />
<allow pages="ProjectList, ProjectDetails, ReportResource, ReportProject" roles="manager" />
- <allow pages="TimeEntry" roles="consultant" />
+ <allow pages="LogTimeEntry" roles="consultant" />
<allow pages="UserCreate,Logout,Login" users="*" />
<deny users="*" />
</authorization>
diff --git a/demos/time-tracker/themes/TimeTracker/project.css b/demos/time-tracker/themes/TimeTracker/project.css
index 7b6863a0..809948cd 100644
--- a/demos/time-tracker/themes/TimeTracker/project.css
+++ b/demos/time-tracker/themes/TimeTracker/project.css
@@ -1,19 +1,17 @@
-fieldset.project label
+fieldset.project label, fieldset.project p
{
- display: block;
font-size: 0.9em;
- margin-bottom: 0.2em;
}
.projectInfo
{
- width: 40%;
+ width: 49%;
float: left;
}
.projectMembers
{
- width: 40%;
+ width: 50%;
float: left;
margin-left: 0.3em;
}
@@ -30,17 +28,20 @@ fieldset.project h2
background-position: center;
}
-.projectInfo div, .projectMembers div
+.projectInfo div, .projectMembers div, .projectCategory div
{
margin: 0.7em 0;
}
-.projectInfo div input, .projectInfo div.manager select
+.projectInfo div input, .projectInfo div.manager select,
+.projectCategory .categoryName input
{
width: 15em;
}
-.projectInfo .estimateHours input
+.projectInfo .estimateHours input,
+.projectCategory .abbrev input,
+.projectCategory .duration input
{
width: 4em;
}
@@ -57,14 +58,87 @@ fieldset.project h2
height: 17em;
}
-.actionButtons
+.projectCategory
{
float: left;
- width: 90%;
- padding: 0.65em;
+ display: block;
+}
+
+.actions
+{
+ float: left;
+ margin-top: 1em;
+ clear: both;
+ width: 100%;
text-align: center;
+}
+
+.actions .buttons
+{
background-color: #D2E8E8;
background-image: url(bar.png);
background-repeat: repeat-x;
background-position: center;
+ padding: 0.65em;
+}
+
+.actions .buttons input
+{
+ padding: 0.15em 1em;
+}
+
+.actions .buttons input.save
+{
+ padding: 0.15em 2.5em;
+}
+
+
+
+fieldset.project .validator
+{
+ display: block;
+}
+
+fieldset.project .categoryName
+{
+ width: 50%;
+ border: 1px solid red;
+}
+
+fieldset.project td.abbrev,
+fieldset.project td.duration,
+fieldset.project td.edit
+{
+ width: 20%;
+ border: 1px solid red;
+}
+
+
+.fromProject select
+{
+ width: 15em;
+}
+
+fieldset.project .projectCategory table
+{
+ border-collapse: collapse;
+ width: 100%;
+}
+
+fieldset.project .projectCategory table th, fieldset.project td.edit
+{
+ white-space: nowrap;
+ text-align: left;
+ padding: 0.2em;
+}
+
+fieldset.project .projectCategory table th
+{
+ font-size: 0.9em;
+}
+
+fieldset.project .projectCategory table td
+{
+ border: 1px solid #6495ED;
+ padding: 0.2em;
} \ No newline at end of file
diff --git a/demos/time-tracker/themes/TimeTracker/site.css b/demos/time-tracker/themes/TimeTracker/site.css
index 386260a6..8a162002 100644
--- a/demos/time-tracker/themes/TimeTracker/site.css
+++ b/demos/time-tracker/themes/TimeTracker/site.css
@@ -226,4 +226,11 @@ fieldset.signup .wizardNav
.row1
{
background-color: #eef;
+}
+
+
+.required-input, .required-input1, .required-input2
+{
+ border: 2px solid red;
+ background-color: #FFE4E1
} \ No newline at end of file
diff --git a/demos/time-tracker/themes/TimeTracker/time-entry.css b/demos/time-tracker/themes/TimeTracker/time-entry.css
new file mode 100644
index 00000000..0956f4e7
--- /dev/null
+++ b/demos/time-tracker/themes/TimeTracker/time-entry.css
@@ -0,0 +1,46 @@
+
+.loghours label, .timesheet label
+{
+ font-size: 0.9em;
+}
+
+.loghours div, .timesheet div
+{
+ margin-bottom: 0.7em;
+}
+.loghours .category select,
+.loghours .project select,
+.loghours .description textarea
+{
+ width: 14em;
+}
+
+.loghours .description textarea
+{
+ width: 95%;
+ height: 4em;
+}
+
+.loghours .hours input
+{
+ width: 4em;
+ font-weight: bold;
+ text-align: center;
+}
+
+.loghours .project, .loghours .category, .loghours .day
+{
+ width: 12em;
+ float: left;
+}
+
+.loghours .addEntry input
+{
+ margin-top: 1em;
+ padding: 0.15em 2.5em;
+}
+
+.sheetfor
+{
+ width: 15em;
+} \ No newline at end of file