diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index 99f2133..8121007 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -29,5 +29,6 @@ jobs: --label traefik.http.routers.tablet.tls.certresolver=letsencrypt \ --label traefik.http.services.tablet.loadbalancer.server.port=3000 \ --env-file /opt/digital-home/tablet.env \ + -v /opt/digital-home/smart-home-tablet-data:/data \ smart-home-tablet:latest echo 'Deploy done' diff --git a/app/api/auth/route.ts b/app/api/auth/route.ts index b10d284..e4a37b9 100644 --- a/app/api/auth/route.ts +++ b/app/api/auth/route.ts @@ -4,7 +4,8 @@ import * as fs from 'fs' import * as path from 'path' const SECRET = process.env.APP_SECRET || 'smart-home-default-secret-change-me' -const CONFIG_PATH = '/tmp/tablet-config.json' +const DATA_DIR = fs.existsSync('/data') ? '/data' : '/tmp' +const CONFIG_PATH = `${DATA_DIR}/tablet-config.json` function loadConfig(): { pin: string } { try { diff --git a/app/api/calendar/route.ts b/app/api/calendar/route.ts index 2d6f325..f6c8e3f 100644 --- a/app/api/calendar/route.ts +++ b/app/api/calendar/route.ts @@ -43,12 +43,21 @@ export async function GET(req: Request) { let timeMin: string let timeMax: string + // Moscow boundaries (UTC+3, no DST). 00:00 MSK = 21:00 UTC previous day. + const MSK_OFFSET_MS = 3 * 3600 * 1000 + const mskNow = new Date(now.getTime() + MSK_OFFSET_MS) + const my = mskNow.getUTCFullYear() + const mm = mskNow.getUTCMonth() + const md = mskNow.getUTCDate() + const mskMidnight = (y: number, m: number, d: number) => + new Date(Date.UTC(y, m, d) - MSK_OFFSET_MS).toISOString() + if (range === 'today') { - timeMin = new Date(now.getFullYear(), now.getMonth(), now.getDate()).toISOString() - timeMax = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1).toISOString() + timeMin = mskMidnight(my, mm, md) + timeMax = mskMidnight(my, mm, md + 1) } else if (range === 'week') { - timeMin = new Date(now.getFullYear(), now.getMonth(), now.getDate()).toISOString() - timeMax = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 7).toISOString() + timeMin = mskMidnight(my, mm, md) + timeMax = mskMidnight(my, mm, md + 7) } else { // month — support year/month query params const targetYear = parseInt(searchParams.get('year') || String(now.getFullYear())) diff --git a/app/api/notes/route.ts b/app/api/notes/route.ts index 04d08e4..aff85e8 100644 --- a/app/api/notes/route.ts +++ b/app/api/notes/route.ts @@ -2,7 +2,8 @@ export const dynamic = 'force-dynamic' import { NextResponse } from 'next/server' import * as fs from 'fs' -const NOTES_PATH = '/tmp/tablet-notes.json' +const DATA_DIR = fs.existsSync('/data') ? '/data' : '/tmp' +const NOTES_PATH = `${DATA_DIR}/tablet-notes.json` interface Note { id: string diff --git a/app/page.tsx b/app/page.tsx index ab1fd13..804b661 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -394,10 +394,19 @@ function HomeTab({ weather, sensors }: { weather: WeatherData | null; sensors: S }) .catch(() => {}) - // Notes + // Notes — pinned (pinDate today or future), fallback to latest fetch('/api/notes') .then(r => r.json()) - .then(d => setPinnedNotes((d.notes || []).slice(0, 3))) + .then(d => { + const all = d.notes || [] + const today = new Date(); today.setHours(0, 0, 0, 0) + const pinned = all.filter((n: any) => { + if (!n.pinDate) return false + const pd = new Date(n.pinDate); pd.setHours(0, 0, 0, 0) + return pd.getTime() >= today.getTime() + }) + setPinnedNotes((pinned.length ? pinned : all).slice(0, 3)) + }) .catch(() => {}) }, []) @@ -650,7 +659,7 @@ function SettingsTab({ city, onCityChange, onLogout, theme, onThemeChange }: { c const currentCity = CITIES.find(c => c.id === city) || CITIES[0] return ( -