From a2175dade5bf207d108e76cf9cd2671ca96c74cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC?= Date: Thu, 13 Jun 2024 17:29:49 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=A1=D0=B4=D0=B5=D0=BB=D0=B0=D0=BB=20?= =?UTF-8?q?=D1=85=D0=B5=D0=B4=D0=B5=D1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main.js | 8 ++ src/model/filter-model.js | 2 +- src/model/points-model.js | 8 +- src/presenter/presenter-filter.js | 8 +- src/presenter/presenter-info-panel.js | 37 +++++++++ src/presenter/presenter-new-point.js | 5 +- src/presenter/presenter-waypoint.js | 3 +- src/presenter/presenter.js | 43 +++++----- src/{utils.js => utils}/const.js | 0 src/{utils.js => utils}/day.js | 0 src/{utils.js => utils}/filter.js | 2 - src/{utils.js => utils}/sort.js | 0 src/{utils.js => utils}/util.js | 5 -- src/view/list-empty.js | 2 +- src/view/sort-panel.js | 2 +- src/view/trip-info.js | 111 +++++++++++++++++++++++--- src/view/waypoint-edit.js | 25 +++--- src/view/waypoint.js | 5 +- 18 files changed, 197 insertions(+), 69 deletions(-) create mode 100644 src/presenter/presenter-info-panel.js rename src/{utils.js => utils}/const.js (100%) rename src/{utils.js => utils}/day.js (100%) rename src/{utils.js => utils}/filter.js (99%) rename src/{utils.js => utils}/sort.js (100%) rename src/{utils.js => utils}/util.js (89%) diff --git a/src/main.js b/src/main.js index c037c7a..11065b1 100644 --- a/src/main.js +++ b/src/main.js @@ -3,6 +3,7 @@ import PointsModel from './model/points-model.js'; import FilterModel from './model/filter-model.js'; import FilterPresenter from './presenter/presenter-filter.js'; import PointsApiService from './points-api-service.js'; +import PresenterInfoPanel from './presenter/presenter-info-panel.js'; import CreationForm from './view/creation-form.js'; import { render } from './framework/render.js'; @@ -35,6 +36,12 @@ const newPointButtonComponent = new CreationForm({ onClick: handleNewPointButtonClick }); +const presenterInfoPanel = new PresenterInfoPanel({ + tripInfoContainer: tripMainElement, + pointsModel +}); + + function handleNewPointButtonClick() { presenter.createPoint(); newPointButtonComponent.element.disabled = true; @@ -55,3 +62,4 @@ pointsModel.init() .finally(() => { newPointButtonComponent.element.disabled = false; }); +presenterInfoPanel.init(); diff --git a/src/model/filter-model.js b/src/model/filter-model.js index 7fbfd7f..c223300 100644 --- a/src/model/filter-model.js +++ b/src/model/filter-model.js @@ -1,4 +1,4 @@ -import { FilterType } from '../utils.js/filter.js'; +import { FilterType } from '../utils/filter.js'; import Observable from '../framework/observable.js'; export default class FilterModel extends Observable { diff --git a/src/model/points-model.js b/src/model/points-model.js index 00d1b33..b1b4d03 100644 --- a/src/model/points-model.js +++ b/src/model/points-model.js @@ -1,6 +1,6 @@ // import { MOCKED_EVENTS } from '../mock/trip-event.js'; import Observable from '../framework/observable.js'; -import { UpdateType } from '../utils.js/const.js'; +import { UpdateType } from '../utils/const.js'; export default class PointsModel extends Observable { #pointsApiService = null; @@ -13,7 +13,7 @@ export default class PointsModel extends Observable { this.#pointsApiService = pointsApiService; } - get event() { + get events() { return this.#points; } @@ -128,5 +128,9 @@ export default class PointsModel extends Observable { getDestinationId(id) { return this.destinations.find((item) => item.id === id); } + + getDestinationName(name) { + return this.#destinations.find((item) => item.name === name); + } } diff --git a/src/presenter/presenter-filter.js b/src/presenter/presenter-filter.js index 0b01e3b..b913f5e 100644 --- a/src/presenter/presenter-filter.js +++ b/src/presenter/presenter-filter.js @@ -1,8 +1,8 @@ -import { FilterType } from '../utils.js/filter.js'; +import { FilterType } from '../utils/filter.js'; import { remove, render, replace } from '../framework/render.js'; -import { filter } from '../utils.js/filter.js'; +import { filter } from '../utils/filter.js'; import FilterView from '../view/filter-view.js'; -import { UpdateType } from '../utils.js/const.js'; +import { UpdateType } from '../utils/const.js'; export default class FilterPresenter { @@ -21,7 +21,7 @@ export default class FilterPresenter { } get filters() { - const points = this.#pointsModel.event; + const points = this.#pointsModel.events; return [ { diff --git a/src/presenter/presenter-info-panel.js b/src/presenter/presenter-info-panel.js new file mode 100644 index 0000000..8a48602 --- /dev/null +++ b/src/presenter/presenter-info-panel.js @@ -0,0 +1,37 @@ +import TripInfo from '../view/trip-info.js'; +import { remove, render, RenderPosition, replace } from '../framework/render.js'; +import { sortByDay } from '../utils/sort.js'; + +export default class PresenterInfoPanel { + #tripInfoContainer = null; + #pointsModel = null; + + #tripInfoComponent = null; + + constructor({ tripInfoContainer, pointsModel }) { + this.#tripInfoContainer = tripInfoContainer; + this.#pointsModel = pointsModel; + + this.#pointsModel.addObserver(this.#handleModelEvent); + } + + init() { + const points = this.#pointsModel.events.sort(sortByDay); + const offers = this.#pointsModel.offers; + const destinations = this.#pointsModel.destinations; + const prevInfoComponent = this.#tripInfoComponent; + this.#tripInfoComponent = new TripInfo(points, offers, destinations); + + if (prevInfoComponent === null) { + render(this.#tripInfoComponent, this.#tripInfoContainer, RenderPosition.AFTERBEGIN); + return; + } + + replace(this.#tripInfoComponent, prevInfoComponent); + remove(prevInfoComponent); + } + + #handleModelEvent = () => { + this.init(); + }; +} diff --git a/src/presenter/presenter-new-point.js b/src/presenter/presenter-new-point.js index b4a460f..0f2f45d 100644 --- a/src/presenter/presenter-new-point.js +++ b/src/presenter/presenter-new-point.js @@ -1,7 +1,7 @@ import WaypointEdit from '../view/waypoint-edit.js'; import { remove, render, RenderPosition } from '../framework/render.js'; -import { isEscapeKey } from '../utils.js/util.js'; -import { UpdateType, UserAction } from '../utils.js/const.js'; +import { isEscapeKey } from '../utils/util.js'; +import { UpdateType, UserAction } from '../utils/const.js'; export default class PresenterNewPoint { #pointListContainer = null; @@ -81,7 +81,6 @@ export default class PresenterNewPoint { UpdateType.MINOR, point, ); - this.destroy(); }; #handleFormCancelButtonClick = () => { diff --git a/src/presenter/presenter-waypoint.js b/src/presenter/presenter-waypoint.js index b33ba77..6f09b79 100644 --- a/src/presenter/presenter-waypoint.js +++ b/src/presenter/presenter-waypoint.js @@ -1,7 +1,7 @@ import { render, replace, remove } from '../framework/render.js'; import Waypoint from '../view/waypoint.js'; import WaypointEdit from '../view/waypoint-edit.js'; -import { UserAction, UpdateType } from '../utils.js/const.js'; +import { UserAction, UpdateType } from '../utils/const.js'; const Mode = { DEFAULT: 'DEFAULT', @@ -126,7 +126,6 @@ export default class PresenterWaypoint { UpdateType.MINOR, point ); - this.#replaceFormToPoint(); }; #handleEditFormDeleteButtonClick = (point) => { diff --git a/src/presenter/presenter.js b/src/presenter/presenter.js index 5d72e42..793ec7c 100644 --- a/src/presenter/presenter.js +++ b/src/presenter/presenter.js @@ -1,15 +1,15 @@ import { render, RenderPosition, remove } from '../framework/render.js'; import SortPanel from '../view/sort-panel.js'; -import TripInfo from '../view/trip-info.js'; +// import TripInfo from '../view/trip-info.js'; import WaypointList from '../view/waypoint-list.js'; import PresenterWaypoint from './presenter-waypoint.js'; import ListEmpty from '../view/list-empty.js'; import PresenterNewPoint from './presenter-new-point.js'; -import { SORT_TYPE } from '../utils.js/sort.js'; -import { sortByDay, sortByTime, sortByPrice } from '../utils.js/sort.js'; -import { UserAction, UpdateType } from '../utils.js/const.js'; -import { filter } from '../utils.js/filter.js'; -import { FilterType } from '../utils.js/filter.js'; +import { SORT_TYPE } from '../utils/sort.js'; +import { sortByDay, sortByTime, sortByPrice } from '../utils/sort.js'; +import { UserAction, UpdateType } from '../utils/const.js'; +import { filter } from '../utils/filter.js'; +import { FilterType } from '../utils/filter.js'; import LoadingView from '../view/loading-view.js'; import UiBlocker from '../framework/ui-blocker/ui-blocker.js'; import ErrorView from '../view/error-view.js'; @@ -21,12 +21,9 @@ const TimeLimit = { export default class Presenter { - #creationForm = null; #sortPanel = null; - #tripInfo = new TripInfo(); + #tripInfo = null; #waypointList = new WaypointList(); - #listEmpty = null; - #destinations = null; #pointsModel = null; #pointPresenterMap = new Map(); #currentSortType = SORT_TYPE.DAY; @@ -47,7 +44,6 @@ export default class Presenter { #pointPresenter = null; - constructor({ pointsModel, filterModel, onNewPointDestroy }) { this.#pointsModel = pointsModel; this.#filterModel = filterModel; @@ -72,7 +68,7 @@ export default class Presenter { get points() { const currentFilterType = this.#filterModel.filter; - const points = this.#pointsModel.event; + const points = this.#pointsModel.events; const filteredPoints = filter[currentFilterType](points); switch (this.#currentSortType) { case SORT_TYPE.PRICE: @@ -174,6 +170,12 @@ export default class Presenter { render(this.#sortPanel, this.#tripEventsElement, RenderPosition.AFTERBEGIN); } + #listEmptyMessage() { + this.#listMessageComponent = new ListEmpty(this.#filterModel.filter); + render(this.#listMessageComponent, this.#tripEventsElement); + } + + #clearPoinsList(resetSortType = false) { this.#presenterNewPoint.destroy(); this.#pointPresenterMap.forEach((presenter) => presenter.destroy()); @@ -187,15 +189,13 @@ export default class Presenter { } } - #renderTripInfo() { - render(this.#tripInfo, this.#tripMainElement, RenderPosition.AFTERBEGIN); - } - - #listEmptyMessage() { - this.#listMessageComponent = new ListEmpty(this.#filterModel.filter); + // #renderTripInfo() { + // this.#tripInfo = new TripInfo({ + // pointsModel: this.#pointsModel + // }); + // render(this.#tripInfo, this.#tripMainElement, RenderPosition.AFTERBEGIN); + // } - render(this.#listMessageComponent, this.#tripEventsElement); - } #renderWaypoints() { this.points.forEach((point) => this.#renderWaypoint(point)); @@ -233,7 +233,6 @@ export default class Presenter { if (this.points.length) { remove(this.#loadingComponent); - remove(this.#listMessageComponent); this.#renderWaypoints(); } else { this.#listEmptyMessage(); @@ -248,7 +247,7 @@ export default class Presenter { }; init() { - this.#renderTripInfo(); + // this.#renderTripInfo(); this.#renderWaypointList(); } } diff --git a/src/utils.js/const.js b/src/utils/const.js similarity index 100% rename from src/utils.js/const.js rename to src/utils/const.js diff --git a/src/utils.js/day.js b/src/utils/day.js similarity index 100% rename from src/utils.js/day.js rename to src/utils/day.js diff --git a/src/utils.js/filter.js b/src/utils/filter.js similarity index 99% rename from src/utils.js/filter.js rename to src/utils/filter.js index 86838f3..1bd85fa 100644 --- a/src/utils.js/filter.js +++ b/src/utils/filter.js @@ -1,6 +1,5 @@ import { appDay } from './day.js'; - const isFutureEvent = (dateFrom) => appDay(dateFrom).isAfter(appDay()); const isPresentEvent = (dateFrom, dateTo) => appDay(dateFrom).isBefore(appDay()) && appDay(dateTo).isAfter(appDay()); const isPastEvent = (dateTo) => appDay(dateTo).isBefore(appDay()); @@ -26,5 +25,4 @@ export const tripMessagesEmpty = { [FilterType.PAST]: 'There are no past events now', }; - export { filter, FilterType }; diff --git a/src/utils.js/sort.js b/src/utils/sort.js similarity index 100% rename from src/utils.js/sort.js rename to src/utils/sort.js diff --git a/src/utils.js/util.js b/src/utils/util.js similarity index 89% rename from src/utils.js/util.js rename to src/utils/util.js index 584acce..0274740 100644 --- a/src/utils.js/util.js +++ b/src/utils/util.js @@ -7,10 +7,6 @@ const getRandomInteger = (a = 0, b = 1) => { return Math.floor(lower + Math.random() * (upper - lower + 1)); }; -// const getRandomArrayElement = (elements) => elements[getRandomInteger(0, elements.length - 1)]; - -// const getRandomInt = (max) => Math.round(Math.random() * max); - const generateDates = () => { const maxGap = 14; @@ -62,7 +58,6 @@ const getDuration = (beginISO, endISO) => { const isEscapeKey = (evt) => evt.key === 'Escape'; -// const dataChange = (item, prop) => ({ ...item, ...prop }); const PRICE_FIELD_PATTERN = /\D+/; diff --git a/src/view/list-empty.js b/src/view/list-empty.js index fff0fc2..19d65a8 100644 --- a/src/view/list-empty.js +++ b/src/view/list-empty.js @@ -1,5 +1,5 @@ import AbstractView from '../framework/view/abstract-view.js'; -import { tripMessagesEmpty } from '../utils.js/filter.js'; +import { tripMessagesEmpty } from '../utils/filter.js'; const createtListempty = (filterType) => `

${tripMessagesEmpty[filterType]}

`; diff --git a/src/view/sort-panel.js b/src/view/sort-panel.js index f453c27..5eb0274 100644 --- a/src/view/sort-panel.js +++ b/src/view/sort-panel.js @@ -1,5 +1,5 @@ import AbstractView from '../framework/view/abstract-view.js'; -import { SORT_TYPE } from '../utils.js/sort.js'; +import { SORT_TYPE } from '../utils/sort.js'; const createSortPanel = (currentSortType) => `
diff --git a/src/view/trip-info.js b/src/view/trip-info.js index b85f29f..84e43e8 100644 --- a/src/view/trip-info.js +++ b/src/view/trip-info.js @@ -1,24 +1,109 @@ +import dayjs from 'dayjs'; import AbstractView from '../framework/view/abstract-view.js'; -const createTripInfo = () => - `
-
-

Amsterdam — Chamonix — Geneva

+const DATE_FORMAT = 'MMM DD'; +const MULTIPLE_SYMBOL = '...'; +const MAX_CITIES_VISIBLE_COUNT = 3; -

18 — 20 Mar

-
+const createTripInfoTemplate = (points, offers, destinations) => { -

- Total: € 1230 -

-
`; + const createTripRouteTemplate = () => { + const routeCities = []; + points.forEach((point) => { + const getPointDestination = destinations.find((item) => point.destination === item.id); + routeCities.push(getPointDestination.name); + }); + const startPoint = routeCities[0]; + const endPoint = routeCities.at(-1); + let middlePoint = routeCities[1]; + let routeString = ''; -export default class TripInfo extends AbstractView { - constructor() { + if (routeCities.length > MAX_CITIES_VISIBLE_COUNT) { + middlePoint = MULTIPLE_SYMBOL; + } + + switch (routeCities.length) { + case 1: + routeString = startPoint; + break; + case 2: + routeString = `${startPoint} — ${endPoint}`; + break; + default: + routeString = `${startPoint} — ${middlePoint} — ${endPoint}`; + } + + if (!routeCities.length) { + routeString = 'No events'; + } + + return `

+ ${routeString} +

`; + }; + + const createTripInfoDatesTemplate = () => { + + if (!points.length) { + return ''; + } + + const startDate = dayjs(points[0].dateFrom); + const endDate = dayjs(points.at(-1).dateTo); + + let endDateFormat = DATE_FORMAT; + + if (endDate.isSame(startDate, 'month')) { + endDateFormat = 'DD'; + } + + return `

${startDate.format(DATE_FORMAT)} — ${endDate.format(endDateFormat)}

`; + }; + + const createTripTotalPriceTemplate = () => { + + let totalPrice = 0; + points.forEach((point) => { + totalPrice += +point.basePrice; + + const pointTypeOffer = offers.find((offer) => offer.type === point.type); + if (!pointTypeOffer) { + return; + } + + const selectedOffers = pointTypeOffer.offers.filter((offer) => point.offers.includes(offer.id)); + selectedOffers.forEach((offer) => { + totalPrice += +offer.price; + }); + }); + + return `

Total: € ${totalPrice}

`; + }; + + return `
+
+ ${createTripRouteTemplate()} + ${createTripInfoDatesTemplate()} +
+ ${createTripTotalPriceTemplate()} +
`; +}; + +export default class TripInfoView extends AbstractView { + #points = null; + #offers = null; + #destinations = null; + + constructor(points, offers, destinations) { super(); + + this.#points = points; + this.#offers = offers; + this.#destinations = destinations; } get template() { - return createTripInfo(); + return createTripInfoTemplate(this.#points, this.#offers, this.#destinations); } + } diff --git a/src/view/waypoint-edit.js b/src/view/waypoint-edit.js index 3678fd1..777c102 100644 --- a/src/view/waypoint-edit.js +++ b/src/view/waypoint-edit.js @@ -1,9 +1,9 @@ import AbstractStatefulView from '../framework/view/abstract-stateful-view.js'; -import { validatePriceField } from '../utils.js/util.js'; +import { validatePriceField } from '../utils/util.js'; import flatpickr from 'flatpickr'; import 'flatpickr/dist/flatpickr.min.css'; -import { appDay } from '../utils.js/day.js'; +import { appDay } from '../utils/day.js'; const DefaultPointData = { DATE_FROM: appDay().toISOString(), @@ -12,7 +12,7 @@ const DefaultPointData = { }; const BLANK_POINT = { - basePrice: '1', + basePrice: '', dateFrom: DefaultPointData.DATE_FROM, dateTo: DefaultPointData.DATE_TO, destination: '', @@ -151,7 +151,7 @@ const createWaypointForm = (waypoint, destinations, offers, pointsModel) => { Price € - + @@ -176,6 +176,7 @@ export default class WaypointEdit extends AbstractStatefulView { #datepickerTo = null; #onEditFormSave = null; #pointsModel = null; + constructor({ waypoint = BLANK_POINT, onEditFormSave, onEditFormRollupButtonClick, onDeleteForm, offers, pointsModel, destinations }) { super(); this._setState(WaypointEdit.parsePointToState(waypoint)); @@ -190,7 +191,7 @@ export default class WaypointEdit extends AbstractStatefulView { } get template() { - return createWaypointForm(this._state, this.#destinations, this.#offers, this.#pointsModel); + return createWaypointForm(this._state, this.#destinations, this.#offers, this.#pointsModel, this.isDestinationText); } reset(waypoint) { @@ -217,12 +218,16 @@ export default class WaypointEdit extends AbstractStatefulView { #eventDestinationToggleHandler = (evt) => { evt.preventDefault(); - if (evt.target.value !== '') { - const selectedDestination = this.#destinations.find((destination) => evt.target.value === destination.name); - this.updateElement({ - destination: selectedDestination.id, - }); + evt.preventDefault(); + + let selectedDestination = this.#destinations.find((destination) => evt.target.value === destination.name); + if (!selectedDestination) { + selectedDestination = ''; } + + this.updateElement({ + destination: selectedDestination.id + }); }; #priceInputHandler = (evt) => { diff --git a/src/view/waypoint.js b/src/view/waypoint.js index 2ee74d5..90ee6e5 100644 --- a/src/view/waypoint.js +++ b/src/view/waypoint.js @@ -1,6 +1,6 @@ import AbstractView from '../framework/view/abstract-view.js'; -import { appDay } from '../utils.js/day.js'; -import { getDuration } from '../utils.js/util.js'; +import { appDay } from '../utils/day.js'; +import { getDuration } from '../utils/util.js'; const createWaypoint = (waypoint, destinationCurrent, offers) => { const { basePrice: price, dateFrom: ISOFrom, dateTo: ISOTo, isFavorite, type, offers: offersPoint } = waypoint; @@ -30,7 +30,6 @@ const createWaypoint = (waypoint, destinationCurrent, offers) => { const pointTypeList = createOffersTemplate(); - return `
  • From 67c7cc2f81c78d694636563eeccd8873d9e16d82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC?= Date: Sat, 15 Jun 2024 12:55:00 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/framework/render.js | 4 +-- src/framework/view/abstract-view.js | 2 +- src/main.js | 27 +++++++--------- src/model/points-model.js | 21 +++---------- src/presenter/presenter-filter.js | 13 ++++---- src/presenter/presenter-info-panel.js | 1 - .../{presenter.js => presenter-main.js} | 31 +++++-------------- src/presenter/presenter-new-point.js | 13 ++------ src/presenter/presenter-waypoint.js | 27 +++++----------- src/utils/const.js | 4 +-- src/utils/filter.js | 4 +-- src/utils/util.js | 1 - src/view/error-view.js | 3 +- src/view/loading-view.js | 2 -- src/view/trip-info.js | 4 --- src/view/waypoint-edit.js | 20 +++++------- src/view/waypoint.js | 10 ++++-- 17 files changed, 61 insertions(+), 126 deletions(-) rename src/presenter/{presenter.js => presenter-main.js} (93%) diff --git a/src/framework/render.js b/src/framework/render.js index 64be3c7..30eae0f 100644 --- a/src/framework/render.js +++ b/src/framework/render.js @@ -32,7 +32,7 @@ function render(component, container, place = RenderPosition.BEFOREEND) { } if (container === null) { - throw new Error('Container element doesn\'t exist'); + throw new Error("Container element doesn't exist"); } container.insertAdjacentElement(place, component.element); @@ -54,7 +54,7 @@ function replace(newComponent, oldComponent) { const parent = oldElement.parentElement; if (parent === null) { - throw new Error('Parent element doesn\'t exist'); + throw new Error("Parent element doesn't exist"); } parent.replaceChild(newElement, oldElement); diff --git a/src/framework/view/abstract-view.js b/src/framework/view/abstract-view.js index 3e31a8b..9c14768 100644 --- a/src/framework/view/abstract-view.js +++ b/src/framework/view/abstract-view.js @@ -16,7 +16,7 @@ export default class AbstractView { constructor() { if (new.target === AbstractView) { - throw new Error('Can\'t instantiate AbstractView, only concrete one.'); + throw new Error("Can't instantiate AbstractView, only concrete one."); } } diff --git a/src/main.js b/src/main.js index 11065b1..0191072 100644 --- a/src/main.js +++ b/src/main.js @@ -1,4 +1,4 @@ -import Presenter from './presenter/presenter.js'; +import PresenterMain from './presenter/presenter-main.js'; import PointsModel from './model/points-model.js'; import FilterModel from './model/filter-model.js'; import FilterPresenter from './presenter/presenter-filter.js'; @@ -10,38 +10,35 @@ import { render } from './framework/render.js'; const filterContainer = document.querySelector('.trip-controls__filters'); const tripMainElement = document.querySelector('.trip-main'); - -const AUTHORIZATION = 'Basic hf7898sdfscv83'; +const AUTHORIZATION = 'Basic hf7898sdfscv89'; const END_POINT = 'https://23.objects.htmlacademy.pro/big-trip'; - const pointsModel = new PointsModel({ - pointsApiService: new PointsApiService(END_POINT, AUTHORIZATION) + pointsApiService: new PointsApiService(END_POINT, AUTHORIZATION), }); const filterModel = new FilterModel(); -const presenter = new Presenter({ +const presenter = new PresenterMain({ pointsModel, filterModel, - onNewPointDestroy: handleNewPointButtonClose + onNewPointDestroy: handleNewPointButtonClose, }); const filterPresenter = new FilterPresenter({ filterContainer: filterContainer, filterModel, - pointsModel + pointsModel, }); const newPointButtonComponent = new CreationForm({ - onClick: handleNewPointButtonClick + onClick: handleNewPointButtonClick, }); const presenterInfoPanel = new PresenterInfoPanel({ tripInfoContainer: tripMainElement, - pointsModel + pointsModel, }); - function handleNewPointButtonClick() { presenter.createPoint(); newPointButtonComponent.element.disabled = true; @@ -55,11 +52,9 @@ render(newPointButtonComponent, tripMainElement); newPointButtonComponent.element.disabled = true; - presenter.init(); filterPresenter.init(); -pointsModel.init() - .finally(() => { - newPointButtonComponent.element.disabled = false; - }); +pointsModel.init().finally(() => { + newPointButtonComponent.element.disabled = false; +}); presenterInfoPanel.init(); diff --git a/src/model/points-model.js b/src/model/points-model.js index b1b4d03..4e56d8b 100644 --- a/src/model/points-model.js +++ b/src/model/points-model.js @@ -40,7 +40,6 @@ export default class PointsModel extends Observable { this.#destinations = []; } - this._notify(UpdateType.INIT); } @@ -54,11 +53,7 @@ export default class PointsModel extends Observable { const response = await this.#pointsApiService.updatePoint(update); const updatedPoint = this.#adaptToClient(response); - this.#points = [ - ...this.#points.slice(0, index), - updatedPoint, - ...this.#points.slice(index + 1) - ]; + this.#points = [...this.#points.slice(0, index), updatedPoint, ...this.#points.slice(index + 1)]; this._notify(updateType, updatedPoint); } catch (err) { @@ -71,16 +66,12 @@ export default class PointsModel extends Observable { const response = await this.#pointsApiService.addPoint(update); const newPoint = this.#adaptToClient(response); - this.#points = [ - newPoint, - ...this.#points - ]; + this.#points = [newPoint, ...this.#points]; this._notify(updateType, newPoint); } catch (err) { throw new Error('Can\'t add point'); } - } async deletePoint(updateType, update) { @@ -91,10 +82,7 @@ export default class PointsModel extends Observable { try { await this.#pointsApiService.deletePoint(update); - this.#points = [ - ...this.#points.slice(0, index), - ...this.#points.slice(index + 1) - ]; + this.#points = [...this.#points.slice(0, index), ...this.#points.slice(index + 1)]; this._notify(updateType); } catch (err) { @@ -108,7 +96,7 @@ export default class PointsModel extends Observable { basePrice: point['base_price'], dateFrom: new Date(point['date_from']), dateTo: new Date(point['date_to']), - isFavorite: point['is_favorite'] + isFavorite: point['is_favorite'], }; delete adaptedPoint['base_price']; @@ -133,4 +121,3 @@ export default class PointsModel extends Observable { return this.#destinations.find((item) => item.name === name); } } - diff --git a/src/presenter/presenter-filter.js b/src/presenter/presenter-filter.js index b913f5e..d3a09c4 100644 --- a/src/presenter/presenter-filter.js +++ b/src/presenter/presenter-filter.js @@ -4,7 +4,6 @@ import { filter } from '../utils/filter.js'; import FilterView from '../view/filter-view.js'; import { UpdateType } from '../utils/const.js'; - export default class FilterPresenter { #filterContainer = null; #filterModel = null; @@ -26,20 +25,20 @@ export default class FilterPresenter { return [ { name: FilterType.EVERYTHING, - count: filter[FilterType.EVERYTHING](points).length + count: filter[FilterType.EVERYTHING](points).length, }, { name: FilterType.PAST, - count: filter[FilterType.PAST](points).length + count: filter[FilterType.PAST](points).length, }, { name: FilterType.PRESENT, - count: filter[FilterType.PRESENT](points).length + count: filter[FilterType.PRESENT](points).length, }, { name: FilterType.FUTURE, - count: filter[FilterType.FUTURE](points).length - } + count: filter[FilterType.FUTURE](points).length, + }, ]; } @@ -50,7 +49,7 @@ export default class FilterPresenter { this.#filterComponent = new FilterView({ filters, currentFilterType: this.#filterModel.filter, - onFilterChange: this.#handleFilterTypeChange + onFilterChange: this.#handleFilterTypeChange, }); if (prevFilterComponent === null) { diff --git a/src/presenter/presenter-info-panel.js b/src/presenter/presenter-info-panel.js index 8a48602..f332da6 100644 --- a/src/presenter/presenter-info-panel.js +++ b/src/presenter/presenter-info-panel.js @@ -5,7 +5,6 @@ import { sortByDay } from '../utils/sort.js'; export default class PresenterInfoPanel { #tripInfoContainer = null; #pointsModel = null; - #tripInfoComponent = null; constructor({ tripInfoContainer, pointsModel }) { diff --git a/src/presenter/presenter.js b/src/presenter/presenter-main.js similarity index 93% rename from src/presenter/presenter.js rename to src/presenter/presenter-main.js index 793ec7c..6b2dadc 100644 --- a/src/presenter/presenter.js +++ b/src/presenter/presenter-main.js @@ -1,6 +1,5 @@ import { render, RenderPosition, remove } from '../framework/render.js'; import SortPanel from '../view/sort-panel.js'; -// import TripInfo from '../view/trip-info.js'; import WaypointList from '../view/waypoint-list.js'; import PresenterWaypoint from './presenter-waypoint.js'; import ListEmpty from '../view/list-empty.js'; @@ -16,11 +15,10 @@ import ErrorView from '../view/error-view.js'; const TimeLimit = { LOWER_LIMIT: 350, - UPPER_LIMIT: 1000 + UPPER_LIMIT: 1000, }; - -export default class Presenter { +export default class PresenterMain { #sortPanel = null; #tripInfo = null; #waypointList = new WaypointList(); @@ -37,7 +35,7 @@ export default class Presenter { #loadingComponent = new LoadingView(); #uiBlocker = new UiBlocker({ lowerLimit: TimeLimit.LOWER_LIMIT, - upperLimit: TimeLimit.UPPER_LIMIT + upperLimit: TimeLimit.UPPER_LIMIT, }); #errorComponent = new ErrorView(); @@ -62,7 +60,7 @@ export default class Presenter { containerList: this.#waypointList.element, onPointChange: this.#handleViewAction, onModeChange: this.#onModeChange, - onDestroy: onNewPointDestroy + onDestroy: onNewPointDestroy, }); } @@ -81,14 +79,12 @@ export default class Presenter { return filteredPoints; } - createPoint() { this.#currentSortType = SORT_TYPE.DAY; this.#filterModel.setFilter(UpdateType.MAJOR, FilterType.EVERYTHING); this.#presenterNewPoint.init(); } - #handleViewAction = async (actionType, updateType, update) => { this.#uiBlocker.block(); @@ -102,11 +98,12 @@ export default class Presenter { } break; case UserAction.ADD_POINT: - this.#presenterNewPoint.setSaving(); try { + this.#presenterNewPoint.setSaving(); + await this.#pointsModel.addPoint(updateType, update); } catch (err) { - this.#pointPresenter.setAborting(); + this.#presenterNewPoint.setAborting(); } break; case UserAction.DELETE_POINT: @@ -120,7 +117,6 @@ export default class Presenter { } this.#uiBlocker.unblock(); - }; #handlerModelEvent = (updateType, data) => { @@ -142,7 +138,6 @@ export default class Presenter { this.#renderWaypointList(); break; } - }; #renderLoadingMessage() { @@ -175,7 +170,6 @@ export default class Presenter { render(this.#listMessageComponent, this.#tripEventsElement); } - #clearPoinsList(resetSortType = false) { this.#presenterNewPoint.destroy(); this.#pointPresenterMap.forEach((presenter) => presenter.destroy()); @@ -189,14 +183,6 @@ export default class Presenter { } } - // #renderTripInfo() { - // this.#tripInfo = new TripInfo({ - // pointsModel: this.#pointsModel - // }); - // render(this.#tripInfo, this.#tripMainElement, RenderPosition.AFTERBEGIN); - // } - - #renderWaypoints() { this.points.forEach((point) => this.#renderWaypoint(point)); } @@ -215,7 +201,6 @@ export default class Presenter { this.#pointPresenterMap.set(point.id, this.#pointPresenter); }; - #renderWaypointList = () => { render(this.#waypointList, this.#tripEventsElement); @@ -240,14 +225,12 @@ export default class Presenter { } }; - #onModeChange = () => { this.#presenterNewPoint.destroy(); this.#pointPresenterMap.forEach((presenter) => presenter.resetView()); }; init() { - // this.#renderTripInfo(); this.#renderWaypointList(); } } diff --git a/src/presenter/presenter-new-point.js b/src/presenter/presenter-new-point.js index 0f2f45d..13cfe4b 100644 --- a/src/presenter/presenter-new-point.js +++ b/src/presenter/presenter-new-point.js @@ -8,7 +8,6 @@ export default class PresenterNewPoint { #onPointChange = null; #handleDestroy = null; #pointsModel = null; - #pointEditComponent = null; constructor({ containerList, onPointChange, pointsModel, onDestroy }) { @@ -28,7 +27,7 @@ export default class PresenterNewPoint { offers: this.#pointsModel.offers, destinations: this.#pointsModel.destinations, onEditFormSave: this.#handleFormSubmit, - onDeleteForm: this.#handleFormCancelButtonClick + onDeleteForm: this.#handleFormCancelButtonClick, }); render(this.#pointEditComponent, this.#pointListContainer, RenderPosition.AFTERBEGIN); @@ -52,7 +51,7 @@ export default class PresenterNewPoint { setSaving() { this.#pointEditComponent.updateElement({ isDisabled: true, - isSaving: true + isSaving: true, }); } @@ -76,16 +75,10 @@ export default class PresenterNewPoint { }; #handleFormSubmit = (point) => { - this.#onPointChange( - UserAction.ADD_POINT, - UpdateType.MINOR, - point, - ); + this.#onPointChange(UserAction.ADD_POINT, UpdateType.MINOR, point); }; #handleFormCancelButtonClick = () => { this.destroy(); }; - - } diff --git a/src/presenter/presenter-waypoint.js b/src/presenter/presenter-waypoint.js index 6f09b79..026456c 100644 --- a/src/presenter/presenter-waypoint.js +++ b/src/presenter/presenter-waypoint.js @@ -46,7 +46,7 @@ export default class PresenterWaypoint { destinationCurrent: this.#destinationCurrent, onFavoriteClick: this.#onFavoriteClick, offerCurrent: this.#offersCurrent, - offers: this.#offers + offers: this.#offers, }); this.#eventEditView = new WaypointEdit({ @@ -57,8 +57,7 @@ export default class PresenterWaypoint { onEditFormSave: this.#onEditFormSave, offers: this.#offers, offerCurrent: this.#offersCurrent, - onDeleteForm: this.#handleEditFormDeleteButtonClick - + onDeleteForm: this.#handleEditFormDeleteButtonClick, }); if ((prevEventViewComponent === null) | (prevEventEditViewComponent === null)) { @@ -121,34 +120,22 @@ export default class PresenterWaypoint { }; #onEditFormSave = (point) => { - this.#onPointChange( - UserAction.UPDATE_POINT, - UpdateType.MINOR, - point - ); + this.#onPointChange(UserAction.UPDATE_POINT, UpdateType.MINOR, point); }; #handleEditFormDeleteButtonClick = (point) => { - this.#onPointChange( - UserAction.DELETE_POINT, - UpdateType.MINOR, - point - ); + this.#onPointChange(UserAction.DELETE_POINT, UpdateType.MINOR, point); }; #onFavoriteClick = () => { - this.#onPointChange( - UserAction.UPDATE_POINT, - UpdateType.PATCH, - { ...this.#point, isFavorite: !this.#point.isFavorite } - ); + this.#onPointChange(UserAction.UPDATE_POINT, UpdateType.PATCH, { ...this.#point, isFavorite: !this.#point.isFavorite }); }; setSaving() { if (this.#mode === Mode.EDITING) { this.#eventEditView.updateElement({ isDisabled: true, - isSaving: true + isSaving: true, }); } } @@ -157,7 +144,7 @@ export default class PresenterWaypoint { if (this.#mode === Mode.EDITING) { this.#eventEditView.updateElement({ isDisabled: true, - isDeleting: true + isDeleting: true, }); } } diff --git a/src/utils/const.js b/src/utils/const.js index 5b82484..5019c8f 100644 --- a/src/utils/const.js +++ b/src/utils/const.js @@ -1,12 +1,12 @@ export const UserAction = { UPDATE_POINT: 'UPDATE_POINT', ADD_POINT: 'ADD_POINT', - DELETE_POINT: 'DELETE_POINT' + DELETE_POINT: 'DELETE_POINT', }; export const UpdateType = { PATCH: 'PATCH', MINOR: 'MINOR', MAJOR: 'MAJOR', - INIT: 'INIT' + INIT: 'INIT', }; diff --git a/src/utils/filter.js b/src/utils/filter.js index 1bd85fa..285d666 100644 --- a/src/utils/filter.js +++ b/src/utils/filter.js @@ -8,14 +8,14 @@ const FilterType = { EVERYTHING: 'everything', FUTURE: 'future', PRESENT: 'present', - PAST: 'past' + PAST: 'past', }; const filter = { [FilterType.EVERYTHING]: (points) => points, [FilterType.FUTURE]: (points) => points.filter((point) => isFutureEvent(point.dateFrom)), [FilterType.PRESENT]: (points) => points.filter((point) => isPresentEvent(point.dateFrom, point.dateTo)), - [FilterType.PAST]: (points) => points.filter((point) => isPastEvent(point.dateTo)) + [FilterType.PAST]: (points) => points.filter((point) => isPastEvent(point.dateTo)), }; export const tripMessagesEmpty = { diff --git a/src/utils/util.js b/src/utils/util.js index 0274740..97c272f 100644 --- a/src/utils/util.js +++ b/src/utils/util.js @@ -58,7 +58,6 @@ const getDuration = (beginISO, endISO) => { const isEscapeKey = (evt) => evt.key === 'Escape'; - const PRICE_FIELD_PATTERN = /\D+/; const validatePriceField = (value) => { diff --git a/src/view/error-view.js b/src/view/error-view.js index 4056abe..5249556 100644 --- a/src/view/error-view.js +++ b/src/view/error-view.js @@ -1,9 +1,8 @@ import AbstractView from '../framework/view/abstract-view.js'; -const createErrorTemplate = () => '

    Data connection error. Please try again later.

    '; +const createErrorTemplate = () => '

    Data connection error. Please try again later. Failed to load latest route information

    '; export default class ErrorView extends AbstractView { - get template() { return createErrorTemplate(); } diff --git a/src/view/loading-view.js b/src/view/loading-view.js index df5e52c..948d613 100644 --- a/src/view/loading-view.js +++ b/src/view/loading-view.js @@ -5,9 +5,7 @@ function createLoadingTemplate() { } export default class LoadingView extends AbstractView { - get template() { return createLoadingTemplate(); } - } diff --git a/src/view/trip-info.js b/src/view/trip-info.js index 84e43e8..337ecc9 100644 --- a/src/view/trip-info.js +++ b/src/view/trip-info.js @@ -6,7 +6,6 @@ const MULTIPLE_SYMBOL = '...'; const MAX_CITIES_VISIBLE_COUNT = 3; const createTripInfoTemplate = (points, offers, destinations) => { - const createTripRouteTemplate = () => { const routeCities = []; points.forEach((point) => { @@ -43,7 +42,6 @@ const createTripInfoTemplate = (points, offers, destinations) => { }; const createTripInfoDatesTemplate = () => { - if (!points.length) { return ''; } @@ -61,7 +59,6 @@ const createTripInfoTemplate = (points, offers, destinations) => { }; const createTripTotalPriceTemplate = () => { - let totalPrice = 0; points.forEach((point) => { totalPrice += +point.basePrice; @@ -105,5 +102,4 @@ export default class TripInfoView extends AbstractView { get template() { return createTripInfoTemplate(this.#points, this.#offers, this.#destinations); } - } diff --git a/src/view/waypoint-edit.js b/src/view/waypoint-edit.js index 777c102..e7adecf 100644 --- a/src/view/waypoint-edit.js +++ b/src/view/waypoint-edit.js @@ -13,8 +13,6 @@ const DefaultPointData = { const BLANK_POINT = { basePrice: '', - dateFrom: DefaultPointData.DATE_FROM, - dateTo: DefaultPointData.DATE_TO, destination: '', isFavorite: false, offers: [], @@ -56,8 +54,8 @@ const createPointOffers = (offerCurrent, offersPoint) => {
    ${offerCurrent.offers.map((offer) => `
    - -
  • `, + ) + .join(''); }; const pointTypeList = createOffersTemplate(); @@ -89,7 +94,6 @@ export default class Waypoint extends AbstractView { this.#rollupButton.addEventListener('click', this.#onClickButtonRollupHandler); this.#favoriteButton = this.element.querySelector('.event__favorite-btn'); this.#favoriteButton.addEventListener('click', this.#onFavoriteClickHandler); - } get template() { From f24b966b5460ab96c664b1060013a95b1ad2d72d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC?= Date: Sat, 15 Jun 2024 13:01:37 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=A3=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8?= =?UTF-8?q?=D0=BB=20=D0=BE=D1=88=D0=B8=D0=B1=D0=BA=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/framework/render.js | 4 ++-- src/framework/view/abstract-view.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/framework/render.js b/src/framework/render.js index 30eae0f..64be3c7 100644 --- a/src/framework/render.js +++ b/src/framework/render.js @@ -32,7 +32,7 @@ function render(component, container, place = RenderPosition.BEFOREEND) { } if (container === null) { - throw new Error("Container element doesn't exist"); + throw new Error('Container element doesn\'t exist'); } container.insertAdjacentElement(place, component.element); @@ -54,7 +54,7 @@ function replace(newComponent, oldComponent) { const parent = oldElement.parentElement; if (parent === null) { - throw new Error("Parent element doesn't exist"); + throw new Error('Parent element doesn\'t exist'); } parent.replaceChild(newElement, oldElement); diff --git a/src/framework/view/abstract-view.js b/src/framework/view/abstract-view.js index 9c14768..3e31a8b 100644 --- a/src/framework/view/abstract-view.js +++ b/src/framework/view/abstract-view.js @@ -16,7 +16,7 @@ export default class AbstractView { constructor() { if (new.target === AbstractView) { - throw new Error("Can't instantiate AbstractView, only concrete one."); + throw new Error('Can\'t instantiate AbstractView, only concrete one.'); } }