Skip to content

Commit

Permalink
[Feat] Responses: update to new UI (#299)
Browse files Browse the repository at this point in the history
* chore(observers ): adjust header title according to the design

* feat(answers): add `answers` module

* i18n(answers): add translations for table columns

* feat(answers): add the `download` functionality to the export button

* feat(answers): add filters according to the design

* refactor(table-container): extract types & interfaces into a separate file

* feat(table-container): allow to use custom `no-rows-found` content

* feat(answers): add `no-rows-found` message

* feat(table-container): allow rows to be clicked

* feat(answers): add `answer-detail` component

* allows to view an answer in detail

* feat(answers): add `answer-details` component

* wip(answer-details): build the base for the forms container

* chore(scss): add global variables for gray common colors

* border-color-gray / dim-gray

* fix(answers): remove unwanted `answer-detail` component

* feat(base-checkbox): add transparent variant

* feat(answer-details): display sections, their forms, alongside checked/unchecked answers

* fix(visually-hidden): remove absolute position

* by using `position: absolute`, in Chrome(and Brave as well) we get a weird error: looks like although the content that overflows is hidden by the `sections container`, the scroll bar behaves as if it wouldn't overflow
* in Firefox we don't have this error

* feat(answer-details): show question's note

* fix(answers): fetch answers without previous `state.urgent` value

* fix(header): make hambuger menu contain all of its items

* feat(answers): add `CanLoad` guard to `answers` module

* feat(answer-notification): add page for sending notifications

* feat(base-button): allow to have inheritet color

* particularly useful when we want the button's color to depend on the class applied on the `container`

* fix(answer-details): change `View Note` button's color in accordance with the question's flagged status

* i18n(answers/*): add translations

* fix(answers): show total number of all records

* instead of the number of current records shown in page

* feat(table): identify a table column by using a custom directive

* feat(answers): make `filters` work

* feat(answers): reset filters

* as a result, the entries will be shown accordingly

* feat(county): add `county` store slice

* feat(answers): select `counties` filter from `select` tag

* feat(answers): show `Location Type` & `Date&Time` columns in table

* feat(answer-details): show `Location Type` & `Date&Time` stats

* refactor(answers): remove `from` & `to` filters

* feat(base-checkbox): allow checkbox to be readonly(disabled)

* feat(answer-details): make every answer readonly

* fix(observers): allow the `table` comp to query the tableColumn properly

* fix(answers.effects): avoid calling for extra details when initial response is empty

* feat(answers/form): fetch forms when only needed

* feat(answers): fetch data only when needed & don't refetch redundantly

* feat(answers-notification): send notification

* feat(notes): fetch data only when needed & don't refetch redundantly

* refactor: replace `/urgents` route with `urgent` filter in `/answers`

* feat(answer-questions): display questions & answers in separate component

* feat(answer-details): add `Notes` tab

* feat(answer-details): add `Notes` tab

* feat(answer-details): scroll to question from `Notes` tab

* feat(answer-details): open modals with content decided by child components

* feat(notes): open modal with note on row click

* refactor(notes): let the `answer-details` hold the template with the modal content

* reason: both `notes` and `answer-questions` are bound to use the same modal template

* feat(answer-questions): show note in modal when the `View Note` is called

* feat(notes): display shrunk note text with ellipsis when necessaryy

* feat(answer-questions): improve highlight of flagged question

* fix: make `visually-hidden` class work on both Chrome and Firefox

* fix(answer-questions): remove empty spaces from `textarea`

* feat(answers): make layout responsive

* fix(notes): fetch notes immediately as `answer-details` is rendered

* this is to show the questions with notes from the crt tab properly

* feat(answers): add loading icon

* feat(answer-details): add loading icon

* fix(login): redirect to `/answers` instead of the old `/urgents`

* feat: reset state after logout

* fix(answers): make `Export` button work

* fix(answer-details): scroll to question from a tab different than the previous one visited

* when, from `Notes` tabm the user is redirected to a form tab which is different than the previous one, shown exactly before the user had visited the `Notes` tab

* i18n(answer-details): add translations

* feat(answer-notification): show message after notification has been sent

* refactor(notes): display '-' when a question link is missing
  • Loading branch information
Andrei0872 authored Nov 27, 2020
1 parent 86788bb commit fb7c53c
Show file tree
Hide file tree
Showing 82 changed files with 2,272 additions and 299 deletions.
5 changes: 5 additions & 0 deletions src/_variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,15 @@ $light-gray: #F3F1F1;
$muted-gray: #B6B6B6;
$readable-dark-gray: #6B6B6B;
$darker-gray: #454545;
$dim-gray: #636363;
$border-color-gray: #EDEDED;
$light-text-gray: #7C8284;

$primary-purple: #5F288D;
$delete-color: #F16359;

$font-weight-medium: 500;
$primary-gray: #707070;

$input-text-color: #A3A3A3;
$selected-row-color: #F9F9FA;
101 changes: 101 additions & 0 deletions src/app/answers/answer-details/answer-details.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<div class="container-fluid c-answer-detail__container">
<app-base-button
[custom-styles]="{ fontSize: '1.2rem' }"
[variant]="BaseButtonVariants.ALLTRANSPARENT"
[routerLink]="['../../']"
>
<div class="d-flex align-items-center">
<svg class="c-profile__back-icon" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 12H5" stroke="#6B6B6B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 16L4 12L8 8" stroke="#6B6B6B" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
&nbsp;
<span>{{ 'BACK' | translate }}</span>
</div>
</app-base-button>

<div class="c-answer-header flex-wrap d-flex justify-content-between align-items-center mt-4">
<h4 class="c-answer-header__title">
{{ 'ANSWERS_WHICH_BELONG_TO' | translate }} {{ (crtPollingStation$ | async)?.observerName }}
</h4>

<app-base-button class="c-answer-header__button" routerLink="notification">
<span class="content">{{ 'SEND_NOTIF' | translate }}</span>
</app-base-button>
</div>

<div class="c-answer-stats">
<ng-container *ngIf="(crtPollingStation$ | async) as crtPollingStation">
<div class="c-answer-stats__container">
<div
*ngFor="let stat of statsLabels"
class="c-answer-stats__item"
>
<span class="c-answer-stats__label">{{ stat.name | async }}</span>: &nbsp; <span>{{ crtPollingStation[stat.propertyName] || '/' }}</span>
</div>
</div>
</ng-container>
</div>

<div class="c-answer-forms">
<div class="c-answer-forms__tabs">
<div
*ngFor="let formTab of formTabs$ | async"
(click)="onTabClicked(formTab)"
[class.is-tab-selected]="crtSelectedTabId === formTab.id"
class="c-answer-form-tab"
>
{{ formTab.description }}
</div>
</div>

<div class="c-answer-forms__sections" *ngIf="(isSectionContentLoading$ | async) === false; else loading">
<app-answer-questions
*ngIf="!isNotesTabShown; else notes"
(showNoteClicked)="showModalWithNote($event)"
[sectionsState]="sectionsState$ | async"
[sections]="sections$ | async"
[scrolled-question-id]="scrolledQuestionId"
></app-answer-questions>

<ng-template #notes>
<app-notes
(showNoteInModal)="showModalWithNote($event)"
(questionLinkClicked)="onTabClicked({ id: $event.formId }); scrolledQuestionId = $event.questionId"
[notes]="notes$ | async"
></app-notes>
</ng-template>
</div>
</div>
</div>

<ng-template #modalTemplateRef let-activeModal>
<div class="c-notes-modal">
<!-- This is needed because, by default, it will focus on the first `focusable` -->
<!-- element, which in this case is the button placed at the end -->
<!-- Without this `hack`, the modal will always be scrolled to that button -->
<input type="text" style="display:none" />

<div class="c-notes-modal__header">
<h4>{{ crtClickedNote.questionCode }} Note</h4>
</div>

<div class="c-notes-modal__content">
<p>{{ crtClickedNote.text }}</p>

<div class="c-notes-modal__image-container" *ngFor="let attachment of crtClickedNote.attachmentsPaths">
<img *ngIf="attachment.isImage" [src]="attachment.src">
</div>

<app-base-button (click)="activeModal.close()" [disabled]="false" [variant]="BaseButtonVariants.PURPLE"
[custom-styles]="{ fontSize: '1rem', padding: '0.3rem 0.5rem', border: 'none' }"
class="c-notes-modal__close-button">
{{ 'CLOSE' | translate }}
</app-base-button>
</div>
</div>
</ng-template>

<ng-template #loading>
<app-loading-indicator></app-loading-indicator>
</ng-template>
115 changes: 115 additions & 0 deletions src/app/answers/answer-details/answer-details.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
@import '../../../variables';

.c-answer-header {
&__title {
color: $darker-gray;
}
}

.c-answer-stats {
background: #fff;
box-shadow: 4px 4px 30px rgba(0, 0, 0, 0.08);
border-radius: 4px;
padding: 1.2rem 1.5rem;
margin-top: 2rem;

&__container {
display: grid;
width: 70%;
grid-template-columns: 1fr 2fr;
row-gap: 1rem;

@media all and (max-width: 920px) {
& {
width: 100%;
}
}

@media all and (max-width: 650px) {
& {
grid-template-columns: 1fr 1fr;
}
}

@media all and (max-width: 380px) {
& {
grid-template-columns: 1fr;
}
}
}

&__label {
color: $dim-gray;
font-weight: bold;

& + span {
color: $readable-dark-gray;
}
}
}

.c-answer-forms {
box-shadow: 4px 4px 30px rgba(0, 0, 0, 0.08);
border-radius: 4px;
background-color: #fff;
margin-top: 2rem;
margin-bottom: 2rem;
padding: 1rem;
display: grid;
grid-template-rows: auto 1fr;
overflow-y: auto;
max-height: 80vh;

&__tabs {
display: flex;
border-bottom: 1px solid $border-color-gray;
padding-top: .5rem;
column-gap: 1.5rem;
}

&__sections {
margin-top: 1rem;
}
}

.c-answer-form-tab {
color: $dim-gray;
padding-bottom: .7rem;
font-size: 1.1rem;
cursor: pointer;

&.is-tab-selected {
color: $primary-purple;
border-bottom: 1px solid $primary-purple;
}
}

.c-notes-modal {
&__header {
border-bottom: 1px solid $border-color-gray;
padding: 1rem 1.4rem;
color: $darker-gray;
}

&__content {
color: $readable-dark-gray;
padding: 1rem 1.2rem;

p {
margin: 0;
}
}

&__close-button {
display: block;
width: max-content;
margin-left: auto;
margin-top: 2rem;
}

&__image-container {
overflow: hidden;
max-height: 45rem;
margin-top: 2rem;
}
}
25 changes: 25 additions & 0 deletions src/app/answers/answer-details/answer-details.component.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';

import { AnswerDetailsComponent } from './answer-details.component';

describe('AnswerDetailsComponent', () => {
let component: AnswerDetailsComponent;
let fixture: ComponentFixture<AnswerDetailsComponent>;

beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AnswerDetailsComponent ]
})
.compileComponents();
}));

beforeEach(() => {
fixture = TestBed.createComponent(AnswerDetailsComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading

1 comment on commit fb7c53c

@vercel
Copy link

@vercel vercel bot commented on fb7c53c Nov 27, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.