working push notifiations
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const EXPO_PUSH_URL = 'https://exp.host/--/api/v2/push/send';
|
||||
|
||||
export interface PushNotificationPayload {
|
||||
to: string;
|
||||
title: string;
|
||||
body: string;
|
||||
data?: Record<string, any>;
|
||||
sound?: string;
|
||||
badge?: number;
|
||||
priority?: 'default' | 'normal' | 'high';
|
||||
channelId?: string;
|
||||
}
|
||||
|
||||
export interface PushTicket {
|
||||
id: string;
|
||||
status: 'ok' | 'error';
|
||||
message?: string;
|
||||
details?: {
|
||||
error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
export interface PushReceipt {
|
||||
status: 'ok' | 'error';
|
||||
message?: string;
|
||||
details?: {
|
||||
error?: string;
|
||||
};
|
||||
}
|
||||
|
||||
interface ExpoPushResponse {
|
||||
data?: PushTicket[] | Record<string, PushReceipt>;
|
||||
}
|
||||
|
||||
export async function sendPushNotification(payload: PushNotificationPayload): Promise<PushTicket> {
|
||||
const response = await fetch(EXPO_PUSH_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
|
||||
const result = (await response.json()) as ExpoPushResponse;
|
||||
if (result.data && Array.isArray(result.data)) {
|
||||
return result.data[0] ?? { id: '', status: 'error', message: 'No ticket returned' };
|
||||
}
|
||||
return { id: '', status: 'error', message: 'No ticket returned' };
|
||||
}
|
||||
|
||||
export async function sendPushNotifications(payloads: PushNotificationPayload[]): Promise<PushTicket[]> {
|
||||
const chunks: PushNotificationPayload[][] = [];
|
||||
for (let i = 0; i < payloads.length; i += 100) {
|
||||
chunks.push(payloads.slice(i, i + 100));
|
||||
}
|
||||
|
||||
const tickets: PushTicket[] = [];
|
||||
for (const chunk of chunks) {
|
||||
const response = await fetch(EXPO_PUSH_URL, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: JSON.stringify(chunk),
|
||||
});
|
||||
const result = (await response.json()) as ExpoPushResponse;
|
||||
if (result.data && Array.isArray(result.data)) {
|
||||
tickets.push(...result.data);
|
||||
}
|
||||
}
|
||||
return tickets;
|
||||
}
|
||||
|
||||
export async function getPushReceipts(ticketIds: string[]): Promise<PushReceipt[]> {
|
||||
if (ticketIds.length === 0) return [];
|
||||
|
||||
const response = await fetch(`${EXPO_PUSH_URL}/receipts`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Accept: 'application/json',
|
||||
},
|
||||
body: JSON.stringify({ ids: ticketIds }),
|
||||
});
|
||||
|
||||
const result = (await response.json()) as ExpoPushResponse;
|
||||
const receipts: PushReceipt[] = [];
|
||||
if (result.data && !Array.isArray(result.data)) {
|
||||
for (const id of ticketIds) {
|
||||
receipts.push(result.data[id] ?? { status: 'error', message: 'No receipt found' });
|
||||
}
|
||||
}
|
||||
return receipts;
|
||||
}
|
||||
|
||||
export function isExpoPushToken(token: string): boolean {
|
||||
return token.startsWith('ExponentPushToken[') || token.startsWith('ExpoPushToken[');
|
||||
}
|
||||
|
||||
export function createTaskReminderPayload(
|
||||
pushToken: string,
|
||||
taskTitle: string,
|
||||
dueTime: string,
|
||||
taskId: string,
|
||||
repeat?: string
|
||||
): PushNotificationPayload {
|
||||
return {
|
||||
to: pushToken,
|
||||
title: taskTitle,
|
||||
body: `Due ${dueTime}${repeat && repeat !== 'none' ? ' · repeating' : ''}`,
|
||||
data: { type: 'task_reminder', taskId },
|
||||
sound: 'default',
|
||||
priority: 'high',
|
||||
channelId: 'task-reminders',
|
||||
};
|
||||
}
|
||||
|
||||
export function createFriendRequestPayload(
|
||||
pushToken: string,
|
||||
fromUsername: string,
|
||||
friendshipId: string
|
||||
): PushNotificationPayload {
|
||||
return {
|
||||
to: pushToken,
|
||||
title: 'New Friend Request',
|
||||
body: `${fromUsername} wants to be your friend`,
|
||||
data: { type: 'friend_request', friendshipId },
|
||||
sound: 'default',
|
||||
priority: 'high',
|
||||
channelId: 'friend-requests',
|
||||
};
|
||||
}
|
||||
|
||||
export function createTaskAssignmentPayload(
|
||||
pushToken: string,
|
||||
taskTitle: string,
|
||||
fromUsername: string,
|
||||
taskId: string
|
||||
): PushNotificationPayload {
|
||||
return {
|
||||
to: pushToken,
|
||||
title: 'Task Assigned',
|
||||
body: `${fromUsername} assigned you "${taskTitle}"`,
|
||||
data: { type: 'task_assignment', taskId },
|
||||
sound: 'default',
|
||||
priority: 'high',
|
||||
channelId: 'task-assignments',
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user