From 7d90c04569f5bbc41764269a8f3e4284667ef2b7 Mon Sep 17 00:00:00 2001 From: PavelUd Date: Thu, 6 Jun 2024 02:47:29 +0500 Subject: [PATCH 1/3] add some fixes --- src/const.js | 4 ++- src/main.js | 13 +++++++--- src/presenter/board-presenter.js | 15 ++++++++++- src/presenter/filter-presenter.js | 1 - src/presenter/point-presenter.js | 2 +- src/view/filter-view.js | 5 ++-- src/view/point-edit-view.js | 10 +++++--- src/view/trip-info-view.js | 42 ++++++++++++++++++++++--------- 8 files changed, 66 insertions(+), 26 deletions(-) diff --git a/src/const.js b/src/const.js index 33eeb84..5e9794f 100644 --- a/src/const.js +++ b/src/const.js @@ -4,6 +4,8 @@ export const DESTINATION_COUNT = 5; export const POINT_COUNT = 5; +const DEFAULT_TYPE = 'flight'; + export const Mode = { DEFAULT: 'default', EDITING: 'editing', @@ -91,7 +93,7 @@ export const POINT_EMPTY = { destination: null, isFavorite: false, offers: [], - type: null, + type: DEFAULT_TYPE, }; const SEC_IN_MIN = 60; diff --git a/src/main.js b/src/main.js index afb3f88..c7ba708 100644 --- a/src/main.js +++ b/src/main.js @@ -1,9 +1,8 @@ -import TripInfoView from './view/trip-info-view.js'; -import {render, RenderPosition} from '../src/framework/render.js'; import BoardPresenter from './presenter/board-presenter.js'; import DestinationsModel from './model/destinations-model.js'; import OffersModel from './model/offers-model.js'; import PointsModel from './model/point-model.js'; +import TripInfoPresenter from './presenter/trip-info-presenter.js'; import PointsApiService from './service/points-api-service.js'; import FilterModel from './model/filter-model.js'; import FilterPresenter from './presenter/filter-presenter.js'; @@ -27,6 +26,13 @@ const newPointButtonPresenter = new NewPointButtonPresenter({ container: tripEventsContainer }); +const tripInfoPresenter = new TripInfoPresenter({ + container: siteMainContainer, + pointsModel, + destinationsModel, + offersModel, +}); + const boardPresenter = new BoardPresenter({ container: tripEventsContainer, destinationsModel, @@ -43,8 +49,6 @@ const filterPresenter = new FilterPresenter({ }); -render(new TripInfoView(), siteMainContainer, RenderPosition.AFTERBEGIN); - newPointButtonPresenter.init({ onButtonClick:boardPresenter.handleNewPointClick }); @@ -52,3 +56,4 @@ newPointButtonPresenter.init({ pointsModel.init(); filterPresenter.init(); boardPresenter.init(); +tripInfoPresenter.init(); diff --git a/src/presenter/board-presenter.js b/src/presenter/board-presenter.js index e0977ea..29661e3 100644 --- a/src/presenter/board-presenter.js +++ b/src/presenter/board-presenter.js @@ -1,5 +1,6 @@ import EventListView from '../view/event-list-view'; import EmptyView from '../view/empty-view'; +import ErrorView from '../view/error-view.js'; import PointPresenter from './point-presenter'; import NewPointPresenter from './new-point-presenter'; import SortPresenter from './sort-presenter'; @@ -19,6 +20,7 @@ export default class BoardPresenter { #emptyListElement = null; #loadingElement = new LoadingView(); #eventListElement = new EventListView(); + #errorElement = new ErrorView(); #pointPresenters = new Map(); #destinationsModel; #offersModel; @@ -75,6 +77,7 @@ export default class BoardPresenter { } if (this.#isError) { + this.#renderError(); this.#clearBoard({ resetSortType: true }); return; } @@ -96,6 +99,10 @@ export default class BoardPresenter { render(this.#emptyListElement, this.#container); }; + #renderError = () => { + render(this.#errorElement, this.#container, RenderPosition.AFTERBEGIN); + }; + #clearBoard = ({resetSortType = false} = {}) => { this.#clearTaskList(); remove(this.#emptyListElement); @@ -132,7 +139,7 @@ export default class BoardPresenter { destinationsModel: this.#destinationsModel, offersModel: this.#offersModel, onPointsChange: this.#onPointChangeHandler, - handleModeChange: this.#modelEventHandler + handleModeChange: this.#handleModeChange }); pointPresenter.init(point); this.#pointPresenters.set(point.id, pointPresenter); @@ -189,6 +196,7 @@ export default class BoardPresenter { this.#isError = true; } else { this.#isLoading = false; + this.#isError = false; remove(this.#loadingElement); } this.#renderBoard(); @@ -207,6 +215,11 @@ export default class BoardPresenter { } }; + #handleModeChange = () => { + this.#pointPresenters.forEach((presenter) => presenter.resetView()); + this.#newPointPresenter.destroy(); + }; + handleNewPointClick = () => { this.#isCreating = true; this.#currentSortType = POINT_SORTS.DAY; diff --git a/src/presenter/filter-presenter.js b/src/presenter/filter-presenter.js index 016c218..aff0a1f 100644 --- a/src/presenter/filter-presenter.js +++ b/src/presenter/filter-presenter.js @@ -35,7 +35,6 @@ export default class FilterPresenter { const prevFilterElement = this.#filterElement; const filters = this.filters; - this.#filterElement = new FilterView({ items: filters, onItemChange: this.#onChangeFilter, diff --git a/src/presenter/point-presenter.js b/src/presenter/point-presenter.js index 10bca7b..c358844 100644 --- a/src/presenter/point-presenter.js +++ b/src/presenter/point-presenter.js @@ -117,8 +117,8 @@ export default class PointPresenter { resetView = () =>{ if(this.#mode !== Mode.DEFAULT){ - this.#replaceToPoint(); this.#editPointElement.reset(this.#point); + this.#replaceToPoint(); } }; diff --git a/src/view/filter-view.js b/src/view/filter-view.js index 651f2f5..3095f15 100644 --- a/src/view/filter-view.js +++ b/src/view/filter-view.js @@ -4,12 +4,13 @@ const createFilterTemplate = (filter) => { const {type, isDisabled, isChecked} = filter; return `
- - + +
`; }; const createFiltersTemplate = ({filters}) =>{ + let filtersTemplate = '
'; filters.forEach((filter) => { filtersTemplate += createFilterTemplate(filter); diff --git a/src/view/point-edit-view.js b/src/view/point-edit-view.js index e5c80cf..cf8ba7f 100644 --- a/src/view/point-edit-view.js +++ b/src/view/point-edit-view.js @@ -2,8 +2,7 @@ import { POINT_EMPTY, TYPES,EditType, ButtonLabel } from '../const.js'; import AbstractStatefulView from '../framework/view/abstract-stateful-view.js'; import {formatToSlashDate} from '../utils/utils.js'; import CalendarView from './calendar-view.js'; - -const DEFAULT_TYPE = 'flight'; +import he from 'he'; function createTypesElements(typeArray){ @@ -87,10 +86,10 @@ function createPointEditElement({state, destinations, offers, pointType}) { const { point, isDeleting, isDisabled, isSaving } = state; const pointDestination = destinations.find((destination) => destination.id === point.destination); const pointOffers = offers.find((subOffers) => subOffers.type === point.type)?.offers; - const name = pointDestination === undefined ? '' : pointDestination.name; + const name = pointDestination === undefined ? '' : he.encode(pointDestination.name); const {basePrice} = point; - const type = point.type === null ? DEFAULT_TYPE : point.type; + const type = point.type; const dateFrom = point.dateFrom === null ? '' : formatToSlashDate(point.dateFrom); const dateTo = point.dateTo === null ? '' : formatToSlashDate(point.dateTo); @@ -241,6 +240,9 @@ export default class EditPointView extends AbstractStatefulView{ #onDestinationChange = (evt) => { const newDestinationName = evt.target.value; const newDestination = this.#destinations.find((dest) => dest.name === newDestinationName); + if (!newDestination) { + return; + } this.updateElement({ point: { ...this._state.point, diff --git a/src/view/trip-info-view.js b/src/view/trip-info-view.js index c029519..5804456 100644 --- a/src/view/trip-info-view.js +++ b/src/view/trip-info-view.js @@ -1,22 +1,40 @@ import AbstractView from '../framework/view/abstract-view.js'; -function createTripInfoElement() { +function createTripInfoElement({route, dates, cost, isEmpty}) { return `
-
-

Amsterdam — Chamonix — Geneva

- -

Mar 18 — 20

-
- -

- Total: € 1230 -

-
`; + ${isEmpty ? '' : ` +
+

${route}

+

${dates}

+
+

+ Total: € ${cost} +

+`} +`; } export default class TripInfoView extends AbstractView { + #route = null; + #dates = null; + #cost = null; + #isEmpty = true; + + constructor({ route, dates, cost, isEmpty }) { + super(); + this.#route = route; + this.#dates = dates; + this.#cost = cost; + this.#isEmpty = isEmpty; + } + get template() { - return createTripInfoElement(); + return createTripInfoElement({ + route: this.#route, + dates: this.#dates, + cost: this.#cost, + isEmpty: this.#isEmpty, + }); } } From 53cde1c17ea0c1e347ed2cb377dd3c89ec349ee2 Mon Sep 17 00:00:00 2001 From: PavelUd Date: Thu, 6 Jun 2024 02:47:38 +0500 Subject: [PATCH 2/3] commint --- src/presenter/trip-info-presenter.js | 53 ++++++++++++++++++++ src/utils/trip-info-utils.js | 74 ++++++++++++++++++++++++++++ 2 files changed, 127 insertions(+) create mode 100644 src/presenter/trip-info-presenter.js create mode 100644 src/utils/trip-info-utils.js diff --git a/src/presenter/trip-info-presenter.js b/src/presenter/trip-info-presenter.js new file mode 100644 index 0000000..3c63e87 --- /dev/null +++ b/src/presenter/trip-info-presenter.js @@ -0,0 +1,53 @@ +import { RenderPosition, remove, render, replace } from '../framework/render'; +import { getTotalCost, getTripRoute, getTripDates } from '../utils/trip-info-utils.js'; +import TripInfoView from '../view/trip-info-view.js'; + +export default class TripInfoPresenter { + + #pointsModel = null; + #destinationsModel = null; + #offersModel = null; + #container = null; + #tripInfoElement = null; + + constructor({ container, pointsModel, destinationsModel, offersModel }) { + this.#container = container; + this.#pointsModel = pointsModel; + this.#destinationsModel = destinationsModel; + this.#offersModel = offersModel; + } + + init() { + this.#renderTripInfo(); + this.#pointsModel.addObserver(this.#handleModelChange); + } + + #renderTripInfo = () => { + const points = this.#pointsModel.getAll(); + const destinations = this.#destinationsModel.getAll(); + const offers = this.#offersModel.getAll(); + const prevTripInfoElement = this.#tripInfoElement; + this.#tripInfoElement = new TripInfoView({ + route: getTripRoute(points, destinations), + dates: getTripDates(points), + cost: getTotalCost(points, offers), + isEmpty: !points.length, + }); + + if (!prevTripInfoElement) { + render( + this.#tripInfoElement, + this.#container, + RenderPosition.AFTERBEGIN + ); + return; + } + + replace(this.#tripInfoElement, prevTripInfoElement); + remove(prevTripInfoElement); + }; + + #handleModelChange = () => { + this.#renderTripInfo(); + }; +} diff --git a/src/utils/trip-info-utils.js b/src/utils/trip-info-utils.js new file mode 100644 index 0000000..023354d --- /dev/null +++ b/src/utils/trip-info-utils.js @@ -0,0 +1,74 @@ +import dayjs from 'dayjs'; +import { sort } from './utils.js'; + +const getOffersCost = (currentOffers, offers) => { + let totalCost = 0; + for (const id of currentOffers) { + const offer = offers.find((ofr) => ofr.id === id); + if (offer) { + totalCost += offer.price; + } + } + return totalCost; +}; + +export const getTripDates = (points) => { + const sortedPoints = sort(points); + + if (sortedPoints.length === 0) { + return ''; + } + + const startDate = dayjs(sortedPoints[0].dateFrom).format('DD MMM'); + const finishDate = dayjs(sortedPoints[sortedPoints.length - 1].dateTo).format('DD MMM'); + + return `${startDate} — ${finishDate}`; +}; + +export const getTripRoute = (points, destinations) => { + const sortedPoints = sort(points); + + const routeNames = sortedPoints.map((point) => + destinations.find((destination) => destination.id === point.destination)?.name + ); + + if (routeNames.length === 0) { + return ''; + } + + const uniqueCities = new Set(routeNames); + const startCity = routeNames[0]; + const endCity = routeNames[routeNames.length - 1]; + + if (uniqueCities.size <= 3 && startCity !== endCity || uniqueCities.size === 1) { + return [...uniqueCities].join(' — '); + } + + return `${startCity} — ... — ${endCity}`; +}; + +export const calculateTripRoute = (points, destinations) => { + const sortedPoints = sort(points); + const route = []; + + for (const point of sortedPoints) { + const destination = destinations.find((dest) => dest.id === point.destination); + if (destination) { + route.push(destination.name); + } + } + + return route; +}; + +export const getTotalCost = (points, offers) => { + let totalCost = 0; + + for (const point of points) { + const offer = offers.find((ofr) => point.type === ofr.type); + const offerCost = getOffersCost(point.offers, offer?.offers) || 0; + totalCost += point.basePrice + offerCost; + } + + return totalCost; +}; From 7994fc5b57aef067d69c4fcd35afeaf0e6a522db Mon Sep 17 00:00:00 2001 From: PavelUd Date: Thu, 6 Jun 2024 06:18:04 +0500 Subject: [PATCH 3/3] =?UTF-8?q?=D0=B2=D1=80=D0=B5=D0=BC=D1=8F=20=D0=BF?= =?UTF-8?q?=D1=80=D0=B8=D1=88=D0=BB=D0=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/const.js | 7 +++ src/main.js | 10 ++-- src/mock/const.js | 49 ------------------- src/mock/destination.js | 19 -------- src/mock/filter.js | 9 ---- src/mock/offer.js | 8 ---- src/mock/point.js | 15 ------ src/mock/util.js | 32 ------------- src/model/point-model.js | 2 +- src/presenter/board-presenter.js | 15 +++--- src/presenter/filter-presenter.js | 2 +- src/presenter/new-point-presenter.js | 22 ++++----- src/presenter/point-presenter.js | 29 +++++++++--- src/service/mock-service.js | 71 ---------------------------- src/utils/{utils.js => common.js} | 6 ++- src/utils/trip-info-utils.js | 2 +- src/view/empty-view.js | 8 ++-- src/view/point-edit-view.js | 6 +-- src/view/point-view.js | 2 +- 19 files changed, 67 insertions(+), 247 deletions(-) delete mode 100644 src/mock/const.js delete mode 100644 src/mock/destination.js delete mode 100644 src/mock/filter.js delete mode 100644 src/mock/offer.js delete mode 100644 src/mock/point.js delete mode 100644 src/mock/util.js delete mode 100644 src/service/mock-service.js rename src/utils/{utils.js => common.js} (93%) diff --git a/src/const.js b/src/const.js index 5e9794f..92a97f2 100644 --- a/src/const.js +++ b/src/const.js @@ -86,6 +86,13 @@ export const EnabledSortType = { [POINT_SORTS.OFFERS]: false }; +export const EmptyListMessage = { + [FILTER_TYPES.EVERYTHING]: 'Click New Event to create your first point', + [FILTER_TYPES.FUTURE]: 'There are no future events now', + [FILTER_TYPES.PRESENT]: 'There are no present events now', + [FILTER_TYPES.PAST]: 'There are no past events now' +}; + export const POINT_EMPTY = { basePrice: 0, dateFrom: null, diff --git a/src/main.js b/src/main.js index c7ba708..2f4750b 100644 --- a/src/main.js +++ b/src/main.js @@ -23,7 +23,7 @@ const pointsModel = new PointsModel({service : service, destinationsModel : dest const filterModel = new FilterModel(); const newPointButtonPresenter = new NewPointButtonPresenter({ - container: tripEventsContainer + container: siteMainContainer }); const tripInfoPresenter = new TripInfoPresenter({ @@ -48,12 +48,10 @@ const filterPresenter = new FilterPresenter({ filterModel, }); - -newPointButtonPresenter.init({ - onButtonClick:boardPresenter.handleNewPointClick -}); - pointsModel.init(); filterPresenter.init(); boardPresenter.init(); +newPointButtonPresenter.init({ + onButtonClick:boardPresenter.handleNewPointClick +}); tripInfoPresenter.init(); diff --git a/src/mock/const.js b/src/mock/const.js deleted file mode 100644 index d41d659..0000000 --- a/src/mock/const.js +++ /dev/null @@ -1,49 +0,0 @@ -export const CITIES = [ - 'Oslo', - 'Kopenhagen', - 'Den Haag', - 'Rotterdam', - 'Sochi', - 'Moscow', - 'London', - 'Amsterdam', - 'Chamonix', - 'Geneva', - 'Saint Petersburg', - 'Paris', - 'Ekaterinburg', -]; - -export const OFFERS = [ - 'Close But No Cigar', - 'On the Same Page', - 'Jaws of Death', - 'Every Cloud Has a Silver Lining', - 'Jig Is Up', - 'In a Pickle', - 'What Goes Up Must Come Down', - 'Break The Ice', - 'In the Red', -]; - -export 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.' -]; - -export const Price = { - MIN: 1, - MAX: 1000 - -}; - -export const Duration = { - DAY: 5, - HOUR: 5, - MINUTE: 59, -}; - diff --git a/src/mock/destination.js b/src/mock/destination.js deleted file mode 100644 index 0849dde..0000000 --- a/src/mock/destination.js +++ /dev/null @@ -1,19 +0,0 @@ -import {getRandomArrayElement} from './util.js'; -import {CITIES, DESCRIPTIONS} from './const.js'; - -export const getRandomDestination = () => { - const city = getRandomArrayElement(CITIES); - const description = getRandomArrayElement(DESCRIPTIONS); - - return { - id: crypto.randomUUID(), - name: city, - description: description, - pictures: [ - { - 'src': `https://loremflickr.com/248/152?random=${crypto.randomUUID()}`, - 'description' : `${city} description` - } - ] - }; -}; diff --git a/src/mock/filter.js b/src/mock/filter.js deleted file mode 100644 index a7eda9d..0000000 --- a/src/mock/filter.js +++ /dev/null @@ -1,9 +0,0 @@ -import {filter} from '../utils'; - -export const generateFilter = (points) => - Object.entries(filter).map( - ([filterName, filterPoints]) => ({ - name: filterName, - count: filterPoints(points).length, - }), - ); diff --git a/src/mock/offer.js b/src/mock/offer.js deleted file mode 100644 index 6ff10be..0000000 --- a/src/mock/offer.js +++ /dev/null @@ -1,8 +0,0 @@ -import {getRandomInteger, getRandomArrayElement} from './util.js'; -import{Price, OFFERS} from './const.js'; - -export const getRandomOffer = () => ({ - id:crypto.randomUUID(), - title: getRandomArrayElement(OFFERS), - price: getRandomInteger(Price.MIN, (Price.MAX / 10)) -}); diff --git a/src/mock/point.js b/src/mock/point.js deleted file mode 100644 index 36d4528..0000000 --- a/src/mock/point.js +++ /dev/null @@ -1,15 +0,0 @@ -import {getRandomInteger, getRandomDate} from './util.js'; -import {Price} from './const.js'; - -export const getRandomPoint = (type, destinationId, offerIds) => ({ - id: crypto.randomUUID(), - basePrice: getRandomInteger(Price.MIN, Price.MAX), - dateFrom: getRandomDate(), - dateTo: getRandomDate({ next: true }), - destination: destinationId, - isFavorite: Boolean(getRandomInteger(0, 1)), - offers: offerIds, - type -}); - - diff --git a/src/mock/util.js b/src/mock/util.js deleted file mode 100644 index 892869c..0000000 --- a/src/mock/util.js +++ /dev/null @@ -1,32 +0,0 @@ -import dayjs from 'dayjs'; -import {Duration} from './const.js'; - -export const getRandomInteger = (a = 0, b = 1) => { - const lower = Math.ceil(Math.min(a, b)); - const upper = Math.floor(Math.max(a, b)); - - return Math.floor(lower + Math.random() * (upper - lower + 1)); -}; - -export const getRandomArrayElement = (items) => items[getRandomInteger(0, items.length - 1)]; - -let date = dayjs().subtract(getRandomInteger(0, Duration.DAY), 'day').toDate(); - -export const getRandomDate = (next) => { - const minsGap = getRandomInteger(0, Duration.MINUTE); - const hoursGap = getRandomInteger(1, Duration.HOUR); - const daysGap = getRandomInteger(0, Duration.DAY); - - if (next) { - date = dayjs(date) - .add(minsGap, 'minute') - .add(hoursGap, 'hour') - .add(daysGap, 'day') - .toDate(); - } - - return date; -}; - -export const updateItem = (items, update) => items.map((item) => item.id === update.id ? update : item); - diff --git a/src/model/point-model.js b/src/model/point-model.js index feb2873..9e76b95 100644 --- a/src/model/point-model.js +++ b/src/model/point-model.js @@ -1,5 +1,5 @@ import Observable from '../framework/observable'; -import { updateItem } from '../mock/util.js'; +import { updateItem } from '../utils/common.js'; import {UpdateType} from '../const.js'; import { adaptToClient, adaptToServer } from '../utils/adapter.js'; diff --git a/src/presenter/board-presenter.js b/src/presenter/board-presenter.js index 29661e3..835b011 100644 --- a/src/presenter/board-presenter.js +++ b/src/presenter/board-presenter.js @@ -5,7 +5,7 @@ import PointPresenter from './point-presenter'; import NewPointPresenter from './new-point-presenter'; import SortPresenter from './sort-presenter'; import {remove, render, RenderPosition} from '../framework/render'; -import { filter, sort } from '../utils/utils'; +import { filter, sort } from '../utils/common.js'; import LoadingView from '../view/load-view.js'; import UiBlocker from '../framework/ui-blocker/ui-blocker.js'; import {FILTER_TYPES, POINT_SORTS, UpdateType, UserAction} from '../const.js'; @@ -70,17 +70,15 @@ export default class BoardPresenter { } #renderBoard = () =>{ - - if (this.#isLoading) { - this.#renderLoader(); - return; - } - if (this.#isError) { this.#renderError(); this.#clearBoard({ resetSortType: true }); return; } + if (this.#isLoading) { + this.#renderLoader(); + return; + } if (!this.points.length && !this.#isCreating) { this.#renderEmptyList(); @@ -181,6 +179,7 @@ export default class BoardPresenter { #clearTaskList = () => { this.#pointPresenters.forEach((presenter) => presenter.destroy()); this.#pointPresenters.clear(); + this.#newPointPresenter.destroy(); }; #handleSortChange = (sortType) => { @@ -203,8 +202,10 @@ export default class BoardPresenter { break; case UpdateType.PATCH: this.#pointPresenters.get(data.id).init(data); + this.#pointPresenters.get(data.id).resetView(); break; case UpdateType.MINOR: + this.#clearBoard(); this.#renderBoard(); break; diff --git a/src/presenter/filter-presenter.js b/src/presenter/filter-presenter.js index aff0a1f..39c6585 100644 --- a/src/presenter/filter-presenter.js +++ b/src/presenter/filter-presenter.js @@ -1,6 +1,6 @@ import { UpdateType } from '../const'; import { render, replace, remove } from '../framework/render'; -import { filter } from '../utils/utils.js'; +import { filter } from '../utils/common.js'; import FilterView from '../view/filter-view'; export default class FilterPresenter { diff --git a/src/presenter/new-point-presenter.js b/src/presenter/new-point-presenter.js index 5b9eeb2..c62ae94 100644 --- a/src/presenter/new-point-presenter.js +++ b/src/presenter/new-point-presenter.js @@ -59,8 +59,6 @@ export default class NewPointPresenter { UpdateType.MINOR, point ); - - this.destroy({ isCanceled: false }); }; setSaving = () => { @@ -70,17 +68,17 @@ export default class NewPointPresenter { }); }; - setAborting = () => { - this.#newPointElement.shake(this.#resetFormState); - }; + setAborting() { + const resetFormState = () => { + this.#newPointElement.updateElement({ + isDisabled: false, + isSaving: false, + isDeleting: false, + }); + }; - #resetFormState = () => { - this.#newPointElement.updateElement({ - isDisabled: false, - isSaving: false, - isDeleting: false, - }); - }; + this.#newPointElement.shake(resetFormState); + } #onCloseForm = () => { this.destroy(); diff --git a/src/presenter/point-presenter.js b/src/presenter/point-presenter.js index c358844..a0783ff 100644 --- a/src/presenter/point-presenter.js +++ b/src/presenter/point-presenter.js @@ -2,7 +2,7 @@ import PointEditView from '../view/point-edit-view'; import PointView from '../view/point-view'; import {render,replace,remove } from '../framework/render'; import { Mode, EditType } from '../const'; -import { isBigDifference } from '../utils/utils.js'; +import { isMinorUpdate } from '../utils/common.js'; import {UpdateType, UserAction} from '../const.js'; @@ -78,7 +78,12 @@ export default class PointPresenter { this.#replaceToForm(); }; - #onCloseEditClick = () => this.#replaceToPoint(); + #onCloseEditClick = () => { + if (!this.#editPointElement.isDisabled) { + this.#editPointElement.reset(this.#point); + this.#replaceToPoint(); + } + }; #escKeydown = (evt) => { if (evt.keyCode === 27 || evt.key === 'Escape') { @@ -101,7 +106,7 @@ export default class PointPresenter { }; setSaving = () => { - if(this.#mode === Mode.DEFAULT){ + if(this.#mode === Mode.EDITING){ this.#editPointElement.updateElement({ isDisabled: true, isSaving: true, @@ -113,6 +118,9 @@ export default class PointPresenter { if(this.#mode === Mode.DEFAULT){ this.#editPointElement.shake(); } + else { + this.#editPointElement.shake(this.#resetFormState); + } }; resetView = () =>{ @@ -129,6 +137,14 @@ export default class PointPresenter { }); }; + #resetFormState = () => { + this.#editPointElement.updateElement({ + isDisabled: false, + isSaving: false, + isDeleting: false + }); + }; + destroy = () => { remove(this.#editPointElement); remove(this.#pointElement); @@ -145,14 +161,15 @@ export default class PointPresenter { }; #formSubmitHandler = (point) => { - const isMinor = isBigDifference(point, this.#point); + const isMinor = isMinorUpdate(point, this.#point); this.#onPointsChangeHandler( UserAction.UPDATE_POINT, isMinor ? UpdateType.MINOR : UpdateType.PATCH, point ); - - this.#replaceToPoint(); + if (!this.#editPointElement._state.isDisabled) { + this.#replaceToPoint(); + } }; #onEditPointDelete = (point) =>{ diff --git a/src/service/mock-service.js b/src/service/mock-service.js deleted file mode 100644 index 30a5508..0000000 --- a/src/service/mock-service.js +++ /dev/null @@ -1,71 +0,0 @@ -import {TYPES, POINT_COUNT, DESTINATION_COUNT, OFFER_COUNT} from '../const.js'; -import {getRandomArrayElement, getRandomInteger} from '../mock/util.js'; -import{getRandomDestination} from '../mock/destination.js'; -import{getRandomOffer} from '../mock/offer.js'; -import{getRandomPoint} from '../mock/point.js'; - - -export default class MockService { - - destinations = []; - offers = []; - points = []; - - constructor() { - this.destinations = this.generateDestinations(); - this.offers = this.generateOffers(); - this.points = this.generatePoints(); - } - - getDestinations() { - return this.destinations; - } - - getOffers(){ - return this.offers; - } - - getPoints(){ - return this.points; - } - - generateDestinations() { - return Array.from({ length: DESTINATION_COUNT }, getRandomDestination); - } - - generateOffers() { - return TYPES.map((type) => ({type, - offers: Array.from({ length: OFFER_COUNT }, getRandomOffer) - })); - } - - generatePoints() { - return Array.from({length: POINT_COUNT}, () =>{ - const type = getRandomArrayElement(TYPES); - const destination = getRandomArrayElement(this.destinations); - const hasOffers = getRandomInteger(0, 1); - - const offersByType = this.offers.find((offerByType) => offerByType.type === type); - const offerIds = (hasOffers) - ? offersByType.offers - .slice(0, getRandomInteger(0, 5)) - .map((offer) => offer.id) - : []; - - return getRandomPoint(type, destination.id, offerIds); - - }); - } - - updatePoint(updatedPoint){ - return updatedPoint; - } - - addPoint(data){ - return {...data, id: crypto.randomUUID()}; - } - - deletePoint(){ - // - } -} diff --git a/src/utils/utils.js b/src/utils/common.js similarity index 93% rename from src/utils/utils.js rename to src/utils/common.js index 50aa47f..ceb60cc 100644 --- a/src/utils/utils.js +++ b/src/utils/common.js @@ -1,9 +1,11 @@ import dayjs from 'dayjs'; import duration from 'dayjs/plugin/duration'; import relativeTime from 'dayjs/plugin/relativeTime'; -import {MSEC_IN_DAY, MSEC_IN_HOUR, FILTER_TYPES, POINT_SORTS} from '../const'; +import {MSEC_IN_DAY, MSEC_IN_HOUR, FILTER_TYPES, POINT_SORTS} from '../const.js'; +export const updateItem = (items, update) => items.map((item) => item.id === update.id ? update : item); + dayjs.extend(duration); dayjs.extend(relativeTime); @@ -39,7 +41,7 @@ export const getPointDuration = (point) => { }}; -export const isBigDifference = (pointA, pointB) => +export const isMinorUpdate = (pointA, pointB) => pointA.dateFrom !== pointB.dateFrom || pointA.basePrice !== pointB.basePrice || getPointDuration(pointA.dateFrom, pointA.dateTo) !== getPointDuration(pointB.dateFrom, pointB.dateTo); diff --git a/src/utils/trip-info-utils.js b/src/utils/trip-info-utils.js index 023354d..e8c75f6 100644 --- a/src/utils/trip-info-utils.js +++ b/src/utils/trip-info-utils.js @@ -1,5 +1,5 @@ import dayjs from 'dayjs'; -import { sort } from './utils.js'; +import { sort } from './common.js'; const getOffersCost = (currentOffers, offers) => { let totalCost = 0; diff --git a/src/view/empty-view.js b/src/view/empty-view.js index ec73d63..a6f8f67 100644 --- a/src/view/empty-view.js +++ b/src/view/empty-view.js @@ -1,8 +1,8 @@ import AbstractView from '../framework/view/abstract-view'; +import { EmptyListMessage } from '../const.js'; - -function createEmptyTemplate(){ - return '

Click New Event to create your first point

'; +function createEmptyTemplate({message}){ + return `

${message}

`; } export default class EmptyView extends AbstractView{ @@ -15,6 +15,6 @@ export default class EmptyView extends AbstractView{ } get template(){ - return createEmptyTemplate(); + return createEmptyTemplate({message : EmptyListMessage[this.#filterType]}); } } diff --git a/src/view/point-edit-view.js b/src/view/point-edit-view.js index cf8ba7f..987089a 100644 --- a/src/view/point-edit-view.js +++ b/src/view/point-edit-view.js @@ -1,6 +1,6 @@ import { POINT_EMPTY, TYPES,EditType, ButtonLabel } from '../const.js'; import AbstractStatefulView from '../framework/view/abstract-stateful-view.js'; -import {formatToSlashDate} from '../utils/utils.js'; +import {formatToSlashDate} from '../utils/common.js'; import CalendarView from './calendar-view.js'; import he from 'he'; @@ -77,7 +77,7 @@ function createRollupButton(){ } function createPointControls({type, isDeleting, isSaving, isDisabled}){ - return `${createSaveButton(isSaving, isDisabled)} + return `${createSaveButton({isSaving, isDisabled})} ${createDeleteButton({type, isDeleting})} ${type === EditType.CREATING ? '' : createRollupButton()}`; } @@ -140,7 +140,7 @@ function createPointEditElement({state, destinations, offers, pointType}) {

Destination

-

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

+

${pointDestination === undefined ? '' : pointDestination.description}

${createDestinationPhotos(pointDestination)}
diff --git a/src/view/point-view.js b/src/view/point-view.js index f37c6b5..87cb944 100644 --- a/src/view/point-view.js +++ b/src/view/point-view.js @@ -1,6 +1,6 @@ import { POINT_EMPTY} from '../const.js'; import AbstractView from '../framework/view/abstract-view.js'; -import{formatStringDateTime, getPointDuration, formatStringTime, formatStringDate} from '../utils/utils.js'; +import{formatStringDateTime, getPointDuration, formatStringTime, formatStringDate} from '../utils/common.js'; function createOfferElements(pointOffers, selectedOffers) {