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
fix: #114 Refactor project list grid
  • Loading branch information
jorgecod committed Apr 16, 2020
commit bc82f7d71017e528d037b4c94c76e3ed536e3b71
5 changes: 5 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@ngrx/effects": "^9.0.0",
"@ngrx/store": "^9.0.0",
"@ngrx/store-devtools": "^9.0.0",
"angular-ng-autocomplete": "^2.0.1",
"bootstrap": "^4.4.1",
"jquery": "^3.4.1",
"minimist": "^1.2.5",
Expand Down
2 changes: 2 additions & 0 deletions src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { EffectsModule } from '@ngrx/effects';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';

import { NgxPaginationModule } from 'ngx-pagination';
import { AutocompleteLibModule } from 'angular-ng-autocomplete';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
Expand Down Expand Up @@ -92,6 +93,7 @@ import { CreateProjectTypeComponent } from './modules/customer-managment/compone
ReactiveFormsModule,
HttpClientModule,
NgxPaginationModule,
AutocompleteLibModule,
StoreModule.forRoot(reducers, {
metaReducers,
}),
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,24 @@
<form [formGroup]="entryForm" (ngSubmit)="onSubmit()">
<div *ngIf="formType === 'entries'" class="input-group input-group-sm mb-3">
<div *ngIf="formType === 'entries'" class="input-group input-group-sm mb-3 flex-nowrap">
<div class="input-group-prepend">
<span class="input-group-text span-width" id="inputGroup-sizing-sm">Project</span>
</div>
<input
id="project"
formControlName="project"
type="text"
class="form-control"
aria-label="Small"
aria-describedby="inputGroup-sizing-sm"
/>
<div class="ng-autocomplete">
<ng-autocomplete
class="autocomplete"
[data]="listProjects && listProjects"
[searchKeyword]="keyword"
[itemTemplate]="itemTemplate"
[notFoundTemplate]="notFoundTemplate"
>
</ng-autocomplete>
<ng-template #itemTemplate let-item>
<a [innerHTML]="item.name"></a>
</ng-template>
<ng-template #notFoundTemplate let-notFound>
<div [innerHTML]="notFound"></div>
</ng-template>
</div>
</div>
<div class="input-group input-group-sm mb-3">
<div class="input-group-prepend">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,23 @@
}
}
}

.ng-autocomplete {
width: 100%;
}

.autocomplete::ng-deep .autocomplete-container {
border: 1px solid #ced4da;
border-radius: 0 0.25rem 0.25rem 0;
box-shadow: none;
height: 2rem;

.input-container {
height: 100%;

input {
border-radius: 0.25rem;
height: 100%;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,28 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TechnologyState } from '../../store/technology.reducers';
import { allTechnologies } from '../../store/technology.selectors';
import { DetailsFieldsComponent } from './details-fields.component';
import { FilterProjectPipe } from '../../../shared/pipes';
import * as actions from '../../store/technology.actions';
import { ProjectState } from '../../../project-management/store/project.reducer';
import { allProjects } from '../../../project-management/store/project.selectors';

describe('DetailsFieldsComponent', () => {
type Merged = TechnologyState & ProjectState;
let component: DetailsFieldsComponent;
let fixture: ComponentFixture<DetailsFieldsComponent>;
let store: MockStore<TechnologyState>;
let store: MockStore<Merged>;
let mockTechnologySelector;
let mockProjectsSelector;
let length;

const state = {
technologyList: { items: [{ name: 'java' }] },
isLoading: false,
projects: {
projectList: [{ id: 'id', name: 'name', description: 'description' }],
isLoading: false,
},
technologies: {
technologyList: { items: [{ name: 'java' }] },
isLoading: false,
},
};

const initialData = {
Expand All @@ -36,12 +45,13 @@ describe('DetailsFieldsComponent', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [DetailsFieldsComponent, FilterProjectPipe],
declarations: [DetailsFieldsComponent],
providers: [provideMockStore({ initialState: state })],
imports: [FormsModule, ReactiveFormsModule],
}).compileComponents();
store = TestBed.inject(MockStore);
mockTechnologySelector = store.overrideSelector(allTechnologies, state);
mockTechnologySelector = store.overrideSelector(allTechnologies, state.technologies);
mockProjectsSelector = store.overrideSelector(allProjects, state.projects);
}));

beforeEach(() => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import { Store, select } from '@ngrx/store';
import * as actions from '../../store/technology.actions';

import { allTechnologies } from '../../store/technology.selectors';
import { Technology } from '../../models';
import { Technology, Project } from '../../models';

import { ProjectState } from '../../../project-management/store/project.reducer';
import { TechnologyState } from '../../store/technology.reducers';
import { allProjects } from '../../../project-management/store/project.selectors';
import * as projectActions from '../../../project-management/store/project.actions';

type Merged = TechnologyState & ProjectState;

@Component({
selector: 'app-details-fields',
Expand All @@ -20,8 +27,10 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
technology: Technology;
selectedTechnology: string[] = [];
isLoading = false;
listProjects: Project[] = [];
keyword = 'name';

constructor(private formBuilder: FormBuilder, private store: Store<Technology>) {
constructor(private formBuilder: FormBuilder, private store: Store<Merged>) {
this.entryForm = this.formBuilder.group({
project: '',
activity: '',
Expand All @@ -36,6 +45,12 @@ export class DetailsFieldsComponent implements OnChanges, OnInit {
this.isLoading = response.isLoading;
this.technology = response.technologyList;
});

this.store.dispatch(new projectActions.LoadProjects());
const projects$ = this.store.pipe(select(allProjects));
projects$.subscribe((response) => {
this.listProjects = response.projectList;
});
}

ngOnChanges(): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
<app-search-project (changeFilterProject)="filterProjects = $event"></app-search-project>
<ul class="list-group content-projects">
<li
class="list-group-item list-group-item-action justify-content-between align-items-center"
*ngFor="let item of listProjects | filterProject: filterProjects; let i = index"
(mouseenter)="showButton = i"
(mouseleave)="showButton = -1"
(click)="clockIn(item.id)"
[ngClass]="{ active: selectedId === item.id }"
<div class="ng-autocomplete">
<ng-autocomplete
class="autocomplete"
(selected)="showButton = ''"
[data]="listProjects && listProjects"
[searchKeyword]="keyword"
[itemTemplate]="itemTemplate"
[notFoundTemplate]="notFoundTemplate"
>
{{ item.name }}
<span *ngIf="showButton === i && selectedId !== item.id" class="badge badge-light">Clock In</span>
</li>
</ul>
</ng-autocomplete>
<ng-template #itemTemplate let-item>
<div class="d-flex">
<div
[innerHTML]="item.name"
(mouseenter)="showButton = item.name"
(mouseleave)="showButton = ''"
(click)="clockIn(item.id)"
class="text-left w-100 py-2 px-3"
></div>
<span *ngIf="showButton === item.name" class="badge badge-light d-flex align-items-center m-2">Clock In</span>
</div>
</ng-template>
<ng-template #notFoundTemplate let-notFound>
<div [innerHTML]="notFound"></div>
</ng-template>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,21 @@
padding: 0 0.3rem;
}

.active {
background-image: $list-item-selected;
border-color: transparent;
.ng-autocomplete {
width: 100%;
}

.autocomplete::ng-deep .autocomplete-container {
border: 1px solid #ced4da;
border-radius: 0.25rem;
box-shadow: none;

.input-container {
height: 100%;

input {
border-radius: 0.25rem;
height: 100%;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,13 @@ export class ProjectListHoverComponent implements OnInit {
@Output() showFields = new EventEmitter<boolean>();

selectedId: string;
showButton: number;
filterProjects = '';
listProjects: Project[] = [];
isLoading: boolean;
filterProjects = '';
showButton = '';
keyword = 'name';

constructor(private store: Store<ProjectState>) {
this.showButton = -1;
}
constructor(private store: Store<ProjectState>) {}

ngOnInit(): void {
this.store.dispatch(new actions.LoadProjects());
Expand Down
13 changes: 7 additions & 6 deletions src/app/modules/time-clock/pages/time-clock.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,18 @@ <h6>Week</h6>
<h3>14:00</h3>
</div>
</div>
<h6 class="text-left"><strong>Projects</strong></h6>
<ul class="list-group">
<app-project-list-hover (showFields)="setShowFields($event)"></app-project-list-hover>
</ul>
<br />
<div class="form-group row">
<label for="activitiesSelect" class="col-sm-2 col-form-label text-center"><strong>Project</strong></label>
<div class="col-sm-10">
<app-project-list-hover (showFields)="setShowFields($event)"></app-project-list-hover>
</div>
</div>
<form *ngIf="!isClockIn || showFields">
<div class="form-group row">
<label for="activitiesSelect" class="col-sm-2 col-form-label text-center"><strong>Activity</strong></label>
<div class="col-sm-10">
<select id="activitiesSelect" class="form-control">
<option *ngFor="let activity of activities;">{{activity.name}}</option>
<option *ngFor="let activity of activities">{{ activity.name }}</option>
</select>
</div>
</div>
Expand Down
17 changes: 11 additions & 6 deletions src/app/modules/time-entries/pages/time-entries.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import { GroupByDatePipe } from '../../shared/pipes';
import { TechnologyState } from '../../shared/store/technology.reducers';
import { allTechnologies } from '../../shared/store/technology.selectors';
import { TimeEntriesComponent } from './time-entries.component';
import { FilterProjectPipe } from '../../shared/pipes';
import { ProjectState } from '../../project-management/store/project.reducer';
import { allProjects } from '../../project-management/store/project.selectors';

describe('TimeEntriesComponent', () => {
type Merged = TechnologyState & ProjectState;
let component: TimeEntriesComponent;
let fixture: ComponentFixture<TimeEntriesComponent>;
let store: MockStore<TechnologyState>;
let store: MockStore<Merged>;
let mockTechnologySelector;
let mockProjectsSelector;

const state = {
projects: {
Expand All @@ -30,8 +33,10 @@ describe('TimeEntriesComponent', () => {
isLoading: false,
message: 'message',
},
technologyList: { items: [{ name: 'test' }] },
isLoading: false,
technologies: {
technologyList: { items: [{ name: 'test' }] },
isLoading: false,
},
};

const entry = {
Expand All @@ -50,7 +55,6 @@ describe('TimeEntriesComponent', () => {
declarations: [
EmptyStateComponent,
DetailsFieldsComponent,
FilterProjectPipe,
GroupByDatePipe,
ModalComponent,
MonthPickerComponent,
Expand All @@ -60,7 +64,8 @@ describe('TimeEntriesComponent', () => {
imports: [FormsModule, ReactiveFormsModule],
}).compileComponents();
store = TestBed.inject(MockStore);
mockTechnologySelector = store.overrideSelector(allTechnologies, state);
mockTechnologySelector = store.overrideSelector(allTechnologies, state.technologies);
mockProjectsSelector = store.overrideSelector(allProjects, state.projects);
}));

beforeEach(() => {
Expand Down