diff --git a/app/Http/Requests/UpdateUserRequest.php b/app/Http/Requests/UpdateUserRequest.php index bc97f78cc..d95cba607 100644 --- a/app/Http/Requests/UpdateUserRequest.php +++ b/app/Http/Requests/UpdateUserRequest.php @@ -34,9 +34,10 @@ public function rules() { $id = $this->route('user')->id; $rules = [ - 'name' => 'required|unique:users,name,'.$id, - 'email' => 'required|email|unique:users,email,'.$id.'|regex:/^[\w\-\.\+]+\@[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/', - 'phone' => 'nullable|numeric|digits:10', + 'name' => 'required|unique:users,name,'.$id, + 'email' => 'required|email|unique:users,email,'.$id.'|regex:/^[\w\-\.\+]+\@[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/', + 'phone' => 'nullable|numeric|digits:10', + 'role_id' => 'required', ]; return $rules; diff --git a/app/Models/User.php b/app/Models/User.php index db381f64d..84bde1672 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -112,15 +112,17 @@ class User extends Authenticatable * @var array */ public static $rules = [ - 'name' => 'required|unique:users,name', - 'email' => 'required|email|unique:users,email|regex:/^[\w\-\.\+]+\@[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/', - 'phone' => 'nullable|numeric|digits:10', + 'name' => 'required|unique:users,name', + 'email' => 'required|email|unique:users,email|regex:/^[\w\-\.\+]+\@[a-zA-Z0-9\.\-]+\.[a-zA-z0-9]{2,4}$/', + 'phone' => 'nullable|numeric|digits:10', + 'role_id' => 'required', ]; public static $messages = [ - 'phone.digits' => 'The phone number must be 10 digits long.', - 'email.regex' => 'Please enter valid email.', - 'photo.mimes' => 'The profile image must be a file of type: jpeg, jpg, png.', + 'phone.digits' => 'The phone number must be 10 digits long.', + 'email.regex' => 'Please enter valid email.', + 'photo.mimes' => 'The profile image must be a file of type: jpeg, jpg, png.', + 'role_id.required' => 'Please select user role.', ]; public static $setPasswordRules = [ diff --git a/app/Repositories/DashboardRepository.php b/app/Repositories/DashboardRepository.php index f96150a04..334a28f64 100644 --- a/app/Repositories/DashboardRepository.php +++ b/app/Repositories/DashboardRepository.php @@ -66,7 +66,7 @@ public function getWorkReport($input) $result = []; // preparing a date array for displaying a labels foreach ($dates['dateArr'] as $date) { - $date = date('d-M', strtotime($date)); + $date = date('jS M', strtotime($date)); $result['date'][] = $date; } $result['projects'] = array_keys($projects); diff --git a/app/Repositories/ReportRepository.php b/app/Repositories/ReportRepository.php index a61abb802..a562ddff2 100644 --- a/app/Repositories/ReportRepository.php +++ b/app/Repositories/ReportRepository.php @@ -266,6 +266,8 @@ public function getReport($report) $project = $entry->task->project; $client = $project->client; $duration = $entry->duration; + $projectPrefix = $project->prefix; + $taskNumber = $entry->task->task_number; // prepare client and duration $result[$clientId]['name'] = $client->name; @@ -306,6 +308,8 @@ public function getReport($report) $time = $result[$clientId]['projects'][$project->id]['users'][$entry->user_id]['tasks'][$entry->task_id]['duration'] + $entry->duration; $result[$clientId]['projects'][$project->id]['users'][$entry->user_id]['tasks'][$entry->task_id]['duration'] = $time; $result[$clientId]['projects'][$project->id]['users'][$entry->user_id]['tasks'][$entry->task_id]['time'] = $this->getDurationTime($time); + $result[$clientId]['projects'][$project->id]['users'][$entry->user_id]['tasks'][$entry->task_id]['project_prefix'] = $projectPrefix; + $result[$clientId]['projects'][$project->id]['users'][$entry->user_id]['tasks'][$entry->task_id]['task_number'] = $taskNumber; } return $result; diff --git a/composer.json b/composer.json index 7e1a902ee..39e157dd9 100644 --- a/composer.json +++ b/composer.json @@ -1,7 +1,7 @@ { "name": "infyomlabs/infy-tracker", "type": "project", - "version": "1.8.1-alpha", + "version": "1.8.2-alpha", "description": "Create Projects / Tasks, Track Time, Show Daily Reports", "keywords": [ "time", diff --git a/database/factories/ReportFactory.php b/database/factories/ReportFactory.php index 89e0ffbd8..27b74f0b2 100644 --- a/database/factories/ReportFactory.php +++ b/database/factories/ReportFactory.php @@ -8,11 +8,13 @@ $factory->define(Report::class, function (Faker $faker) { $user = factory(User::class)->create(); + $startDate = date('Y-m-d H:i:s', strtotime('-1 day')); + $endDate = date('Y-m-d H:i:s'); return [ 'name' => $faker->word, 'owner_id' => $user->id, - 'start_date' => $faker->dateTime, - 'end_date' => $faker->dateTime, + 'start_date' => $startDate, + 'end_date' => $endDate, ]; }); diff --git a/database/factories/TaskFactory.php b/database/factories/TaskFactory.php index 46a58a230..1fec508ac 100644 --- a/database/factories/TaskFactory.php +++ b/database/factories/TaskFactory.php @@ -10,12 +10,15 @@ $factory->define(Task::class, function (Faker $faker) { $project = factory(Project::class)->create(); + $dueDate = date('Y-m-d H:i:s', strtotime('+ 4hours')); + + $dueDate = date('Y-m-d H:i:s', strtotime('+ 4hours')); return [ 'title' => $faker->sentence, 'description' => $faker->text, 'project_id' => $project->id, - 'due_date' => $faker->dateTime, + 'due_date' => $dueDate, 'status' => Task::STATUS_ALL, 'task_number' => $faker->unique()->randomDigitNotNull, ]; diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index eee07d140..dce948130 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -22,5 +22,8 @@ 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10), + 'is_active' => true, + 'is_email_verified' => true, + 'set_password' => true, ]; }); diff --git a/resources/assets/js/custom.js b/resources/assets/js/custom.js index d1bf03c29..35922a485 100644 --- a/resources/assets/js/custom.js +++ b/resources/assets/js/custom.js @@ -165,3 +165,32 @@ window.displaySuccessMessage = function (message) { position: 'top-right', }); }; + +$(function () { + $(".dataTables_length").css('padding-top', '6px'); + $(".dataTables_info").css('padding-top', '24px'); +}); + +$.extend($.fn.dataTable.defaults, { + drawCallback: function (settings) { + let thisTableId = settings.sTableId; + if (settings.fnRecordsDisplay() > settings._iDisplayLength) { + $('#' + thisTableId + '_paginate').show(); + } else { + $('#' + thisTableId + '_paginate').hide(); + } + } +}); + +//focus on select2 +$(document).on('focus', '.select2-selection.select2-selection--single', function (e) { + $(this).closest(".select2-container").siblings('select:enabled').select2('open'); +}); + +$(function () { + $(".modal").on('shown.bs.modal', function () { + setTimeout(function () { + $(".modal").find('input:text, .select2-selection.select2-selection--single').first().focus(); + },150); + }); +}); diff --git a/resources/assets/js/dashboard/dashboard.js b/resources/assets/js/dashboard/dashboard.js index 0ae2fd7a0..d5553e820 100644 --- a/resources/assets/js/dashboard/dashboard.js +++ b/resources/assets/js/dashboard/dashboard.js @@ -20,7 +20,7 @@ timeRange.on('apply.daterangepicker', function (ev, picker) { }); window.cb = function (start, end) { - timeRange.find('span').html(start.format('MMMM D, YYYY') + ' - ' + end.format('MMMM D, YYYY')); + timeRange.find('span').html(start.format('MMM D, YYYY') + ' - ' + end.format('MMM D, YYYY')); }; cb(start, end); @@ -67,7 +67,6 @@ window.loadUserWorkReport = function (startDate, endDate, userId) { window.prepareUserWorkReport = function (result) { $('#daily-work-report').html(''); let data = result.data; - console.log(result); if (data.totalRecords === 0) { $('#work-report-container').html(''); $('#work-report-container').append('
No Records Found
'); @@ -96,12 +95,15 @@ window.prepareUserWorkReport = function (result) { mode: 'index', callbacks: { label: function (tooltipItem, data) { + result = roundToQuarterHour(tooltipItem.yLabel); + if(result == '0min') { + return ''; + } let label = data.datasets[tooltipItem.datasetIndex].label || ''; if (label) { label += ': '; } - result = roundToQuarterHour(tooltipItem.yLabel); return label + result; } } diff --git a/resources/assets/js/dashboard/developers-daily-report.js b/resources/assets/js/dashboard/developers-daily-report.js index cfd0d3719..a763e45cc 100644 --- a/resources/assets/js/dashboard/developers-daily-report.js +++ b/resources/assets/js/dashboard/developers-daily-report.js @@ -11,7 +11,7 @@ $datePicker.on('apply.daterangepicker', function (ev, picker) { }); window.cb = function (start) { - $datePicker.find('span').html(start.format('MMMM D, YYYY')); + $datePicker.find('span').html(start.format('MMM D, YYYY')); }; cb(start); diff --git a/resources/assets/js/profile/profile.js b/resources/assets/js/profile/profile.js index a9d83f822..a01fd1513 100644 --- a/resources/assets/js/profile/profile.js +++ b/resources/assets/js/profile/profile.js @@ -4,7 +4,7 @@ $('#editProfileForm').submit(function (event) { if(!isValidate){ return false; } - let loadingButton = jQuery(this).find("#btnEditSave"); + let loadingButton = jQuery(this).find("#btnPrEditSave"); loadingButton.button('loading'); $.ajax({ url: usersUrl + 'profile-update', @@ -120,4 +120,14 @@ function validatePassword() { return false; } return true; -} \ No newline at end of file +} + +$(".changeType").click(function () { + let inputField = $(this).parent().siblings(); + let oldType = inputField.attr('type'); + if(oldType == 'password') { + inputField.attr('type', 'text'); + } else { + inputField.attr('type', 'password'); + } +}); diff --git a/resources/assets/js/report/report.js b/resources/assets/js/report/report.js index e2a152a06..dcd8c3509 100644 --- a/resources/assets/js/report/report.js +++ b/resources/assets/js/report/report.js @@ -44,6 +44,10 @@ $('#end_date').datetimepicker({ maxDate: moment() }); +$(function () { + $('form').find('input:text').filter(':input:visible:first').first().focus(); +}); + $("#start_date").on("dp.change", function (e) { $('#end_date').data("DateTimePicker").minDate(e.date); }); diff --git a/resources/assets/js/task/task.js b/resources/assets/js/task/task.js index c139adec1..187bb9a1f 100644 --- a/resources/assets/js/task/task.js +++ b/resources/assets/js/task/task.js @@ -318,9 +318,9 @@ $(document).on('change', '#task_users', function () { taskId = taskUserId[1]; userId = taskUserId[0]; } - let url = taskDetailUrl + '/' + taskId + let url = taskDetailUrl + '/' + taskId; if (userId !== 0) { - url = url + '?user_id=' + userId + url = url + '?user_id=' + userId; } $.ajax({ url: url, @@ -374,7 +374,8 @@ window.drawTaskDetailTable = function (data) { $('#no-record-info-msg').hide(); stopLoader(); - $('#taskDetailsTable tbody').on('click', 'td.details-control', function () { + $('#taskDetailsTable tbody').off('click', 'tr td.details-control'); + $('#taskDetailsTable tbody').on('click', 'tr td.details-control', function () { var tr = $(this).closest('tr'); var row = taskDetailsTable.row(tr); @@ -384,7 +385,7 @@ window.drawTaskDetailTable = function (data) { tr.removeClass('shown'); } else { // Open this row - row.child(formatCollapsableRow(row.data())).show(); + row.child('
' + row.data().note + '
').show(); tr.addClass('shown'); } }); diff --git a/resources/assets/js/task/task_detail.js b/resources/assets/js/task/task_detail.js index 84d08c33f..23df41144 100644 --- a/resources/assets/js/task/task_detail.js +++ b/resources/assets/js/task/task_detail.js @@ -239,11 +239,10 @@ Dropzone.options.dropzone = { let newFileName = fileNameExtArr[0]; let newFileExt = fileNameExtArr[1]; let prevFileName = fileuploded.innerHTML.split('.')[0]; - let fileUrl = attachmentUrl + fileName; fileuploded.innerHTML = fileName; - $(".dz-preview:last-child").children(':last-child').attr('data-file-id', attachment.id); - $(".dz-preview:last-child").children(':last-child').attr('data-file-url', attachment.file_url); + $(file.previewTemplate).find('.dz-remove').attr('data-file-id', attachment.id); + $(file.previewTemplate).find('.dz-remove').attr('data-file-url', attachment.file_url); if($.inArray(newFileExt,['jpg','jpge','png']) > -1) { $(".previewEle").find('.' + prevFileName).attr('href', attachment.file_url); $(".previewEle").find('.' + prevFileName).attr('class', newFileName); diff --git a/resources/assets/js/time_entries/time_entry.js b/resources/assets/js/time_entries/time_entry.js index 5ad667a39..66dfb0bf6 100644 --- a/resources/assets/js/time_entries/time_entry.js +++ b/resources/assets/js/time_entries/time_entry.js @@ -261,6 +261,7 @@ $('#startTime,#endTime').on('dp.change', function (selected) { $('#startTime').data("DateTimePicker").maxDate(moment().endOf('now')); $('#endTime').data("DateTimePicker").maxDate(moment().endOf('now')); }); +$('#endTime').val(moment().format('YYYY-MM-DD HH:mm:ss')); $('#editTimeEntryForm').submit(function (event) { event.preventDefault(); diff --git a/resources/assets/js/time_tracker/time_tracker.js b/resources/assets/js/time_tracker/time_tracker.js index 05fe3b4eb..d676bb53e 100644 --- a/resources/assets/js/time_tracker/time_tracker.js +++ b/resources/assets/js/time_tracker/time_tracker.js @@ -191,7 +191,7 @@ $("#stopTimer").click(function (e) { enableTimerData(); $('#loader').show(); - storeTimeEntry(); + checkTimeEntry(); }); function enableTimerData() { @@ -215,10 +215,102 @@ function stopTime() { seconds = minutes = hours = 0; } -function storeTimeEntry() { +function diff_mins(dt2, dt1) { + dt2 = new Date(dt2); + dt1 = new Date(dt1); + var diff = (dt2.getTime() - dt1.getTime()) / 1000; + diff /= (60); + return Math.abs(Math.round(diff)); +} + +function adjustTimeEntry() { + let startDate = getItemFromLocalStorage('start_time'); + $("#tmAdjustValidationErrorsBox").show(); + $("#tmAdjustValidationErrorsBox").html("Time Entry must be less than 12 hours."); + $('#adjustStartTime').val(startDate); + $('#adjustStartTime').attr('disabled', 'true'); + $("#timeEntryAdjustModal").modal(); + $('#stopTimer').removeAttr('disabled'); +} + +$('#timeEntryAdjustModal').on('hidden.bs.modal', function () { + $('#adjustEndTime').prop('disabled', false); + $('#adjustStartTime').prop('disabled', false); + $("#adjustEndTime").data("DateTimePicker").date(null); + $("#adjustStartTime").data("DateTimePicker").date(null); + resetModalForm('#timeEntryAdjustForm'); + $('#tmAdjustValidationErrorsBox').hide(); +}); + +$('#adjustStartTime').datetimepicker({ + format: 'YYYY-MM-DD HH:mm:ss', + useCurrent: true, + icons: { + up: "icon-arrow-up icons", + down: "icon-arrow-down icons", + previous: 'icon-arrow-left icons', + next: 'icon-arrow-right icons', + }, + sideBySide: true, + maxDate: moment().endOf('day'), +}); +$('#adjustEndTime').datetimepicker({ + format: 'YYYY-MM-DD HH:mm:ss', + useCurrent: true, + icons: { + up: "icon-arrow-up icons", + down: "icon-arrow-down icons", + previous: 'icon-arrow-left icons', + next: 'icon-arrow-right icons', + }, + sideBySide: true, + maxDate: moment().endOf('day'), +}); + +$('#adjustStartTime,#adjustEndTime').on('dp.change', function () { + const startTime = $('#adjustStartTime').val(); + const endTime = $('#adjustEndTime').val(); + let minutes = 0; + if (endTime) { + const diff = new Date(Date.parse(endTime) - Date.parse(startTime)); + minutes = diff / (1000 * 60); + if (!Number.isInteger(minutes)) { + minutes = minutes.toFixed(2); + } + } + $('#adjustDuration').val(minutes).prop('disabled', true); + $('#adjustStartTime').data("DateTimePicker").maxDate(moment().endOf('now')); + $('#adjustEndTime').data("DateTimePicker").maxDate(moment().endOf('now')); + if(minutes < 720) { + $('#tmAdjustValidationErrorsBox').hide(); + } +}); + +$('#adjustBtnSave').click(function () { + let startTime = $('#adjustStartTime').val(); + let endTime = $('#adjustEndTime').val(); + let totalMin = diff_mins(endTime, startTime); + if(totalMin > 720) { + $("#tmAdjustValidationErrorsBox").show(); + $("#tmAdjustValidationErrorsBox").html("Time Entry must be less than 12 hours."); + } else { + $("#adjustBtnCancel").trigger('click'); + storeTimeEntry(startTime, endTime); + } +}); + +function checkTimeEntry() { let startTime = getItemFromLocalStorage('start_time'); let endTime = getCurrentTime(); + let totalMin = diff_mins(endTime, startTime); + if(totalMin > 720) { + adjustTimeEntry(); + } else { + storeTimeEntry(startTime, endTime); + } +} +function storeTimeEntry(startTime, endTime) { $.ajax({ url: storeTimeEntriesUrl, type: 'POST', diff --git a/resources/assets/js/users/user.js b/resources/assets/js/users/user.js index a6cd92def..0e8bcfb73 100644 --- a/resources/assets/js/users/user.js +++ b/resources/assets/js/users/user.js @@ -4,7 +4,8 @@ $(function () { }); $('#roleId,#editRoleId').select2({ width: '100%', - placeholder: "Select Role" + placeholder: "Select Role", + minimumResultsForSearch: -1 }); }); diff --git a/resources/assets/style/sass/style.scss b/resources/assets/style/sass/style.scss index b42637b49..25ef0ac9a 100644 --- a/resources/assets/style/sass/style.scss +++ b/resources/assets/style/sass/style.scss @@ -483,7 +483,7 @@ table.dataTable { } .edit-profile__file-upload { - padding: 10px; + padding: 7px 10px; background: #20a8d8; display: table; color: $white; @@ -550,3 +550,9 @@ table.dataTable { overflow-y: auto; max-height: 750px; } + +.input-group__addon { + border-top-right-radius: 0 !important; + border-bottom-right-radius: 0 !important; +} + diff --git a/resources/views/dashboard/index.blade.php b/resources/views/dashboard/index.blade.php index 05427369b..f2771ac45 100644 --- a/resources/views/dashboard/index.blade.php +++ b/resources/views/dashboard/index.blade.php @@ -28,11 +28,11 @@
@permission('manage_users') -
+
{!! Form::select('users', $users, Auth::id(), ['id' => 'userId','class'=>'user_filter_dropdown']) !!}
@endpermission -
+
   + + @yield('page_css') @yield('css') @@ -70,6 +74,7 @@
@include('time_tracker.index'); +@include('time_tracker.adjust_time_entry');