From 91401a52940ac59474004839e36170e00e370a91 Mon Sep 17 00:00:00 2001 From: PavelUd Date: Sun, 26 May 2024 23:05:35 +0500 Subject: [PATCH] =?UTF-8?q?=D1=83=D1=80=D0=B0=20=D0=BF=D0=BE=D0=B1=D0=B5?= =?UTF-8?q?=D0=B4=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/index.html | 2 - src/const.js | 17 +++ src/main.js | 25 +++- src/mock/point.js | 2 + src/model/filter-model.js | 14 ++ src/model/point-model.js | 37 ++++- src/presenter/board-presenter.js | 142 ++++++++++++++++---- src/presenter/filter-presenter.js | 58 ++++++++ src/presenter/new-point-button-presenter.js | 27 ++++ src/presenter/new-point-presenter.js | 76 +++++++++++ src/presenter/point-presenter.js | 40 ++++-- src/presenter/sort-presenter.js | 6 +- src/service/mock-service.js | 12 ++ src/utils.js | 6 +- src/view/empty-view.js | 9 ++ src/view/filter-view.js | 29 ++-- src/view/new-point-button-view.js | 28 ++++ src/view/point-edit-view.js | 92 +++++++++---- src/view/radio-list-view.js | 1 - src/view/sort-view.js | 2 +- 20 files changed, 534 insertions(+), 91 deletions(-) create mode 100644 src/model/filter-model.js create mode 100644 src/presenter/filter-presenter.js create mode 100644 src/presenter/new-point-button-presenter.js create mode 100644 src/presenter/new-point-presenter.js create mode 100644 src/view/new-point-button-view.js diff --git a/public/index.html b/public/index.html index 44c26b4..a29324b 100644 --- a/public/index.html +++ b/public/index.html @@ -21,8 +21,6 @@

Filter events

- - diff --git a/src/const.js b/src/const.js index 4671ecc..4a52cc7 100644 --- a/src/const.js +++ b/src/const.js @@ -21,6 +21,23 @@ export const TYPES = [ 'restaurant', ]; +export const UpdateType = { + PATCH: 'PATCH', + MINOR: 'MINOR', + MAJOR: 'MAJOR' +}; + +export const EditType = { + EDITING: 'EDITING', + CREATING: 'CREATING', +}; + +export const UserAction = { + UPDATE_POINT: 'UPDATE_POINT', + ADD_POINT: 'ADD_POINT', + DELETE_POINT: 'DELETE_POINT', +}; + export const FILTER_TYPES = { EVERYTHING: 'everything', FUTURE: 'future', diff --git a/src/main.js b/src/main.js index 8d39544..e01e098 100644 --- a/src/main.js +++ b/src/main.js @@ -1,4 +1,3 @@ -import FilterView from './view/filter-view.js'; import TripInfoView from './view/trip-info-view.js'; import {render, RenderPosition} from '../src/framework/render.js'; import BoardPresenter from './presenter/board-presenter.js'; @@ -6,7 +5,9 @@ import DestinationsModel from './model/destinations-model.js'; import OffersModel from './model/offers-model.js'; import PointsModel from './model/point-model.js'; import MockService from './service/mock-service.js'; -import { generateFilter } from './mock/filter.js'; +import FilterModel from './model/filter-model.js'; +import FilterPresenter from './presenter/filter-presenter.js'; +import NewPointButtonPresenter from './presenter/new-point-button-presenter.js'; const siteMainContainer = document.querySelector('.trip-main'); @@ -17,18 +18,32 @@ const service = new MockService(); const destinationsModel = new DestinationsModel(service); const offersModel = new OffersModel(service); const pointsModel = new PointsModel(service); +const filterModel = new FilterModel(); +const newPointButtonPresenter = new NewPointButtonPresenter({ + container: tripEventsContainer +}); const boardPresenter = new BoardPresenter({ container: tripEventsContainer, destinationsModel, offersModel, - pointsModel + pointsModel, + filterModel, + newPointButtonPresenter }); -const filters = generateFilter(pointsModel.points); +const filterPresenter = new FilterPresenter({ + container: filterContainer, + pointsModel, + filterModel, +}); render(new TripInfoView(), siteMainContainer, RenderPosition.AFTERBEGIN); -render(new FilterView(filters), filterContainer); +newPointButtonPresenter.init({ + onButtonClick:boardPresenter.handleNewPointClick +}); + +filterPresenter.init(); boardPresenter.init(); diff --git a/src/mock/point.js b/src/mock/point.js index 9d686e0..36d4528 100644 --- a/src/mock/point.js +++ b/src/mock/point.js @@ -11,3 +11,5 @@ export const getRandomPoint = (type, destinationId, offerIds) => ({ offers: offerIds, type }); + + diff --git a/src/model/filter-model.js b/src/model/filter-model.js new file mode 100644 index 0000000..48ac959 --- /dev/null +++ b/src/model/filter-model.js @@ -0,0 +1,14 @@ +import Observable from '../framework/observable.js'; +import {FILTER_TYPES} from '../const.js'; + +export default class FilterModel extends Observable { + #filter = FILTER_TYPES.EVERYTHING; + get() { + return this.#filter; + } + + set(updteType, update){ + this.#filter = update; + this._notify(updteType, update); + } +} diff --git a/src/model/point-model.js b/src/model/point-model.js index afc4b43..934cd52 100644 --- a/src/model/point-model.js +++ b/src/model/point-model.js @@ -1,10 +1,39 @@ -export default class PointsModel { +import Observable from '../framework/observable'; +import { updateItem } from '../mock/util.js'; + +export default class PointsModel extends Observable { + #points; + #service; + constructor(service) { - this.service = service; - this.points = this.service.getPoints(); + super(); + this.#service = service; + this.#points = this.#service.getPoints(); } getAll() { - return this.points; + return this.#points; + } + + getById(id) { + return this.#points.find((point) => point.id === id); + } + + add(type, point) { + const newPoint = this.#service.addPoint(point); + this.#points.push(newPoint); + this._notify(type, newPoint); + } + + update(type, point) { + const updatedPoint = this.#service.updatePoint(point); + this.#points = updateItem(this.#points, updatedPoint); + this._notify(type, updatedPoint); + } + + delete(type, deletedPoint) { + this.#service.deletePoint(deletedPoint); + this.#points = this.#points.filter((point) => point.id !== deletedPoint.id); + this._notify(type); } } diff --git a/src/presenter/board-presenter.js b/src/presenter/board-presenter.js index 06ebad2..d8a5b87 100644 --- a/src/presenter/board-presenter.js +++ b/src/presenter/board-presenter.js @@ -1,43 +1,96 @@ import EventListView from '../view/event-list-view'; import EmptyView from '../view/empty-view'; import PointPresenter from './point-presenter'; +import NewPointPresenter from './new-point-presenter'; import SortPresenter from './sort-presenter'; -import {render} from '../framework/render'; -import { updateItem } from '../mock/util'; -import { sort } from '../utils'; +import {remove, render} from '../framework/render'; +import { filter, sort } from '../utils'; +import {FILTER_TYPES, POINT_SORTS, UpdateType, UserAction} from '../const.js'; export default class BoardPresenter { #sortPresenter = null; - #eventListComponent = new EventListView(); + #emptyListElement = null; + #eventListElement = new EventListView(); #pointPresenters = new Map(); #destinationsModel; #offersModel; - #points = []; + #filterModel; + #pointsModel; + #newPointButtonPresenter; + #currentSortType = POINT_SORTS.DAY; + #isCreating = false; + #container; + #newPointPresenter; - constructor({container, destinationsModel, offersModel, pointsModel}) { - this.container = container; + constructor({container, destinationsModel, offersModel, pointsModel, filterModel, newPointButtonPresenter}) { + this.#container = container; this.#destinationsModel = destinationsModel; this.#offersModel = offersModel; - this.pointsModel = pointsModel; - this.#points = sort([...pointsModel.getAll()]); + this.#pointsModel = pointsModel; + this.#filterModel = filterModel; + this.#newPointButtonPresenter = newPointButtonPresenter; + + this.#newPointPresenter = new NewPointPresenter({ + container: this.#eventListElement.element, + destinationsModel: this.#destinationsModel, + offersModel: this.#offersModel, + onDataChange: this.#onPointChangeHandler, + onDestroy: this.#handleNewPointDestroy + }); + + this.#pointsModel.addObserver(this.#modelEventHandler); + this.#filterModel.addObserver(this.#modelEventHandler); + } + + get points() { + const filterType = this.#filterModel.get(); + const filteredPoints = filter[filterType](this.#pointsModel.getAll()); + + return sort(filteredPoints, this.#currentSortType); } init(){ + this.#renderBoard(); + } + + #renderBoard = () =>{ + if (!this.points.length && !this.#isCreating) { + this.#renderEmptyList(); + return; + } + this.#renderSort(); - render(this.#eventListComponent, this.container); + render(this.#eventListElement, this.#container); this.#renderPointList(); - if (this.#points.length === 0){ - render(new EmptyView(), this.container); + }; + + #renderEmptyList = () => { + this.#emptyListElement = new EmptyView({ + filterType: this.#filterModel.get(), + }); + render(this.#emptyListElement, this.#container); + }; + + #clearBoard = ({resetSortType = false} = {}) => { + this.#clearTaskList(); + remove(this.#emptyListElement); + if (this.#sortPresenter) { + this.#sortPresenter.destroy(); + this.#sortPresenter = null; } - } + + if (resetSortType) { + this.#currentSortType = POINT_SORTS.DAY; + } + }; #renderPointList = () =>{ - this.#points.forEach((point) => this.#renderPoint(point)); + this.points.forEach((point) => this.#renderPoint(point)); }; #renderSort = () =>{ this.#sortPresenter = new SortPresenter({ - container: this.container, + container: this.#container, handleSortChange: this.#handleSortChange, }); this.#sortPresenter.init(); @@ -45,24 +98,28 @@ export default class BoardPresenter { #renderPoint(point){ const pointPresenter = new PointPresenter({ - container: this.#eventListComponent.element, + container: this.#eventListElement.element, destinationsModel: this.#destinationsModel, offersModel: this.#offersModel, onPointsChange: this.#onPointChangeHandler, - handleModeChange: this.#handleModeChange + handleModeChange: this.#modelEventHandler }); pointPresenter.init(point); this.#pointPresenters.set(point.id, pointPresenter); } - - #onPointChangeHandler = (changedPoint) => { - this.#points = updateItem(this.#points, changedPoint); - this.#pointPresenters.get(changedPoint.id).init(changedPoint); - }; - - #handleModeChange = () => { - this.#pointPresenters.forEach((presenter) => presenter.resetView()); + #onPointChangeHandler = (action, updateType, point) => { + switch (action) { + case UserAction.ADD_POINT: + this.#pointsModel.add(updateType, point); + break; + case UserAction.UPDATE_POINT: + this.#pointsModel.update(updateType, point); + break; + case UserAction.DELETE_POINT: + this.#pointsModel.delete(updateType, point); + break; + } }; #clearTaskList = () => { @@ -71,8 +128,41 @@ export default class BoardPresenter { }; #handleSortChange = (sortType) => { - this.#points = sort(this.#points, sortType); + this.#currentSortType = sortType; this.#clearTaskList(); this.#renderPointList(); }; + + #modelEventHandler = (updateType, data) => { + switch (updateType) { + case UpdateType.PATCH: + this.#pointPresenters.get(data.id).init(data); + break; + case UpdateType.MINOR: + this.#clearBoard(); + this.#renderBoard(); + break; + case UpdateType.MAJOR: + this.#clearBoard(); + this.#renderBoard({resetSortType: true}); + break; + } + }; + + handleNewPointClick = () => { + this.#isCreating = true; + this.#currentSortType = POINT_SORTS.DAY; + this.#filterModel.set(UpdateType.MAJOR, FILTER_TYPES.EVERYTHING); + this.#newPointButtonPresenter.disableButton(); + this.#newPointPresenter.init(); + }; + + #handleNewPointDestroy = ({isCanceled}) => { + this.#isCreating = false; + this.#newPointButtonPresenter.enableButton(); + if (!this.points.length && isCanceled) { + this.#clearBoard(); + this.#renderBoard(); + } + }; } diff --git a/src/presenter/filter-presenter.js b/src/presenter/filter-presenter.js new file mode 100644 index 0000000..43c7509 --- /dev/null +++ b/src/presenter/filter-presenter.js @@ -0,0 +1,58 @@ +import { UpdateType } from '../const'; +import { render, replace, remove } from '../framework/render'; +import { filter } from '../utils'; +import FilterView from '../view/filter-view'; + +export default class FilterPresenter { + #filterElement = null; + #container = null; + #pointsModel = null; + #filterModel = null; + #currentFilter = null; + + constructor({ container, pointsModel, filterModel }) { + this.#container = container; + this.#pointsModel = pointsModel; + this.#filterModel = filterModel; + + this.#pointsModel.addObserver(this.#handleModelChange); + this.#filterModel.addObserver(this.#handleModelChange); + } + + get filters() { + const points = this.#pointsModel.getAll(); + return Object.entries(filter) + .map(([filterType, filterPoints]) => ({ + type: filterType, + isDisabled: filterPoints(points).length === 0, + isChecked: filterType === this.#currentFilter, + })); + } + + init() { + this.#currentFilter = this.#filterModel.get(); + const prevFilterElement = this.#filterElement; + + const filters = this.filters; + this.#filterElement = new FilterView({ + items: filters, + onItemChange: this.#onChangeFilter, + }); + + if (!prevFilterElement) { + render(this.#filterElement, this.#container); + return; + } + + replace(this.#filterElement, prevFilterElement); + remove(prevFilterElement); + } + + #onChangeFilter = (filterType) => { + this.#filterModel.set(UpdateType.MAJOR, filterType); + }; + + #handleModelChange = () => { + this.init(); + }; +} diff --git a/src/presenter/new-point-button-presenter.js b/src/presenter/new-point-button-presenter.js new file mode 100644 index 0000000..b34f628 --- /dev/null +++ b/src/presenter/new-point-button-presenter.js @@ -0,0 +1,27 @@ +import {render} from '../framework/render.js'; +import NewPointButtonView from '../view/new-point-button-view.js'; + +export default class NewPointButtonPresenter { + + #container; + #button; + #onButtonClick; + + constructor({container}){ + this.#container = container; + } + + init({onButtonClick}){ + this.#onButtonClick = onButtonClick; + this.#button = new NewPointButtonView({onClick: this.#onButtonClick}); + render(this.#button, this.#container); + } + + enableButton() { + this.#button.setDisabled(false); + } + + disableButton() { + this.#button.setDisabled(true); + } +} diff --git a/src/presenter/new-point-presenter.js b/src/presenter/new-point-presenter.js new file mode 100644 index 0000000..889a32c --- /dev/null +++ b/src/presenter/new-point-presenter.js @@ -0,0 +1,76 @@ +import { remove, render, RenderPosition } from '../framework/render.js'; +import { UserAction, UpdateType, EditType } from '../const.js'; +import PointEditView from '../view/point-edit-view'; + +export default class NewPointPresenter { + #container; + + #destinationsModel; + #offersModel; + + #handleDataChange; + #handleDestroy; + + #newPointElement = null; + constructor({ + container, + destinationsModel, + offersModel, + onDataChange, + onDestroy, + }) { + this.#container = container; + this.#destinationsModel = destinationsModel; + this.#offersModel = offersModel; + this.#handleDataChange = onDataChange; + this.#handleDestroy = onDestroy; + } + + init() { + if (this.#newPointElement !== null) { + return; + } + this.#newPointElement = new PointEditView({ + destinations: this.#destinationsModel.getAll(), + offers: this.#offersModel.getAll(), + onSubmiClick: this.#onSubmitForm, + onCloseEditPoint: this.#onCloseForm, + pointType: EditType.CREATING + }); + + render(this.#newPointElement, this.#container, RenderPosition.AFTERBEGIN); + document.addEventListener('keydown', this.#onEscKeydownDocument); + } + + destroy = ({ isCanceled = true } = {}) => { + if (!this.#newPointElement) { + return; + } + remove(this.#newPointElement); + this.#newPointElement = null; + document.removeEventListener('keydown', this.#onEscKeydownDocument); + + this.#handleDestroy({ isCanceled }); + }; + + #onSubmitForm = (point) => { + this.#handleDataChange( + UserAction.ADD_POINT, + UpdateType.MINOR, + point + ); + + this.destroy({ isCanceled: false }); + }; + + #onCloseForm = () => { + this.destroy(); + }; + + #onEscKeydownDocument = (evt) => { + if (evt.keyCode === 27 || evt.key === 'Escape') { + evt.preventDefault(); + this.destroy(); + } + }; +} diff --git a/src/presenter/point-presenter.js b/src/presenter/point-presenter.js index 9cf4ab0..48e59f3 100644 --- a/src/presenter/point-presenter.js +++ b/src/presenter/point-presenter.js @@ -1,7 +1,9 @@ import PointEditView from '../view/point-edit-view'; import PointView from '../view/point-view'; import {render,replace,remove } from '../framework/render'; -import { Mode } from '../const'; +import { Mode, EditType } from '../const'; +import { isBigDifference } from '../utils.js'; +import {UpdateType, UserAction} from '../const.js'; export default class PointPresenter { @@ -50,7 +52,9 @@ export default class PointPresenter { destinations: this.#destinationsModel.getAll(), offers: this.#offersModel.getAll(), onCloseEditPoint: this.#onCloseEditClick, - onSubmiClick: this.#onSubmiClick, + onSubmiClick: this.#formSubmitHandler, + onDeleteClick: this.#onEditPointDelete, + pointType: EditType.EDITING }); if(!prevEditPointElement || !prevPointElement){ @@ -67,8 +71,6 @@ export default class PointPresenter { #onEditClick = () => this.#replaceToForm(); - #onSubmiClick = () => this.#replaceToPoint(); - #onCloseEditClick = () => this.#replaceToPoint(); #escKeydown = (evt) => { @@ -104,9 +106,31 @@ export default class PointPresenter { }; #favoriteClickHandler = () =>{ - this.#onPointsChangeHandler({ - ...this.#point, - isFavorite: !this.#point.isFavorite - }); + this.#onPointsChangeHandler( + UserAction.UPDATE_POINT, + UpdateType.PATCH, + { + ...this.#point, + isFavorite: !this.#point.isFavorite + }); + }; + + #formSubmitHandler = (point) => { + const isMinor = isBigDifference(point, this.#point); + this.#onPointsChangeHandler( + UserAction.UPDATE_POINT, + isMinor ? UpdateType.MINOR : UpdateType.PATCH, + point + ); + this.#replaceToPoint(); + }; + + #onEditPointDelete = (point) =>{ + + this.#onPointsChangeHandler( + UserAction.DELETE_POINT, + UpdateType.MINOR, + point + ); }; } diff --git a/src/presenter/sort-presenter.js b/src/presenter/sort-presenter.js index b718109..6cacb2d 100644 --- a/src/presenter/sort-presenter.js +++ b/src/presenter/sort-presenter.js @@ -1,5 +1,5 @@ import { EnabledSortType, POINT_SORTS } from '../const'; -import { render } from '../framework/render'; +import { render, remove } from '../framework/render'; import SortView from '../view/sort-view'; export default class SortPresenter { @@ -14,6 +14,10 @@ export default class SortPresenter { this.#handleSortChange = handleSortChange; } + destroy() { + remove(this.#sortElement); + } + init() { const items = Object.values(POINT_SORTS).map((sort) => ({ type: sort, diff --git a/src/service/mock-service.js b/src/service/mock-service.js index 7c1864d..30a5508 100644 --- a/src/service/mock-service.js +++ b/src/service/mock-service.js @@ -56,4 +56,16 @@ export default class MockService { }); } + + updatePoint(updatedPoint){ + return updatedPoint; + } + + addPoint(data){ + return {...data, id: crypto.randomUUID()}; + } + + deletePoint(){ + // + } } diff --git a/src/utils.js b/src/utils.js index adf46ed..aa5123f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -39,10 +39,14 @@ export const getPointDuration = (point) => { }}; +export const isBigDifference = (pointA, pointB) => + pointA.dateFrom !== pointB.dateFrom || + pointA.basePrice !== pointB.basePrice || + getPointDuration(pointA.dateFrom, pointA.dateTo) !== getPointDuration(pointB.dateFrom, pointB.dateTo); export const getDateDiff = (pointA, pointB) => dayjs(pointA.dateFrom).diff(dayjs(pointB.dateFrom)); -export const getPriceDiff = (pointA, pointB) => pointB.basePrice - pointA.basePrice; +export const getPriceDiff = (pointA, pointB) => pointA.basePrice - pointB.basePrice; export const getDurationDiff = (pointA, pointB) => dayjs(pointB.dateTo).diff(dayjs(pointB.dateFrom)) - dayjs(pointA.dateTo).diff(dayjs(pointA.dateFrom)); diff --git a/src/view/empty-view.js b/src/view/empty-view.js index de7f788..ec73d63 100644 --- a/src/view/empty-view.js +++ b/src/view/empty-view.js @@ -1,10 +1,19 @@ import AbstractView from '../framework/view/abstract-view'; + function createEmptyTemplate(){ return '

Click New Event to create your first point

'; } export default class EmptyView extends AbstractView{ + + #filterType = null; + + constructor({filterType}) { + super(); + this.#filterType = filterType; + } + get template(){ return createEmptyTemplate(); } diff --git a/src/view/filter-view.js b/src/view/filter-view.js index ecf9ddd..651f2f5 100644 --- a/src/view/filter-view.js +++ b/src/view/filter-view.js @@ -1,36 +1,27 @@ -import AbstractView from '../framework/view/abstract-view.js'; +import AbstractRadioListView from './radio-list-view.js'; -const createFilterTemplate = (filter, isChecked) => { - const {name, count} = filter; +const createFilterTemplate = (filter) => { + const {type, isDisabled, isChecked} = filter; return `
- - + +
`; }; -const createFiltersTemplate = (filters) =>{ - +const createFiltersTemplate = ({filters}) =>{ let filtersTemplate = '
'; - - filters.forEach((filter, i) => { - filtersTemplate += createFilterTemplate(filter, i === 0); + filters.forEach((filter) => { + filtersTemplate += createFilterTemplate(filter); }); filtersTemplate += '
'; return filtersTemplate; }; -export default class FilterView extends AbstractView{ - - #filters = null; - - constructor(filters) { - super(); - this.#filters = filters; - } +export default class FilterView extends AbstractRadioListView{ get template() { - return createFiltersTemplate(this.#filters); + return createFiltersTemplate({filters: this.items}); } } diff --git a/src/view/new-point-button-view.js b/src/view/new-point-button-view.js new file mode 100644 index 0000000..ac3dfe0 --- /dev/null +++ b/src/view/new-point-button-view.js @@ -0,0 +1,28 @@ +import AbstractView from '../framework/view/abstract-view'; + +const createNewPointButtonTemplate = () => ` + +`; + +export default class NewPointButtonView extends AbstractView { + #handleClick = null; + + constructor({ onClick }) { + super(); + this.#handleClick = onClick; + this.element.addEventListener('click', this.#clickHandler); + } + + get template() { + return createNewPointButtonTemplate(); + } + + setDisabled = (isDisabled) => { + this.element.disabled = isDisabled; + }; + + #clickHandler = (evt) => { + evt.preventDefault(); + this.#handleClick(); + }; +} diff --git a/src/view/point-edit-view.js b/src/view/point-edit-view.js index bee48d9..48560b9 100644 --- a/src/view/point-edit-view.js +++ b/src/view/point-edit-view.js @@ -1,8 +1,10 @@ -import { POINT_EMPTY, TYPES } from '../const.js'; +import { POINT_EMPTY, TYPES,EditType } from '../const.js'; import AbstractStatefulView from '../framework/view/abstract-stateful-view.js'; import {formatToSlashDate} from '../utils.js'; import CalendarView from './calendar-view.js'; +const DEFAULT_TYPE = 'flight'; + function createTypesElements(typeArray){ let typesElements = ''; @@ -19,7 +21,7 @@ function createTypesElements(typeArray){ function createDestinationPhotos(pointDestination){ let photos = '
'; - pointDestination.pictures.forEach((picture) =>{ + pointDestination?.pictures.forEach((picture) =>{ photos += `${picture.description}`; }); return `${photos}
`; @@ -39,7 +41,7 @@ function createOfferSelector(pointOffers, offersArray){

Offers

`; - offersArray.forEach((offer) => { + offersArray?.forEach((offer) => { const checked = pointOffers.some((offerId) => offerId === offer.id) ? 'checked' : ''; offersElements += `
@@ -55,12 +57,36 @@ function createOfferSelector(pointOffers, offersArray){ return offersElements; } +function createSaveButton() { + return ''; +} -function createPointEditElement({point, destinations, offers}) { +function createDeleteButton({type}){ + const label = type === EditType.CREATING ? 'Cancel' : 'Delete'; + return ``; +} + +function createRollupButton(){ + return ``; +} + +function createPointControls({type}){ + return `${createSaveButton()} + ${createDeleteButton({type})} + ${type === EditType.CREATING ? '' : createRollupButton()}`; +} + +function createPointEditElement({point, destinations, offers, pointType}) { const pointDestination = destinations.find((destination) => destination.id === point.destination); - const pointOffers = offers.find((subOffers) => subOffers.type === point.type).offers; + const pointOffers = offers.find((subOffers) => subOffers.type === point.type)?.offers; - const {basePrice, dateFrom, dateTo, type} = point; + const name = pointType === EditType.CREATING ? '' : pointDestination.name; + const {basePrice} = point; + const type = pointType === EditType.CREATING ? DEFAULT_TYPE : point.type; + const dateFrom = pointType === EditType.CREATING ? '' : formatToSlashDate(point.dateFrom); + const dateTo = pointType === EditType.CREATING ? '' : formatToSlashDate(point.dateTo); return `
  • @@ -85,16 +111,16 @@ function createPointEditElement({point, destinations, offers}) { - + ${createDestinationList(destinations)}
  • - + - +
    @@ -102,21 +128,17 @@ function createPointEditElement({point, destinations, offers}) { Price € - +
    - - - + ${createPointControls({type : pointType})}
    - ${createOfferSelector(point.offers, pointOffers)} + ${createOfferSelector(point?.offers, pointOffers)}

    Destination

    -

    ${pointDestination.description}

    +

    ${pointType === EditType.CREATING ? '' : pointDestination.description}

    ${createDestinationPhotos(pointDestination)}
    @@ -134,22 +156,24 @@ export default class EditPointView extends AbstractStatefulView{ #onSubmiClick; #datepickerFrom; #datepickerTo; + #onDeleteClick; + #pointType; - constructor({point = POINT_EMPTY, destinations, offers, onCloseEditPoint, onSubmiClick}) { + constructor({point = POINT_EMPTY, destinations, offers, onCloseEditPoint, onSubmiClick, onDeleteClick, pointType = EditType.EDITING}) { super(); this.#destinations = destinations; + this.onDeleteClick = onDeleteClick; this.#offers = offers; this.#onCloseEditPoint = onCloseEditPoint; this.#onSubmiClick = onSubmiClick; + this.#onDeleteClick = onDeleteClick; + this.#pointType = pointType; this._setState(EditPointView.parsePointToState({point})); this.#submitEditPoint(); this._restoreHandlers(); } _restoreHandlers = () =>{ - this.element - .querySelector('.event__rollup-btn') - .addEventListener('click', this.#closeEditPointHandler); this.element .querySelector('.event__input--destination') @@ -167,6 +191,22 @@ export default class EditPointView extends AbstractStatefulView{ .querySelector('.event__type-group') .addEventListener('change', this.#typeChangeHandler); + + if (this.#pointType === EditType.EDITING) { + this.element + .querySelector('.event__rollup-btn') + .addEventListener('click', this.#closeEditPointHandler); + + this.element + .querySelector('.event__reset-btn') + .addEventListener('click', this.#deleteClickHandler); + } + + if (this.#pointType === EditType.CREATING) { + this.element + .querySelector('.event__reset-btn') + .addEventListener('click', this.#closeEditPointHandler); + } this.#setDatapickers(); }; @@ -174,7 +214,8 @@ export default class EditPointView extends AbstractStatefulView{ return createPointEditElement({ point: this._state.point, destinations: this.#destinations, - offers: this.#offers + offers: this.#offers, + pointType: this.#pointType, }); } @@ -251,7 +292,7 @@ export default class EditPointView extends AbstractStatefulView{ #submiClickHandler = (evt) => { evt.preventDefault(); - this.#onSubmiClick(); + this.#onSubmiClick(EditPointView.parseStateToPoint(this._state)); }; #setDatapickers = () =>{ @@ -293,6 +334,11 @@ export default class EditPointView extends AbstractStatefulView{ this.#datepickerTo.set('minDate', this._state.point.dateTo); }; + #deleteClickHandler = (evt) => { + evt.preventDefault(); + this.#onDeleteClick(EditPointView.parseStateToPoint(this._state)); + }; + static parsePointToState = ({ point }) => ({ point }); static parseStateToPoint = (state) => state.point; } diff --git a/src/view/radio-list-view.js b/src/view/radio-list-view.js index 92baa3d..baf6edf 100644 --- a/src/view/radio-list-view.js +++ b/src/view/radio-list-view.js @@ -7,7 +7,6 @@ export default class RadioListView extends AbstractView{ constructor({items, onItemChange}){ super(); - this.#handleItemChange = onItemChange; this.items = items; this.element.addEventListener('change', this.#itemChangeHandler); diff --git a/src/view/sort-view.js b/src/view/sort-view.js index 4bdf087..89890a5 100644 --- a/src/view/sort-view.js +++ b/src/view/sort-view.js @@ -5,7 +5,7 @@ function createSortElement({ sorts }) { sorts.forEach((sort) => { text += `
    + ${sort.isChecked ? 'checked' : ''}>
    `; });