From 71561a2eeefb24b47b0fe143b7fc379e88619fe7 Mon Sep 17 00:00:00 2001 From: DarKylX Date: Tue, 13 Oct 2026 14:37:58 +0300 Subject: [PATCH] fix(analytics): show platform visits and participants without a visit --- .../program-analytics-drilldown.service.ts | 15 +++----- ...program-manager-attention.use-case.spec.ts | 10 +++--- ...er-participants-without-visit.use-case.ts} | 6 ++-- .../program/ports/program.repository.port.ts | 2 +- .../domain/program/program-analytics.model.ts | 8 ++--- .../adapters/program/program-http.adapter.ts | 4 +-- .../repository/program/program.repository.ts | 4 +-- .../detail/analytics/analytics.component.html | 6 ++-- .../analytics/analytics.component.spec.ts | 36 ++++++++++--------- .../detail/analytics/analytics.component.ts | 26 +++++++------- .../analytics-attention-route.spec.ts | 8 ++--- .../analytics-attention.component.spec.ts | 36 +++++++++---------- .../analytics-drilldown.component.ts | 8 ++--- 13 files changed, 84 insertions(+), 85 deletions(-) rename projects/social_platform/src/app/api/program/use-cases/{get-program-manager-participants-without-onboarding.use-case.ts => get-program-manager-participants-without-visit.use-case.ts} (82%) diff --git a/projects/social_platform/src/app/api/program/facades/detail/program-analytics-drilldown.service.ts b/projects/social_platform/src/app/api/program/facades/detail/program-analytics-drilldown.service.ts index 3489257a4..74db7de95 100644 --- a/projects/social_platform/src/app/api/program/facades/detail/program-analytics-drilldown.service.ts +++ b/projects/social_platform/src/app/api/program/facades/detail/program-analytics-drilldown.service.ts @@ -8,7 +8,7 @@ import { ProgramAnalyticsCaseMetrics } from "@domain/program/program-analytics.m import { GetProgramManagerAssignmentsUseCase } from "@api/program/use-cases/get-program-manager-assignments.use-case"; import { GetProgramManagerAssignmentScoresUseCase } from "@api/program/use-cases/get-program-manager-assignment-scores.use-case"; import { GetProgramManagerParticipantsWithoutTeamUseCase } from "@api/program/use-cases/get-program-manager-participants-without-team.use-case"; -import { GetProgramManagerParticipantsWithoutOnboardingUseCase } from "@api/program/use-cases/get-program-manager-participants-without-onboarding.use-case"; +import { GetProgramManagerParticipantsWithoutVisitUseCase } from "@api/program/use-cases/get-program-manager-participants-without-visit.use-case"; import { GetProgramManagerProjectsAwaitingEvaluationUseCase } from "@api/program/use-cases/get-program-manager-projects-awaiting-evaluation.use-case"; import { GetProgramManagerProjectsNotSubmittedUseCase } from "@api/program/use-cases/get-program-manager-projects-not-submitted.use-case"; import { @@ -28,7 +28,7 @@ import { /** Root-списки внимания используют тот же modal context, не вложенную модалку. */ export type AnalyticsAttentionView = - | "participants-without-onboarding" + | "participants-without-visit" | "participants-without-team" | "projects-awaiting-evaluation" | "projects-not-submitted"; @@ -60,9 +60,7 @@ export class ProgramAnalyticsDrilldownService { private readonly getAssignments = inject(GetProgramManagerAssignmentsUseCase); private readonly getScores = inject(GetProgramManagerAssignmentScoresUseCase); private readonly getParticipants = inject(GetProgramManagerParticipantsWithoutTeamUseCase); - private readonly getWithoutOnboarding = inject( - GetProgramManagerParticipantsWithoutOnboardingUseCase, - ); + private readonly getWithoutVisit = inject(GetProgramManagerParticipantsWithoutVisitUseCase); private readonly getProjects = inject(GetProgramManagerProjectsAwaitingEvaluationUseCase); private readonly getNotSubmitted = inject(GetProgramManagerProjectsNotSubmittedUseCase); private readonly destroyRef = inject(DestroyRef); @@ -96,8 +94,7 @@ export class ProgramAnalyticsDrilldownService { readonly attentionError = signal(null); readonly isParticipantView = computed( () => - this.view() === "participants-without-team" || - this.view() === "participants-without-onboarding", + this.view() === "participants-without-team" || this.view() === "participants-without-visit", ); readonly isAttentionView = computed( () => @@ -179,9 +176,7 @@ export class ProgramAnalyticsDrilldownService { }; if (this.isParticipantView()) { const useCase = - this.view() === "participants-without-onboarding" - ? this.getWithoutOnboarding - : this.getParticipants; + this.view() === "participants-without-visit" ? this.getWithoutVisit : this.getParticipants; useCase .execute(this.programId, query) .pipe(takeUntil(this.cancelAttention), takeUntilDestroyed(this.destroyRef)) diff --git a/projects/social_platform/src/app/api/program/use-cases/get-program-manager-attention.use-case.spec.ts b/projects/social_platform/src/app/api/program/use-cases/get-program-manager-attention.use-case.spec.ts index 58d4ecece..1050102a6 100644 --- a/projects/social_platform/src/app/api/program/use-cases/get-program-manager-attention.use-case.spec.ts +++ b/projects/social_platform/src/app/api/program/use-cases/get-program-manager-attention.use-case.spec.ts @@ -12,7 +12,7 @@ import { notSubmittedPage, } from "@domain/program/program-analytics-attention.fixture"; import { GetProgramManagerParticipantsWithoutTeamUseCase } from "./get-program-manager-participants-without-team.use-case"; -import { GetProgramManagerParticipantsWithoutOnboardingUseCase } from "./get-program-manager-participants-without-onboarding.use-case"; +import { GetProgramManagerParticipantsWithoutVisitUseCase } from "./get-program-manager-participants-without-visit.use-case"; import { GetProgramManagerProjectsAwaitingEvaluationUseCase } from "./get-program-manager-projects-awaiting-evaluation.use-case"; import { GetProgramManagerProjectsNotSubmittedUseCase } from "./get-program-manager-projects-not-submitted.use-case"; @@ -30,9 +30,9 @@ describe("Attention: adapter → repository → use cases", () => { for (const [method, endpoint, useCase, page] of [ [ - "getManagerParticipantsWithoutOnboarding", - "participants-without-onboarding", - GetProgramManagerParticipantsWithoutOnboardingUseCase, + "getManagerParticipantsWithoutVisit", + "participants-without-visit", + GetProgramManagerParticipantsWithoutVisitUseCase, participantsPage(), ], [ @@ -57,7 +57,7 @@ describe("Attention: adapter → repository → use cases", () => { const injectUseCase = () => TestBed.inject< | GetProgramManagerParticipantsWithoutTeamUseCase - | GetProgramManagerParticipantsWithoutOnboardingUseCase + | GetProgramManagerParticipantsWithoutVisitUseCase | GetProgramManagerProjectsAwaitingEvaluationUseCase | GetProgramManagerProjectsNotSubmittedUseCase >(useCase); diff --git a/projects/social_platform/src/app/api/program/use-cases/get-program-manager-participants-without-onboarding.use-case.ts b/projects/social_platform/src/app/api/program/use-cases/get-program-manager-participants-without-visit.use-case.ts similarity index 82% rename from projects/social_platform/src/app/api/program/use-cases/get-program-manager-participants-without-onboarding.use-case.ts rename to projects/social_platform/src/app/api/program/use-cases/get-program-manager-participants-without-visit.use-case.ts index 8d197cce4..e401fe8a2 100644 --- a/projects/social_platform/src/app/api/program/use-cases/get-program-manager-participants-without-onboarding.use-case.ts +++ b/projects/social_platform/src/app/api/program/use-cases/get-program-manager-participants-without-visit.use-case.ts @@ -11,9 +11,9 @@ import { ProgramAnalyticsError } from "@domain/program/program-analytics.model"; import { fail, ok, Result } from "@domain/shared/result.type"; import { catchError, map, Observable, of } from "rxjs"; -/** Уникальные участники программы с незавершённым онбордингом платформы. */ +/** Уникальные участники программы без зафиксированного посещения платформы. */ @Injectable({ providedIn: "root" }) -export class GetProgramManagerParticipantsWithoutOnboardingUseCase { +export class GetProgramManagerParticipantsWithoutVisitUseCase { private readonly repository = inject(ProgramRepositoryPort); execute( @@ -25,7 +25,7 @@ export class GetProgramManagerParticipantsWithoutOnboardingUseCase { ProgramAnalyticsError > > { - return this.repository.getManagerParticipantsWithoutOnboarding(programId, query).pipe( + return this.repository.getManagerParticipantsWithoutVisit(programId, query).pipe( map(value => ok(value)), catchError((error: unknown) => { const status = error instanceof HttpErrorResponse ? error.status : 0; diff --git a/projects/social_platform/src/app/domain/program/ports/program.repository.port.ts b/projects/social_platform/src/app/domain/program/ports/program.repository.port.ts index daeafeb69..ca5a5d813 100644 --- a/projects/social_platform/src/app/domain/program/ports/program.repository.port.ts +++ b/projects/social_platform/src/app/domain/program/ports/program.repository.port.ts @@ -46,7 +46,7 @@ export abstract class ProgramRepositoryPort { abstract getManagerOverview(programId: number): Observable; - abstract getManagerParticipantsWithoutOnboarding( + abstract getManagerParticipantsWithoutVisit( programId: number, query: ProgramAnalyticsAttentionQuery, ): Observable>; diff --git a/projects/social_platform/src/app/domain/program/program-analytics.model.ts b/projects/social_platform/src/app/domain/program/program-analytics.model.ts index ec6311306..b2629be65 100644 --- a/projects/social_platform/src/app/domain/program/program-analytics.model.ts +++ b/projects/social_platform/src/app/domain/program/program-analytics.model.ts @@ -13,8 +13,8 @@ export interface ProgramAnalyticsOverview { participantFunnel: { registrations: number; uniqueParticipants: number; - /** Completed platform onboarding; absent during a staggered API rollout. */ - onboardedParticipants?: number; + /** Recorded platform activity or login; absent during a staggered API rollout. */ + visitedParticipants?: number; withTeam: number; projectCreators: number; submittedProjectCreators: number; @@ -41,8 +41,8 @@ export interface ProgramAnalyticsOverview { }; }; attention: { - /** Absent until the API deployment provides the onboarding attention list. */ - participantsWithoutOnboarding?: number; + /** Registered users with neither recorded activity nor login; optional during rollout. */ + participantsWithoutVisit?: number; participantsWithoutTeam: number; projectsAwaitingEvaluation: number; /** Несданные связи: требование сдачи применимо только к конкурсной программе. */ diff --git a/projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.ts b/projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.ts index e61dd1bc1..4f56bff18 100644 --- a/projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.ts +++ b/projects/social_platform/src/app/infrastructure/adapters/program/program-http.adapter.ts @@ -88,12 +88,12 @@ export class ProgramHttpAdapter { } /** Без автозагрузки остальных страниц; camelcase преобразует общий interceptor. */ - getManagerParticipantsWithoutOnboarding( + getManagerParticipantsWithoutVisit( programId: number, query: ProgramAnalyticsAttentionQuery, ): Observable> { return this.apiService.get( - `${this.PROGRAMS_URL}/${programId}/manager-overview/participants-without-onboarding/`, + `${this.PROGRAMS_URL}/${programId}/manager-overview/participants-without-visit/`, this.attentionParams(query), ); } diff --git a/projects/social_platform/src/app/infrastructure/repository/program/program.repository.ts b/projects/social_platform/src/app/infrastructure/repository/program/program.repository.ts index 77965b4fa..aae0d1e63 100644 --- a/projects/social_platform/src/app/infrastructure/repository/program/program.repository.ts +++ b/projects/social_platform/src/app/infrastructure/repository/program/program.repository.ts @@ -82,11 +82,11 @@ export class ProgramRepository implements ProgramRepositoryPort { } /** Свежий manager-список при каждом открытии/поиске, без EntityCache. */ - getManagerParticipantsWithoutOnboarding( + getManagerParticipantsWithoutVisit( programId: number, query: ProgramAnalyticsAttentionQuery, ): Observable> { - return this.programAdapter.getManagerParticipantsWithoutOnboarding(programId, query); + return this.programAdapter.getManagerParticipantsWithoutVisit(programId, query); } /** Свежий manager-список при каждом открытии/поиске, без EntityCache. */ diff --git a/projects/social_platform/src/app/ui/pages/program/detail/analytics/analytics.component.html b/projects/social_platform/src/app/ui/pages/program/detail/analytics/analytics.component.html index 22e7c4de2..86f93e9ad 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/analytics/analytics.component.html +++ b/projects/social_platform/src/app/ui/pages/program/detail/analytics/analytics.component.html @@ -170,8 +170,8 @@

Требует внимания

[disabled]="item.value === 0" (click)=" drilldown.openAttention( - item.key === 'without-onboarding' - ? 'participants-without-onboarding' + item.key === 'without-visit' + ? 'participants-without-visit' : item.key === 'without-team' ? 'participants-without-team' : 'projects-awaiting-evaluation', @@ -315,7 +315,7 @@