feat: Settings page, notification times, task/habit reminders

This commit is contained in:
Cosmo
2026-02-06 14:11:27 +00:00
parent 208101195c
commit b7ce5ab1fb

View File

@@ -1,6 +1,6 @@
import { useState, useEffect } from "react"
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"
import { ArrowLeft, Bell, MessageCircle, Globe, Save, Copy, Check } from "lucide-react"
import { ArrowLeft, Bell, MessageCircle, Globe, Save, Copy, Check, User, Sun, Moon } from "lucide-react"
import { Link } from "react-router-dom"
import { profileApi } from "../api/profile"
import Navigation from "../components/Navigation"
@@ -27,9 +27,12 @@ const TIMEZONES = [
export default function Settings() {
const queryClient = useQueryClient()
const [copied, setCopied] = useState(false)
const [username, setUsername] = useState("")
const [chatId, setChatId] = useState("")
const [notificationsEnabled, setNotificationsEnabled] = useState(true)
const [timezone, setTimezone] = useState("Europe/Moscow")
const [morningTime, setMorningTime] = useState("09:00")
const [eveningTime, setEveningTime] = useState("21:00")
const [hasChanges, setHasChanges] = useState(false)
const { data: profile, isLoading } = useQuery({
@@ -39,21 +42,27 @@ export default function Settings() {
useEffect(() => {
if (profile) {
setUsername(profile.username || "")
setChatId(profile.telegram_chat_id?.toString() || "")
setNotificationsEnabled(profile.notifications_enabled ?? true)
setTimezone(profile.timezone || "Europe/Moscow")
setMorningTime(profile.morning_reminder_time || "09:00")
setEveningTime(profile.evening_reminder_time || "21:00")
}
}, [profile])
useEffect(() => {
if (profile) {
const changed =
username !== (profile.username || "") ||
(chatId !== (profile.telegram_chat_id?.toString() || "")) ||
notificationsEnabled !== (profile.notifications_enabled ?? true) ||
timezone !== (profile.timezone || "Europe/Moscow")
timezone !== (profile.timezone || "Europe/Moscow") ||
morningTime !== (profile.morning_reminder_time || "09:00") ||
eveningTime !== (profile.evening_reminder_time || "21:00")
setHasChanges(changed)
}
}, [chatId, notificationsEnabled, timezone, profile])
}, [username, chatId, notificationsEnabled, timezone, morningTime, eveningTime, profile])
const mutation = useMutation({
mutationFn: profileApi.update,
@@ -67,6 +76,12 @@ export default function Settings() {
const data = {
notifications_enabled: notificationsEnabled,
timezone: timezone,
morning_reminder_time: morningTime,
evening_reminder_time: eveningTime,
}
if (username && username !== profile?.username) {
data.username = username
}
if (chatId) {
@@ -77,7 +92,7 @@ export default function Settings() {
}
const copyInstruction = () => {
navigator.clipboard.writeText("@PulseNotifyBot")
navigator.clipboard.writeText("@pulse_tracking_bot")
setCopied(true)
setTimeout(() => setCopied(false), 2000)
}
@@ -103,6 +118,32 @@ export default function Settings() {
</header>
<main className="max-w-lg mx-auto px-4 py-6 space-y-6">
{/* Profile Section */}
<section className="bg-white rounded-2xl p-4 shadow-sm">
<div className="flex items-center gap-3 mb-4">
<div className="w-10 h-10 rounded-xl bg-green-100 flex items-center justify-center">
<User className="text-green-600" size={20} />
</div>
<div>
<h2 className="font-semibold">Профиль</h2>
<p className="text-sm text-gray-500">Основная информация</p>
</div>
</div>
<div>
<label className="block text-sm font-medium text-gray-700 mb-1.5">
Имя пользователя
</label>
<input
type="text"
value={username}
onChange={(e) => setUsername(e.target.value)}
placeholder="Ваше имя"
className="input"
/>
</div>
</section>
{/* Telegram Section */}
<section className="bg-white rounded-2xl p-4 shadow-sm">
<div className="flex items-center gap-3 mb-4">
@@ -125,7 +166,7 @@ export default function Settings() {
className="flex items-center gap-2 text-sm font-medium text-blue-600 hover:text-blue-700"
>
{copied ? <Check size={16} /> : <Copy size={16} />}
{copied ? "Скопировано!" : "@PulseNotifyBot"}
{copied ? "Скопировано!" : "@pulse_tracking_bot"}
</button>
<p className="text-sm text-blue-800 mt-2">
2. Скопируй Chat ID из ответа бота и вставь ниже
@@ -155,10 +196,11 @@ export default function Settings() {
</div>
<div>
<h2 className="font-semibold">Уведомления</h2>
<p className="text-sm text-gray-500">Настрой push-уведомления</p>
<p className="text-sm text-gray-500">Настрой ежедневные уведомления</p>
</div>
</div>
<div className="space-y-4">
<label className="flex items-center justify-between p-3 bg-gray-50 rounded-xl cursor-pointer">
<span className="text-sm font-medium">Включить уведомления</span>
<div className="relative">
@@ -172,6 +214,43 @@ export default function Settings() {
<div className="absolute left-1 top-1 w-4 h-4 bg-white rounded-full peer-checked:translate-x-5 transition-transform"></div>
</div>
</label>
{notificationsEnabled && (
<>
<div className="flex items-center gap-3 p-3 bg-yellow-50 rounded-xl">
<Sun className="text-yellow-600" size={20} />
<div className="flex-1">
<label className="block text-sm font-medium text-gray-700">
Утреннее уведомление
</label>
<p className="text-xs text-gray-500">Задачи и привычки на сегодня</p>
</div>
<input
type="time"
value={morningTime}
onChange={(e) => setMorningTime(e.target.value)}
className="px-3 py-1.5 border border-gray-200 rounded-lg text-sm"
/>
</div>
<div className="flex items-center gap-3 p-3 bg-indigo-50 rounded-xl">
<Moon className="text-indigo-600" size={20} />
<div className="flex-1">
<label className="block text-sm font-medium text-gray-700">
Вечернее уведомление
</label>
<p className="text-xs text-gray-500">Итоги дня: выполнено / осталось</p>
</div>
<input
type="time"
value={eveningTime}
onChange={(e) => setEveningTime(e.target.value)}
className="px-3 py-1.5 border border-gray-200 rounded-lg text-sm"
/>
</div>
</>
)}
</div>
</section>
{/* Timezone Section */}