Skip to content

Commit d9f937a

Browse files
Merge pull request #18 from valburyakov/master
Feat: confirmation dialog and fixes
2 parents 7327b19 + d640f75 commit d9f937a

File tree

9 files changed

+119
-37
lines changed

9 files changed

+119
-37
lines changed

src/app/app.module.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
import { BrowserModule } from '@angular/platform-browser';
22
import { NgModule } from '@angular/core';
33

4-
import { ReactiveFormsModule } from "@angular/forms";
4+
import { ReactiveFormsModule } from '@angular/forms';
55
import { AppComponent } from './app.component';
66
import { routing } from './app.routing';
7-
import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http";
7+
import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
88
import { UserService } from './service/user.service';
99
import { EpisodeListComponent } from './episode-list/episode-list.component';
1010
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
1111
import { EpisodeDetailsComponent } from './episode-details/episode-details.component';
1212
import { LayoutModule } from '@angular/cdk/layout';
13-
import { MatToolbarModule, MatButtonModule, MatSidenavModule, MatIconModule, MatListModule } from '@angular/material';
13+
import { MatToolbarModule, MatButtonModule, MatSidenavModule, MatIconModule, MatListModule, MatDialogModule } from '@angular/material';
1414
import { UiModule } from './ui/ui.module';
1515
import { FilterPipe } from './pipes/filter.pipe';
1616
import { ExportComponent } from './export/export.component';
@@ -31,7 +31,8 @@ import { PostEditComponent } from './post-edit/post-edit.component';
3131
import { PostComponent } from './post/post.component';
3232
import { SidenavComponent } from './sidenav/sidenav.component';
3333
import { LinkifyWithTextPipe } from './pipes/linkifyWithText.pipe';
34-
import {SafeResourceUrlPipe} from "./pipes/safeResourceUrl.pipe";
34+
import { SafeResourceUrlPipe } from './pipes/safeResourceUrl.pipe';
35+
import { ConfirmationDialogComponent } from './shared/confirmation-dialog/confirmation-dialog.component';
3536

3637

3738
@NgModule({
@@ -56,7 +57,8 @@ import {SafeResourceUrlPipe} from "./pipes/safeResourceUrl.pipe";
5657
PostDetailsComponent,
5758
PostEditComponent,
5859
PostComponent,
59-
SidenavComponent
60+
SidenavComponent,
61+
ConfirmationDialogComponent
6062
],
6163
imports: [
6264
BrowserModule,
@@ -70,9 +72,16 @@ import {SafeResourceUrlPipe} from "./pipes/safeResourceUrl.pipe";
7072
MatSidenavModule,
7173
MatIconModule,
7274
MatListModule,
75+
MatDialogModule,
7376
UiModule
7477
],
75-
providers: [ { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true }, UserService],
78+
entryComponents: [
79+
ConfirmationDialogComponent
80+
],
81+
providers: [
82+
{ provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true },
83+
UserService
84+
],
7685
bootstrap: [AppComponent]
7786
})
7887
export class AppModule { }

src/app/episode-details/episode-details.component.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
</div>
77
<div class="row">
88
<div class="col">
9-
Current: {{ now | date:'hh:mm:ss EEEE dd LLL' }}
9+
Current: {{ now$ | async | date:'hh:mm:ss EEEE dd LLL' }}
1010
</div>
1111
</div>
1212
<div class="row mb-2">
@@ -97,4 +97,4 @@ <h2>{{episode.name}}</h2>
9797
</div>
9898
</div>
9999

100-
</div>
100+
</div>

src/app/episode-details/episode-details.component.ts

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import { Component, OnInit, Input } from '@angular/core';
2-
import { EpisodeService } from '../service/episode.service';
3-
import { Episode } from '../model/episode';
42
import { Location } from '@angular/common';
53
import { ActivatedRoute, Router, NavigationEnd } from '@angular/router';
64
import { FormBuilder, Validators, FormGroup } from '@angular/forms';
5+
import { map, share } from 'rxjs/operators';
6+
import { interval } from 'rxjs';
7+
import { EpisodeService } from '../service/episode.service';
8+
import { Episode } from '../model/episode';
79
import { Theme } from '../model/theme';
8-
import { filter } from 'rxjs/operators';
910
import { environment } from '../../environments/environment';
1011
import { User } from '../model/user';
1112
import { LoggedUserService } from '../service/logged-user.service';
@@ -17,24 +18,20 @@ import { LoggedUserService } from '../service/logged-user.service';
1718
})
1819
export class EpisodeDetailsComponent implements OnInit {
1920

20-
public now: Date = new Date();
2121
episode: Episode;
2222
addForm: FormGroup;
2323
currentUser: User;
24-
editableTheme: Theme
25-
24+
editableTheme: Theme;
2625
updateForm: FormGroup;
2726

27+
now$ = interval(1000).pipe(map(x => new Date()), share());
28+
2829
constructor(private formBuilder: FormBuilder,
29-
private router: Router,
30-
private route: ActivatedRoute,
30+
private router: Router,
31+
private route: ActivatedRoute,
3132
private episodeService: EpisodeService,
32-
private sessionUserService: LoggedUserService,
33-
private location: Location) {
34-
setInterval(() => {
35-
this.now = new Date();
36-
}, 1);
37-
}
33+
private sessionUserService: LoggedUserService,
34+
private location: Location) { }
3835

3936
ngOnInit() {
4037
this.addForm = this.formBuilder.group({

src/app/episode-list/episode-list.component.ts

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms';
66
import { Location } from '@angular/common';
77
import { User } from '../model/user';
88
import { LoggedUserService } from '../service/logged-user.service';
9+
import { ConfirmationDialogComponent } from '../shared/confirmation-dialog/confirmation-dialog.component';
10+
import { filter, switchMapTo, take } from 'rxjs/operators';
11+
import { MatDialog } from '@angular/material';
912

1013
@Component({
1114
selector: 'app-episode-list',
@@ -17,12 +20,13 @@ export class EpisodeListComponent implements OnInit {
1720
episodes: Episode[];
1821
selectedEpisode: Episode;
1922
addForm: FormGroup;
20-
currentUser: User
21-
added: boolean
22-
error: Object
23+
currentUser: User;
24+
added: boolean;
25+
error: Object;
2326

24-
constructor(private formBuilder: FormBuilder,
25-
private router: Router,
27+
constructor(private formBuilder: FormBuilder,
28+
private router: Router,
29+
private dialog: MatDialog,
2630
private episodeService: EpisodeService,
2731
private sessionUserService: LoggedUserService) { }
2832

@@ -34,43 +38,52 @@ export class EpisodeListComponent implements OnInit {
3438
this.currentUser = this.sessionUserService.getSessionUser();
3539

3640
this.episodeService.getAllEpisodes()
37-
.subscribe(data => this.episodes = data)
41+
.subscribe(data => this.episodes = data);
3842
}
3943

40-
showDetails(episode: Episode){
44+
showDetails(episode: Episode) {
4145
this.router.navigate([`episode-details/${episode.id}`]);
4246
}
4347

4448
onSelect(episode: Episode): void {
4549
this.selectedEpisode = episode;
4650
this.getAllEpisodes();
47-
this.showDetails(episode);
51+
this.showDetails(episode);
4852
}
4953

5054
onSubmit() {
5155
this.episodeService.createEpisode(this.addForm.value)
5256
.subscribe(data => {
5357
this.addForm.reset();
5458
this.getAllEpisodes();
55-
this.added = true;
56-
},
59+
this.added = true;
60+
},
5761
error => {
58-
this.error = error
62+
this.error = error;
5963
});
6064
}
6165

6266
addEpisode() {
6367
this.router.navigate(['add-episode']);
6468
}
6569

66-
removeEpisode(episode: Episode){
67-
this.episodeService.removeEpisode(episode.id).subscribe(data => {
70+
removeEpisode(episode: Episode) {
71+
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
72+
width: '350px',
73+
data: `Do you confirm the deletion of episode ${episode.name}?`
74+
});
75+
dialogRef.afterClosed().pipe(
76+
take(1),
77+
filter(Boolean),
78+
switchMapTo(this.episodeService.removeEpisode(episode.id))
79+
)
80+
.subscribe(data => {
6881
this.getAllEpisodes();
6982
});
7083
}
7184

7285
getAllEpisodes(): void {
7386
this.episodeService.getAllEpisodes()
74-
.subscribe(data => this.episodes = data)
87+
.subscribe(data => this.episodes = data);
7588
}
7689
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.mat-dialog-actions {
2+
justify-content: flex-end;
3+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<div mat-dialog-content>
2+
{{message}}
3+
</div>
4+
<div mat-dialog-actions>
5+
<button class="btn btn-secondary" mat-button (click)="onNoClick()">No</button>
6+
<button class="btn btn-primary" mat-button [mat-dialog-close]="true" cdkFocusInitial>Yes</button>
7+
</div>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { ConfirmationDialogComponent } from './confirmation-dialog.component';
4+
5+
describe('ConfirmationDialogComponent', () => {
6+
let component: ConfirmationDialogComponent;
7+
let fixture: ComponentFixture<ConfirmationDialogComponent>;
8+
9+
beforeEach(async(() => {
10+
TestBed.configureTestingModule({
11+
declarations: [ ConfirmationDialogComponent ]
12+
})
13+
.compileComponents();
14+
}));
15+
16+
beforeEach(() => {
17+
fixture = TestBed.createComponent(ConfirmationDialogComponent);
18+
component = fixture.componentInstance;
19+
fixture.detectChanges();
20+
});
21+
22+
it('should create', () => {
23+
expect(component).toBeTruthy();
24+
});
25+
});
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { Component, Inject, OnInit } from '@angular/core';
2+
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
3+
4+
@Component({
5+
selector: 'app-confirmation-dialog',
6+
templateUrl: './confirmation-dialog.component.html',
7+
styleUrls: ['./confirmation-dialog.component.css']
8+
})
9+
export class ConfirmationDialogComponent implements OnInit {
10+
11+
constructor(private dialogRef: MatDialogRef<ConfirmationDialogComponent>,
12+
@Inject(MAT_DIALOG_DATA) public message: string) { }
13+
14+
ngOnInit() {
15+
}
16+
17+
onNoClick() {
18+
this.dialogRef.close(false);
19+
}
20+
}

src/styles.css

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,12 @@ body {
1515

1616
.comma-list:last-child::after {
1717
content: "";
18-
}
18+
}
19+
20+
.ng-valid[required], .ng-valid.required {
21+
border-left: 5px solid #42A948; /* green */
22+
}
23+
24+
.ng-invalid.ng-touched:not(form) {
25+
border-left: 5px solid #a94442; /* red */
26+
}

0 commit comments

Comments
 (0)