Тестовое задание на Angular. Создание страницы бронирования.

Aleksandr Serenko
F.A.F.N.U.R
Published in
4 min readJul 5, 2021

В данной статье создадим страницу для отображения вариантов для бронирования.

Создание BookingPage

После того как были созданы BookingState и BookingService создадим страницу на которой выведем варианты для бронирования.

ng g c booking-page

На странице с компонентом будем выводить два компонента: BookingMapComponent и BookingListComponent.

  • BookingMapComponent — компонент, в котором выводится карта и отображаются доступные варианты для бронирования в виде маркеров на карте.
  • BookingListComponent — компонент, который просто выводит список доступных вариантов в виде списка.

Создадим каждый из вариантов:

ng g c booking-map
ng g c booking-list

Отличие мобильной версии от десктопной версии заключается в том, что в мобильной версии отображается либо карта, либо список, где по умолчанию отображается карта, а для того чтобы переключится на список, внизу будет плавающая кнопка, при клике по которой будет происходить смена экрана.

Добавим BookingPage:

Как видно из реализации, мы добавляем контейнер, и в зависимости от расширения экрана показываем либо мобильную версию, либо версию для настольного компьютера:

<app-container mode="fluid" height="max-height">
<ng-container *ngIf="isDesktopScreen; then desktopTpl; else mobileTpl"></ng-container>
</app-container>

Переменная isDesktopScreen определяется с помощью Angular CDK:

this.breakpointObserver
.observe(mediaBreakpointUp(GridBreakpointType.Md))
.pipe(
tap((breakpoints) => {
this.isDesktopScreen = breakpoints.matches;
this.changeDetectorRef.markForCheck();
}),
takeUntil(this.destroy$)
)
.subscribe();

BreakpointObserver позволяет отслеживать изменения размера экрана. В данном случае мы передаем на отслеживание правило — min-width: 768px, которое формируется с помощью утилиты mediaBreakpointUp().

И если ширина экрана более 768px, то тогда отображаем версию для настольного компьютера:

<ng-template #desktopTpl>
<app-row>
<app-column>
<app-booking-list automation-id="booking-list-desktop"></app-booking-list>
</app-column>
<app-column>
<app-booking-map automation-id="booking-map-desktop"><app-booking-card></app-booking-card></app-booking-map>
</app-column>
</app-row>
</ng-template>

В данном случае, здесь выводиться 2 компонента:

  • BookingListComponent — компонент, который выводит список доступных вариантов для бронирования в виде списка
  • BookingMapComponent — компонент, который выводит на карте список доступных вариантов для бронирования в виде маркеров, при клике на который можно открыть страницу с подробным описанием варианта.
  • RowComponent и ColumnComponent — создают колонки, аналогично сетке bootstrap.

В мобильной версии будет выведен макет:

<ng-template #mobileTpl>
<ng-container *ngIf="isMapShow; then mapMobileTpl; else listMobileTpl"></ng-container>
<div class="booking-actions">
<button class="booking-action" automation-id="booking-view-toggle" mat-icon-button type="button" (click)="onToggleView()">
<mat-icon *ngIf="isMapShow">view_list</mat-icon>
<mat-icon *ngIf="!isMapShow">map</mat-icon>
</button>
</div>
</ng-template>
<ng-template #mapMobileTpl>
<app-booking-map automation-id="booking-map-mobile"><app-booking-box></app-booking-box></app-booking-map>
</ng-template>

<ng-template #listMobileTpl>
<app-booking-list automation-id="booking-list-mobile"></app-booking-list>
</ng-template>

В зависимости от выбранного варианта (isMapShow) отображения доступных вариантов для бронирования, выводится либо список либо карта.

Переключение вариантов происходит с помощью клика по кнопке:

<button class="booking-action" automation-id="booking-view-toggle" mat-icon-button type="button" (click)="onToggleView()">
<mat-icon *ngIf="isMapShow">view_list</mat-icon>
<mat-icon *ngIf="!isMapShow">map</mat-icon>
</button>

где в компоненте просто меняется значение на противоположное:

onToggleView(): void {
this.isMapShow = !this.isMapShow;
}

Создание BookingMap

Добавим реализацию компонента, который будет выводить карту с доступными вариантами.

Как видно из реализации, в BookingMap используется ранее созданный компонент карты (Добавление google maps).

<ng-container *ngIf="mapMarkers$ | async as mapMarkers">
<app-google-map
automation-id="booking-map-google"
[options]="options"
[markerOptions]="markerOptions"
[markers]="mapMarkers"
(mapMarkerClicked)="onMapMarkerClicked($event)"
(mapInfoWindowClosed)="onMapInfoWindowClosed()"
>
<ng-content></ng-content>
</app-google-map>
</ng-container>

В качестве параметров установим значения:

options: google.maps.MapOptions = {
center: {
lat: 59.93839227045331,
lng: 30.360033589998572,
},
zoom: 14,
};
markerOptions: google.maps.MarkerOptions = { draggable: false, icon: '/' };

Значения маркеров получим из BookingService:

mapMarkers$!: Observable<MapMarkerConfig[]>;

constructor(private readonly bookingService: BookingService) {}

ngOnInit(): void {
this.mapMarkers$ = this.bookingService.mapMarkers$;
}

И соответственно при клике на пин или на карту происходят события открытия пина и закрытие ранее открытого варианта:

onMapMarkerClicked(markerConfig: MapMarkerConfig<BookingVariant>): void {
this.bookingService.setBookingVariant(markerConfig.data);
}

onMapInfoWindowClosed(): void {
this.bookingService.clearBookingVariant();
}

Стоит отметить, что в мобильной и десктопной версии имеются разные превью для доступных вариантов. В мобильной версии используется BookingBox, а в десктопной версии BookingCard.

BookingBox:

BookingCard:

BookingCard и BookingBox выводят короткую информацию о доступном варианте. И соответственно при клике произойдет переход на страницу данного варианта.

Создание BookingList

Для вывода списка доступных вариантов создадим компонент:

Как видно из реализации, в компоненте получаем список доступных вариантов для бронирования:

bookingVariants$!: Observable<BookingVariant[]>;

constructor(private readonly bookingService: BookingService) {}

ngOnInit(): void {
this.bookingVariants$ = this.bookingService.bookingVariants$;
}

и затем их выводим, где для вывода используется BookingPortlet:

<ng-container *ngIf="bookingVariants.length">
<app-booking-portlet
automation-id="booking-list-portlet"
[bookingVariant]="bookingVariant"
*ngFor="let bookingVariant of bookingVariants"
></app-booking-portlet>
</ng-container>

BookingPortlet принимает вид:

В карточке доступного варианта выводим изображения первого номера, а также его цену и адрес.

Ссылки

Вернуться к оглавлению — Введение.

Следующая статья — Создание страницы апартаментов.

Предыдущая статья — Создание UI kit для приложения.

Все исходники на github/fafnur/barinb.

Группа в Medium: https://medium.com/fafnur
Группа в Vkontakte: https://vk.com/fafnur
Группа в Facebook: https://www.facebook.com/groups/fafnur/
Telegram канал: https://t.me/f_a_f_n_u_r
Twitter: https://twitter.com/Fafnur1
LinkedIn: https://www.linkedin.com/in/fafnur

--

--

Aleksandr Serenko
F.A.F.N.U.R

Senior Front-end Developer, Angular evangelist, Nx apologist, NodeJS warlock