From 1e7fcaf1e2ebc52d409294fb98ee398f2238a568 Mon Sep 17 00:00:00 2001 From: DarKylX Date: Sun, 18 Oct 2026 01:38:04 +0300 Subject: [PATCH] fix: restore compact expert project rating cards --- .../range-criterion-input.component.html | 17 +++- .../range-criterion-input.component.scss | 36 +++++++ .../range-criterion-input.component.ts | 1 + .../project-rating.component.html | 38 +++++--- .../project-rating.component.scss | 97 +++++++++++++++++++ .../project-rating.component.spec.ts | 42 ++++++++ .../project-rating.component.ts | 1 + .../rating-card/rating-card.component.scss | 1 + .../criteria/criteria.component.html | 6 +- .../search/search.component.spec.ts | 14 +++ .../ui/primitives/search/search.component.ts | 5 +- 11 files changed, 238 insertions(+), 20 deletions(-) diff --git a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.html b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.html index d5bcfd85a..e27dc5334 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.html +++ b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.html @@ -1,12 +1,16 @@ -
+
+ @if (compact()) { + + }
diff --git a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.scss b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.scss index b51f21d04..5ccaec3c5 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.scss +++ b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.scss @@ -1,5 +1,6 @@ /** @format */ @use "styles/ui-foundation"; +@use "styles/responsive"; :host { display: block; @@ -16,3 +17,38 @@ .field__input--error { border-color: var(--red-dark); } + +.field--compact { + display: flex; + gap: 6px; + align-items: center; + + .field__input { + width: 36px; + min-height: 32px; + padding: 4px; + font-size: 12px; + text-align: center; + border-radius: var(--rounded-sm); + appearance: textfield; + } + + .field__input::-webkit-inner-spin-button, + .field__input::-webkit-outer-spin-button { + margin: 0; + appearance: none; + } + + .field__scale { + font-size: 10px; + color: var(--grey-for-text); + white-space: nowrap; + } + + @include responsive.apply-mobile { + .field__input { + width: 44px; + min-height: 44px; + } + } +} diff --git a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.ts b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.ts index 7facc331d..53c27c2fd 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.ts +++ b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/components/range-criterion-input/range-criterion-input.component.ts @@ -35,6 +35,7 @@ export class RangeCriterionInputComponent implements ControlValueAccessor { readonly step = input(1); readonly label = input("Оценка"); readonly error = input(false); + readonly compact = input(false); value!: number | null; diff --git a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.html b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.html index 0af485057..713ef56ec 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.html +++ b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.html @@ -1,11 +1,19 @@ -
+
@for (criterion of criteria; track criterion.id) { -
-

{{ criterion.name }}

+
+ @if (layout() === "compact" && criterion.description) { +
+ {{ criterion.name }} +

{{ criterion.description }}

+
+ } @else { +

{{ criterion.name }}

+ } @if (criterion.type === "int" || criterion.type === "float") { {{ criterion.name }} !!form.get(criterion.id.toString())?.touched " /> -

- {{ criterion.description }} - {{ criterion.type === "int" ? "Целые баллы" : "Дробные баллы" }} · - {{ criterion.minValue === null ? "без минимума" : "от " + criterion.minValue - }}{{ criterion.maxValue === null ? ", без максимума" : " до " + criterion.maxValue }} -

+ @if (layout() === "full") { +

+ {{ criterion.description }} + {{ criterion.type === "int" ? "Целые баллы" : "Дробные баллы" }} · + {{ criterion.minValue === null ? "без минимума" : "от " + criterion.minValue + }}{{ criterion.maxValue === null ? ", без максимума" : " до " + criterion.maxValue }} +

+ } } @else if (criterion.type === "bool") { - @if (criterion.description) { + @if (layout() === "full" && criterion.description) {

{{ criterion.description }}

}
@@ -49,9 +59,11 @@

{{ criterion.name }}

Нет
-

«Нет» — заполненный ответ.

+ @if (layout() === "full") { +

«Нет» — заполненный ответ.

+ } } @else { - @if (criterion.description) { + @if (layout() === "full" && criterion.description) {

{{ criterion.description }}

}

diff --git a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.scss b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.scss index 146d1763d..8a76a8b6f 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.scss +++ b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.scss @@ -1,5 +1,6 @@ /** @format */ @use "styles/ui-foundation"; +@use "styles/responsive"; :host { display: block; @@ -72,3 +73,99 @@ p { resize: vertical; border-radius: 15px; } + +.rating--compact { + gap: 8px; + + .rating__criterion { + grid-template-columns: 72px minmax(0, 1fr); + gap: 6px 8px; + align-items: center; + } + + h4, + summary { + font-size: 10px; + font-weight: 400; + line-height: 1.4; + color: var(--grey-for-text); + overflow-wrap: anywhere; + } + + summary { + cursor: pointer; + } + + summary:focus-visible { + outline: 2px solid var(--accent); + outline-offset: 3px; + } + + .rating__details p { + margin-top: 6px; + } + + .rating__criterion:not(.rating__criterion--text) { + h4, + .rating__details { + grid-row: 1; + grid-column: 2; + } + } + + app-range-criterion-input, + .rating__boolean { + grid-row: 1; + grid-column: 1; + align-self: start; + } + + .rating__boolean { + gap: 4px; + } + + .rating__boolean .ui-button { + width: 36px; + min-width: 36px; + min-height: 32px; + padding: 4px; + font-size: 12px; + } + + .rating__criterion--text { + grid-template-columns: minmax(0, 1fr); + } + + textarea.ui-field { + min-height: 66px; + padding: 10px 12px; + font-size: 12px; + } + + .rating__counter, + .rating__error { + grid-column: 1 / -1; + font-size: 10px; + } + + @include responsive.apply-mobile { + .rating__criterion:not(.rating__criterion--text) { + grid-template-columns: 92px minmax(0, 1fr); + } + + h4, + summary { + font-size: 12px; + } + + .rating__boolean .ui-button { + width: 44px; + min-width: 44px; + min-height: 44px; + } + + summary { + padding-block: 6px; + } + } +} diff --git a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.spec.ts b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.spec.ts index aacde357e..481b8f1db 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.spec.ts +++ b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.spec.ts @@ -5,6 +5,48 @@ import { ProjectRatingComponent } from "./project-rating.component"; import { ProjectRatingCriterion } from "@domain/project/project-rating-criterion"; describe("Shared expert form lifecycle", () => { + it("keeps answers and descriptions when switching between compact cards and full preview", async () => { + await TestBed.configureTestingModule({ + imports: [ProjectRatingComponent], + providers: [provideZonelessChangeDetection()], + }).compileComponents(); + const fixture = TestBed.createComponent(ProjectRatingComponent); + const criterion: ProjectRatingCriterion = { + id: 1, + name: "Обоснованность решения", + description: "Проверьте расчёты команды.", + type: "int", + minValue: 0, + maxValue: 10, + value: 0, + expertId: 0, + }; + fixture.componentRef.setInput("criteria", [ + criterion, + { ...criterion, id: 2, name: "Соответствует кейсу", type: "bool", value: "false" }, + { ...criterion, id: 3, name: "Комментарий", type: "str", value: "Хорошее решение" }, + ]); + await fixture.whenStable(); + const root: HTMLElement = fixture.nativeElement; + expect(root.querySelector(".rating--compact")).not.toBeNull(); + expect(root.querySelector("summary")?.textContent).toContain(criterion.name); + expect(root.querySelector("details")?.textContent).toContain(criterion.description); + expect(root.querySelector("details")?.open).toBe(false); + expect(root.querySelector(".field__scale")?.textContent).toContain("/ 10"); + expect(root.querySelector("textarea")?.rows).toBe(2); + const answers = fixture.componentInstance.form.getRawValue(); + expect(answers).toEqual({ 1: 0, 2: false, 3: "Хорошее решение" }); + + fixture.componentRef.setInput("layout", "full"); + await fixture.whenStable(); + expect(root.querySelector(".rating--compact")).toBeNull(); + expect(root.querySelector("details")).toBeNull(); + expect(root.textContent).toContain(criterion.description); + expect(root.textContent).toContain("Целые баллы"); + expect(root.querySelector("textarea")?.rows).toBe(6); + expect(fixture.componentInstance.form.getRawValue()).toEqual(answers); + }); + it("publishes zero and default No after replacing criteria, validates the new scale", async () => { await TestBed.configureTestingModule({ imports: [ProjectRatingComponent], diff --git a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.ts b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.ts index 907004509..417a729a6 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.ts +++ b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/project-rating/project-rating.component.ts @@ -87,6 +87,7 @@ export class ProjectRatingComponent implements OnDestroy, ControlValueAccessor, private controlDisabled = false; readonly currentUserId = input(); + readonly layout = input<"compact" | "full">("compact"); /** Сигнал для хранения критериев оценки */ _criteria = signal([]); diff --git a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/rating-card.component.scss b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/rating-card.component.scss index 2644d0d2e..aafbc5a57 100644 --- a/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/rating-card.component.scss +++ b/projects/social_platform/src/app/ui/pages/program/detail/list/rating-card/rating-card.component.scss @@ -7,6 +7,7 @@ display: grid; grid-template-columns: 1fr; gap: 20px; + align-items: start; @include responsive.apply-desktop { grid-template-columns: 5fr 3fr; diff --git a/projects/social_platform/src/app/ui/pages/program/management/criteria/criteria.component.html b/projects/social_platform/src/app/ui/pages/program/management/criteria/criteria.component.html index ccde622c4..c59b413ef 100644 --- a/projects/social_platform/src/app/ui/pages/program/management/criteria/criteria.component.html +++ b/projects/social_platform/src/app/ui/pages/program/management/criteria/criteria.component.html @@ -215,7 +215,11 @@

Предпросмотр формы экспер

Так эксперт увидит критерии. Ответы в предпросмотре не сохраняются и не фиксируют набор.

- +