habits.andr33v.ru/app/pages/index.vue

187 lines
5.5 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="page-container">
<!-- ================================= -->
<!-- Authenticated User Dashboard -->
<!-- ================================= -->
<div v-if="isAuthenticated && user" class="dashboard-content">
<h1>Ваши цели на сегодня</h1>
<p class="text-color-light">Цели обновляются раз в сутки. Получаемые бонусы усиливаются, если посещать сайт ежедневно.</p>
<div class="streak-section">
<div class="streak-card" :class="{ 'active-streak': user.dailyStreak === 1 }">
<h2>x1</h2>
<p>Базовые</p>
</div>
<div class="streak-card" :class="{ 'active-streak': user.dailyStreak === 2 }">
<h2>x2</h2>
<p>Двойные</p>
</div>
<div class="streak-card" :class="{ 'active-streak': user.dailyStreak >= 3 }">
<h2>x3</h2>
<p>Тройные</p>
</div>
</div>
<div class="habits-section">
<h2>Привычки</h2>
<div v-if="habitsPending">Загрузка привычек...</div>
<div v-else-if="habitsError">Не удалось загрузить привычки.</div>
<div v-else-if="habits && habits.length > 0">
<HabitCard
v-for="habit in habits"
:key="habit.id"
:habit="habit"
:is-submitting-habit="isSubmittingHabit"
:exploding-habit-id="explodingHabitId"
@complete="completeHabit"
/>
</div>
<div v-else>
<p>У вас еще нет привычек. Перейдите на страницу <NuxtLink to="/habits">Мои привычки</NuxtLink>, чтобы создать их.</p>
</div>
</div>
</div>
<!-- ================================= -->
<!-- Anonymous User Onboarding Funnel -->
<!-- ================================= -->
<div v-else-if="isAnonymous" class="onboarding-container">
<OnboardingFunnel />
</div>
<!-- ================================= -->
<!-- New/Unidentified User Welcome -->
<!-- ================================= -->
<div v-else class="welcome-content">
<h1>Добро пожаловать в SmurfHabits!</h1>
<p class="text-color-light">Отслеживайте свои привычки и развивайте свою деревню.</p>
<div class="auth-buttons">
<button @click="startOnboarding" class="btn btn-primary">Начать онбординг</button>
<NuxtLink to="/login" class="btn btn-secondary">У меня уже есть аккаунт</NuxtLink>
</div>
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue';
// Use the refactored auth composable
const { user, isAuthenticated, isAnonymous, updateUser, startOnboarding } = useAuth();
const api = useApi();
// --- Habits Data (This part only runs for authenticated users but is fine to leave here) ---
const { data: habits, pending: habitsPending, error: habitsError, refresh: refreshHabits } = await useFetch('/api/habits', {
lazy: true,
server: false,
});
// --- Actions & UI State ---
const isSubmittingHabit = ref(false);
const explodingHabitId = ref(null);
const completeHabit = async (habitId) => { // Removed event param since it's handled by HabitCard
if (isSubmittingHabit.value) return;
isSubmittingHabit.value = true;
try {
const response = await api(`/api/habits/${habitId}/complete`, { method: 'POST' });
if (updateUser && response) {
updateUser({
coins: response.updatedCoins,
exp: response.updatedExp,
});
}
const habit = habits.value.find(h => h.id === habitId);
if (habit) {
// Optimistically update the completions. This assumes the API call is successful.
if (!habit.completions) {
habit.completions = [];
}
habit.completions.push({
id: Math.random(), // Temporary ID for reactivity
habitId: habitId,
date: new Date().toISOString(),
});
}
explodingHabitId.value = habitId;
setTimeout(() => {
explodingHabitId.value = null;
}, 1000);
} catch (err) {
alert(err.data?.message || 'Failed to complete habit.');
} finally {
isSubmittingHabit.value = false;
}
};
</script>
<style scoped>
.dashboard-content, .welcome-content, .onboarding-container {
text-align: center;
}
.welcome-content {
padding: 40px 0;
}
.streak-section {
display: flex;
justify-content: center;
gap: 16px;
margin: 24px 0 32px 0;
}
.streak-card {
background: #f8f9fa;
border: 2px solid var(--border-color);
border-radius: 12px;
padding: 16px 20px;
width: 110px;
transition: all 0.3s ease;
}
.streak-card h2 {
margin: 0 0 5px 0;
font-size: 2em;
color: var(--text-color-light);
}
.streak-card p {
margin: 0;
font-size: 0.9em;
color: var(--text-color-light);
}
.active-streak {
border-color: var(--primary-color);
background-color: #f0f5ff;
box-shadow: 0 4px 12px rgba(0,0,0,0.1);
transform: translateY(-4px);
}
.active-streak h2 {
color: var(--primary-color);
}
.active-streak p {
color: var(--text-color);
font-weight: 600;
}
.habits-section {
margin: 40px 0;
}
.auth-buttons {
display: flex;
justify-content: center;
gap: 16px;
margin-top: 32px;
}
</style>