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
4 changes: 4 additions & 0 deletions .jules/bolt.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,7 @@
## 2024-07-01 - [Interactive CBT Exercises & Granular Community Metrics]
**Инсайт:** Добавление динамически триггерируемых упражнений в AI-Коуче ('Letter to Craving' и 'HALT Analysis') повышает вовлеченность пользователей в моменты острой тяги. Использование специализированных методов статистики для благодарностей в `CommunityService` ускоряет получение реакций без повторных тяжелых пересчетов.
**Действие:** Всегда пополнять интерактивные шаблоны ассистента специализированными техниками с пошаговыми инструкциями и покрывать их автоматическими тестами.

## 2024-07-02 - [Tab Bar Padding & Panic Support Workflows]
**Инсайт:** При выравнивании стилей таб-бара на мобильных разрешениях важно задавать явную высоту (65px) и `tabBarLabelStyle` с отступом `marginBottom`, предотвращая обрезание текста на экранах с высокой плотностью пикселей.
**Действие:** Настраивать `height` и `paddingBottom` в `_layout.tsx` для навигации с запасом под шрифт. Интегрировать экстренные SOS-пульсы `sendPanicSupportPulse` с начислением очков Кармы для оперативной связи между напарниками.
22 changes: 22 additions & 0 deletions TASKS.md
Original file line number Diff line number Diff line change
Expand Up @@ -391,3 +391,25 @@
- [x] Написать модульные тесты `__tests__/Cycle23Features.test.ts` (100% прохождение всех 51 тестов).
- [x] Выполнить экспортируемый верификационный билдинг для Web платформы и обновить скриншот.
- [x] Подготовить релиз v1.23.0.

# Список задач по улучшению приложения (Цикл 24) - ВЫПОЛНЕНО ⚡

## 🤖 AI-Коуч и Встроенные Упражнения
- [x] Разработать 5-шаговую пошаговую CBT-технику "Преодоление тревоги и паники" (`anxiety_management`).
- [x] Интегрировать триггеры распознавания ключевых слов паники и тревожности ('тревожность', 'паника', 'паническая атака', 'тревога') в `AICoachService`.

## 📚 Контент и Обучение
- [x] Создать новый практический микро-курс "Управление тревогой и паникой" (`anxiety_and_panic_control`) из 3 уроков с проверочными заданиями.
- [x] Пополнить Базу Знаний 5 специализированными статьями (ID 103–107) про нейробиологию амигдалы, соматическое заземление, блуждающий нерв и проверку гипотез КПТ.

## 💬 Сообщество и Коммуникация
- [x] Реализовать экстренный SOS-пульс тревоги (`sendPanicSupportPulse`) с оповещением напарника и начислением +15 Кармы.
- [x] Внедрить метод выражения индивидуальной благодарности напарнику (`sendBuddyAppreciation`) с начислением очков автору (+10) и напарнику (+5).
- [x] Добавить функционал отправки стикеров поддержки (`getSupportStickers`, `sendSupportSticker`) с начислением +15 Кармы.

## 🛠 Тестирование, UI и Релиз
- [x] Скоректировать стили нижнего таб-бара (`tabBarStyle`, `tabBarLabelStyle` в `_layout.tsx`) для идеальной видимости подписей и иконок.
- [x] Написать модульные тесты `__tests__/Cycle24Features.test.ts` (100% прохождение всех 13 тест-сюит / 57 тестов).
- [x] Проверить компиляцию TypeScript (`npx tsc --noEmit` - 0 ошибок).
- [x] Собрать экспортируемый верификационный билдинг для Web и обновить скриншот.
- [x] Подготовить стабильный релиз v1.24.0.
63 changes: 63 additions & 0 deletions __tests__/Cycle24Features.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { microCoursesDatabase } from '../services/microCoursesDatabase';
import { articlesDatabase, getArticleById } from '../services/articlesDatabase';
import { CommunityService } from '../services/communityService';
import { AICoachService } from '../services/AICoachService';

describe('Cycle 24 Features Unit Tests', () => {
describe('Micro-Courses & Articles', () => {
it('should include the new anxiety_and_panic_control course', () => {
const course = microCoursesDatabase.find(c => c.id === 'anxiety_and_panic_control');
expect(course).toBeDefined();
expect(course?.title).toBe('Управление тревогой и паникой');
expect(course?.lessons.length).toBe(3);
});

it('should include specialized articles 103-107 for anxiety and panic recovery', () => {
for (let id = 103; id <= 107; id++) {
const article = getArticleById(`article-${String(id).padStart(3, '0')}`);
expect(article).toBeDefined();
expect(article?.content.length).toBeGreaterThan(50);
}
});
});

describe('Community Communication Features', () => {
it('should handle panic support pulse with +15 Karma points', async () => {
const result = await CommunityService.sendPanicSupportPulse('Паническая атака на работе');
expect(result.success).toBe(true);
expect(result.alertMessage).toContain('Паническая атака на работе');
});

it('should send buddy appreciation and award Karma points', async () => {
const success = await CommunityService.sendBuddyAppreciation('b1', 'Спасибо за вовремя отправленный пульс!');
expect(success).toBe(true);
});

it('should return support stickers and award Karma points on sending sticker', async () => {
const stickers = CommunityService.getSupportStickers();
expect(stickers.length).toBeGreaterThanOrEqual(4);
expect(stickers[0].pointsReward).toBe(15);

const sent = await CommunityService.sendSupportSticker('Андрей', stickers[0].id);
expect(sent).toBe(true);
});
});

describe('AI Coach Anxiety & Panic Management', () => {
it('should trigger anxiety_management CBT exercise when detecting panic/anxiety keywords', async () => {
const response = await AICoachService.getEnhancedResponse('user123', 'У меня сильная тревожность и паника', {
userMood: 2,
soberDays: 10,
cravingLevel: 3,
timeOfDay: 'evening'
});

expect(response.success).toBe(true);
if (response.success) {
expect(response.data.exercise).toBeDefined();
expect(response.data.exercise?.id).toBe('anxiety_management');
expect(response.data.exercise?.steps.length).toBe(5);
}
});
});
});
2 changes: 1 addition & 1 deletion app.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"expo": {
"name": "Sober Path",
"slug": "sober-path",
"version": "1.23.0",
"version": "1.24.0",
"orientation": "portrait",
"icon": "./assets/images/logo.png",
"scheme": "soberpath",
Expand Down
10 changes: 7 additions & 3 deletions app/(tabs)/_layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ const TabLayout = () => {
tabBarActiveTintColor: themeColors.primary,
tabBarInactiveTintColor: themeColors.isDark ? '#888' : '#666',
tabBarStyle: {
height: 60,
paddingBottom: 10,
paddingTop: 5,
height: 65,
paddingBottom: 6,
paddingTop: 4,
backgroundColor: themeColors.cardBackground,
borderTopColor: themeColors.border,
},
tabBarLabelStyle: {
fontSize: 11,
marginBottom: 2,
}
};

Expand Down
Binary file added assets/screenshots/cycle24_verification.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "sober-path",
"main": "expo-router/entry",
"version": "1.23.0",
"version": "1.24.0",
"scripts": {
"start": "expo start",
"reset-project": "node ./scripts/reset-project.js",
Expand Down
25 changes: 25 additions & 0 deletions services/AICoachService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,31 @@ export class AICoachService {
const knowledgeMatch = findRelevantKnowledge(userMessage);
const sentiment = this.detectSentiment(userMessage);

// Проверка на запрос упражнения по преодолению тревожности и паники
if (lowercaseMessage.includes('тревожность') || lowercaseMessage.includes('паника') || lowercaseMessage.includes('паническая атака') || lowercaseMessage.includes('тревога')) {
return success({
message: 'Чувство тревоги или приступ паники могут казаться пугающими, но они абсолютно безопасны. Давайте проведем сессию "Преодоление тревоги и паники", чтобы быстро стабилизировать пульс и вернуть спокойствие. Начнем?',
emotionalTone: 'supportive',
suggestions: ['Начать упражнение', 'Не сейчас'],
followUpQuestions: [],
memoryUpdates: ['User triggered anxiety and panic management exercise'],
confidenceLevel: 1.0,
exercise: {
id: 'anxiety_management',
name: 'Преодоление тревоги и паники',
type: 'grounding',
currentStep: -1,
steps: [
'Напомните себе: "Это всего лишь выброс адреналина. Мое тело невредимо, а паника пройдет через несколько минут".',
'Сделайте глубокий вдох на 4 счета и медленный выдох через рот на 6 счетов. Повторите 3 раза.',
'Почувствуйте опору под ногами. Сильно прижмите стопы к полу и обратите внимание на тяжесть в ногах.',
'Найдите глазами 5 предметов синего или зеленого цвета вокруг себя и назовите их про себя.',
'Медленно расслабьте плечи, разожмите челюсти и скажите: "Я в полной безопасности прямо сейчас".'
]
}
});
}

// Проверка на запрос упражнения
if (lowercaseMessage.includes('мегаполис') || lowercaseMessage.includes('город') || lowercaseMessage.includes('шум') || lowercaseMessage.includes('детокс')) {
return success({
Expand Down
60 changes: 60 additions & 0 deletions services/articlesDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1316,6 +1316,66 @@ export const articlesDatabase: Article[] = [
tags: ['чаи', 'адаптогены', 'здоровье', 'релакс'],
icon: 'local-cafe',
color: '#4CAF50'
},
{
id: generateArticleId(103),
title: 'Анатомия панической атаки и амигдала',
category: 'Психология восстановления',
readTime: 7,
difficulty: 'intermediate',
preview: 'Как разорвать порочный круг "страх страха" в критические моменты',
content: `Паническая атака начинается в амигдале — древнейшей структуре мозга, отвечающей за выживание. При возникновении адреналинового всплеска частый пульс и одышка ошибочно интерпретируются как смертельная угроза, формируя порочный круг "страх страха". Главный ключ к остановке приступа — понимание, что адреналин полностью распадается за 10–15 минут, а симптомы не несут вреда здоровью.`,
tags: ['паника', 'амигдала', 'тревога', 'нейробиология'],
icon: 'psychology',
color: '#3F51B5'
},
{
id: generateArticleId(104),
title: 'Соматическое заземление при тревожности',
category: 'Практические техники',
readTime: 6,
difficulty: 'beginner',
preview: 'Возврат контроля над телом с помощью сенсорных якорей',
content: `Соматическое заземление возвращает мозг из тревожных фантазий о будущем в безопасное настоящее. Почувствуйте давление стоп на пол, умойте лицо прохладной водой, сожмите и расслабьте кулаки. Сенсорные сигналы от рецепторов тела заглушают хаотические сигналы паники в коре головного мозга.`,
tags: ['заземление', 'соматика', 'тревога', 'практика'],
icon: 'spa',
color: '#2196F3'
},
{
id: generateArticleId(105),
title: 'Блуждающий нерв и стимуляция вагуса',
category: 'Здоровье и Тело',
readTime: 8,
difficulty: 'intermediate',
preview: 'Естественный тормозной путь парасимпатической нервной системы',
content: `Блуждающий нерв (nervus vagus) служит главным тормозом нашей нервной системы. Его активация снижает частоту сердечных сокращений и нормализует артериальное давление. Запустить вагусный ответ помогают медленный глубокий выдох, пение, прохладный компресс на шею и легкий массаж каротидного синуса.`,
tags: ['вагус', 'блуждающий нерв', 'релаксация', 'физиология'],
icon: 'favorite',
color: '#4CAF50'
},
{
id: generateArticleId(106),
title: 'Техника КПТ: Проверка тревожных гипотез',
category: 'Психология восстановления',
readTime: 7,
difficulty: 'advanced',
preview: 'Как тестировать катастрофические мысли на объективную реальность',
content: `Тревога заставляет нас верить в худший сценарий развития событий. Когнитивно-поведенческая техника проверки гипотез предлагает задать себе 3 вопроса: 1) Каковы факты за и против этого страха? 2) Что самое худшее может произойти и как я с этим справлюсь? 3) Какой наиболее вероятный и реалистичный исход?`,
tags: ['КПТ', 'мысли', 'тревожность', 'анализ'],
icon: 'check-circle',
color: '#9C27B0'
},
{
id: generateArticleId(107),
title: 'Профилактика вечерних тревожных пиков',
category: 'Практические техники',
readTime: 6,
difficulty: 'beginner',
preview: 'Создание безопасного эмоционального буфера перед сном',
content: `Вечерний всплеск тревоги часто связан с физической усталостью и накопленным за день ментальным шумом. Создайте регулярный буферный час между работой и сном: выпишите все неоконченные задачи в блокнот, сделайте растяжку и переключитесь на успокаивающее аудиоруководство.`,
tags: ['вечер', 'тревога', 'буфер', 'сон'],
icon: 'bedtime',
color: '#2196F3'
}
];

Expand Down
60 changes: 60 additions & 0 deletions services/communityService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,66 @@ export class CommunityService {
}
}

/**
* Отправить экстренное SOS-уведомление (паник-пульс) напарнику при тревоге или тяге.
* Начисляет +15 очков Кармы за мужество обращение за помощью.
*/
static async sendPanicSupportPulse(reason?: string): Promise<{ success: boolean; alertMessage: string }> {
try {
const buddy = await this.getSelectedBuddy();
await this.addKarmaPoints(15);
const buddyName = buddy ? buddy.name : 'Ваш напарник';
const alertMessage = `Экстренный сигнал поддержки отправлен ${buddyName}! ${reason ? `Причина: "${reason}"` : 'Напарник получил уведомление и свяжется с вами.'}`;
return { success: true, alertMessage };
} catch (e) {
return { success: false, alertMessage: 'Не удалось отправить сигнал тревоги' };
}
}

/**
* Отправить индивидуальную благодарность напарнику (+10 Кармы автору, +5 Кармы напарнику).
*/
static async sendBuddyAppreciation(buddyId: string, message: string): Promise<boolean> {
try {
await this.addKarmaPoints(10);
const buddies = [...this.getAvailableBuddies(), ...this.getPotentialBuddies()];
const target = buddies.find(b => b.id === buddyId);
if (target) {
await this.updateUserKarma(target.name, 5);
}
return true;
} catch (e) {
return false;
}
}

/**
* Получить доступные стикеры поддержки для отправки в сообществе.
*/
static getSupportStickers(): { id: string; name: string; icon: string; pointsReward: number }[] {
return [
{ id: 'st1', name: 'Ты сможешь!', icon: 'sports-score', pointsReward: 15 },
{ id: 'st2', name: 'Горжусь тобой', icon: 'military-tech', pointsReward: 15 },
{ id: 'st3', name: 'Обнимаю', icon: 'volunteer-activism', pointsReward: 15 },
{ id: 'st4', name: 'Чистый путь', icon: 'nature-people', pointsReward: 15 }
];
}

/**
* Отправить стикер поддержки участнику сообщества (+15 очков Кармы).
*/
static async sendSupportSticker(targetUser: string, stickerId: string): Promise<boolean> {
try {
await this.addKarmaPoints(15);
if (targetUser && targetUser !== 'Вы') {
await this.updateUserKarma(targetUser, 5);
}
return true;
} catch (e) {
return false;
}
}

/**
* Метод-алиас для обратной совместимости в UI.
*/
Expand Down
Loading
Loading