From 15a32851b35f3cbbbe9622899870b813e1dae841 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=A1=D0=BE=D1=84=D1=8C=D1=8F?= Date: Mon, 27 May 2024 17:25:14 +0500 Subject: [PATCH] =?UTF-8?q?2.10.=20=D0=A8=D0=B0=D0=B1=D0=BB=D0=BE=D0=BD?= =?UTF-8?q?=D0=B8=D0=B7=D0=B8=D1=80=D1=83=D0=B9=20=D1=8D=D1=82=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 13 +++ package.json | 3 + src/const.js | 34 ++++++ src/consts.js | 3 - src/main.js | 14 ++- src/mock/point.js | 136 ++++++++++++++++++++++ src/model/destinations-model.js | 13 +++ src/model/offers-model.js | 26 +++++ src/model/points-model.js | 10 ++ src/presenter/list-presenter.js | 18 ++- src/utils.js | 41 +++++++ src/view/add-new-point-view.js | 186 ------------------------------ src/view/edit-point-view.js | 198 ++++++++++++++------------------ src/view/list-point-view.js | 65 +++++++---- 14 files changed, 431 insertions(+), 329 deletions(-) create mode 100644 src/const.js delete mode 100644 src/consts.js create mode 100644 src/mock/point.js create mode 100644 src/model/destinations-model.js create mode 100644 src/model/offers-model.js create mode 100644 src/model/points-model.js create mode 100644 src/utils.js delete mode 100644 src/view/add-new-point-view.js diff --git a/package-lock.json b/package-lock.json index 8109ca4..cce28b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,9 @@ "": { "name": "big-trip", "version": "19.0.0", + "dependencies": { + "dayjs": "1.11.6" + }, "devDependencies": { "@babel/core": "7.20.5", "@babel/preset-env": "7.20.2", @@ -3186,6 +3189,11 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/dayjs": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -9941,6 +9949,11 @@ "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", "dev": true }, + "dayjs": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.6.tgz", + "integrity": "sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==" + }, "debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", diff --git a/package.json b/package.json index f25db71..8f454d6 100644 --- a/package.json +++ b/package.json @@ -29,5 +29,8 @@ }, "engines": { "node": "18" + }, + "dependencies": { + "dayjs": "1.11.6" } } diff --git a/src/const.js b/src/const.js new file mode 100644 index 0000000..5abf5aa --- /dev/null +++ b/src/const.js @@ -0,0 +1,34 @@ +const POINT_COUNT = 4; + +const DESTINATIONS = ['Paris', 'London', 'New York', 'Shanghai', 'Moscow']; + +const DESCRIPTIONS = [ + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras aliquet varius magna, non porta ligula feugiat eget.', + 'Fusce tristique felis at fermentum pharetra. Aliquam id orci ut lectus varius viverra. Nullam nunc ex, convallis sed finibus eget, sollicitudin eget ante.', + 'Phasellus eros mauris, condimentum sed nibh vitae, sodales efficitur ipsum.', + 'Sed blandit, eros vel aliquam faucibus, purus ex euismod diam, eu luctus nunc ante ut dui. Sed sed nisi sed augue convallis suscipit in sed felis.', + 'Aliquam erat volutpat. Nunc fermentum tortor ac porta dapibus. In rutrum ac purus sit amet tempus.' +]; + +const TYPES = ['Taxi', 'Bus', 'Train', 'Ship', 'Drive', 'Flight', 'Check-in', 'Sightseeing', 'Restaurant']; + +const DATE_FORMAT = 'MMM D'; + +const TIME_FORMAT = 'HH:mm'; + +const HOUR_IN_DAY = 24; + +const MINUTES_IN_HOUR = 60; + +const DEFAULT_POINT_DATA = { + id: null, + basePrice: 0, + dateFrom: null, + dateTo: null, + destination: null, + isFavorite: false, + offers: [], + type: 'Flight' +}; + +export {POINT_COUNT, DESTINATIONS, DESCRIPTIONS, DATE_FORMAT, TIME_FORMAT, HOUR_IN_DAY, MINUTES_IN_HOUR, TYPES, DEFAULT_POINT_DATA}; diff --git a/src/consts.js b/src/consts.js deleted file mode 100644 index a00b7f1..0000000 --- a/src/consts.js +++ /dev/null @@ -1,3 +0,0 @@ -const POINT_COUNT = 3; - -export {POINT_COUNT}; diff --git a/src/main.js b/src/main.js index c2f8e84..096a597 100644 --- a/src/main.js +++ b/src/main.js @@ -2,10 +2,22 @@ import FilterView from './view/filter-view.js'; import SortView from './view/sort-view.js'; import ListPresenter from './presenter/list-presenter.js'; import {render} from './render.js'; +import PointsModel from './model/points-model.js'; +import DestinationsModel from './model/destinations-model.js'; +import OffersModel from './model/offers-model.js'; const filterContainer = document.querySelector('.trip-controls__filters'); const sortAndListContainer = document.querySelector('.trip-events'); -const listPresenter = new ListPresenter({container: sortAndListContainer}); + +const pointsModel = new PointsModel(); +const destinationsModel = new DestinationsModel({pointsModel}); +const offersModel = new OffersModel({pointsModel}); +const listPresenter = new ListPresenter({ + container: sortAndListContainer, + pointsModel: pointsModel, + destinationsModel: destinationsModel, + offersModel: offersModel +}); render(new FilterView(), filterContainer); render(new SortView(), sortAndListContainer); diff --git a/src/mock/point.js b/src/mock/point.js new file mode 100644 index 0000000..3c5b9e4 --- /dev/null +++ b/src/mock/point.js @@ -0,0 +1,136 @@ +import {getRandomArrayElement, getRandomArbitrary} from '../utils.js'; +import {DESTINATIONS, DESCRIPTIONS} from '../const.js'; + +const mockPoints = [ + { + id: 0, + basePrice: 1100, + dateFrom: '2019-07-10T22:10', + dateTo: '2019-07-11T23:00', + destination: 0, + isFavorite: false, + offers: [1, 2], + type: 'Train' + }, + { + id: 1, + basePrice: 120, + dateFrom: '2019-07-13T12:00', + dateTo: '2019-07-13T12:45', + destination: 1, + isFavorite: false, + offers: [], + type: 'Taxi' + }, + { + id: 2, + basePrice: 75, + dateFrom: '2019-07-15T7:55', + dateTo: '2019-07-15T14:20', + destination: 2, + isFavorite: true, + offers: [0], + type: 'Sightseeing' + } +]; + +const destinations = [ + { + id: 0, + description: getRandomArrayElement(DESCRIPTIONS), + name: getRandomArrayElement(DESTINATIONS), + pictures: [ + { + src: `https://loremflickr.com/248/152?random=${getRandomArbitrary(1, 15)}`, + description: 'Beautiful place' + }, + { + src: `https://loremflickr.com/248/152?random=${getRandomArbitrary(1, 15)}`, + description: 'Picture description' + } + ] + }, + { + id: 1, + description: getRandomArrayElement(DESCRIPTIONS), + name: getRandomArrayElement(DESTINATIONS), + pictures: [ + { + src: `https://loremflickr.com/248/152?random=${getRandomArbitrary(1, 15)}`, + description: 'Some text' + }, + ] + }, + { + id: 2, + description: getRandomArrayElement(DESCRIPTIONS), + name: getRandomArrayElement(DESTINATIONS), + pictures: [] + }, +]; + +const offers = [ + { + type: 'Taxi', + offers: [ + { + id: 0, + name: 'Switch to comfort', + price: 35 + } + ] + }, + { + type: 'Train', + offers: [ + { + id: 0, + name: 'Switch to comfort', + price: 500 + }, + { + id: 1, + name: 'Add luggage', + price: 20 + }, + { + id: 2, + name: 'Add breakfast', + price: 28 + } + ] + }, + { + type: 'Sightseeing', + offers: [ + { + id: 0, + name: 'Rent a car', + price: 280 + }, + { + id: 1, + name: 'Order Uber', + price: 100 + }, + ] + } +]; + +function getRandomPoint() { + return getRandomArrayElement(mockPoints); +} + +function getDestinationById(id) { + return destinations.find((destination) => destination.id === id); +} + +function getOffersByType(type) { + return offers.find((offersByType) => offersByType.type === type).offers; +} + +function getOfferById(offersByType, id) { + return offersByType.find((offer) => offer.id === id); +} + +export {getRandomPoint, getDestinationById, getOffersByType, getOfferById}; diff --git a/src/model/destinations-model.js b/src/model/destinations-model.js new file mode 100644 index 0000000..5a13eae --- /dev/null +++ b/src/model/destinations-model.js @@ -0,0 +1,13 @@ +import {getDestinationById} from '../mock/point.js'; + +export default class DestinationsModel { + destinations = []; + + getDestinations(points) { + for (let i = 0; i < points.length; i++) { + this.destinations.push(getDestinationById(points[i].destination)); + } + + return this.destinations; + } +} diff --git a/src/model/offers-model.js b/src/model/offers-model.js new file mode 100644 index 0000000..f68dc18 --- /dev/null +++ b/src/model/offers-model.js @@ -0,0 +1,26 @@ +import {getOffersByType, getOfferById} from '../mock/point.js'; + +export default class OffersModel { + selectedOffersList = []; + typesOffersList = []; + + getSelectedOffers(points) { + for (let i = 0; i < points.length; i++) { + const pointOffers = []; + const offersByType = getOffersByType(points[i].type); + const offersIdList = points[i].offers; + for (let j = 0; j < offersIdList.length; j++){ + pointOffers.push(getOfferById(offersByType, offersIdList[j])); + } + this.selectedOffersList.push(pointOffers); + } + return this.selectedOffersList; + } + + getTypesOffers(points) { + for (let i = 0; i < points.length; i++) { + this.typesOffersList.push(getOffersByType(points[i].type)); + } + return this.typesOffersList; + } +} diff --git a/src/model/points-model.js b/src/model/points-model.js new file mode 100644 index 0000000..a0e4d7a --- /dev/null +++ b/src/model/points-model.js @@ -0,0 +1,10 @@ +import {getRandomPoint} from '../mock/point.js'; +import {POINT_COUNT} from '../const.js'; + +export default class PointsModel { + points = Array.from({length: POINT_COUNT}, getRandomPoint); + + getPoints() { + return this.points; + } +} diff --git a/src/presenter/list-presenter.js b/src/presenter/list-presenter.js index 5f0ad30..e61f2d7 100644 --- a/src/presenter/list-presenter.js +++ b/src/presenter/list-presenter.js @@ -1,4 +1,3 @@ -import {POINT_COUNT} from '../consts.js'; import ListView from '../view/list-view.js'; import EditPointView from '../view/edit-point-view.js'; import ListPointView from '../view/list-point-view.js'; @@ -7,16 +6,25 @@ import {render} from '../render.js'; export default class ListPresenter { listComponent = new ListView(); - constructor({container}) { + constructor({container, pointsModel, destinationsModel, offersModel}) { this.container = container; + this.pointsModel = pointsModel; + this.destinationsModel = destinationsModel; + this.offersModel = offersModel; } init() { + this.points = [...this.pointsModel.getPoints()]; + this.destinations = [...this.destinationsModel.getDestinations(this.points)]; + this.selectedOffers = [...this.offersModel.getSelectedOffers(this.points)]; + this.typesOffers = [...this.offersModel.getTypesOffers(this.points)]; render(this.listComponent, this.container); - render(new EditPointView(), this.listComponent.getElement()); + render(new EditPointView({pointData: this.points[0], destinationData: this.destinations[0], offersByType: this.typesOffers[0]}), + this.listComponent.getElement()); - for (let i = 0; i < POINT_COUNT; i++) { - render(new ListPointView(), this.listComponent.getElement()); + for (let i = 1; i < this.points.length; i++) { + render(new ListPointView({pointData: this.points[i], destinationData: this.destinations[i], + selectedOffersData: this.selectedOffers[i]}), this.listComponent.getElement()); } } } diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..b1c5b65 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,41 @@ +import dayjs from 'dayjs'; +import {DATE_FORMAT, TIME_FORMAT, HOUR_IN_DAY, MINUTES_IN_HOUR} from './const'; + +function humanizeDueDate(dueDate) { + return dueDate ? dayjs(dueDate).format(DATE_FORMAT) : ''; +} + +function humanizeDueTime(dueDate) { + return dueDate ? dayjs(dueDate).format(TIME_FORMAT) : ''; +} + +function humanizeDuration(start, end) { + const duration = start && end ? dayjs(end).diff(start, 'minute') : ''; + if (duration === '') { + return ''; + } + const minutes = duration % MINUTES_IN_HOUR; + let hours = Math.floor(duration / MINUTES_IN_HOUR); + let days = 0; + if (hours >= HOUR_IN_DAY) { + days = Math.floor(hours / HOUR_IN_DAY); + hours = hours % HOUR_IN_DAY; + } + if (days > 0) { + return `${days}D ${hours}H ${minutes}M`; + } else if (hours > 0) { + return `${hours}H ${minutes}M`; + } else { + return `${minutes}M`; + } +} + +function getRandomArrayElement(items) { + return items[Math.floor(Math.random() * items.length)]; +} + +function getRandomArbitrary(min, max) { + return Math.random() * (max - min) + min; +} + +export {getRandomArrayElement, getRandomArbitrary, humanizeDueDate, humanizeDueTime, humanizeDuration}; diff --git a/src/view/add-new-point-view.js b/src/view/add-new-point-view.js deleted file mode 100644 index 9996696..0000000 --- a/src/view/add-new-point-view.js +++ /dev/null @@ -1,186 +0,0 @@ -import {createElement} from '../render.js'; - -function createNewPointTemplate() { - return ` -
  • -
    -
    -
    - - - -
    -
    - Event type - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    -
    -
    -
    - -
    - - - - - - - -
    - -
    - - - — - - -
    - -
    - - -
    - - - -
    -
    -
    -

    Offers

    - -
    -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    -
    -
    - -
    -

    Destination

    -

    Geneva is a city in Switzerland that lies at the southern tip of expansive Lac LĂ©man (Lake Geneva). Surrounded by the Alps and Jura mountains, the city has views of dramatic Mont Blanc.

    - -
    -
    - Event photo - Event photo - Event photo - Event photo - Event photo -
    -
    -
    -
    -
    -
  • - `; -} - -export default class AddNewPointView { - getTemplate() { - return createNewPointTemplate(); - } - - getElement() { - if (!this.element) { - this.element = createElement(this.getTemplate()); - } - - return this.element; - } - - removeElement() { - this.element = null; - } -} diff --git a/src/view/edit-point-view.js b/src/view/edit-point-view.js index bfc75ff..1abb960 100644 --- a/src/view/edit-point-view.js +++ b/src/view/edit-point-view.js @@ -1,158 +1,73 @@ -import {createElement} from '../render'; +import {createElement} from '../render.js'; +import {TYPES, DESTINATIONS} from '../const.js'; -function createEditPointTemplate() { +function editPointTemplate(point, destination, typesTemplate, offersTemplate, picturesTemplate, destinationsTemplate) { return `
  • -
    -
    - - + + — - - + +
    -
    - - +

    Offers

    -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    - -
    - - -
    + ${offersTemplate}

    Destination

    -

    Chamonix-Mont-Blanc (usually shortened to Chamonix) is a resort area near the junction of France, Switzerland and Italy. At the base of Mont Blanc, the highest summit in the Alps, it's renowned for its skiing.

    +

    ${destination.description}

    + +
    +
    + ${picturesTemplate} +
    +
    @@ -161,8 +76,65 @@ function createEditPointTemplate() { } export default class EditPointView { + constructor({pointData, destinationData, offersByType}) { + this.pointData = pointData; + this.destinationData = destinationData; + this.offersByType = offersByType; + } + + getTypesTemplate() { + let typesTemplate = ''; + for (let i = 0; i < TYPES.length; i++) { + const isChecked = TYPES[i] === this.pointData.type ? 'checked' : ''; + typesTemplate += ` +
    + + +
    `; + } + return typesTemplate; + } + + getDestinationsTemplate() { + let destinationsTemplate = ''; + for (let i = 0; i < DESTINATIONS.length; i++) { + destinationsTemplate += ` + `; + } + return destinationsTemplate; + } + + getOffersTemplate() { + let offersTemplate = ''; + for (let i = 0; i < this.offersByType.length; i++) { + const isChecked = this.offersByType[i].id in this.pointData.offers ? 'checked' : ''; + const offerShortName = this.offersByType[i].name.toLowerCase().split(' ').at(-1); + offersTemplate += ` +
    + + +
    `; + } + return offersTemplate; + } + + getPicturesTemplate() { + let picturesTemplate = ''; + for (let i = 0; i < this.destinationData.pictures.length; i++) { + const picture = this.destinationData.pictures[i]; + picturesTemplate += ` + ${picture.description}`; + } + return picturesTemplate; + } + getTemplate() { - return createEditPointTemplate(); + return editPointTemplate(this.pointData, this.destinationData, this.getTypesTemplate(), + this.getOffersTemplate(), this.getPicturesTemplate(), this.getDestinationsTemplate()); } getElement() { diff --git a/src/view/list-point-view.js b/src/view/list-point-view.js index f3b585e..1db74ab 100644 --- a/src/view/list-point-view.js +++ b/src/view/list-point-view.js @@ -1,39 +1,31 @@ import {createElement} from '../render.js'; +import {humanizeDueDate, humanizeDueTime, humanizeDuration} from '../utils.js'; -function createListPointTemplate() { +function createListPointTemplate(point, totalPrice, destination, selectedOffersTemplate, isFavorite) { return `
  • - +
    - Event type icon + Event type icon
    -

    Flight Chamonix

    +

    ${destination.name}

    - + — - +

    -

    01H 10M

    +

    ${humanizeDuration(point.dateFrom, point.dateTo)}

    - € 160 + € ${totalPrice}

    Offers:

      -
    • - Add luggage - +€  - 50 -
    • -
    • - Switch to comfort - +€  - 80 -
    • + ${selectedOffersTemplate}
    -