// Теория под себя — интерактив: сценарии, чат Töre, форма ожидания
(function () {
"use strict";
var STORE_KEY = "tore-theory-chat-v1";
var WAIT_KEY = "tore-theory-wait-v1";
var MAX_STORED = 30;
var SCENARIOS = {
habits: {
title: "Привычки",
question: "Покажи, какие мои утренние привычки повторяются каждый день.",
answer:
"Собрал за 14 дней подряд: подъём до 08:00 — 12 раз, прогулка 20 минут — 10, кофе до работы — 14 из 14.",
points: [
"Самая устойчивая связка: подъём + прогулка до 09:00.",
"В дни без прогулки уровень энергии к обеду заметно ниже.",
"Предлагаю закрепить прогулку в 08:15 на этой неделе."
],
followups: ["Что добавить в утро?", "Как выглядит типичный день?"]
},
time: {
title: "Распределение времени",
question: "Куда уходит больше всего времени по будням?",
answer:
"Разложил 24 рабочих часа по блокам. Топ: фокус-задачи — 9 ч, переписки и звонки — 6 ч, обучение — 3 ч.",
points: [
"Больше всего «съедает» переписка по средам и пятницам.",
"Фокус-задачи лучше всего получаются до 11:00.",
"Если собрать переписку в один слот в 13:00, высвобождается около 1,5 ч."
],
followups: [
"Где я теряю время?",
"Что сдвинуть, чтобы найти час на обучение?"
]
},
results: {
title: "Результаты за неделю",
question: "Сравни мою неделю с прошлой: что выросло?",
answer:
"Сверил две недели по трём метрикам: закрытых задач 18 против 14, новых навыков в работе 2 против 0, просроченных — 1 против 3.",
points: [
"Рост стабильный третий период подряд: в среднем +12% по закрытым задачам.",
"Просрочки упали после того, как приоритеты стали меняться только утром.",
"На следующей неделе стоит добавить ещё один глубокий фокус-слот."
],
followups: ["Составь план на след. неделю", "Что мешает росту?"]
}
};
var GENERAL_ANSWERS = [
{
keys: ["привычк", "утро", "подъём"],
text: {
answer: "Посмотрел по дням: устойчивых повторов больше, чем кажется. Твоя «сильная» зона — начало дня.",
points: [
"Регулярнее всего повторяются подъём, кофе и короткая разминка.",
"Новые вещи закрепляются, если ставить их сразу после устойчивого шага."
]
}
},
{
keys: ["время", "час", "растор", "потеря"],
text: {
answer: "Посчитаю по блокам времени: где оно собирается, а где разбивается на мелкие куски.",
points: [
"Длинные фокус-блоки редки: чаще 25–35 минут до прерывания.",
"Лучший приём недели — собрать мелкие дела в один вечерний слот."
]
}
},
{
keys: ["результат", "недел", "рост", "показател", "сравн"],
text: {
answer: "По последним периодам динамика вверх: ключевые цифры растут второй период кряду.",
points: [
"Рост ровный, без провалов — значит, методика сработала.",
"Следующая точка роста — добавить один новый фокус-слот."
]
}
},
{
keys: ["план", "рекомендац", "что делать", "совет"],
text: {
answer: "Вот короткая рекомендация на ближайшие 7 дней, под твой текущий ритм.",
points: [
"Фиксировать утро: два шага, без выбора и откладывания.",
"Один большой блок работы до обеда, без переписок.",
"В воскресенье — 15 минут на сверку: что сработало, что нет."
],
followups: ["Составь план на неделю", "Что мешает росту?"]
}
},
{
keys: ["план", "след"],
text: {
answer: "Собрал план на неделю по твоим метрикам.",
points: [
"Пн–чт: по одному фокус-блоку на главную задачу.",
"Пт: разбор недели, 20 минут, без новых задач."
],
}
}
];
function byId(id) { return document.getElementById(id); }
function esc(s) {
return String(s).replace(/[&<>"]/g, function (c) {
return { "&": "&", "<": "<", ">": ">", '"': """ }[c];
});
}
function loadChat() {
try {
var raw = localStorage.getItem(STORE_KEY);
if (!raw) return [];
var arr = JSON.parse(raw);
return Array.isArray(arr) ? arr : [];
} catch (e) { return []; }
}
function saveChat(list) {
try {
if (list.length > MAX_STORED) list = list.slice(list.length - MAX_STORED);
localStorage.setItem(STORE_KEY, JSON.stringify(list));
} catch (e) { /* квота — молча пропускаем */ }
}
function msgHtml(m) {
if (m.role === "user") {
return '
Ты
' + esc(m.text) + "
";
}
var html = '
' +
'' +
"Töre · " + esc(m.time) + "
";
if (m.text) html += "
" + esc(m.text) + "
";
if (m.points && m.points.length) {
html += '
';
for (var i = 0; i < m.points.length; i++) html += "
" + esc(m.points[i]) + "
";
html += "
";
}
if (m.followups && m.followups.length) {
html += '
';
for (var j = 0; j < m.followups.length; j++) {
html += '";
}
html += "
";
}
return html + "
";
}
function appendMsg(m, stored) {
var log = byId("chat-log");
if (!log) return;
var div = document.createElement("div");
div.innerHTML = msgHtml(m);
var node = div.firstChild;
log.appendChild(node);
log.scrollTop = log.scrollHeight;
if (stored) {
var list = loadChat();
list.push(m);
saveChat(list);
}
}
function renderStored(list) {
var log = byId("chat-log");
if (!log) return;
log.innerHTML = "";
for (var i = 0; i < list.length; i++) {
var div = document.createElement("div");
div.innerHTML = msgHtml(list[i]);
log.appendChild(div.firstChild);
}
log.scrollTop = log.scrollHeight;
}
function answerFor(text) {
var t = text.toLowerCase();
for (var i = 0; i < GENERAL_ANSWERS.length; i++) {
var keys = GENERAL_ANSWERS[i].keys;
for (var j = 0; j < keys.length; j++) {
if (t.indexOf(keys[j]) !== -1) return GENERAL_ANSWERS[i].text;
}
}
return FALLBACK;
}
function nowTime() {
var d = new Date();
var hh = ("0" + d.getHours()).slice(-2);
var mm = ("0" + d.getMinutes()).slice(-2);
return hh + ":" + mm;
}
function sendUser(text) {
if (!text) return;
appendMsg({ role: "user", text: text, time: nowTime() }, true);
setTimeout(function () {
var res = answerFor(text);
var msg = { role: "ai", text: res.answer, points: res.points || null, time: nowTime() };
if (res.points) msg.followups = res.followups || null;
appendMsg(msg, true);
}, 450);
}
function initChat() {
var log = byId("chat-log");
if (!log) return;
var stored = loadChat();
if (stored.length) {
renderStored(stored);
} else {
appendMsg({
role: "ai",
text: "Привет! Я Töre — ИИ-аналитик. Выбери сценарий выше или спроси меня о своих данных: привычки, время, результаты.",
points: null,
time: nowTime()
}, false);
}
var form = byId("chat-form");
var input = byId("chat-input");
if (form && input) {
form.addEventListener("submit", function (e) {
e.preventDefault();
var v = input.value.trim();
if (!v) return;
input.value = "";
input.style.height = "auto";
sendUser(v);
});
input.addEventListener("keydown", function (e) {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
form.requestSubmit();
}
});
input.addEventListener("input", function () {
input.style.height = "auto";
input.style.height = Math.min(input.scrollHeight, 120) + "px";
});
}
// Чипы-продолжения: делегирование
log.addEventListener("click", function (e) {
var btn = e.target;
while (btn && btn.tagName !== "BUTTON") btn = btn.parentNode;
if (!btn || !btn.classList || !btn.classList.contains("tk-prompt-chip")) return;
var q = btn.getAttribute("data-q");
if (q) sendUser(q);
});
}
function initScenarios() {
var tabs = document.querySelectorAll("#scenario-list .kt-ai-tab");
for (var i = 0; i < tabs.length; i++) {
(function (tab) {
tab.addEventListener("click", function () {
var id = tab.getAttribute("data-scenario");
for (var k = 0; k < tabs.length; k++) tabs[k].setAttribute("data-active", "false");
tab.setAttribute("data-active", "true");
var s = SCENARIOS[id];
if (!s) return;
sendUser(s.question);
});
})(tabs[i]);
}
}
function initWait() {
var input = byId("wait-email");
var btn = byId("wait-submit");
var note = byId("wait-note");
var field = input ? input.closest(".kt-ai-field") : null;
if (!input || !btn) return;
var saved = "";
try { saved = localStorage.getItem(WAIT_KEY) || ""; } catch (e) {}
if (saved) {
input.value = saved;
if (note) note.textContent = "Сохранено: " + saved + ". При запуске пришлём уведомление.";
}
btn.addEventListener("click", function () {
var v = input.value.trim();
if (field) field.setAttribute("data-invalid", "false");
if (!v) {
if (field) field.setAttribute("data-invalid", "true");
input.focus();
if (note) note.textContent = "Введите адрес, чтобы сохранить заявку.";
return;
}
if (v.indexOf("@") === -1 || v.indexOf("@") === 0 || v.indexOf("@") === v.length - 1) {
if (field) field.setAttribute("data-invalid", "true");
if (note) note.textContent = "Похоже, в адресе опечатка — проверь формат.";
return;
}
try { localStorage.setItem(WAIT_KEY, v); } catch (e) {}
if (note) note.textContent = "Сохранено: " + v + ". При запуске пришлём уведомление.";
});
input.addEventListener("input", function () {
if (field) field.setAttribute("data-invalid", "false");
});
}
function initNav() {
var links = document.querySelectorAll("a[href^='#']");
for (var i = 0; i < links.length; i++) {
(function (a) {
a.addEventListener("click", function () {
var id = a.getAttribute("href");
if (id.length > 1) {
var el = byId(id.slice(1));
if (el) el.scrollIntoView({ behavior: "smooth", block: "start" });
}
});
})(links[i]);
}
}
function init() {
initChat();
initScenarios();
initWait();
initNav();
var hint = byId("chat-hint");
if (hint) hint.textContent = "Диалог сохраняется в этом браузере — можно вернуться позже.";
}
if (document.readyState === "loading") {
document.addEventListener("DOMContentLoaded", init);
} else {
init();
}
})();