Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,62 +1,57 @@
<div class="row scroll-table mt-5 ml-0">
<table
class="table table-striped mb-0"
datatable
[dtTrigger]="dtTrigger"
[dtOptions]="dtOptions"
*ngIf="(reportDataSource$ | async) as dataSource">
<thead class="thead-blue">
<tr class="d-flex">
<th class="hidden-col">ID</th>
<th class="col md-col">User email</th>
<th class="col sm-col">Date</th>
<th class="col sm-col" title="Duration (hours)">Duration</th>
<th class="col x-sm-col" title="Time in">Time in</th>
<th class="col x-sm-col" title="Time out">Time out</th>
<th class="col md-col">Project</th>
<th class="hidden-col">Project ID</th>
<th class="col md-col">Customer</th>
<th class="hidden-col">Customer ID</th>
<th class="col md-col">Activity</th>
<th class="col lg-col">Ticket</th>
<th class="col lg-col">Description</th>
<th class="col lg-col">Technologies</th>
</tr>
</thead>
<app-loading-bar *ngIf="dataSource.isLoading"></app-loading-bar>
<tbody *ngIf="!dataSource.isLoading">
<tr class="d-flex" *ngFor="let entry of dataSource.data">
<td class="hidden-col">{{ entry.id }}</td>
<td class="col md-col">{{ entry.owner_email }}</td>
<td class="col sm-col">
{{ entry.start_date | date: 'MM/dd/yyyy' }}
</td>
<td class="col sm-col">
{{ entry.end_date | substractDate: entry.start_date }}
</td>
<td class="col x-sm-col">{{ entry.start_date | date: 'HH:mm' }}</td>
<td class="col x-sm-col">{{ entry.end_date | date: 'HH:mm' }}</td>
<td class="col md-col">{{ entry.project_name }}</td>
<td class="hidden-col">{{ entry.project_id }}</td>
<td class="col md-col">{{ entry.customer_name }}</td>
<td class="hidden-col">{{ entry.customer_id }}</td>
<td class="col md-col">{{ entry.activity_name }}</td>
<td class="col lg-col">
<ng-container *ngIf="entry.uri !== null">
<a [class.is-url]="isURL(entry.uri)" (click)="openURLInNewTab(entry.uri)">
<table class="table table-striped mb-0" datatable [dtTrigger]="dtTrigger" [dtOptions]="dtOptions" *ngIf="(reportDataSource$ | async) as dataSource">
<thead class="thead-blue">
<tr class="d-flex">
<th class="hidden-col">ID</th>
<th class="col md-col">User email</th>
<th class="col sm-col">Date</th>
<th class="col sm-col" title="Duration (hours)">Duration</th>
<th class="col x-sm-col" title="Time in">Time in</th>
<th class="col x-sm-col" title="Time out">Time out</th>
<th class="col md-col">Project</th>
<th class="hidden-col">Project ID</th>
<th class="col md-col">Customer</th>
<th class="hidden-col">Customer ID</th>
<th class="col md-col">Activity</th>
<th class="col lg-col">Ticket</th>
<th class="col lg-col">Description</th>
<th class="col lg-col">Technologies</th>
</tr>
</thead>
<app-loading-bar *ngIf="dataSource.isLoading"></app-loading-bar>
<tbody *ngIf="!dataSource.isLoading">
<tr class="d-flex" *ngFor="let entry of dataSource.data">
<td class="hidden-col">{{ entry.id }}</td>
<td class="col md-col">{{ entry.owner_email }}</td>
<td class="col sm-col">
{{ entry.start_date | date: 'MM/dd/yyyy' }}
</td>
<td class="col sm-col">
{{ entry.end_date | substractDate: entry.start_date }}
</td>
<td class="col x-sm-col">{{ dateTimeOffset.parseDateTimeOffset(entry.start_date,entry.timezone_offset) }}</td>
<td class="col x-sm-col">{{ dateTimeOffset.parseDateTimeOffset(entry.end_date , entry.timezone_offset) }}</td>
<td class="col md-col">{{ entry.project_name }}</td>
<td class="hidden-col">{{ entry.project_id }}</td>
<td class="col md-col">{{ entry.customer_name }}</td>
<td class="hidden-col">{{ entry.customer_id }}</td>
<td class="col md-col">{{ entry.activity_name }}</td>
<td class="col lg-col">
<ng-container *ngIf="entry.uri !== null">
<a [class.is-url]="isURL(entry.uri)" (click)="openURLInNewTab(entry.uri)">
{{ entry.uri }}
</a>
</ng-container>
</td>
<td class="col lg-col">{{ entry.description }}</td>
<td class="col lg-col">
<ng-container *ngIf="entry.technologies.length > 0">
<div *ngFor="let technology of entry.technologies" class="badge bg-secondary text-wrap">
{{ technology }}
</div>
</ng-container>
</td>
</tr>
</tbody>
</table>
</div>
</ng-container>
</td>
<td class="col lg-col">{{ entry.description }}</td>
<td class="col lg-col">
<ng-container *ngIf="entry.technologies.length > 0">
<div *ngFor="let technology of entry.technologies" class="badge bg-secondary text-wrap">
{{ technology }}
</div>
</ng-container>
</td>
</tr>
</tbody>
</table>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Entry } from 'src/app/modules/shared/models';
import { DataSource } from 'src/app/modules/shared/models/data-source.model';
import { EntryState } from '../../../time-clock/store/entry.reducer';
import { getReportDataSource } from '../../../time-clock/store/entry.selectors';
import { ParseDateTimeOffset } from '../../../shared/formatters/parse-date-time-offset/parse-date-time-offset';

@Component({
selector: 'app-time-entries-table',
Expand Down Expand Up @@ -60,9 +61,11 @@ export class TimeEntriesTableComponent implements OnInit, OnDestroy, AfterViewIn
isLoading$: Observable<boolean>;
reportDataSource$: Observable<DataSource<Entry>>;
rerenderTableSubscription: Subscription;
dateTimeOffset: ParseDateTimeOffset;

constructor(private store: Store<EntryState>) {
this.reportDataSource$ = this.store.pipe(select(getReportDataSource));
this.dateTimeOffset = new ParseDateTimeOffset();
}

ngOnInit(): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { ParseDateTimeOffset } from './parse-date-time-offset';

describe('ParseDateToUtcComponent', () => {

it('returns converted date when his offset is 300', () => {
let parseTimeOffset = new ParseDateTimeOffset();
const date = '2022-03-30T13:00:00Z';
const timezone_offset = 300;
const dateOffset:string = '08:00';

expect(parseTimeOffset.parseDateTimeOffset(date, timezone_offset)).toEqual(dateOffset);
});

it('returns converted date when his offset is 420', () => {
let parseTimeOffset = new ParseDateTimeOffset();
const date = '2022-03-30T16:30:00Z';
const timezone_offset = 420;
const dateOffset:string = '09:30';

expect(parseTimeOffset.parseDateTimeOffset(date, timezone_offset)).toEqual(dateOffset);
});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import * as moment from 'moment';

export class ParseDateTimeOffset {

parseDateTimeOffset(date:string, offset): string{
return moment.utc(date).utcOffset(-1*offset).format("HH:mm");
}
}
170 changes: 60 additions & 110 deletions src/app/modules/time-entries/pages/time-entries.component.html
Original file line number Diff line number Diff line change
@@ -1,135 +1,85 @@
<div>
<div>
<button
type="button"
(click)="newEntry()"
data-toggle="modal"
data-target="#editRecordsByDate"
class="btn btn-primary"
>
<div>
<button type="button" (click)="newEntry()" data-toggle="modal" data-target="#editRecordsByDate" class="btn btn-primary">
Add new entry
</button>
<button
type="button"
(click)="onDisplayModeChange()"
class="btn btn-primary float-right"
*ngIf="isFeatureToggleCalendarActive"
>
<button type="button" (click)="onDisplayModeChange()" class="btn btn-primary float-right" *ngIf="isFeatureToggleCalendarActive">
<em class="fas fa-list" *ngIf="displayGridView"></em>
<em class="fas fa-th" *ngIf="!displayGridView"></em>
</button>
</div>
<div style="height: 15px"></div>
<app-month-picker [selectedDate]="selectedDate" (dateSelected)="dateSelected($event)"></app-month-picker>
<div style="height: 15px"></div>
</div>
<div style="height: 15px"></div>
<app-month-picker [selectedDate]="selectedDate" (dateSelected)="dateSelected($event)"></app-month-picker>
<div style="height: 15px"></div>


<div id="gridView" [hidden]="!displayGridView">
<div *ngIf="timeEntriesDataSource$ | async as dataSource">
<app-loading-bar *ngIf="dataSource.isLoading"></app-loading-bar>
<app-calendar
*ngIf="!dataSource.isLoading"
[timeEntries$]="timeEntriesDataSource$"
[currentDate]="selectedDate.toDate()"
[calendarView]="calendarView"
(changeDate)="changeDate($event)"
(changeView)="changeView($event)"
(viewModal)="editEntry($event.id)"
(deleteTimeEntry)="openModal($event.timeEntry)"
>
</app-calendar>
<div id="gridView" [hidden]="!displayGridView">
<div *ngIf="timeEntriesDataSource$ | async as dataSource">
<app-loading-bar *ngIf="dataSource.isLoading"></app-loading-bar>
<app-calendar *ngIf="!dataSource.isLoading" [timeEntries$]="timeEntriesDataSource$" [currentDate]="selectedDate.toDate()" [calendarView]="calendarView" (changeDate)="changeDate($event)" (changeView)="changeView($event)" (viewModal)="editEntry($event.id)"
(deleteTimeEntry)="openModal($event.timeEntry)">
</app-calendar>
</div>
</div>
</div>

<div id="listView" [hidden]="displayGridView">
<table
class="table table-sm table-striped mb-0"
datatable
[dtTrigger]="dtTrigger"
[dtOptions]="dtOptions"
*ngIf="(timeEntriesDataSource$ | async) as dataSource">
<caption></caption>
<thead class="thead-blue">
<tr class="d-flex">
<th class="col">Date</th>
<th class="col">Time in - out</th>
<th class="col">Duration</th>
<th class="col">Customer</th>
<th class="col">Project</th>
<th class="col">Activity</th>
<th class="col"></th>
</tr>
</thead>
<app-loading-bar *ngIf="dataSource.isLoading"></app-loading-bar>
<tbody *ngIf="!dataSource.isLoading">
<tr class="d-flex" *ngFor="let entry of dataSource.data">
<td class="col">{{ entry.start_date | date: 'MM/dd/yyyy' }}</td>
<td class="col">{{ entry.start_date | date: 'HH:mm' }} - {{ entry.end_date | date: 'HH:mm' }}</td>
<td class="col">{{ entry.end_date | substractDate: entry.start_date }}</td>
<td class="col">{{ entry.customer_name }}</td>
<td class="col">{{ entry.project_name }}</td>
<td class="col">{{ entry.activity_name }}</td>
<td class="col">
<button
class="btn btn-sm btn-primary"
data-toggle="modal"
data-target="#editRecordsByDate"
(click)="editEntry(entry.id)"
>
<div id="listView" [hidden]="displayGridView">
<table class="table table-sm table-striped mb-0" datatable [dtTrigger]="dtTrigger" [dtOptions]="dtOptions" *ngIf="(timeEntriesDataSource$ | async) as dataSource">
<caption></caption>
<thead class="thead-blue">
<tr class="d-flex">
<th class="col">Date</th>
<th class="col">Time in - out</th>
<th class="col">Duration</th>
<th class="col">Customer</th>
<th class="col">Project</th>
<th class="col">Activity</th>
<th class="col"></th>
</tr>
</thead>
<app-loading-bar *ngIf="dataSource.isLoading"></app-loading-bar>
<tbody *ngIf="!dataSource.isLoading">
<tr class="d-flex" *ngFor="let entry of dataSource.data">
<td class="col">{{ entry.start_date | date: 'MM/dd/yyyy' }}</td>
<td class="col">{{ dateTimeOffset.parseDateTimeOffset(entry.start_date,entry.timezone_offset) }} - {{ dateTimeOffset.parseDateTimeOffset(entry.end_date,entry.timezone_offset) }}</td>
<td class="col">{{ entry.end_date | substractDate: entry.start_date }}</td>
<td class="col">{{ entry.customer_name }}</td>
<td class="col">{{ entry.project_name }}</td>
<td class="col">{{ entry.activity_name }}</td>
<td class="col">
<button class="btn btn-sm btn-primary" data-toggle="modal" data-target="#editRecordsByDate" (click)="editEntry(entry.id)">
<i class="fa fa-edit fa-xs"></i>
</button>
<button
class="btn btn-sm btn-danger ml-2"
data-toggle="modal"
data-target="#deleteModal"
(click)="openModal(entry)"
>
<button class="btn btn-sm btn-danger ml-2" data-toggle="modal" data-target="#deleteModal" (click)="openModal(entry)">
<i class="fa fa-trash fa-xs"></i>
</button>
</td>
</tr>
</tbody>
</table>
</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>

<div class="modal fade" id="editRecordsByDate" tabindex="-1" role="dialog">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content" cdkDrag (cdkDragEnded)="resetDraggablePosition($event)">
<div class="modal-header">
<h5 class="modal-title">{{ entryId ? 'Edit Entry' : 'New Entry' }}</h5>
<div>
<button class="btn shadow-none" data-bs-toggle="tooltip" title="Clean form values" (click)="detailsFields.cleanFieldsForm()">
<div class="modal-dialog modal-dialog-centered modal-lg" role="document">
<div class="modal-content" cdkDrag (cdkDragEnded)="resetDraggablePosition($event)">
<div class="modal-header">
<h5 class="modal-title">{{ entryId ? 'Edit Entry' : 'New Entry' }}</h5>
<div>
<button class="btn shadow-none" data-bs-toggle="tooltip" title="Clean form values" (click)="detailsFields.cleanFieldsForm()">
<em class="fa fa-eraser"> </em>
</button>
<button class="btn shadow-none" data-bs-toggle="tooltip" title="Drag modal" cdkDragHandle>
<button class="btn shadow-none" data-bs-toggle="tooltip" title="Drag modal" cdkDragHandle>
<em class="fa fa-grip-vertical"></em>
</button>
</div>
</div>
<div class="modal-body">
<app-details-fields [entryToEdit]="entry" (saveEntry)="saveEntry($event)" (projectSelected)="projectSelected($event)" [canMarkEntryAsWIP]="canMarkEntryAsWIP" #detailsFields>
</app-details-fields>
</div>
</div>
</div>
<div class="modal-body">
<app-details-fields
[entryToEdit]="entry"
(saveEntry)="saveEntry($event)"
(projectSelected)="projectSelected($event)"
[canMarkEntryAsWIP]="canMarkEntryAsWIP"
#detailsFields
>
</app-details-fields>
</div>
</div>
</div>
</div>

<app-dialog
*ngIf="showModal"
class="modal fade"
id="deleteModal"
tabindex="-1"
role="dialog"
aria-hidden="true"
[body]="message"
[title]="'Delete Entry'"
(closeModalEvent)="removeEntry()"
>
</app-dialog>
<app-dialog *ngIf="showModal" class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-hidden="true" [body]="message" [title]="'Delete Entry'" (closeModalEvent)="removeEntry()">
</app-dialog>
Loading