ba-cafe

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit b07af1eb2bb373268c70db85050cb1f57bea3519
parent 37e202492d1702703615f50276914cd1be512d06
Author: Sunny <122193933+Sunny-JP@users.noreply.github.com>
Date:   Sat, 24 Jan 2026 21:01:41 +0900

Merge pull request #17 from Sunny-JP/v4-sunny-dev

V4 sunny dev
Diffstat:
Msrc/app/about/page.tsx | 5+++++
Msrc/app/api/tap/route.ts | 56+++++++++++++++++++++++++-------------------------------
2 files changed, 30 insertions(+), 31 deletions(-)

diff --git a/src/app/about/page.tsx b/src/app/about/page.tsx @@ -19,6 +19,11 @@ export default function AboutPage() { <li>招待券のクールタイム管理</li> <li>タップ履歴のカレンダー表示</li> </ul> + <h2 className="text-xl font-bold mt-8 mb-4 text-foreground">対応プラットフォーム</h2> + <p> + PCおよびスマートフォンの最新ブラウザで動作します。<br /> + PWAに対応しているため、ホーム画面に追加してアプリのように使うことができます。 + </p> </div> <div className="mt-8 pt-4"> diff --git a/src/app/api/tap/route.ts b/src/app/api/tap/route.ts @@ -5,8 +5,8 @@ import { shouldScheduleNotification } from '@/lib/timeUtils'; export const runtime = 'edge'; -const ONESIGNAL_APP_ID = process.env.NEXT_PUBLIC_ONESIGNAL_APP_ID; -const ONESIGNAL_REST_KEY = process.env.ONESIGNAL_REST_API_KEY; +const APP_ID = process.env.NEXT_PUBLIC_ONESIGNAL_APP_ID; +const API_KEY = process.env.ONESIGNAL_REST_API_KEY; export async function POST(request: Request) { try { @@ -20,11 +20,7 @@ export async function POST(request: Request) { ); const { data: { user }, error: authError } = await supabase.auth.getUser(); if (authError || !user) return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); - - if (onesignalId) { - await cleanupOldDevices(user.id); - } - + await cleanupDevices(user.id); const { data: profile } = await supabase.from('profiles').select('tap_history').eq('id', user.id).single(); const newHistory = tapTime ? [...(profile?.tap_history || []), tapTime] : (profile?.tap_history || []); const { error: upsertError } = await supabase.from('profiles').upsert({ @@ -36,42 +32,41 @@ export async function POST(request: Request) { ticket2_time: ticket2Time ? new Date(ticket2Time).toISOString() : (ticket2Time === null ? null : undefined), }); if (upsertError) throw new Error(upsertError.message); - if (tapTime && shouldScheduleNotification(new Date(tapTime))) { - await cleanupOldDevices(user.id); await scheduleNotification(user.id, tapTime); } return NextResponse.json({ success: true, history: newHistory }); } catch (error: any) { - console.error("API Error:", error); + console.error("Critical API Error:", error); return NextResponse.json({ error: error.message }, { status: 500 }); } } -async function cleanupOldDevices(userId: string) { +async function cleanupDevices(userId: string) { try { - const res = await fetch(`https://api.onesignal.com/apps/${ONESIGNAL_APP_ID}/users/by/external_id/${userId}`, { - headers: { "Authorization": `Basic ${ONESIGNAL_REST_KEY}` } + const res = await fetch(`https://onesignal.com/api/v1/apps/${APP_ID}/users/by/external_id/${userId}`, { + headers: { "Authorization": `Basic ${API_KEY}` } }); if (!res.ok) return; - const { subscriptions } = await res.json(); - const allPushSubs = (subscriptions || []) + const data = await res.json(); + const pushSubs = (data.subscriptions || []) .filter((s: any) => s.type === "Push") - .sort((a: any, b: any) => - new Date(b.last_active || 0).getTime() - new Date(a.last_active || 0).getTime() - ); - if (allPushSubs.length > 2) { - const toDelete = allPushSubs.slice(2); - - await Promise.all(toDelete.map((sub: any) => - fetch(`https://api.onesignal.com/apps/${ONESIGNAL_APP_ID}/subscriptions/${sub.id}`, { + .sort((a: any, b: any) => { + const timeA = new Date(a.last_active || a.created_at || 0).getTime(); + const timeB = new Date(b.last_active || b.created_at || 0).getTime(); + return timeB - timeA; + }); + if (pushSubs.length > 2) { + const targets = pushSubs.slice(2); + for (const sub of targets) { + await fetch(`https://onesignal.com/api/v1/apps/${APP_ID}/subscriptions/${sub.id}`, { method: "DELETE", - headers: { "Authorization": `Basic ${ONESIGNAL_REST_KEY}` } - }) - )); + headers: { "Authorization": `Basic ${API_KEY}` } + }); + } } } catch (e) { - console.error("OneSignal Cleanup Error:", e); + console.error("Cleanup failed:", e); } } @@ -79,14 +74,14 @@ async function scheduleNotification(userId: string, tapTime: string) { const sendAfter = new Date(tapTime); sendAfter.setHours(sendAfter.getHours() + 3); const msg = messages[Math.floor(Math.random() * messages.length)] || { title: "Cafe Timer", body: "カフェ業務の時間です" }; - const res = await fetch("https://onesignal.com/api/v1/notifications", { + await fetch("https://onesignal.com/api/v1/notifications", { method: "POST", headers: { "Content-Type": "application/json", - "Authorization": `Basic ${ONESIGNAL_REST_KEY}` + "Authorization": `Basic ${API_KEY}` }, body: JSON.stringify({ - app_id: ONESIGNAL_APP_ID, + app_id: APP_ID, include_aliases: { external_id: [userId] }, target_channel: "push", contents: { en: msg.body, ja: msg.body }, @@ -94,5 +89,4 @@ async function scheduleNotification(userId: string, tapTime: string) { send_after: sendAfter.toISOString(), }) }); - if (!res.ok) console.error("Notification Error:", await res.text()); } \ No newline at end of file