Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions Beverage.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
function createBeverage(options) {
const view = document.createElement('fieldset');
view.className = 'beverage';
view.innerHTML = `
<span class="btn-delete">&times;</span>
<h4 class="beverage-count">Напиток №<span class="number">${options.number}</span></h4>
<label class="field">
<span class="label-text">Я буду</span>
<select name="name">
<option value="espresso">Эспрессо</option>
<option value="cappuccino" selected>Капучино</option>
<option value="cacao">Какао</option>
</select>
</label>
<div class="field">
<span class="checkbox-label">Сделайте напиток на</span>
<label class="checkbox-field">
<input type="radio" name="milk-${options.number}" value="usual" checked />
<span>обычном молоке</span>
</label>
<label class="checkbox-field">
<input type="radio" name="milk-${options.number}" value="no-fat" />
<span>обезжиренном молоке</span>
</label>
<label class="checkbox-field">
<input type="radio" name="milk-${options.number}" value="soy" />
<span>соевом молоке</span>
</label>
<label class="checkbox-field">
<input type="radio" name="milk-${options.number}" value="coconut" />
<span>кокосовом молоке</span>
</label>
</div>
<div class="field">
<span class="checkbox-label">Добавьте к напитку:</span>
<label class="checkbox-field">
<input type="checkbox" name="options-${options.number}" value="whipped cream" />
<span>взбитых сливок</span>
</label>
<label class="checkbox-field">
<input type="checkbox" name="options-${options.number}" value="marshmallow" />
<span>зефирок</span>
</label>
<label class="checkbox-field">
<input type="checkbox" name="options-${options.number}" value="chocolate" />
<span>шоколад</span>
</label>
<label class="checkbox-field">
<input type="checkbox" name="options-${options.number}" value="cinnamon" />
<span>корицу</span>
</label>
</div>
<label class="field">
<span>И ещё вот что</span>
<textarea class="wishes" name="wishes"></textarea>
<span>Важи пожелания:</span>
<p class="wishes-result"></p>
</label>`;
return view;
}

class Beverage {
view;
#container;
#number;
#numberView;
#variableElements;

constructor(options) {
this.view = createBeverage(options);
this.#number = options.number;
this.#container = options.container;
this.#numberView = this.view.getElementsByClassName('number')[0];
this.#variableElements = Array.from(this.view.getElementsByTagName('input'));

const wishesInput = this.view.querySelector('.wishes');
const wishesResult = this.view.querySelector('.wishes-result')
wishesInput.addEventListener('input', event => {
const regex = /срочно|быстрее|побыстрее|скорее|поскорее|очень нужно/gmi;
wishesResult.innerHTML = event.target.value.replace(regex, `<b>$&</b>`);
});

const deleteButton = this.view.querySelector('.btn-delete');
deleteButton.addEventListener('click', () => {
this.#container ? this.#container.remove(this.#number - 1) : this.view.remove();
});
}

set number(value) {
if (value < 0) {
throw 'incorrect number';
}
this.#number = value;
this.#updateView();
}

#updateView() {
this.#numberView.textContent = this.#number;
this.#variableElements.forEach(element => element.name = element.name.replace(/\d+/, this.#number));
}
}
27 changes: 27 additions & 0 deletions ItemContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class ItemContainer {
#source = [];
#view;

constructor(view) {
this.#view = view;
}

get count() {
return this.#source.length;
}

append(item) {
this.#source.push(item);
this.#view.append(item.view);
}

remove(index) {
if (this.count > 1) {
const [removedItem] = this.#source.splice(index, 1);
removedItem.view.remove();
for (let subIndex = index; subIndex < this.#source.length; subIndex++) {
this.#source[subIndex].number = subIndex + 1;
}
}
}
}
83 changes: 33 additions & 50 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,56 +6,10 @@
<link rel="stylesheet" href="styles.css" />
</head>
<body>
<form>
<fieldset class="beverage">
<h4 class="beverage-count">Напиток №1</h4>
<label class="field">
<span class="label-text">Я буду</span>
<select>
<option value="espresso">Эспрессо</option>
<option value="capuccino" selected>Капучино</option>
<option value="cacao">Какао</option>
</select>
</label>
<div class="field">
<span class="checkbox-label">Сделайте напиток на</span>
<label class="checkbox-field">
<input type="radio" name="milk" value="usual" checked />
<span>обычном молоке</span>
</label>
<label class="checkbox-field">
<input type="radio" name="milk" value="no-fat" />
<span>обезжиренном молоке</span>
</label>
<label class="checkbox-field">
<input type="radio" name="milk" value="soy" />
<span>соевом молоке</span>
</label>
<label class="checkbox-field">
<input type="radio" name="milk" value="coconut" />
<span>кокосовом молоке</span>
</label>
</div>
<div class="field">
<span class="checkbox-label">Добавьте к напитку:</span>
<label class="checkbox-field">
<input type="checkbox" name="options" value="whipped cream" />
<span>взбитых сливок</span>
</label>
<label class="checkbox-field">
<input type="checkbox" name="options" value="marshmallow" />
<span>зефирок</span>
</label>
<label class="checkbox-field">
<input type="checkbox" name="options" value="chocolate" />
<span>шоколад</span>
</label>
<label class="checkbox-field">
<input type="checkbox" name="options" value="cinnamon" />
<span>корицу</span>
</label>
</div>
</fieldset>
<form class="beverage-form">
<div class="beverage-list">
</div>

<div>
<button type="button" class="add-button">+ Добавить напиток</button>
</div>
Expand All @@ -64,6 +18,35 @@ <h4 class="beverage-count">Напиток №1</h4>
</div>
</form>

<dialog class="confirmation">
<div class="modal-header">
<span class="modal-title">Заказ принят!</span>
<span class="btn-close">&times;</span>
</div>
<div class="modal-body">
<span class="modal-title">Вы заказали <span class="count"></span></span>
<table class="beverage-table">
<thead>
<tr>
<th>Напиток</th>
<th>Молоко</th>
<th>Дополнительно</th>
<th>Пожелания</th>
</tr>
</thead>
</table>
</div>
<div class="modal-footer">
<label>
<span>Время заказа</span>
<input type="date" name="deliver-date">
</label>
<button class="btn-confirm">Оформить</button>
</div>
</dialog>

<script src="ItemContainer.js"></script>
<script src="Beverage.js"></script>
<script src="index.js"></script>
</body>
</html>
123 changes: 123 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
const translation = {
'espresso': 'эспрессо',
'cappuccino': 'капучино',
'cacao': 'какао',
'usual': 'обычное',
'no-fat': 'обезжиренное',
'soy': 'соевое',
'coconut': 'кокосовое',
'whipped cream': 'взбитые сливки',
'marshmallow': 'зефирки',
'chocolate': 'шоколад',
'cinnamon': 'корицу'
};

const form = document.querySelector('.beverage-form');
const beverageList = document.querySelector('.beverage-list');
const beverageContainer = new ItemContainer(beverageList);

const addButton = document.querySelector('.add-button');
const doneButton = document.querySelector('.submit-button');

const modal = document.querySelector('.confirmation');
const modalConfirm = document.querySelector('.confirmation .btn-confirm');
const modalClose = document.querySelector('.confirmation .btn-close');

const modalCounter = document.querySelector('.confirmation .modal-title .count');
const table = modal.querySelector('table');

beverageContainer.append(new Beverage({
container: beverageContainer,
number: 1
}));

addButton.addEventListener('click', () => {
beverageContainer.append(new Beverage({
container: beverageContainer,
number: beverageContainer.count + 1,
}));
});
doneButton.addEventListener('click', submitHandler);

modalConfirm.addEventListener('click', modalConfirmHandle);
modalClose.addEventListener('click', () => modal.close());

function modalConfirmHandle() {
const deliverDateField = modal.querySelector('[name="deliver-date"]');
const inputDate = new Date(deliverDateField.value);
if (inputDate < Date.now()) {
deliverDateField.style.backgroundColor = 'rgba(239,29,25,0.07)';
alert('Мы не умеем перемещаться во времени. Выберите время позже, чем текущее');
} else {
deliverDateField.style.backgroundColor = '#fff';
modal.close()
}
}

function submitHandler(event) {
event.preventDefault();
renderConfirmation();
modal.showModal();
}

function renderConfirmation() {
const formData = getFormData(form);
const count = formData.length;
const declinations = ['напиток', 'напитка', 'напитков'];
modalCounter.textContent = `${count} ${getDeclination(count, declinations)}`;
fillTable(table, formData);
}

function getFormData(form) {
const beverageForms = Array.from(form.querySelectorAll('.beverage'));
return beverageForms.map(getBeverageData);
}

function getBeverageData(beverageForm) {
const name = beverageForm.querySelector('[name="name"]');
const milk = beverageForm.querySelector('[name^="milk-"]:checked');
const options = Array.from(beverageForm.querySelectorAll('[name^="options-"]:checked'));
const wishes = beverageForm.querySelector('.wishes-result');

return {
name: name.value,
milk: milk.value,
options: options.map(option => option.value),
wishes: wishes.innerHTML
}
}

function fillTable(table, formData) {
const content = formData.map(data => {
const row = document.createElement('tr');
row.innerHTML = `
<td>${translation[data.name.toLowerCase()]}</td>
<td>${translation[data.milk.toLowerCase()]}</td>
<td>${data.options.map(option => translation[option.toLowerCase()]).join(', ') || ''}</td>
<td>${data.wishes}</td>
`;
return row;
});

const oldTableBody = table.querySelector('tbody');
oldTableBody && oldTableBody.remove();

const tableBody = table.createTBody();
tableBody.append(...content);
}

function getDeclination(number, declinations) {
let n = Math.abs(number);
n %= 100;
if (n >= 5 && n <= 20) {
return declinations[2];
}
n %= 10;
if (n === 1) {
return declinations[0];
}
if (n >= 2 && n <= 4) {
return declinations[1];
}
return declinations[2];
}
Loading