diff --git a/src/const.js b/src/const.js index 2020d90..9a58917 100644 --- a/src/const.js +++ b/src/const.js @@ -3,11 +3,11 @@ const WAYPOINTS_COUNT = 3; const PRICES = [100, 150, 200]; const DATES = [ - {from: '2019-05-24T23:55:43.845Z', to: '2019-05-24T09:13:25.845Z'}, - {from: '2020-09-05T13:34:15.845Z', to: '2020-09-05T22:05:34.845Z'}, - {from: '2021-03-12T10:21:12.845Z', to: '2021-03-12T12:18:24.845Z'}, + {from: '2024-01-24T23:55:43.845Z', to: '2024-03-24T09:13:25.845Z'}, + {from: '2024-04-05T13:34:15.845Z', to: '2024-06-05T22:05:34.845Z'}, + {from: '2025-03-12T10:21:12.845Z', to: '2025-03-12T12:18:24.845Z'}, {from: '2022-01-31T19:54:08.845Z', to: '2022-01-31T21:45:19.845Z'}, - {from: '2023-06-17T16:15:14.845Z', to: '2023-06-19T02:06:08.845Z'} + {from: '2025-06-17T16:15:14.845Z', to: '2025-06-19T02:06:08.845Z'} ]; const DESTINATIONS = [ @@ -91,6 +91,18 @@ const EDITING_FORM = { offers: [ '1', '2' ], }; +const ACTIONS = { + UPDATE_POINT: 'update', + ADD_POINT: 'add', + DELETE_POINT: 'delete', +}; + +const UPDATE_TYPE = { + MINOR: 'MINOR', + MAJOR: 'MAJOR', +}; + + const DATE_FORMAT_EDIT = 'DD/MM/YY hh:mm'; const DATE_FORMAT_DAY = 'MMM DD'; const DATE_FORMAT_HOURS = 'hh:mm'; @@ -116,4 +128,4 @@ export { DESTINATIONS }; export { OFFERS }; export { DATE_FORMAT_EDIT, DATE_FORMAT_DAY, DATE_FORMAT_HOURS }; export { EDITING_FORM }; -export { FILTER_TYPE, SORTING_TYPES }; +export { FILTER_TYPE, SORTING_TYPES, ACTIONS, UPDATE_TYPE }; diff --git a/src/main.js b/src/main.js index 194b2a0..0c3f0b9 100644 --- a/src/main.js +++ b/src/main.js @@ -1,10 +1,12 @@ -import { render, RenderPosition } from './framework/render.js'; -import FilterView from './view/filter-view.js'; +import {render, RenderPosition} from './framework/render.js'; import InfoView from './view/info-view.js'; import EventPresenter from './presenter/event-presenter.js'; import WaypointsModel from './model/waypoint-model.js'; -import { getMockFilters } from './mock/filter.js'; -import { getMockSorts } from './mock/sort.js'; +import {getMockFilters} from './mock/filter.js'; +import {getMockSorts} from './mock/sort.js'; +import FilterPresenter from './presenter/filter-presenter'; +import FilterModel from './model/filter-model'; +import NewPointButtonView from './view/new-point-button-view'; const mainContainer = document.querySelector('.trip-main'); const filterContainer = document.querySelector('.trip-controls__filters'); @@ -13,10 +15,42 @@ const eventContainer = document.querySelector('.trip-events'); const mockFilters = getMockFilters(); const mockSorts = getMockSorts(); + const waypointsModel = new WaypointsModel(); -const eventPresenter = new EventPresenter({eventContainer, waypointsModel, sorts: mockSorts}); +const filterModel = new FilterModel(); + +const filterPresenter = new FilterPresenter({ + filterContainer, + filterModel, + filters: mockFilters +}); + +const newPointButtonComponent = new NewPointButtonView({ + onClick: handleNewPointButtonClick +}); + +function handleNewPointFormClose() { + newPointButtonComponent.element.disabled = false; +} + +const eventPresenter = new EventPresenter({ + eventContainer, + waypointsModel, + filterModel, + sorts: mockSorts, + filters: mockFilters, + onNewPointDestroy: handleNewPointFormClose +}); + + +function handleNewPointButtonClick() { + eventPresenter.createWaypoint(); + newPointButtonComponent.element.disabled = true; +} + render(new InfoView(), mainContainer, RenderPosition.AFTERBEGIN); -render(new FilterView({filters: mockFilters}), filterContainer); +render(newPointButtonComponent, mainContainer, RenderPosition.BEFOREEND); +filterPresenter.init(); eventPresenter.init(); diff --git a/src/mock/waypoint.js b/src/mock/waypoint.js index 006a405..9a640fb 100644 --- a/src/mock/waypoint.js +++ b/src/mock/waypoint.js @@ -1,5 +1,5 @@ import {BOOL, DATES, OFFERS, PRICES, TYPES} from '../const.js'; -import {getRandomArrayElement, getRandomArrayElements, getRandomInt} from '../utils.js'; +import {getId, getRandomArrayElement, getRandomArrayElements, getRandomInt} from '../utils.js'; function getMockWaypoint() { const type = getRandomArrayElement(TYPES); @@ -25,7 +25,7 @@ const mockWaypoints = [ function getRandomWaypoint() { return { ...getRandomArrayElement(mockWaypoints), - id: Date.now().toString(36) + Math.random().toString(36).slice(2) + id: getId() }; } diff --git a/src/model/filter-model.js b/src/model/filter-model.js new file mode 100644 index 0000000..3dc8fb2 --- /dev/null +++ b/src/model/filter-model.js @@ -0,0 +1,16 @@ +import {FILTER_TYPE, UPDATE_TYPE} from '../const'; +import Observable from '../framework/observable.js'; + + +export default class FilterModel extends Observable { + #filter = FILTER_TYPE.EVERYTHING; + + get filter() { + return this.#filter; + } + + setFilter(filter) { + this.#filter = filter; + this._notify(UPDATE_TYPE.MAJOR, filter); + } +} diff --git a/src/model/waypoint-model.js b/src/model/waypoint-model.js index 7056b11..509553d 100644 --- a/src/model/waypoint-model.js +++ b/src/model/waypoint-model.js @@ -1,10 +1,62 @@ -import { getRandomWaypoint } from '../mock/waypoint.js'; -import { WAYPOINTS_COUNT } from '../const.js'; +import {getRandomWaypoint} from '../mock/waypoint.js'; +import {UPDATE_TYPE, WAYPOINTS_COUNT} from '../const.js'; +import Observable from '../framework/observable'; -export default class WaypointsModel { +export default class WaypointsModel extends Observable { waypoints = Array.from({length: WAYPOINTS_COUNT}, getRandomWaypoint); getWaypoints() { return this.waypoints; } + + getWaypoint(id) { + return this.waypoints.find((waypoint) => waypoint.id === id); + } + + setWaypoints(waypoints) { + this.waypoints = waypoints; + } + + setWaypoint(waypoint, id) { + this.waypoints = [...this.waypoints.filter((other) => other.id !== id), waypoint]; + } + + addPoint(updateType, update) { + this.waypoints = [ + update, + ...this.waypoints, + ]; + this._notify(updateType, update); + } + + updatePoint(updateType, update) { + const index = this.waypoints.findIndex((point) => point.id === update.id); + + if (index === -1) { + throw new Error('The point doesn\'t exist!'); + } + + this.waypoints = [ + ...this.waypoints.slice(0, index), + update, + ...this.waypoints.slice(index + 1), + ]; + + this._notify(updateType, update); + } + + deletePoint(updateType, update) { + const index = this.waypoints.findIndex((point) => point.id === update.id); + + if (index === -1) { + throw new Error('The point doesn\'t exist!'); + } + + this.waypoints = [ + ...this.waypoints.slice(0, index), + ...this.waypoints.slice(index + 1), + ]; + + this._notify(UPDATE_TYPE.MINOR, update); + } } diff --git a/src/presenter/event-presenter.js b/src/presenter/event-presenter.js index 817e7b2..e9fb80c 100644 --- a/src/presenter/event-presenter.js +++ b/src/presenter/event-presenter.js @@ -1,44 +1,97 @@ -import {render} from '../framework/render.js'; +import {remove, render, RenderPosition} from '../framework/render.js'; import SortView from '../view/sort-view.js'; import EventListView from '../view/event-list-view.js'; import WaypointPresenter from './waypoint-presenter'; +import {ACTIONS as USER_ACTION, SORTING_TYPES, UPDATE_TYPE} from '../const'; +import NewWaypointPresenter from './new-waypoint-presenter'; export default class EventPresenter { #eventListContainer = new EventListView(); #waypointPresenters = []; #eventContainer; #sorts; + #filters; #currentSortType; + #emptyComponent; + #filterModel; + #newPointPresenter; + #onNewPointDestroy; - constructor({eventContainer, waypointsModel, sorts}) { + constructor({eventContainer, waypointsModel, filterModel, sorts, filters, onNewPointDestroy}) { this.#eventContainer = eventContainer; this.#sorts = sorts; - this.waypoints = waypointsModel.getWaypoints(); + this.#filters = filters; + this.waypointsModel = waypointsModel; + this.#filterModel = filterModel; + this.#onNewPointDestroy = onNewPointDestroy; this.#currentSortType = sorts[0].name; this.#sortWaypoints(sorts[0].name); } init() { - render(new SortView({sorts: this.#sorts, onChange: this.#handleSortTypeChange}), this.#eventContainer); + render( + new SortView({sorts: this.#sorts, currentSort: this.#currentSortType, onChange: this.#handleSortTypeChange}), + this.#eventContainer, + RenderPosition.BEFOREEND + ); + this.renderWaypoints(); + this.#filterModel.addObserver(this.#handleFilterTypeChange.bind(this)); + this.waypointsModel.addObserver(this.#handleModelEvent); + } + + createWaypoint() { + this.#newPointPresenter = new NewWaypointPresenter({ + pointListContainer: this.#eventListContainer.element, + onDataChange: this.#handleWaypointChange, + onDestroy: this.#onNewPointDestroy, + closeAllEditForms: () => this.#closeAllEditForms(), + }); + + this.#newPointPresenter.init(); + } + + renderWaypoints() { render(this.#eventListContainer, this.#eventContainer); - this.waypoints.forEach((waypoint) => this.#renderWaypoint(waypoint)); + const filteredPoints = this.#getFilteredWaypoints(this.waypointsModel.getWaypoints()); + filteredPoints.forEach((waypoint) => this.#renderWaypoint(waypoint)); + } + + reset() { + this.#waypointPresenters.forEach((waypointPresenter) => waypointPresenter.destroy()); + this.#waypointPresenters = []; + + if (this.#emptyComponent) { + remove(this.#emptyComponent); + } } #closeAllEditForms() { + if (this.#newPointPresenter) { + this.#newPointPresenter.destroy(); + } + this.#waypointPresenters.forEach((waypoint) => waypoint.closeForm()); } - #handleWaypointChange = (updatedWaypoint) => { - this.waypoints = this.waypoints.map((waypoint) => waypoint.id === updatedWaypoint.id ? updatedWaypoint : waypoint); - this.#waypointPresenters - .find((waypointPresenter) => waypointPresenter.id === updatedWaypoint.id) - .init(updatedWaypoint); + #handleWaypointChange = (action, type, waypoint) => { + switch (action) { + case USER_ACTION.ADD_POINT: + this.#sortWaypoints(SORTING_TYPES.DAY); + this.waypointsModel.addPoint(type, waypoint); + break; + case USER_ACTION.DELETE_POINT: + this.waypointsModel.deletePoint(type, waypoint); + break; + case USER_ACTION.UPDATE_POINT: + this.waypointsModel.updatePoint(type, waypoint); + break; + } }; #renderWaypoint(waypoint) { const waypointPresenter = new WaypointPresenter({ waypoint, - containerElement: this.#eventContainer, + containerElement: this.#eventListContainer.element, closeAllEditForms: () => this.#closeAllEditForms(), onChange: this.#handleWaypointChange }); @@ -52,16 +105,40 @@ export default class EventPresenter { } this.#sortWaypoints(sortType); this.#deleteWaypoints(); - this.waypoints.forEach((waypoint) => this.#renderWaypoint(waypoint)); + this.waypointsModel.getWaypoints().forEach((waypoint) => this.#renderWaypoint(waypoint)); }; #sortWaypoints(sortType) { - this.#sorts.find((sort) => sort.name === sortType).getPoints(this.waypoints); + this.#sorts.find((sort) => sort.name === sortType).getPoints(this.waypointsModel.getWaypoints()); this.#currentSortType = sortType; } + #getFilteredWaypoints(waypoints) { + return this.#filters.find((filter) => filter.name === this.#filterModel.filter).getPoints(waypoints); + } + #deleteWaypoints() { this.#waypointPresenters.forEach((waypoint) => waypoint.destroy()); this.#waypointPresenters = []; } + + #handleFilterTypeChange() { + this.reset(); + this.#currentSortType = SORTING_TYPES.DAY; + this.renderWaypoints(); + } + + #handleModelEvent = (updateType) => { + switch (updateType) { + case UPDATE_TYPE.MINOR: + this.reset(); + this.renderWaypoints(); + break; + case UPDATE_TYPE.MAJOR: + this.reset(); + this.renderWaypoints(); + this.#currentSortType = SORTING_TYPES.DAY; + break; + } + }; } diff --git a/src/presenter/filter-presenter.js b/src/presenter/filter-presenter.js new file mode 100644 index 0000000..d68d54e --- /dev/null +++ b/src/presenter/filter-presenter.js @@ -0,0 +1,45 @@ +import {remove, render, replace} from '../framework/render'; +import FilterView from '../view/filter-view'; + +export default class FilterPresenter { + #filterContainer; + #filters; + #filterComponent = null; + #filterModel; + + constructor({filterContainer, filterModel, filters}) { + this.#filterContainer = filterContainer; + this.#filters = filters; + this.#filterModel = filterModel; + + this.#filterModel.addObserver(this.init.bind(this)); + } + + init() { + const prevFilterComponent = this.#filterComponent; + + this.#filterComponent = new FilterView({ + filters: this.#filters, + type: this.#filterModel.filter, + onChange: this.#handleTypeChange + }); + + if (prevFilterComponent === null) { + render(this.#filterComponent, this.#filterContainer); + return; + } + + replace(this.#filterComponent, prevFilterComponent); + remove(prevFilterComponent); + + render(this.#filterComponent, this.#filterContainer); + } + + #handleTypeChange = (type) => { + if (this.#filterModel.filter === type) { + return; + } + + this.#filterModel.setFilter(type); + }; +} diff --git a/src/presenter/new-waypoint-presenter.js b/src/presenter/new-waypoint-presenter.js new file mode 100644 index 0000000..a116c01 --- /dev/null +++ b/src/presenter/new-waypoint-presenter.js @@ -0,0 +1,73 @@ +import {remove, render, RenderPosition} from '../framework/render.js'; +import {ACTIONS as USER_ACTION, UPDATE_TYPE} from '../const'; +import EditingFormView from '../view/editing-form-view'; + +export default class NewWaypointPresenter { + #pointListContainer; + #newWaypointComponent = null; + #handleDataChange; + #handleDestroy; + #closeAllEditForms; + + constructor({pointListContainer, onDataChange, onDestroy, closeAllEditForms}) { + this.#handleDataChange = onDataChange; + this.#handleDestroy = onDestroy; + this.#pointListContainer = pointListContainer; + this.#closeAllEditForms = closeAllEditForms; + } + + init() { + if (this.#newWaypointComponent !== null) { + return; + } + + this.#closeAllEditForms(); + + this.#newWaypointComponent = new EditingFormView({ + formType: 'create', + waypoint: {type: 'flight', destination: '', price: '0', offers: []}, + onFormSubmit: (newWaypoint) => this.#handleSaveClick(newWaypoint), + onClose: () => this.#handleCancelClick(), + onDelete: this.#handleCancelClick + }); + + render(this.#newWaypointComponent, this.#pointListContainer, RenderPosition.AFTERBEGIN); + document.addEventListener('keydown', this.#escKeyDownHandler); + } + + destroy() { + if (this.#newWaypointComponent === null) { + return; + } + + this.#handleDestroy(); + + remove(this.#newWaypointComponent); + this.#newWaypointComponent = null; + + document.removeEventListener('keydown', this.#escKeyDownHandler); + } + + #handleSaveClick = (point) => { + this.#handleDataChange( + USER_ACTION.ADD_POINT, + UPDATE_TYPE.MAJOR, + { + id: Date.now().toString(36) + Math.random().toString(36).slice(2), + ...point + }, + ); + this.destroy(); + }; + + #handleCancelClick = () => { + this.destroy(); + }; + + #escKeyDownHandler = (evt) => { + if (evt.key === 'Esc' || evt.key === 'Escape') { + evt.preventDefault(); + this.destroy(); + } + }; +} diff --git a/src/presenter/waypoint-presenter.js b/src/presenter/waypoint-presenter.js index f561834..ca38f33 100644 --- a/src/presenter/waypoint-presenter.js +++ b/src/presenter/waypoint-presenter.js @@ -1,6 +1,8 @@ import {remove, render, replace} from '../framework/render.js'; import EditingFormView from '../view/editing-form-view.js'; import WaypointView from '../view/waypoint-view.js'; +import {ACTIONS as USER_ACTION, UPDATE_TYPE} from '../const'; +import {getId} from '../utils'; export default class WaypointPresenter { #waypoint; @@ -38,6 +40,7 @@ export default class WaypointPresenter { waypoint: waypoint, onFormSubmit: (newWaypoint) => this.#handleSaveClick(newWaypoint), onClose: () => this.closeForm(), + onDelete: this.#handleDeleteClick }); if (!prevWaypointComponent || !prevEditComponent) { @@ -80,11 +83,22 @@ export default class WaypointPresenter { }; #handleFavoriteClick = () => { - this.#onChange({...this.#waypoint, isFavorite: !this.#waypoint.isFavorite}); + this.#onChange( + USER_ACTION.UPDATE_POINT, + UPDATE_TYPE.MINOR, + {...this.#waypoint, isFavorite: !this.#waypoint.isFavorite} + ); }; #handleSaveClick = (waypoint) => { - this.#onChange({...waypoint}); + this.#onChange( + USER_ACTION.UPDATE_POINT, + UPDATE_TYPE.MINOR, + { + id: getId(), + ...waypoint + } + ); this.closeForm(); }; @@ -92,4 +106,12 @@ export default class WaypointPresenter { remove(this.#waypointComponent); remove(this.#editComponent); } + + #handleDeleteClick = (point) => { + this.#onChange( + USER_ACTION.DELETE_POINT, + UPDATE_TYPE.MINOR, + point, + ); + }; } diff --git a/src/utils.js b/src/utils.js index a77442c..e3f991c 100644 --- a/src/utils.js +++ b/src/utils.js @@ -64,11 +64,15 @@ function stringToDate(str, format) { return new Date(year, month, day, hour, minute, second); } +function getId() { + return Date.now().toString(36) + Math.random().toString(36).slice(2); +} + const filters = { [FILTER_TYPE.EVERYTHING]: (points) => points.filter((point) => point), - [FILTER_TYPE.FUTURE]: (points) => points.filter((point) => point), - [FILTER_TYPE.PRESENT]: (points) => points.filter((point) => point), - [FILTER_TYPE.PAST]: (points) => points.filter((point) => point), + [FILTER_TYPE.FUTURE]: (points) => points.filter((point) => new Date(point.dateFrom) > new Date()), + [FILTER_TYPE.PRESENT]: (points) => points.filter((point) => new Date(point.dateFrom) <= new Date() && new Date() <= new Date(point.dateTo)), + [FILTER_TYPE.PAST]: (points) => points.filter((point) => new Date(point.dateTo) < new Date()), }; const sorts = { @@ -87,6 +91,7 @@ export { getRandomInt, countDuration, formatDuration, - stringToDate + stringToDate, + getId }; export {filters, sorts}; diff --git a/src/view/editing-form-view.js b/src/view/editing-form-view.js index 825d2ca..183f9cc 100644 --- a/src/view/editing-form-view.js +++ b/src/view/editing-form-view.js @@ -19,7 +19,7 @@ function getEventOffer({id, title, price, isChecked}) { function getEventOffers(checkedOffers, type) { let result = ''; for (const offer of OFFERS.find((findOffer) => findOffer.type === type).offers) { - result += getEventOffer({...offer, isChecked: checkedOffers.includes(offer.id)}); + result += getEventOffer({...offer, isChecked: checkedOffers?.includes(offer.id)}); } return result; } @@ -49,8 +49,10 @@ function getDestinations() { return result; } -function createEditingFormTemplate({type, destination, offers, price, dateFrom, dateTo}) { +function createEditingFormTemplate({formType, type, destination, offers, price, dateFrom, dateTo}) { const destinationObject = DESTINATIONS.find((dest) => dest.id === destination); + const waypointType = type || 'flight'; + const offersList = getEventOffers(offers, waypointType); return `
  • @@ -59,7 +61,7 @@ function createEditingFormTemplate({type, destination, offers, price, dateFrom,
    @@ -74,9 +76,9 @@ function createEditingFormTemplate({type, destination, offers, price, dateFrom,
    - + ${getDestinations()} @@ -95,27 +97,26 @@ function createEditingFormTemplate({type, destination, offers, price, dateFrom, Price € - +
    - +
    -

    Offers

    - +

    ${offersList ? 'Offers' : ''}

    - ${getEventOffers(offers, type)} + ${offersList}
    -

    Destination

    -

    ${destinationObject.description}

    +

    ${destinationObject ? 'Destination' : ''}

    +

    ${destinationObject?.description || ''}

    @@ -126,21 +127,25 @@ function createEditingFormTemplate({type, destination, offers, price, dateFrom, export default class EditingFormView extends AbstractStatefulView { #onFormSubmit; #onClose; + #onDelete; + #formType; #destinations; - constructor({waypoint, onFormSubmit, onClose}) { + constructor({formType, waypoint, onFormSubmit, onClose, onDelete}) { super(); + this.#formType = formType || 'edit'; this._state = waypoint; this.editingForm = Object.assign({}, waypoint); this.#onFormSubmit = onFormSubmit; this.#onClose = onClose; - this.#destinations = DESTINATIONS; // TODO передавать извне + this.#onDelete = onDelete; + this.#destinations = DESTINATIONS; this._restoreHandlers(); } get template() { - return createEditingFormTemplate(this._state); + return createEditingFormTemplate({formType: this.#formType, ...this._state}); } reset(waypoint) { @@ -216,6 +221,12 @@ export default class EditingFormView extends AbstractStatefulView { }); }; + + #deleteFromHandler = (evt) => { + evt.preventDefault(); + this.#onDelete(this.editingForm); + }; + _restoreHandlers() { this.element.querySelector('.event--edit').addEventListener('submit', this.#submitFormHandler); this.element.querySelector('.event__rollup-btn').addEventListener('click', this.#closeFormHandler); @@ -226,8 +237,9 @@ export default class EditingFormView extends AbstractStatefulView { this.element.querySelector('.event__input--price').addEventListener('change', this.#changePriceHandler); this.element.querySelector('input[name="event-start-time"]').addEventListener('change', this.#changeStartTimeHandler); this.element.querySelector('input[name="event-end-time"]').addEventListener('change', this.#changeEndTimeHandler); - this.element.querySelectorAll('.event__offer-checkbox').forEach((el) => { - el.addEventListener('click', this.#changeOffersHandler); + this.element.querySelectorAll('.event__offer-checkbox').forEach((element) => { + element.addEventListener('click', this.#changeOffersHandler); }); + this.element.querySelector('.event__reset-btn').addEventListener('click', this.#deleteFromHandler); } } diff --git a/src/view/filter-view.js b/src/view/filter-view.js index 99a2db1..b1c15de 100644 --- a/src/view/filter-view.js +++ b/src/view/filter-view.js @@ -10,9 +10,9 @@ function createFilterItemTemplate(filter, isChecked) { `); } -function createFilterTemplate(filters) { +function createFilterTemplate(filters, type) { const filterItemsTemplate = filters - .map((filter, index) => createFilterItemTemplate(filter, index === 0)) // TODO заменить условие + .map((filter) => createFilterItemTemplate(filter, type === filter.name)) .join(''); return (` @@ -25,13 +25,25 @@ function createFilterTemplate(filters) { export default class FilterView extends AbstractView { #filters; + #type; + #handleTypeChange; - constructor({filters}) { + constructor({filters, type, onChange}) { super(); this.#filters = filters; + this.#type = type; + this.#handleTypeChange = onChange; + + this.element.addEventListener('click', this.#typeChangeHandler); } get template() { - return createFilterTemplate(this.#filters); + return createFilterTemplate(this.#filters, this.#type); } + + #typeChangeHandler = (event) => { + if (event.target.classList.contains('trip-filters__filter-input')) { + this.#handleTypeChange(event.target.value); + } + }; } diff --git a/src/view/new-point-button-view.js b/src/view/new-point-button-view.js new file mode 100644 index 0000000..d94f37b --- /dev/null +++ b/src/view/new-point-button-view.js @@ -0,0 +1,24 @@ +import AbstractView from '../framework/view/abstract-view'; + +function createNewPointButtonTemplate() { + return ''; +} + +export default class NewPointButtonView extends AbstractView { + #handleClick; + + constructor({onClick}) { + super(); + this.#handleClick = onClick; + this.element.addEventListener('click', this.#clickHandler); + } + + get template() { + return createNewPointButtonTemplate(); + } + + #clickHandler = (evt) => { + evt.preventDefault(); + this.#handleClick(); + }; +} diff --git a/src/view/sort-view.js b/src/view/sort-view.js index c03d349..f7e2d0c 100644 --- a/src/view/sort-view.js +++ b/src/view/sort-view.js @@ -11,9 +11,9 @@ function createSortingItemTemplate(sorting, isChecked) { `); } -function createSortTemplate(sortingItems) { +function createSortTemplate(sortingItems, currentSort) { const SORTING_ITEM_TEMPLATE = sortingItems - .map((sorting, index) => createSortingItemTemplate(sorting, index === 0)) + .map((sorting) => createSortingItemTemplate(sorting, sorting.name === currentSort)) .join(''); return (` @@ -26,17 +26,19 @@ function createSortTemplate(sortingItems) { export default class SortView extends AbstractView { #sorts; #handleTypeChange; + #currentSort; - constructor({sorts, onChange}) { + constructor({sorts, onChange, currentSort}) { super(); this.#sorts = sorts; + this.#currentSort = currentSort; this.#handleTypeChange = onChange; this.element.addEventListener('click', this.#changeTypeHandler); } get template() { - return createSortTemplate(this.#sorts); + return createSortTemplate(this.#sorts, this.#currentSort); } #changeTypeHandler = (evt) => { diff --git a/src/view/waypoint-view.js b/src/view/waypoint-view.js index cfa49ee..db15e06 100644 --- a/src/view/waypoint-view.js +++ b/src/view/waypoint-view.js @@ -19,7 +19,7 @@ function createOffers (offers) { function createWaypointTemplate({type, destination, offers, price, dateFrom, dateTo, isFavorite}) { const destinationObject = DESTINATIONS.find((dest) => dest.id === destination); - const offersObject = OFFERS.find((offer) => offer.type === type).offers.filter((offer) => offers.includes(offer.id)); + const offersObject = OFFERS.find((offer) => offer.type === type)?.offers.filter((offer) => offers.includes(offer.id)); const favoriteClassName = isFavorite ? 'event__favorite-btn--active' @@ -32,7 +32,7 @@ function createWaypointTemplate({type, destination, offers, price, dateFrom, dat
    Event type icon
    -

    ${type} ${destinationObject.name}

    +

    ${type} ${destinationObject?.name}

    @@ -46,7 +46,7 @@ function createWaypointTemplate({type, destination, offers, price, dateFrom, dat

    Offers:

      - ${createOffers(offersObject)} + ${createOffers(offersObject).join('')}