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:
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