diff --git a/src/main.js b/src/main.js index 0992185..5a8b10e 100644 --- a/src/main.js +++ b/src/main.js @@ -1,19 +1,29 @@ -import BoardPresenter from './presenter/board-presenter.js'; +import TripPresenter from './presenter/trip-presenter.js'; +import FilterPresenter from './presenter/filter-presenter.js'; + import DestinationModel from './model/destination-model.js'; import OfferModel from './model/offers-model.js'; import PointModel from './model/point-model.js'; import MockService from './service/mock-service.js'; const bodyElement = document.querySelector('body'); + const mockService = new MockService(); const destinationsModel = new DestinationModel(mockService); const pointsModel = new PointModel(mockService); const offersModel = new OfferModel(mockService); -const boardPresenterElement = new BoardPresenter({ - boardContainer: bodyElement, + +const filterPresenterElement = new FilterPresenter({ + filterContainer: bodyElement, + pointsModel +}); + +const tripPresenterElement = new TripPresenter({ + tripContainer: bodyElement, destinationsModel, offersModel, pointsModel }); -boardPresenterElement.init(); +filterPresenterElement.init(); +tripPresenterElement.init(); diff --git a/src/mock/const.js b/src/mock/const.js index cbf7317..498ceed 100644 --- a/src/mock/const.js +++ b/src/mock/const.js @@ -5,9 +5,9 @@ export const FULL_TIME_FOMAT = 'YYYY-MM-DDTHH:mm'; export const SLASH_TIME_FOMAT = 'DD/MM/YY HH:mm'; export const MILLISECONDS_IN_DAY = 86400000; export const MILLISECONDS_IN_HOUR = 3600000; -export const DESTINATION_COUNT = 4; -export const POINT_COUNT = 4; -export const OFFER_COUNT = 7; +export const POINT_COUNT = 5; +export const DESTINATION_COUNT = POINT_COUNT; +export const OFFER_COUNT = 10; export const BooleanValues = [ true, @@ -15,13 +15,21 @@ export const BooleanValues = [ ]; export const POINT_EMPTY = { + id: 1, basePrice: 0, - dateFrom: null, - dateTo: null, - destination: null, + dateFrom: '', + dateTo: '', + destination: '', ifFavorite: false, offers: [], - type: 'flight', + type: 'Flight', +}; + +export const EMPTY_WARNINGS = { + EVERYTHING: 'Click New Event to create your first', + FUTURE: 'There are no past events now', + PRESENT: 'There are no present events now', + PAST: 'There are no future events now' }; export const DESCRIPTION = [ @@ -37,10 +45,10 @@ export const OFFERS = [ 'Close But No Cigar', 'On the Same Page', 'Jaws of Death', - 'Every Cloud Has a Silver Lining', + 'Every Cloud Has a Silver', 'Jig Is Up', 'In a Pickle', - 'What Goes Up Must Come Down', + 'What Goes Up Must Come', 'Break The Ice', 'In the Red', ]; @@ -59,12 +67,26 @@ export const ROUTE_TYPE = [ export const CITIES = [ 'Salisbury', - 'Kingston upon Hull', + 'Kingston', 'Ripon', 'Liverpool', 'Carlisle', 'Oxford', 'Manchester', 'Chelmsford', - 'Carlisle' ]; + +export const FilterType = { + EVERYTHING: 'Everything', + FUTURE: 'Future', + PRESENT: 'Present', + PAST: 'Past' +}; + +export const SortType = { + DAY: 'DAY', + EVENT: 'EVENT', + TIME: 'TIME', + PRICE: 'PRICE', + OFFERS: 'OFFERS' +}; diff --git a/src/mock/filters.js b/src/mock/filters.js new file mode 100644 index 0000000..fe6f070 --- /dev/null +++ b/src/mock/filters.js @@ -0,0 +1,16 @@ +import {FilterType} from './const.js'; +import {ispointExpired} from '../utils.js'; + +const filter = { + [FilterType.EVERYTHING]: (points) => points.filter((point) => point), + [FilterType.FUTURE]:(points) => points.filter((point) => !ispointExpired(point.dateFrom) && !ispointExpired(point.dateTo)), + [FilterType.PRESENT]:(points) => points.filter((point) => ispointExpired(point.dateFrom) && !ispointExpired(point.dateTo)), + [FilterType.PAST]: (points) => points.filter((point) => ispointExpired(point.dateFrom) && ispointExpired(point.dateTo)) +}; + +export const generateFilter = (points) => ( + Object.entries(filter).map(([filterType, filterPoints]) => ({ + type: filterType, + filteredPoints: filterPoints(points) + })) +); diff --git a/src/mock/offer.js b/src/mock/offer.js index 333e9a9..9918ff7 100644 --- a/src/mock/offer.js +++ b/src/mock/offer.js @@ -1,10 +1,8 @@ import {getRandomArrayElement, getRandomInt} from '../utils.js'; import {OFFERS} from './const.js'; + export const generateOffer = () => ({ - offers: - { - id: crypto.randomUUID(), - title: getRandomArrayElement(OFFERS), - price: getRandomInt() - } + id: crypto.randomUUID(), + title: getRandomArrayElement(OFFERS), + price: getRandomInt() }); diff --git a/src/mock/point.js b/src/mock/point.js index 4ae0c90..fe73304 100644 --- a/src/mock/point.js +++ b/src/mock/point.js @@ -1,12 +1,13 @@ -import {getRandomInt, getRandomBulValue, getDate} from '../utils.js'; +import {getRandomInt, getRandomBulValue, getDate, getRandomArrayElement} from '../utils.js'; + export const generatePoint = (offerType, destinationId, offerIds) => ({ id: crypto.randomUUID(), basePrice: getRandomInt(), - dateFrom: getDate(false), + dateFrom: getDate(true), dateTo: getDate(true), destination: destinationId, isFavorite: getRandomBulValue(), - offers: offerIds, + offers: offerIds.map(() => (getRandomArrayElement(offerIds))), type: offerType } ); diff --git a/src/mock/sort.js b/src/mock/sort.js new file mode 100644 index 0000000..41fb73d --- /dev/null +++ b/src/mock/sort.js @@ -0,0 +1,17 @@ +import {SortType} from './const.js'; +import {getPointDuration} from '../utils.js'; + +const sort = { + [SortType.DAY]: (points) => points.sort((point) => point.dateFrom), + [SortType.EVENT]: (points) => points.sort((point) => point), + [SortType.TIME]:(points) => points.sort((point) => getPointDuration(point.dateFrom, point.dateTo)), + [SortType.PRICE]: (points) => points.sort((point) => point.basePrice), + [SortType.OFFERS]: (points) => points.sort((point) => point), +}; + +export const generateSorter = (points) => ( + Object.entries(sort).map(([sortType, sortPoints]) => ({ + type: sortType, + sortedPoints: sortPoints(points) + })) +); diff --git a/src/model/destination-model.js b/src/model/destination-model.js index 1a1810d..980187c 100644 --- a/src/model/destination-model.js +++ b/src/model/destination-model.js @@ -1,13 +1,15 @@ export default class DestinationModel { + #destinations = null; + constructor(service){ - this.destinations = service.getDestinations(); + this.#destinations = service.getDestinations(); } get() { - return this.destinations; + return this.#destinations; } getById(id) { - return this.destinations.find((destinations) => destinations.id === id); + return this.#destinations.find((destinations) => destinations.id === id); } } diff --git a/src/model/offers-model.js b/src/model/offers-model.js index f316e94..b92b1bb 100644 --- a/src/model/offers-model.js +++ b/src/model/offers-model.js @@ -1,13 +1,15 @@ export default class OfferModel { + #offers = null; + constructor(service){ - this.offers = service.getOffers(); + this.#offers = service.getOffers(); } get() { - return this.offers; + return this.#offers; } getByType(type) { - return this.offers.find((offers) => offers.type === type).offers; + return this.#offers.find((offers) => offers.type === type).offers; } } diff --git a/src/model/point-model.js b/src/model/point-model.js index 8739f4d..fc86c80 100644 --- a/src/model/point-model.js +++ b/src/model/point-model.js @@ -1,13 +1,15 @@ export default class PointModel { + #points = null; + constructor(service) { - this.points = service.getPoints(); + this.#points = service.getPoints(); } get() { - return this.points; + return this.#points; } getById(id) { - return this.points.find((points) => points.id === id); + return this.#points.find((points) => points.id === id); } } diff --git a/src/presenter/board-presenter.js b/src/presenter/board-presenter.js deleted file mode 100644 index 5178d0a..0000000 --- a/src/presenter/board-presenter.js +++ /dev/null @@ -1,86 +0,0 @@ -import {render, replace} from '../framework/render.js'; -import FilterView from '../view/filter-view.js'; -import SortView from '../view/sort-view.js'; -import EditPointView from '../view/edit-point-view.js'; -import EventPointView from '../view/event-point-view.js'; -import EventListView from '../view/event-list-view.js'; -import TripInfoView from '../view/trip-info-view.js'; - -export default class BoardPresenter { - #boardContainer = null; - #destinationsModel = null; - #offersModel = null; - #pointsModel = null; - - constructor({boardContainer, destinationsModel, offersModel, pointsModel}) { - this.#boardContainer = boardContainer; - this.#destinationsModel = destinationsModel; - this.#offersModel = offersModel; - this.#pointsModel = pointsModel; - } - - #eventList = new EventListView(); - - init(){ - const points = [...this.#pointsModel.get()]; - const tripControlFiltersElement = this.#boardContainer.querySelector('.trip-controls__filters'); - const tripInfoElement = this.#boardContainer.querySelector('.trip-main'); - const tripEventsElement = this.#boardContainer.querySelector('.trip-events'); - - render(new TripInfoView({ - point: points, - pointDestination: this.#destinationsModel.get().map((destination) => destination.name), - }), tripInfoElement, 'afterbegin'); - render(new FilterView(), tripControlFiltersElement); - render(new SortView(), tripEventsElement); - render(this.#eventList, tripEventsElement); - - points.forEach((point) => { - this.#renderPoints(point); - }); - } - - #renderPoints(point) { - const escKeyDownHandler = (evt) => { - if (evt.key === 'Escape') { - evt.preventDefault(); - replaceFormToPoint(); - document.removeEventListener('keydown', escKeyDownHandler); - } - }; - - const eventPoint = new EventPointView({ - point: point, - pointDestination: this.#destinationsModel.getById(point.destination), - pointOffers: this.#offersModel.getByType(point.type), - onEditClick: () => { - replacePointToForm(); - document.addEventListener('keydown', escKeyDownHandler); - } - }); - - const eventEditPoint = new EditPointView({ - point: point, - pointDestination: this.#destinationsModel.getById(point.destination), - pointOffers: this.#offersModel.getByType(point.type), - onSubmitClick: () => { - replaceFormToPoint(); - document.addEventListener('keydown', escKeyDownHandler); - }, - onRollUpClick: () => { - replaceFormToPoint(); - document.addEventListener('keydown', escKeyDownHandler); - } - }); - - function replacePointToForm() { - replace(eventEditPoint, eventPoint); - } - - function replaceFormToPoint() { - replace(eventPoint, eventEditPoint); - } - - render(eventPoint, this.#eventList.element); - } -} diff --git a/src/presenter/filter-presenter.js b/src/presenter/filter-presenter.js new file mode 100644 index 0000000..be07b45 --- /dev/null +++ b/src/presenter/filter-presenter.js @@ -0,0 +1,34 @@ +import {render} from '../framework/render.js'; +import FilterView from '../view/filter-view.js'; +import {generateFilter} from '../mock/filters.js'; + +export default class FilterPresenter{ + #filterContainer = null; + #pointsModel = null; + + constructor({filterContainer, pointsModel}) { + this.#filterContainer = filterContainer; + this.#pointsModel = pointsModel; + } + + init(){ + const points = [...this.#pointsModel.get()]; + const tripControlFiltersElement = this.#filterContainer.querySelector('.trip-controls__filters'); + const filters = generateFilter(points); + + render(new FilterView({ + filters, + onFilterClick: (filterType) => { + this.#renderFilteredPoints(filters.filter((filter) => (filter.type === filterType))[0]); + } + }), tripControlFiltersElement); + } + + #renderFilteredPoints(points){ + points.filteredPoints.forEach((point) => { + //Заглушка, пока не знаю, как решить + // eslint-disable-next-line no-console + console.log(point); + }); + } +} diff --git a/src/presenter/trip-presenter.js b/src/presenter/trip-presenter.js new file mode 100644 index 0000000..88033bb --- /dev/null +++ b/src/presenter/trip-presenter.js @@ -0,0 +1,135 @@ +import {render, replace, remove} from '../framework/render.js'; +import EditPointView from '../view/edit-point-view.js'; +import EventPointView from '../view/event-point-view.js'; +import EventListView from '../view/event-list-view.js'; +import AddPointView from '../view/add-point-view.js'; +import EmptyListView from '../view/empty-list-view.js'; +import SortView from '../view/sort-view.js'; +import {generateSorter} from '../mock/sort.js'; +import TripInfoView from '../view/trip-info-view.js'; + +export default class TripPresenter { + #tripContainer = null; + #destinationsModel = null; + #offersModel = null; + #pointsModel = null; + + constructor({tripContainer, destinationsModel, offersModel, pointsModel}) { + this.#tripContainer = tripContainer; + this.#destinationsModel = destinationsModel; + this.#offersModel = offersModel; + this.#pointsModel = pointsModel; + } + + #eventList = new EventListView(); + #emptyList = new EmptyListView(); + + init(){ + const points = [...this.#pointsModel.get()]; + const tripInfoElement = this.#tripContainer.querySelector('.trip-main'); + const newEventElement = document.querySelector('.trip-main__event-add-btn'); + const tripEventsElement = this.#tripContainer.querySelector('.trip-events'); + + if (this.#pointsModel.get().length === 0) { + render(new EmptyListView(), tripEventsElement); + return; + } + + newEventElement.addEventListener('click', () => this.#addPointHandler(newEventElement)); + const sorter = generateSorter(points); + + render(new TripInfoView({ + points: points, + pointDestination: this.#destinationsModel.get(), + pointOffers: this.#offersModel.get(), + }), tripInfoElement, 'afterbegin'); + render(new SortView({sorter}), tripEventsElement); + + render(this.#eventList, tripEventsElement); + + points.forEach((point) => { + this.#renderPoints(point); + }); + } + + + #addPointHandler(newEventElement) { + newEventElement.setAttribute('disabled', ''); + this.#renderAddPoint(newEventElement); + } + + #renderPoints(point) { + const escKeyDownHandler = (evt) => { + if (evt.key === 'Escape') { + evt.preventDefault(); + replaceFormToPoint(); + document.removeEventListener('keydown', escKeyDownHandler); + } + }; + + const eventPoint = new EventPointView({ + point: point, + pointDestination: this.#destinationsModel.getById(point.destination), + pointOffers: this.#offersModel.getByType(point.type), + onEditClick: () => { + replacePointToForm(); + document.addEventListener('keydown', escKeyDownHandler); + } + }); + + const eventEditPoint = new EditPointView({ + point: point, + pointDestination: this.#destinationsModel.getById(point.destination), + pointOffers: this.#offersModel.getByType(point.type), + onSubmitClick: () => { + replaceFormToPoint(); + document.addEventListener('keydown', escKeyDownHandler); + }, + onDeleteClick: () => { + if (document.querySelectorAll('.trip-events__item').length - 1 === 0) { + render(this.#emptyList, this.#tripContainer.querySelector('.trip-events')); + } + remove(eventEditPoint); + document.addEventListener('keydown', escKeyDownHandler); + }, + onRollUpClick: () => { + replaceFormToPoint(); + document.addEventListener('keydown', escKeyDownHandler); + } + }); + + function replacePointToForm() { + replace(eventEditPoint, eventPoint); + } + + function replaceFormToPoint() { + replace(eventPoint, eventEditPoint); + } + + render(eventPoint, this.#eventList.element); + } + + #renderAddPoint(newEventElement) { + if (document.querySelectorAll('.trip-events__item').length - 1 !== 0) { + remove(this.#emptyList); + } + const eventAddPoint = new AddPointView({ + pointOffers: this.#offersModel, + onSaveClick: () => { + }, + onCancelClick: () => { + deleteForm(this.#emptyList); + } + }); + + function deleteForm(emptyList) { + newEventElement.removeAttribute('disabled'); + if (document.querySelectorAll('.trip-events__item').length - 1 === 0) { + render(emptyList, document.querySelector('.trip-events')); + } + remove(eventAddPoint); + } + + render(eventAddPoint, this.#eventList.element, 'afterbegin'); + } +} diff --git a/src/service/mock-service.js b/src/service/mock-service.js index c91a798..4ca7867 100644 --- a/src/service/mock-service.js +++ b/src/service/mock-service.js @@ -43,7 +43,7 @@ export default class MockService { const type = getRandomArrayElement(ROUTE_TYPE); const destination = getRandomArrayElement(this.#destinations); const offersByType = this.#offers.find((offerByType) => offerByType.type === type); - const offerIds = offersByType.offers.map((offer) => offer.offers.id); + const offerIds = offersByType.offers.map((offer) => offer.id); return generatePoint(type, destination.id, offerIds); }); } diff --git a/src/view/add-point-view.js b/src/view/add-point-view.js new file mode 100644 index 0000000..91b906a --- /dev/null +++ b/src/view/add-point-view.js @@ -0,0 +1,135 @@ +import AbstractView from '../framework/view/abstract-view.js'; +import {POINT_EMPTY, CITIES, ROUTE_TYPE} from '../mock/const.js'; + +const getDestinationItem = (city) => ``; + +const getEventTypeItem = (typeItem, type) => `
+ + +
`; + +const getOfferItem = (offer) => `
+ + +
`; + +const createAddPointTemplate = ({point, pointOffers}) => { + const {basePrice, dateFrom, dateTo, destination, type, id} = point; + const cityItemsTemplate = CITIES.map((cityItem) => getDestinationItem(cityItem)).join(''); + const typeItemsTemplate = ROUTE_TYPE.map((typeItem) => getEventTypeItem(typeItem, type)).join(''); + const offerItemsTemplate = pointOffers.map((offer) => getOfferItem(offer, point.offers)).join(''); + + return (`
  • +
    +
    +
    + + + +
    +
    + Event type + ${typeItemsTemplate} +
    +
    +
    + +
    + + + + ${cityItemsTemplate} + +
    + +
    + + + — + + +
    + +
    + + +
    + + + +
    +
    + ${pointOffers.length !== 0 + ? `
    +

    Offers

    +
    + ${offerItemsTemplate} +
    +
    ` + : ''} + + ${destination !== '' ? `
    +

    Destination

    +

    ${''}

    + +
    +
    + ${''} +
    +
    +
    ` : ''} +
    +
    +
  • `); +}; + +export default class AddPointView extends AbstractView{ + #point = null; + #pointDestination = []; + #pointOffers = []; + + #handleSaveClick = null; + #handleCancelClick = null; + + constructor({point = POINT_EMPTY, pointOffers, onSaveClick, onCancelClick}) { + super(); + this.#point = point; + this.#pointOffers = pointOffers.getByType(point.type); + + this.#handleSaveClick = onSaveClick; + this.#handleCancelClick = onCancelClick; + + this.element.querySelector('.event__save-btn').addEventListener('submit', this.#saveClickHandler); + this.element.querySelector('.event__reset-btn').addEventListener('click', this.#cancelClickHandler); + } + + get template() { + return createAddPointTemplate({ + point: this.#point, + pointOffers: this.#pointOffers + }); + } + + #saveClickHandler = (evt) => { + evt.preventDefault(); + this.#handleSaveClick(); + }; + + #cancelClickHandler = (evt) => { + evt.preventDefault(); + this.#handleCancelClick(); + }; +} diff --git a/src/view/edit-point-view.js b/src/view/edit-point-view.js index 03155b9..ea2c2b0 100644 --- a/src/view/edit-point-view.js +++ b/src/view/edit-point-view.js @@ -1,86 +1,59 @@ import {formatToSlashDate} from '../utils.js'; -import {POINT_EMPTY, ROUTE_TYPE} from '../mock/const.js'; +import {CITIES, POINT_EMPTY, ROUTE_TYPE} from '../mock/const.js'; import AbstractView from '../framework/view/abstract-view.js'; -const getPicrtureArrayElement = (picturesArray) => { - let tapeElements = ''; +const getPicrtureItem = (picture) => `${picture.description}`; - picturesArray.forEach((picture) => { - tapeElements += `${picture.description}`; - }); +const getDestinationItem = (city) => ``; - return tapeElements; -}; +const getEventTypeItem = (typeItem, type) => `
    + + +
    `; -const getOffersArrayElement = (offersArray) => { - if (offersArray.length !== 0) { - let offersElements = `
    -

    Offers

    `; - - offersArray.forEach((offer, i) => { - offersElements += ` -
    -
    - -
    '; - - return offersElements; - } else { - return ''; - } -}; - -const getEventTypeElements = (typeArray) => { - let typeElements = ''; - - typeArray.forEach((type) => { - typeElements += `
    - - -
    `; - }); - - return typeElements; -}; + `; const createEditPointTemplate = ({point, pointDestination, pointOffers}) => { - const {basePrice, dateFrom, dateTo, type} = point; + const {basePrice, dateFrom, dateTo, type, id} = point; + const pictureItemsTemplate = pointDestination.pictures.map((picture) => getPicrtureItem(picture)).join(''); + const typeItemsTemplate = ROUTE_TYPE.map((typeItem) => getEventTypeItem(typeItem, type)).join(''); + const cityItemsTemplate = CITIES.map((cityItem) => getDestinationItem(cityItem)).join(''); + const offerItemsTemplate = pointOffers.map((offer) => getOfferItem(offer, point.offers)).join(''); return `
  • -
    - - - + ${cityItemsTemplate}
    @@ -97,7 +70,11 @@ const createEditPointTemplate = ({point, pointDestination, pointOffers}) => { Price € - + @@ -107,14 +84,21 @@ const createEditPointTemplate = ({point, pointDestination, pointOffers}) => {
    - ${getOffersArrayElement(pointOffers)} + ${pointOffers.length !== 0 + ? `
    +

    Offers

    +
    + ${offerItemsTemplate} +
    +
    ` + : ''}

    Destination

    ${pointDestination.description}

    - ${getPicrtureArrayElement(pointDestination.pictures)} + ${pictureItemsTemplate}
    @@ -128,18 +112,21 @@ export default class EditPointView extends AbstractView{ #pointDestination = []; #pointOffers = []; #handleSubmitClick = null; + #handleDeleteClick = null; #handleRollUpClick = null; - constructor({point = POINT_EMPTY, pointDestination, pointOffers, onSubmitClick, onRollUpClick}) { + constructor({point = POINT_EMPTY, pointDestination, pointOffers, onSubmitClick, onDeleteClick, onRollUpClick}) { super(); this.#point = point; this.#pointDestination = pointDestination; this.#pointOffers = pointOffers; this.#handleSubmitClick = onSubmitClick; + this.#handleDeleteClick = onDeleteClick; this.#handleRollUpClick = onRollUpClick; this.element.querySelector('.event__save-btn').addEventListener('submit', this.#submitClickHandler); + this.element.querySelector('.event__reset-btn').addEventListener('click', this.#deleteClickHandler); this.element.querySelector('.event__rollup-btn').addEventListener('click', this.#rollUpClickHandler); } @@ -156,6 +143,11 @@ export default class EditPointView extends AbstractView{ this.#handleSubmitClick(); }; + #deleteClickHandler = (evt) => { + evt.preventDefault(); + this.#handleDeleteClick(); + }; + #rollUpClickHandler = (evt) => { evt.preventDefault(); this.#handleRollUpClick(); diff --git a/src/view/empty-list-view.js b/src/view/empty-list-view.js new file mode 100644 index 0000000..0724f00 --- /dev/null +++ b/src/view/empty-list-view.js @@ -0,0 +1,9 @@ +import AbstractView from '../framework/view/abstract-view.js'; + +const createTipEventListViewTemplate = () => '

    Click New Event to create your first point

    '; + +export default class EmptyListView extends AbstractView{ + get template() { + return createTipEventListViewTemplate(); + } +} diff --git a/src/view/event-point-view.js b/src/view/event-point-view.js index cdc6550..4fd09ac 100644 --- a/src/view/event-point-view.js +++ b/src/view/event-point-view.js @@ -2,25 +2,15 @@ import {formatToTime, formatToDate, formatToShortDate, getPointDuration} from '. import {POINT_EMPTY} from '../mock/const.js'; import AbstractView from '../framework/view/abstract-view.js'; -const offerShow = (offersArray) => { - if (offersArray.length !== 0) { - let offerElements = ''; - - offersArray.forEach((offer) => { - offerElements += `
  • - ${offer.offers.title} +const getOfferItem = (offer) => `
  • + ${offer.title} +€  - ${offer.offers.price} + ${offer.price}
  • `; - }); - - return offerElements; - } - return ''; -}; const createEventPointTemplate = ({point, pointDestination, pointOffers}) => { const {basePrice, dateFrom, dateTo, isFavorite, type} = point; + const offerItemsTemplate = pointOffers.map((offer) => getOfferItem(offer)).join(''); return (`
  • @@ -38,11 +28,12 @@ const createEventPointTemplate = ({point, pointDestination, pointOffers}) => {

    ${getPointDuration(dateFrom, dateTo)}

    - € ${basePrice} + €  + ${pointOffers.map((offer) => offer.price).reduce((sum, x) => sum + x, 0) + basePrice}

    Offers:

      - ${offerShow(pointOffers)} + ${offerItemsTemplate}
    -
  • `; +`); +}; export default class FilterView extends AbstractView{ + #filters = null; + #handleFilterClick = null; + constructor({filters, onFilterClick}) { + super(); + this.#filters = filters; + this.#handleFilterClick = onFilterClick; + + this.element.querySelectorAll('.trip-filters__filter') + .forEach((filterElement) => filterElement.addEventListener('click', this.#filterClickHandler)); + } + get template() { - return createFilterTemplate(); + return createFilterTemplate(this.#filters); } + + #filterClickHandler = (evt) => { + evt.preventDefault(); + this.#handleFilterClick(evt.target.innerHTML); + }; } diff --git a/src/view/sort-view.js b/src/view/sort-view.js index 88f1bad..295aa71 100644 --- a/src/view/sort-view.js +++ b/src/view/sort-view.js @@ -1,34 +1,33 @@ import AbstractView from '../framework/view/abstract-view.js'; -const createSortTemplate = () => `
    -
    - - -
    +const createSortItemTemplate = (sorter, isChecked) => { + const {type} = sorter; -
    - - -
    + return (`
    + + +
    `); +}; -
    - - -
    +const createSortTemplate = (sorterItems) => { + const sorterItemsTemplate = sorterItems.map((sorter, index) => createSortItemTemplate(sorter, index === 0)).join(''); -
    - - -
    - -
    - - -
    -
    `; + return (`
    +${sorterItemsTemplate} +
    `); +}; export default class SortView extends AbstractView { + #sorter = null; + + constructor({sorter}) { + super(); + this.#sorter = sorter; + } + get template() { - return createSortTemplate(); + return createSortTemplate(this.#sorter); } } diff --git a/src/view/tip-event-list-view.js b/src/view/tip-event-list-view.js index d28737c..c3bc328 100644 --- a/src/view/tip-event-list-view.js +++ b/src/view/tip-event-list-view.js @@ -2,7 +2,7 @@ import AbstractView from '../framework/view/abstract-view.js'; const createTipEventListViewTemplate = () => '
      '; -export default class TipEventList extends AbstractView{ +export default class TipEventListView extends AbstractView{ get template() { return createTipEventListViewTemplate(); } diff --git a/src/view/trip-info-view.js b/src/view/trip-info-view.js index 0f573ba..02e583e 100644 --- a/src/view/trip-info-view.js +++ b/src/view/trip-info-view.js @@ -2,41 +2,49 @@ import {POINT_EMPTY} from '../mock/const.js'; import {formatToShortDate, formatToDay} from '../utils.js'; import AbstractView from '../framework/view/abstract-view.js'; -const createDestinationElement = (pointDestination) => { - let destinationElements = ''; +const findDestinationForPoint = (point, pointDestination) => + pointDestination.find((destination) => destination.id === point.destination); - pointDestination.forEach((destination) => { - destinationElements += `${destination} - `; - }); +const findOffersForPoint = (point, pointOffers) => + pointOffers.find((offer) => offer.type === point.type); - return destinationElements.slice(0, -2); -}; +const createDestinationElement = (pointDestination) => + pointDestination.length <= 3 + ? pointDestination.map((destination) => (`${destination} - `)).join('').slice(0, -2) + : `${pointDestination[0]} - ... - ${pointDestination[pointDestination.length - 1]}`; -const createTripInfoTemplate = ({point, pointDestination}) => (`
      +const createTripInfoTemplate = ({points, pointDestination}) => (`

      ${createDestinationElement(pointDestination)}

      -

      ${formatToShortDate(point[0].dateFrom)} — ${formatToDay(point[point.length - 1].dateTo)}

      +

      ${formatToShortDate(points[0].dateFrom)} — ${formatToDay(points[points.length - 1].dateTo)}

      - Total: € 1230 + Total: €  + ${points.map((point) => point.basePrice).reduce((sum, x) => sum + x, 0)}

      `); export default class TripInfoView extends AbstractView { - #point = null; + #points = null; #pointDestination = []; + #pointOffers = []; - constructor({point = POINT_EMPTY, pointDestination}) { + constructor({points = POINT_EMPTY, pointDestination, pointOffers}) { super(); - this.#point = point; - this.#pointDestination = pointDestination; + this.#points = points; + this.#pointDestination = points + .map((point) => findDestinationForPoint(point, pointDestination)) + .map((destination) => destination.name); + this.#pointOffers = points + .map((point) => findOffersForPoint(point, pointOffers)) + .map((offer) => offer.offers); } get template() { return createTripInfoTemplate({ - point: this.#point, + points: this.#points, pointDestination: this.#pointDestination, }); }