From 01b6fb1af1cfc1d416ead6c56d495c89d02d4052 Mon Sep 17 00:00:00 2001 From: Danilina Mariya Date: Tue, 3 Sep 2024 20:20:00 +0700 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D1=8F?= =?UTF-8?q?=D0=B5=D1=82=20=D0=9C=D0=BE=D0=B4=D0=B5=D0=BB=D1=8C=20=D0=B8=20?= =?UTF-8?q?=20=D1=81=D1=82=D1=80=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=8B=20?= =?UTF-8?q?=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85,=20=D0=B8=D1=81=D0=BF?= =?UTF-8?q?=D1=80=D0=B0=D0=B2=D0=BB=D1=8F=D0=B5=D1=82=20=D0=BA=D0=BE=D0=B4?= =?UTF-8?q?=20=D0=B4=D0=BB=D1=8F=20=D0=BF=D0=BE=D0=BB=D1=83=D1=87=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D1=8F=20=D0=B4=D0=B0=D0=BD=D0=BD=D1=8B=D1=85=20?= =?UTF-8?q?=D1=81=D0=BD=D0=B0=D1=80=D1=83=D0=B6=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package-lock.json | 8 + package.json | 3 + src/const.js | 133 ++++++++++++ src/main.js | 8 +- src/mock/points.js | 38 ++++ src/model/points-model.js | 12 ++ src/presenter/board-presenter.js | 22 +- src/utils.js | 45 ++++ src/view/{filters.js => filters-view.js} | 4 +- src/view/form-point-view.js | 148 +++++++++++++ src/view/form-point.js | 195 ------------------ .../{list-points.js => list-points-view.js} | 2 +- src/view/{loading.js => loading-view.js} | 4 +- src/view/point-view.js | 74 +++++++ src/view/point.js | 60 ------ src/view/sort-view.js | 36 ++++ src/view/sort.js | 56 ----- 17 files changed, 519 insertions(+), 329 deletions(-) create mode 100644 src/const.js create mode 100644 src/mock/points.js create mode 100644 src/model/points-model.js create mode 100644 src/utils.js rename src/view/{filters.js => filters-view.js} (90%) create mode 100644 src/view/form-point-view.js delete mode 100644 src/view/form-point.js rename src/view/{list-points.js => list-points-view.js} (90%) rename src/view/{loading.js => loading-view.js} (82%) create mode 100644 src/view/point-view.js delete mode 100644 src/view/point.js create mode 100644 src/view/sort-view.js delete mode 100644 src/view/sort.js diff --git a/package-lock.json b/package-lock.json index 56bfe83..50788bf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,6 +7,9 @@ "": { "name": "big-trip", "version": "22.0.0", + "dependencies": { + "dayjs": "1.11.7" + }, "devDependencies": { "@babel/core": "7.21.4", "@babel/preset-env": "7.21.4", @@ -3222,6 +3225,11 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/dayjs": { + "version": "1.11.7", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.7.tgz", + "integrity": "sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==" + }, "node_modules/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 c7b4b0f..e1b6175 100644 --- a/package.json +++ b/package.json @@ -29,5 +29,8 @@ }, "engines": { "node": "20" + }, + "dependencies": { + "dayjs": "1.11.7" } } diff --git a/src/const.js b/src/const.js new file mode 100644 index 0000000..5b81da2 --- /dev/null +++ b/src/const.js @@ -0,0 +1,133 @@ +const FILTER__VALUE = ['everything', 'future', 'present', 'past']; + +const SORT__VALUE = ['day', 'event', 'time', 'price', 'offer']; + +const TYPES_ITEM = ['taxi', 'bus', 'train', 'ship', 'drive', 'flight', 'check-in', 'sightseeing', 'restaurant']; + +const OFFERS = [ + { + id: 'luggage', + value: 'luggage', + title: 'Add luggage', + prise: '30' + }, + { + id: 'comfort', + value: 'comfort', + title: 'Switch to comfort class', + prise: '100' + }, + { + id: 'meal', + value: 'meal', + title: 'Add meal', + prise: '15' + }, + { + id: 'seats', + value: 'seats', + title: 'Choose seats', + prise: '5' + }, + { + id: 'train', + value: 'train', + title: 'Travel by train', + prise: '40' + }, + { + id: 'Uber', + value: 'uber', + title: 'Order Uber', + prise: '20' + }, + { + id: 'rent', + value: 'rent', + title: 'Rent a car', + prise: '200' + }, + { + id: 'breakfast', + value: 'breakfast', + title: 'Add breakfast', + prise: '50' + }, + { + id: 'tickets', + value: 'tickets', + title: 'Book tickets', + prise: '40' + }, + { + id: 'lunch', + value: 'lunch', + title: 'Lunch in city', + prise: '30' + } +]; + +const DESTINATIONS = [ + { + id: 'amsterdam', + name: 'Amsterdam', + description: '', + picture: [] + }, + { + id: 'geneva', + name: 'Geneva', + description: '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.', + picture: [ + { + src: 'img/photos/1.jpg', + description: 'Event photo' + }, + { + src: 'img/photos/2.jpg', + description: 'Event photo' + }, + { + src: 'img/photos/3.jpg', + description: 'Event photo' + }, + { + src: 'img/photos/4.jpg', + description: 'Event photo' + }, + { + src: 'img/photos/5.jpg', + description: 'Event photo' + } + ] + }, + { + id: 'chamonix', + name: 'Chamonix', + description: 'Chamonix, is a beautiful city, a true asian pearl, with crowded streets.', + picture: [ + { + src: 'https://loremflickr.com/248/152?random=15', + description: 'Event photo' + }, + { + src: 'https://loremflickr.com/248/152?random=1554', + description: 'Event photo' + }, + { + src: 'https://loremflickr.com/248/152?random=557', + description: 'Event photo' + }, + { + src: 'https://loremflickr.com/248/152?random=954', + description: 'Event photo' + }, + { + src: 'img/photos/5.jpg', + description: 'Event photo' + } + ] + } +]; + +export {FILTER__VALUE, SORT__VALUE, TYPES_ITEM, DESTINATIONS, OFFERS}; diff --git a/src/main.js b/src/main.js index e117782..ce5893e 100644 --- a/src/main.js +++ b/src/main.js @@ -1,14 +1,16 @@ -import Filters from './view/filters.js'; +import FiltersView from './view/filters-view.js'; import {render} from './render.js'; import BoardPresenter from './presenter/board-presenter.js'; +import PointsModel from './model/points-model.js'; const header = document.querySelector('.trip-main'); const filtersContainer = header.querySelector('.trip-controls__filters'); const main = document.querySelector('.page-main'); const mainContainer = main.querySelector('.trip-events'); -const boardPresenter = new BoardPresenter({boardContainer: mainContainer}); +const pointsModel = new PointsModel(); +const boardPresenter = new BoardPresenter({boardContainer: mainContainer, pointsModel}); -render(new Filters(), filtersContainer); +render(new FiltersView(), filtersContainer); boardPresenter.init(); diff --git a/src/mock/points.js b/src/mock/points.js new file mode 100644 index 0000000..3c8dd06 --- /dev/null +++ b/src/mock/points.js @@ -0,0 +1,38 @@ +import {getRandomArrayElement} from '../utils.js'; +import { TYPES_ITEM, DESTINATIONS } from '../const.js'; + +const mockPoints = [ + { + type: getRandomArrayElement(TYPES_ITEM), + destination: getRandomArrayElement(DESTINATIONS).id, + startDate: '2019-03-18T10:30', + endDate: '2019-03-18T11:00', + price: '130', + offers: ['luggage', 'meal'], + isFavorite: true, + }, + { + type: getRandomArrayElement(TYPES_ITEM), + destination: getRandomArrayElement(DESTINATIONS).id, + startDate: '2019-03-18T14:30', + endDate: '2019-03-18T16:05', + price: '30', + offers: ['luggage'], + isFavorite: false, + }, + { + type: getRandomArrayElement(TYPES_ITEM), + destination: getRandomArrayElement(DESTINATIONS).id, + startDate: '2019-03-20T08:25', + endDate: '2019-03-20T09:25', + price: '40', + offers: ['train'], + isFavorite: false, + } +]; + +function getRandomPoint() { + return getRandomArrayElement(mockPoints); +} + +export {getRandomPoint}; diff --git a/src/model/points-model.js b/src/model/points-model.js new file mode 100644 index 0000000..76410b9 --- /dev/null +++ b/src/model/points-model.js @@ -0,0 +1,12 @@ +import { getRandomPoint } from '../mock/points'; + +const POINT_COUNT = 4; + +export default class PointsModel { + points = Array.from({length: POINT_COUNT}, getRandomPoint); + + + getTasks() { + return this.points; + } +} diff --git a/src/presenter/board-presenter.js b/src/presenter/board-presenter.js index 03230b4..f0391de 100644 --- a/src/presenter/board-presenter.js +++ b/src/presenter/board-presenter.js @@ -1,24 +1,26 @@ -import Sort from '../view/sort.js'; -import ListPoints from '../view/list-points.js'; -import FormPoint from '../view/form-point.js'; -import Point from '../view/point.js'; +import SortView from '../view/sort-view.js'; +import ListPointsView from '../view/list-points-view.js'; +import FormPointView from '../view/form-point-view.js'; +import PointView from '../view/point-view.js'; import {RenderPosition, render} from '../render.js'; export default class BoardPresenter { - listContainer = new ListPoints(); + listContainer = new ListPointsView(); - constructor({boardContainer}) { + constructor({boardContainer, pointsModel}) { this.boardContainer = boardContainer; + this.pointsModel = pointsModel; } init() { - render(new Sort(), this.boardContainer); + this.boardPoints = [...this.pointsModel.getTasks()]; + render(new SortView(), this.boardContainer); render(this.listContainer, this.boardContainer); - render(new FormPoint(true, false), this.listContainer.getElement(), RenderPosition.AFTERBEGIN); + render(new FormPointView(true, false), this.listContainer.getElement(), RenderPosition.AFTERBEGIN); - for (let i = 0; i < 3; i++) { - render(new Point(), this.listContainer.getElement()); + for (let i = 1; i < this.boardPoints.length; i++) { + render(new PointView(this.boardPoints[i]), this.listContainer.getElement()); } } } diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..2972918 --- /dev/null +++ b/src/utils.js @@ -0,0 +1,45 @@ +import dayjs from 'dayjs'; + +const FORMATS = { + DATE: 'D MMM', + TIME: 'HH:mm', + FORM: 'DD/MM/YY HH:mm' +}; + +function getRandomArrayElement(items) { + return items[Math.floor(Math.random() * items.length)]; +} + +function humanizePointDate(date, format = FORMATS.DATE) { + return date ? dayjs(date).format(format) : ''; +} + +function capitalizeFirstLetter(text) { + const textFirstCapitalLetter = text.charAt(0).toUpperCase() + text.slice(1); + return textFirstCapitalLetter; +} + +function humanizePointDuration(date1, date2) { + const startDate = dayjs(date1); + const endDate = dayjs(date2); + const durationMinutes = endDate.diff(startDate, 'minute'); + let duration = ''; + + if (durationMinutes > 1140) { + const days = Math.trunc(durationMinutes / 1440); + const hours = Math.trunc((durationMinutes - (days * 1440)) / 60); + const minute = (durationMinutes - (days * 1440)) % 60; + duration = `${days.toString().padStart(2, '0')}D ${hours.toString().padStart(2, '0')}H ${minute.toString().padStart(2, '0')}M`; + } else { + if(durationMinutes >= 60) { + const hours = Math.trunc(durationMinutes / 60); + const minute = durationMinutes % 60; + duration = `${hours.toString().padStart(2, '0')}H ${minute.toString().padStart(2, '0')}M`; + }else { + duration = `${durationMinutes.toString().padStart(2, '0')}M`; + } + } + return duration; +} + +export {getRandomArrayElement, humanizePointDate, humanizePointDuration, capitalizeFirstLetter, FORMATS}; diff --git a/src/view/filters.js b/src/view/filters-view.js similarity index 90% rename from src/view/filters.js rename to src/view/filters-view.js index 6c0e563..bb2ac9b 100644 --- a/src/view/filters.js +++ b/src/view/filters-view.js @@ -1,5 +1,5 @@ import {createElement} from '../render.js'; -const FILTER__VALUE = ['everything', 'future', 'present', 'past']; +import { FILTER__VALUE } from '../const.js'; function createFilterItemTemplate(value) { return `
@@ -17,7 +17,7 @@ function createFiltersTemplate() { ); } -export default class Filters { +export default class FiltersView { getTemplate() { return createFiltersTemplate(); } diff --git a/src/view/form-point-view.js b/src/view/form-point-view.js new file mode 100644 index 0000000..850570c --- /dev/null +++ b/src/view/form-point-view.js @@ -0,0 +1,148 @@ +import {createElement} from '../render.js'; +import { DESTINATIONS, TYPES_ITEM } from '../const.js'; +import { OFFERS } from '../const.js'; +import { capitalizeFirstLetter, FORMATS, humanizePointDate } from '../utils.js'; + +const BLANK_POINT = { + type: 'flight', + destination: '', + startDate: '', + endDate: '', + price: '0', + offers: ['luggage', 'comfort', 'meal', 'seats', 'train'], +}; + +function createTypeItemTemplate(type) { + return ` +
+ + +
`; +} + +function createDetailsTemplate(offers, destination) { + const details = []; + if (offers) { + details.push(` +
+

Offers

+
+ ${offers.map((e) => { + const offer = OFFERS.find((item) => item.id === e); + return (` +
+ + +
`); + }).join('')} +
+
`); + } + + if (destination) { + const destinationDefault = DESTINATIONS.find((item) => item.id === destination); + details.push (` +
+

Destination

+ ${destinationDefault.description.trim() === 0 ? '' : `

${destinationDefault.description}

`} + ${destinationDefault.picture.length > 0 ? + `
+
+ ${destinationDefault.picture.map((e)=> `${e.description}`).join('')} +
+ ` : ''} +
`); + } + return details; +} + + +function createEventTemplate(point, edit) { + const {type, destination, startDate, endDate, price, offers} = point; + return ` +
  • +
    +
    +
    + + + +
    +
    + Event type + ${TYPES_ITEM.map((e)=> createTypeItemTemplate(e)).join('')} +
    +
    +
    + +
    + + + + ${DESTINATIONS.map((e)=> ``).join('')} + +
    + +
    + + + — + + +
    + +
    + + +
    + + + +
    +
    + ${createDetailsTemplate(offers, destination).join('')} +
    +
    +
  • `; +} + + +export default class FormPointView { + constructor({point = BLANK_POINT}) { + this.point = point; + } + + getTemplate() { + return createEventTemplate(this.point); + } + + getElement() { + if (!this.element) { + this.element = createElement(this.getTemplate()); + } + + return this.element; + } + // форма редактирования + + // editElement() { + // this.element = createElement(this.getTemplate(this.point, true)); + // return this.element; + // } + + removeElement() { + this.element = null; + } +} diff --git a/src/view/form-point.js b/src/view/form-point.js deleted file mode 100644 index f9b4a2f..0000000 --- a/src/view/form-point.js +++ /dev/null @@ -1,195 +0,0 @@ -import {createElement} from '../render.js'; - -const TYPES_ITEM = [ - { - value: 'taxi', - text: 'Taxi', - }, - { - value: 'bus', - text: 'Bus', - }, - { - value: 'train', - text: 'Train', - }, - { - value: 'ship', - text: 'Ship', - }, - { - value: 'drive', - text: 'Drive', - }, - { - value: 'flight', - text: 'Flight', - }, - { - value: 'check-in', - text: 'Check-in', - }, - { - value: 'sightseeing', - text: 'Sightseeing', - }, - { - value: 'restaurant', - text: 'Restaurant', - }, -]; - -const OFFERS = [ - { - value: 'luggage', - title: 'Add luggage', - prise: '30' - }, - { - value: 'comfort', - title: 'Switch to comfort class', - prise: '100' - }, - { - value: 'meal', - title: 'Add meal', - prise: '15' - }, - { - value: 'seats', - title: 'Choose seats', - prise: '5' - }, - { - value: 'train', - title: 'Travel by train', - prise: '40' - }, -]; - -function createTypeItemTemplate({value, text}) { - return ` -
    - - -
    `; -} - -function createDetailsTemplate(offers = true, destination = true) { - const details = []; - if (offers) { - details.push(` -
    -

    Offers

    -
    - ${OFFERS.map(({value, title, prise})=> ` -
    - - -
    `).join('')} -
    -
    `); - } - - if (destination) { - details.push(` -
    -

    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 -
    -
    -
    `); - } - - return details; -} - - -function createEventTemplate(offers, destination) { - return ` -
  • -
    -
    -
    - - - -
    -
    - Event type - ${TYPES_ITEM.map((e)=> createTypeItemTemplate(e)).join('')} -
    -
    -
    - -
    - - - - - - - -
    - -
    - - - — - - -
    - -
    - - -
    - - - -
    -
    - ${createDetailsTemplate(offers, destination).join('')} -
    -
    -
  • `; -} - - -export default class FormPoint { - getTemplate() { - return createEventTemplate(); - } - - getElement() { - if (!this.element) { - this.element = createElement(this.getTemplate()); - } - - return this.element; - } - - removeElement() { - this.element = null; - } -} diff --git a/src/view/list-points.js b/src/view/list-points-view.js similarity index 90% rename from src/view/list-points.js rename to src/view/list-points-view.js index 7a2c776..345e2ec 100644 --- a/src/view/list-points.js +++ b/src/view/list-points-view.js @@ -5,7 +5,7 @@ function createListTemplate() { } -export default class ListPoints { +export default class ListPointsView { getTemplate() { return createListTemplate(); } diff --git a/src/view/loading.js b/src/view/loading-view.js similarity index 82% rename from src/view/loading.js rename to src/view/loading-view.js index 7c89527..6e557b2 100644 --- a/src/view/loading.js +++ b/src/view/loading-view.js @@ -1,12 +1,12 @@ import {createElement} from '../render.js'; -function createLoadingTemlate() { +function createLoadingTemplate() { return '

    Loading...

    '; } export default class Loading { getTemplate() { - return createLoadingTemlate(); + return createLoadingTemplate(); } getElement() { diff --git a/src/view/point-view.js b/src/view/point-view.js new file mode 100644 index 0000000..d8d5735 --- /dev/null +++ b/src/view/point-view.js @@ -0,0 +1,74 @@ +import {createElement} from '../render.js'; +import {humanizePointDate, humanizePointDuration, capitalizeFirstLetter, FORMATS} from '../utils.js'; +import { OFFERS, DESTINATIONS } from '../const.js'; + +function createOffersTemplate(id) { + const offer = OFFERS.find((item) => item.id === id); + return ` +
  • + ${offer.title} + +€  + ${offer.prise} +
  • `; +} + +function createPointTemplate(point) { + const {type, destination, startDate, endDate, price, offers, isFavorite} = point; + const destinationDefault = DESTINATIONS.find((item) => item.id === destination).name; + return ` +
  • +
    + +
    + Event type icon +
    +

    ${capitalizeFirstLetter(type)} ${destinationDefault}

    +
    +

    + + — + +

    +

    ${humanizePointDuration(startDate,endDate)}

    +
    +

    + € ${price} +

    +

    Offers:

    +
      + ${offers.map((e) => createOffersTemplate(e)).join('')} +
    + + +
    +
  • `; +} + +export default class PointView { + constructor(point) { + this.point = point; + } + + getTemplate() { + return createPointTemplate(this.point); + } + + getElement() { + if (!this.element) { + this.element = createElement(this.getTemplate()); + } + + return this.element; + } + + removeElement() { + this.element = null; + } +} diff --git a/src/view/point.js b/src/view/point.js deleted file mode 100644 index 0ce9204..0000000 --- a/src/view/point.js +++ /dev/null @@ -1,60 +0,0 @@ -import {createElement} from '../render.js'; - -function createPointTemplate() { - return ` -
  • -
    - -
    - Event type icon -
    -

    Taxi Amsterdam

    -
    -

    - - — - -

    -

    30M

    -
    -

    - € 20 -

    -

    Offers:

    -
      -
    • - Order Uber - +€  - 20 -
    • -
    - - -
    -
  • `; -} - -export default class Point { - getTemplate() { - return createPointTemplate(); - } - - getElement() { - if (!this.element) { - this.element = createElement(this.getTemplate()); - } - - return this.element; - } - - removeElement() { - this.element = null; - } -} diff --git a/src/view/sort-view.js b/src/view/sort-view.js new file mode 100644 index 0000000..d209fc6 --- /dev/null +++ b/src/view/sort-view.js @@ -0,0 +1,36 @@ +import {createElement} from '../render.js'; +import { SORT__VALUE } from '../const.js'; +import { capitalizeFirstLetter } from '../utils.js'; + +function createSortItemTemplate(item) { + return `
    + + +
    `; +} + +function createSortTemplate() { + return ( + `
    + ${SORT__VALUE.map((e)=> createSortItemTemplate(e)).join('')} +
    ` + ); +} + +export default class Sort { + getTemplate() { + return createSortTemplate(); + } + + getElement() { + if (!this.element) { + this.element = createElement(this.getTemplate()); + } + + return this.element; + } + + removeElement() { + this.element = null; + } +} diff --git a/src/view/sort.js b/src/view/sort.js deleted file mode 100644 index 1b96ab8..0000000 --- a/src/view/sort.js +++ /dev/null @@ -1,56 +0,0 @@ -import {createElement} from '../render.js'; -const SORT__VALUE = [ - { - value: 'day', - text: 'Day' - }, - { - value: 'event', - text: 'Event' - }, - { - value: 'time', - text: 'Time' - }, - { - value: 'price', - text: 'Price' - }, - { - value: 'offer', - text: 'Offer' - } -]; - -function createSortItemTemplate({value, text}) { - return `
    - - -
    `; -} - -function createSortTemplate() { - return ( - `
    - ${SORT__VALUE.map((e)=> createSortItemTemplate(e)).join('')} -
    ` - ); -} - -export default class Sort { - getTemplate() { - return createSortTemplate(); - } - - getElement() { - if (!this.element) { - this.element = createElement(this.getTemplate()); - } - - return this.element; - } - - removeElement() { - this.element = null; - } -}