Skip to content
Open
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
233 changes: 127 additions & 106 deletions public/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,111 @@ let focusedAutocompleteIndex = -1;
let lastLoadedItems = [];

// ======================================
// ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ
// ВСПОМОГАТЕЛЬНЫЕ ФУНКЦИИ И КОНФИГУРАЦИЯ
// ======================================

const TYPE_CONFIG = {
'root': {
optionsHtml: `
<option value="house">Дом</option>
<option value="item">Вещь (Участок)</option>
<option value="container">Контейнер (Участок)</option>
<option value="pocket">Пакет (Участок)</option>
`,
hideDescription: true,
apiMap: {
'house': { url: '/api/houses', parentField: null },
'item': { url: '/api/items', parentField: null },
'container': { url: '/api/items', parentField: null },
'pocket': { url: '/api/items', parentField: null }
},
viewAction: async () => await showHouses()
},
'house': {
optionsHtml: `
<option value="room">Комната</option>
<option value="item">Вещь (На Участок)</option>
<option value="container">Контейнер (На Участок)</option>
<option value="pocket">Пакет (На Участок)</option>
`,
hideDescription: true,
apiMap: {
'room': { url: '/api/rooms', parentField: 'house_id' },
'item': { url: '/api/items', parentField: 'house_id' },
'container': { url: '/api/items', parentField: 'house_id' },
'pocket': { url: '/api/items', parentField: 'house_id' }
},
viewAction: async (step) => await showRooms(step.id, step.name)
},
'room': {
optionsHtml: `
<option value="item">Вещь</option>
<option value="cabinet">Шкаф</option>
<option value="container">Контейнер</option>
<option value="pocket">Пакет</option>
`,
hideDescription: false,
apiMap: {
'item': { url: '/api/items', parentField: 'room_id' },
'cabinet': { url: '/api/items', parentField: 'room_id' },
'container': { url: '/api/items', parentField: 'room_id' },
'pocket': { url: '/api/items', parentField: 'room_id' }
},
viewAction: async (step) => await showItems(step.id, step.name, step.type)
},
'cabinet': {
optionsHtml: `
<option value="shelf">Полка</option>
<option value="container">Контейнер</option>
<option value="pocket">Пакет</option>
<option value="item">Вещь</option>
`,
hideDescription: false,
apiMap: {
'shelf': { url: '/api/items', parentField: 'parent_item_id' },
'container': { url: '/api/items', parentField: 'parent_item_id' },
'pocket': { url: '/api/items', parentField: 'parent_item_id' },
'item': { url: '/api/items', parentField: 'parent_item_id' }
},
viewAction: async (step) => await showItems(step.id, step.name, step.type)
},
'shelf': {
optionsHtml: `<option value="item">Вещь</option>`,
hideDescription: false,
apiMap: {
'item': { url: '/api/items', parentField: 'parent_item_id' }
},
viewAction: async (step) => await showItems(step.id, step.name, step.type)
},
'container': {
optionsHtml: `<option value="item">Вещь</option>`,
hideDescription: false,
apiMap: {
'item': { url: '/api/items', parentField: 'parent_item_id' }
},
viewAction: async (step) => await showItems(step.id, step.name, step.type)
},
'pocket': {
optionsHtml: `<option value="item">Вещь</option>`,
hideDescription: false,
apiMap: {
'item': { url: '/api/items', parentField: 'parent_item_id' }
},
viewAction: async (step) => await showItems(step.id, step.name, step.type)
}
};

async function refreshView(step) {
if (!step) {
return await showHouses();
}
const config = TYPE_CONFIG[step.type];
if (config && config.viewAction) {
return await config.viewAction(step);
}
return await showItems(step.id, step.name, step.type);
}

/**
* Определяет фактического родителя для нового предмета с учетом флага "Бросить на пол/Участок".
* (Реализация принципов паттерна "Цепочка Обязанностей" для размещения)
Expand Down Expand Up @@ -99,43 +201,13 @@ function updateForm() {
const lastStep = currentPath[currentPath.length - 1];

// --- Настройка типов элементов ---
if (lastStep.type === 'root') {
// На корневом уровне можно создать Дом ИЛИ сразу сбросить предмет на Глобальный Участок
itemTypeSelect.innerHTML = `
<option value="house">Дом</option>
<option value="item">Вещь (Участок)</option>
<option value="container">Контейнер (Участок)</option>
<option value="pocket">Пакет (Участок)</option>
`;
descriptionInput.style.display = 'none';

} else if (lastStep.type === 'house') {
// В Доме можно создать Комнату ИЛИ сбросить предмет на Участок Дома
itemTypeSelect.innerHTML = `
<option value="room">Комната</option>
<option value="item">Вещь (На Участок)</option>
<option value="container">Контейнер (На Участок)</option>
<option value="pocket">Пакет (На Участок)</option>
`;
descriptionInput.style.display = 'none';

} else if (lastStep.type === 'room') {
itemTypeSelect.innerHTML = `
<option value="item">Вещь</option>
<option value="cabinet">Шкаф</option>
<option value="container">Контейнер</option>
<option value="pocket">Пакет</option>
`;
} else if (lastStep.type === 'cabinet') {
itemTypeSelect.innerHTML = `
<option value="shelf">Полка</option>
<option value="container">Контейнер</option>
<option value="pocket">Пакет</option>
<option value="item">Вещь</option>
`;
} else if (lastStep.type === 'shelf' || lastStep.type === 'container' || lastStep.type === 'pocket') {
itemTypeSelect.innerHTML = `<option value="item">Вещь</option>`;

const config = TYPE_CONFIG[lastStep.type];

if (config) {
itemTypeSelect.innerHTML = config.optionsHtml;
if (config.hideDescription) {
descriptionInput.style.display = 'none';
}
} else {
itemTypeSelect.innerHTML = '';
descriptionInput.style.display = 'none';
Expand Down Expand Up @@ -313,13 +385,7 @@ async function deleteItem(id, level) {
throw new Error(error.error || 'Ошибка при удалении.');
}
const lastStep = currentPath[currentPath.length - 1];
if (lastStep.type === 'root') {
showHouses();
} else if (lastStep.type === 'house') {
showRooms(lastStep.id, lastStep.name);
} else {
showItems(lastStep.id, lastStep.name, lastStep.type);
}
await refreshView(lastStep);
} catch (error) {
console.error('Ошибка:', error);
errorMessageEl.textContent = error.message;
Expand Down Expand Up @@ -422,16 +488,10 @@ async function editItem(item, level) {
}
};

const restoreView = () => {
const restoreView = async () => {
// Восстановим отображение в текущем контексте — но без перезагрузки данных, если уже обновили DOM
const lastStep = currentPath[currentPath.length - 1];
if (!lastStep || lastStep.type === 'root') {
showHouses();
} else if (lastStep.type === 'house') {
showRooms(lastStep.id, lastStep.name);
} else {
showItems(lastStep.id, lastStep.name, lastStep.type);
}
await refreshView(lastStep);
};

const handleSave = async () => {
Expand Down Expand Up @@ -619,41 +679,18 @@ async function handleSubmitItemForm(e) {

// 2. ФОРМИРОВАНИЕ ЗАПРОСА В ЗАВИСИМОСТИ ОТ ЭФФЕКТИВНОГО РОДИТЕЛЯ

if (effectiveParent.type === 'root') {
if (type === 'house') {
url = '/api/houses'; // Создание Дома
} else if (type === 'item' || type === 'container' || type === 'pocket') {
url = '/api/items'; // Глобальный Участок (без house_id/room_id)
} else {
errorMessageEl.textContent = 'Невозможно добавить элемент на корневом уровне.';
return;
}

} else if (effectiveParent.type === 'house') {
if (type === 'room') {
url = '/api/rooms'; // Создание Комнаты
finalPayload.house_id = effectiveParent.id;
} else if (type === 'item' || type === 'container' || type === 'pocket') {
url = '/api/items'; // Участок Дома (с house_id, без room_id/parent_item_id)
finalPayload.house_id = effectiveParent.id;
} else {
errorMessageEl.textContent = 'Невозможно добавить элемент на уровне Дома, кроме Комнаты или базовых контейнеров/вещей.';
return;
}

} else if (effectiveParent.type === 'room') {
url = '/api/items'; // Пол Комнаты (с room_id)
finalPayload.room_id = effectiveParent.id;

} else if (effectiveParent.type === 'cabinet' || effectiveParent.type === 'shelf' || effectiveParent.type === 'container' || effectiveParent.type === 'pocket') {
url = '/api/items'; // Внутри Контейнера (с parent_item_id)
finalPayload.parent_item_id = effectiveParent.id;

} else {
errorMessageEl.textContent = 'Невозможно добавить элемент на текущем уровне.';
const config = TYPE_CONFIG[effectiveParent.type];
if (!config || !config.apiMap[type]) {
errorMessageEl.textContent = 'Невозможно добавить элемент выбранного типа на текущем уровне.';
return;
}

const apiConfig = config.apiMap[type];
url = apiConfig.url;
if (apiConfig.parentField) {
finalPayload[apiConfig.parentField] = effectiveParent.id;
}

// 3. Отправка данных
try {
const response = await fetch(url, {
Expand All @@ -672,13 +709,7 @@ async function handleSubmitItemForm(e) {
document.getElementById('description').value = '';

// Перезагрузка текущего содержимого (возвращаемся к effectiveParent)
if (effectiveParent.type === 'root') {
await showHouses();
} else if (effectiveParent.type === 'house') {
await showRooms(effectiveParent.id, effectiveParent.name);
} else {
await showItems(effectiveParent.id, effectiveParent.name, effectiveParent.type);
}
await refreshView(effectiveParent);

} catch (error) {
console.error('Ошибка при отправке формы:', error);
Expand Down Expand Up @@ -1070,7 +1101,7 @@ document.addEventListener('DOMContentLoaded', () => {

// --- НАВИГАЦИЯ (ХЛЕБНЫЕ КРОШКИ) ---
if (breadcrumbsDiv) {
breadcrumbsDiv.addEventListener('click', (e) => {
breadcrumbsDiv.addEventListener('click', async (e) => {
if (e.target.tagName === 'A') {
const link = e.target;
const index = parseInt(link.dataset.index);
Expand All @@ -1079,19 +1110,13 @@ document.addEventListener('DOMContentLoaded', () => {
currentPath = currentPath.slice(0, index + 1);
const step = currentPath[currentPath.length - 1];

if (step.type === 'root') {
showHouses();
} else if (step.type === 'house') {
showRooms(step.id, step.name);
} else {
showItems(step.id, step.name, step.type);
}
await refreshView(step);
}
});
}
// --- НАВИГАЦИЯ (СПИСОК ЭЛЕМЕНТОВ) ---
if (contentDiv) {
contentDiv.addEventListener('click', (e) => {
contentDiv.addEventListener('click', async (e) => {
const link = e.target.closest('a');

if (link && link.dataset.id && link.closest('.item-list')) {
Expand All @@ -1104,11 +1129,7 @@ if (contentDiv) {
// в showRooms/showItems, что делает код чище и избегает дублирования
// currentPath.push({ id: id, type: type, name: name });

if (type === 'house') {
showRooms(id, name);
} else if (type === 'room' || type === 'cabinet' || type === 'container' || type === 'pocket' || type === 'shelf') {
showItems(id, name, type);
}
await refreshView({ id, name, type });
}
});
}
Expand Down