Skip to content

Commit de6e32a

Browse files
committed
add loading service to project & fix program loading error
1 parent 44004b0 commit de6e32a

3 files changed

Lines changed: 104 additions & 66 deletions

File tree

projects/social_platform/src/app/app.component.ts

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
import { MatProgressBarModule } from "@angular/material/progress-bar";
1919
import { AsyncPipe, NgIf } from "@angular/common";
2020
import { TokenService } from "@corelib";
21+
import { LoadingService } from "@office/services/loading.service";
2122

2223
/**
2324
* Корневой компонент приложения
@@ -36,7 +37,8 @@ export class AppComponent implements OnInit, OnDestroy {
3637
constructor(
3738
private authService: AuthService,
3839
private tokenService: TokenService,
39-
private router: Router
40+
private router: Router,
41+
private loadingService: LoadingService
4042
) {}
4143

4244
ngOnInit(): void {
@@ -45,17 +47,26 @@ export class AppComponent implements OnInit, OnDestroy {
4547
this.authService.getChangeableRoles(),
4648
]).subscribe(noop);
4749

48-
this.showLoaderEvents = this.router.events.pipe(
50+
const showLoaderEvents = this.router.events.pipe(
4951
filter(evt => evt instanceof ResolveStart),
5052
map(() => true)
5153
);
52-
this.hideLoaderEvents = this.router.events.pipe(
54+
55+
const hideLoaderEvents = this.router.events.pipe(
5356
filter(evt => evt instanceof ResolveEnd),
5457
debounceTime(200),
5558
map(() => false)
5659
);
5760

58-
this.isLoading$ = merge(this.hideLoaderEvents, this.showLoaderEvents);
61+
this.routerLoadingSub$ = merge(hideLoaderEvents, showLoaderEvents).subscribe(isLoading => {
62+
if (isLoading) {
63+
this.loadingService.show();
64+
} else {
65+
this.loadingService.hide();
66+
}
67+
});
68+
69+
this.isLoading$ = this.loadingService.isLoading$;
5970

6071
if (location.pathname === "/") {
6172
if (this.tokenService.getTokens() === null) {
@@ -80,18 +91,17 @@ export class AppComponent implements OnInit, OnDestroy {
8091

8192
ngOnDestroy(): void {
8293
this.rolesSub$?.unsubscribe();
94+
this.routerLoadingSub$?.unsubscribe();
8395
this.appHeight$?.unsubscribe();
8496
}
8597

8698
rolesSub$?: Subscription;
99+
routerLoadingSub$?: Subscription;
87100

88101
private loadEvent?: Observable<Event>;
89102
private resizeEvent?: Observable<Event>;
90103

91104
private appHeight$?: Subscription;
92105

93106
isLoading$?: Observable<boolean>;
94-
private showLoaderEvents?: Observable<boolean>;
95-
96-
private hideLoaderEvents?: Observable<boolean>;
97107
}

projects/social_platform/src/app/office/program/detail/main/main.component.ts

Lines changed: 60 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,17 @@ import {
1010
} from "@angular/core";
1111
import { ProgramService } from "@office/program/services/program.service";
1212
import { ActivatedRoute, Router, RouterLink } from "@angular/router";
13-
import { concatMap, fromEvent, map, noop, of, Subscription, tap, throttleTime } from "rxjs";
13+
import {
14+
concatMap,
15+
fromEvent,
16+
map,
17+
noop,
18+
Observable,
19+
of,
20+
Subscription,
21+
tap,
22+
throttleTime,
23+
} from "rxjs";
1424
import { Program } from "@office/program/models/program.model";
1525
import { ProgramNewsService } from "@office/program/services/program-news.service";
1626
import { FeedNews } from "@office/projects/models/project-news.model";
@@ -25,51 +35,10 @@ import { TagComponent } from "@ui/components/tag/tag.component";
2535
import { NewsFormComponent } from "@office/shared/news-form/news-form.component";
2636
import { ModalComponent } from "@ui/components/modal/modal.component";
2737
import { ProjectService } from "@office/services/project.service";
38+
import { MatProgressBarModule } from "@angular/material/progress-bar";
39+
import { AsyncPipe } from "@angular/common";
40+
import { LoadingService } from "@office/services/loading.service";
2841

29-
/**
30-
* Главный компонент детальной страницы программы
31-
*
32-
* Отображает основную информацию о программе и новостную ленту:
33-
* - Детальное описание программы с возможностью развернуть/свернуть
34-
* - Информацию о датах и регистрации
35-
* - Новостную ленту для участников программы
36-
* - Форму добавления новостей
37-
* - Взаимодействие с новостями (лайки, просмотры)
38-
*
39-
* Принимает:
40-
* @param {ProgramService} programService - Сервис программ
41-
* @param {ProgramNewsService} programNewsService - Сервис новостей программы
42-
* @param {ActivatedRoute} route - Для получения данных программы
43-
* @param {ChangeDetectorRef} cdRef - Для ручного обновления представления
44-
*
45-
* Состояние (signals):
46-
* @property {Signal<FeedNews[]>} news - Массив новостей программы
47-
* @property {Signal<number>} totalNewsCount - Общее количество новостей
48-
* @property {Signal<number>} fetchLimit - Лимит загрузки новостей (10)
49-
* @property {Signal<number>} fetchPage - Текущая страница новостей
50-
* @property {Signal<Subscription[]>} subscriptions$ - Подписки для очистки
51-
*
52-
* Данные программы:
53-
* @property {Program} program - Объект программы
54-
* @property {boolean} registerDateExpired - Истек ли срок регистрации
55-
* @property {boolean} descriptionExpandable - Можно ли развернуть описание
56-
* @property {boolean} readFullDescription - Развернуто ли описание
57-
*
58-
* ViewChild:
59-
* @ViewChild NewsFormComponent - Ссылка на компонент формы новостей
60-
* @ViewChild descEl - Ссылка на элемент описания
61-
*
62-
* Методы:
63-
* @method fetchNews(offset, limit) - Загружает новости с пагинацией
64-
* @method onScroll() - Обработчик прокрутки для подгрузки новостей
65-
* @method onNewsInVew(entries) - Отмечает новости как просмотренные
66-
* @method onAddNews(news) - Добавляет новую новость
67-
* @method onLike(newsId) - Переключает лайк новости
68-
* @method onExpandDescription() - Разворачивает/сворачивает описание
69-
*
70-
* Возвращает:
71-
* HTML шаблон с информацией о программе и новостной лентой
72-
*/
7342
@Component({
7443
selector: "app-main",
7544
templateUrl: "./main.component.html",
@@ -83,10 +52,12 @@ import { ProjectService } from "@office/services/project.service";
8352
ProgramNewsCardComponent,
8453
TagComponent,
8554
UserLinksPipe,
55+
AsyncPipe,
8656
ParseBreaksPipe,
8757
ParseLinksPipe,
8858
NewsFormComponent,
8959
ModalComponent,
60+
MatProgressBarModule,
9061
],
9162
})
9263
export class ProgramDetailMainComponent implements OnInit, OnDestroy {
@@ -96,7 +67,8 @@ export class ProgramDetailMainComponent implements OnInit, OnDestroy {
9667
private readonly projectService: ProjectService,
9768
private readonly router: Router,
9869
private readonly route: ActivatedRoute,
99-
private readonly cdRef: ChangeDetectorRef
70+
private readonly cdRef: ChangeDetectorRef,
71+
private readonly loadingService: LoadingService
10072
) {}
10173

10274
news = signal<FeedNews[]>([]);
@@ -110,6 +82,7 @@ export class ProgramDetailMainComponent implements OnInit, OnDestroy {
11082
programId?: number;
11183

11284
subscriptions$ = signal<Subscription[]>([]);
85+
11386
ngOnInit(): void {
11487
const programIdSubscription$ = this.route.params
11588
.pipe(
@@ -123,6 +96,8 @@ export class ProgramDetailMainComponent implements OnInit, OnDestroy {
12396

12497
const routeModalSub$ = this.route.queryParams.subscribe(param => {
12598
if (param["access"] === "accessDenied") {
99+
this.loadingService.hide();
100+
126101
this.showProgramModal.set(true);
127102
this.showProgramModalErrorMessage.set("У вас не доступа к этой вкладке!");
128103

@@ -150,13 +125,25 @@ export class ProgramDetailMainComponent implements OnInit, OnDestroy {
150125
}
151126
})
152127
)
153-
.subscribe(news => {
154-
if (news.results?.length) {
155-
this.news.set(news.results);
156-
this.totalNewsCount.set(news.count);
157-
}
128+
.subscribe({
129+
next: news => {
130+
if (news.results?.length) {
131+
this.news.set(news.results);
132+
this.totalNewsCount.set(news.count);
133+
}
134+
135+
this.loadingService.hide();
136+
},
137+
error: () => {
138+
this.loadingService.hide();
139+
140+
this.showProgramModal.set(true);
141+
this.showProgramModalErrorMessage.set("Произошла ошибка при загрузке программы");
142+
},
158143
});
159144

145+
this.loadEvent = fromEvent(window, "load");
146+
160147
this.subscriptions$().push(program$);
161148
this.subscriptions$().push(programIdSubscription$);
162149
this.subscriptions$().push(routeModalSub$);
@@ -216,6 +203,7 @@ export class ProgramDetailMainComponent implements OnInit, OnDestroy {
216203

217204
@ViewChild(NewsFormComponent) newsFormComponent?: NewsFormComponent;
218205
@ViewChild("descEl") descEl?: ElementRef;
206+
219207
onNewsInVew(entries: IntersectionObserverEntry[]): void {
220208
const ids = entries.map(e => {
221209
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
@@ -263,20 +251,33 @@ export class ProgramDetailMainComponent implements OnInit, OnDestroy {
263251

264252
closeModal(): void {
265253
this.showProgramModal.set(false);
254+
this.loadingService.hide();
266255
}
267256

268257
addProject(): void {
269-
this.projectService.create().subscribe(project => {
270-
this.projectService.projectsCount.next({
271-
...this.projectService.projectsCount.getValue(),
272-
my: this.projectService.projectsCount.getValue().my + 1,
273-
});
274-
this.router
275-
.navigateByUrl(`/office/projects/${project.id}/edit?editingStep=main`)
276-
.then(() => console.debug("Route change from ProjectsComponent"));
258+
this.loadingService.show();
259+
260+
this.projectService.create().subscribe({
261+
next: project => {
262+
this.projectService.projectsCount.next({
263+
...this.projectService.projectsCount.getValue(),
264+
my: this.projectService.projectsCount.getValue().my + 1,
265+
});
266+
this.router
267+
.navigateByUrl(`/office/projects/${project.id}/edit?editingStep=main`)
268+
.then(() => {
269+
console.debug("Route change from ProjectsComponent");
270+
});
271+
},
272+
error: error => {
273+
this.loadingService.hide();
274+
console.error("Project creation error:", error);
275+
},
277276
});
278277
}
279278

279+
private loadEvent?: Observable<Event>;
280+
280281
program?: Program;
281282
registerDateExpired!: boolean;
282283
descriptionExpandable!: boolean;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/** @format */
2+
3+
import { Injectable } from "@angular/core";
4+
import { BehaviorSubject, Observable } from "rxjs";
5+
6+
@Injectable({
7+
providedIn: "root",
8+
})
9+
export class LoadingService {
10+
private _isLoading$ = new BehaviorSubject<boolean>(false);
11+
12+
get isLoading$(): Observable<boolean> {
13+
return this._isLoading$.asObservable();
14+
}
15+
16+
show(): void {
17+
this._isLoading$.next(true);
18+
}
19+
20+
hide(): void {
21+
this._isLoading$.next(false);
22+
}
23+
24+
toggle(): void {
25+
this._isLoading$.next(!this._isLoading$.value);
26+
}
27+
}

0 commit comments

Comments
 (0)