mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-08-30 09:48:57 +00:00
ADD - mock paginated messaging APIs
This commit is contained in:
@@ -12,6 +12,44 @@ let draft = null
|
||||
let linkedAccount = null
|
||||
let mockNotes = []
|
||||
const deviceData = {}
|
||||
let contactSequence = 2
|
||||
const contacts = [
|
||||
{
|
||||
created_at: '2026-08-04 12:00:00',
|
||||
id: 'contact-1',
|
||||
name: 'Jenica Chong',
|
||||
phone_number: '5558675309',
|
||||
updated_at: '2026-08-04 12:00:00',
|
||||
},
|
||||
]
|
||||
const attachmentAssets = {
|
||||
gif: new Set(['celebrate', 'hearts', 'party', 'thumbs_up', 'wow']),
|
||||
image: new Set([
|
||||
'camera-1', 'camera-2', 'camera-3', 'city-lights', 'desert-road',
|
||||
'ocean-air', 'sunset-drive',
|
||||
]),
|
||||
video: new Set(['city-loop', 'ocean-loop', 'sunset-loop']),
|
||||
}
|
||||
const gifMocks = [
|
||||
['ICOgUNjpvO0PC', 'Cat reaction'],
|
||||
['MDJ9IbxxvDUQM', 'Happy dog'],
|
||||
['l0HlPystfePnAI3G8', 'Celebrate'],
|
||||
['26ufdipQqU2lhNA4g', 'Wow'],
|
||||
['3o7abKhOpu0NwenH3O', 'Perfect'],
|
||||
['xT0xeJpnrWC4XWblEk', 'Party'],
|
||||
['111ebonMs90YLu', 'Thumbs up'],
|
||||
['5GoVLqeAOo6PK', 'Excited'],
|
||||
['TdfyKrN7HGTIY', 'Happy dance'],
|
||||
['14udF3WUwwGMaA', 'Surprised'],
|
||||
['3o6Zt6ML6BklcajjsA', 'Applause'],
|
||||
['13CoXDiaCcCoyk', 'Let us go'],
|
||||
['R6gvnAxj2ISzJdbA63', 'Yes'],
|
||||
['xUPGcEliCc7bETyfO8', 'Laughing'],
|
||||
['26BRuo6sLetdllPAQ', 'Dancing'],
|
||||
['l46CyJmS9KUbokzsI', 'Amazing'],
|
||||
['g9582DNuQppxC', 'Celebration'],
|
||||
['artj92V8o75VPL7AeQ', 'High five'],
|
||||
]
|
||||
const accountDevices = [
|
||||
{
|
||||
created_at: '2026-08-04 12:00:00',
|
||||
@@ -75,6 +113,38 @@ const messages = [
|
||||
trashed_at: '2026-08-04 08:00:00',
|
||||
},
|
||||
]
|
||||
const smsMessages = [
|
||||
{
|
||||
body: 'Bin gleich am Würfelpark. Kommst du auch?',
|
||||
created_at: '2026-08-06 13:04:00',
|
||||
direction: 'received',
|
||||
id: 'sms-1',
|
||||
media_duration_ms: null,
|
||||
media_mime: null,
|
||||
media_payload: null,
|
||||
media_waveform: null,
|
||||
message_type: 'text',
|
||||
media_asset_id: null,
|
||||
read_at: null,
|
||||
recipient_number: '5551234567',
|
||||
sender_number: '5558675309',
|
||||
},
|
||||
{
|
||||
body: 'Ja, gib mir fünf Minuten.',
|
||||
created_at: '2026-08-06 13:05:00',
|
||||
direction: 'sent',
|
||||
id: 'sms-2',
|
||||
media_duration_ms: null,
|
||||
media_mime: null,
|
||||
media_payload: null,
|
||||
media_waveform: null,
|
||||
message_type: 'text',
|
||||
media_asset_id: null,
|
||||
read_at: null,
|
||||
recipient_number: '5558675309',
|
||||
sender_number: '5551234567',
|
||||
},
|
||||
]
|
||||
|
||||
function counts() {
|
||||
return {
|
||||
@@ -114,6 +184,196 @@ app.post('/api/:endpoint', (request, response) => {
|
||||
})
|
||||
return
|
||||
}
|
||||
if (endpoint === 'messages:conversations') {
|
||||
const grouped = new Map()
|
||||
for (const message of [...smsMessages].reverse()) {
|
||||
const phoneNumber =
|
||||
message.direction === 'sent'
|
||||
? message.recipient_number
|
||||
: message.sender_number
|
||||
const conversation = grouped.get(phoneNumber)
|
||||
if (conversation) {
|
||||
if (message.direction === 'received' && !message.read_at)
|
||||
conversation.unread += 1
|
||||
continue
|
||||
}
|
||||
grouped.set(phoneNumber, {
|
||||
lastMessage: message.body,
|
||||
lastMessageAt: message.created_at,
|
||||
lastMessageType: message.message_type,
|
||||
phoneNumber,
|
||||
unread: message.direction === 'received' && !message.read_at ? 1 : 0,
|
||||
})
|
||||
}
|
||||
response.json({ success: true, data: [...grouped.values()] })
|
||||
return
|
||||
}
|
||||
if (endpoint === 'messages:gifs') {
|
||||
const offset = Math.max(0, Number(request.body.offset ?? 0))
|
||||
const pageSize = 6
|
||||
const results = gifMocks.slice(offset, offset + pageSize).map(([id, title]) => ({
|
||||
height: 200,
|
||||
id,
|
||||
previewUrl: `https://media.giphy.com/media/${id}/200w.gif`,
|
||||
title,
|
||||
url: `https://media.giphy.com/media/${id}/giphy.gif`,
|
||||
width: 200,
|
||||
}))
|
||||
response.json({
|
||||
success: true,
|
||||
data: {
|
||||
hasMore: offset + results.length < gifMocks.length,
|
||||
nextOffset: offset + results.length,
|
||||
results,
|
||||
},
|
||||
})
|
||||
return
|
||||
}
|
||||
if (endpoint === 'messages:thread') {
|
||||
const number = String(request.body.phoneNumber)
|
||||
const thread = smsMessages.filter(
|
||||
(message) =>
|
||||
message.sender_number === number || message.recipient_number === number,
|
||||
)
|
||||
for (const message of thread) {
|
||||
if (message.direction === 'received') message.read_at = message.read_at ?? '2026-08-06 13:06:00'
|
||||
}
|
||||
response.json({
|
||||
success: true,
|
||||
data: thread.map(({ media_payload, ...message }) => ({
|
||||
...message,
|
||||
media_asset_id: ['image', 'gif', 'video'].includes(message.message_type)
|
||||
? media_payload
|
||||
: null,
|
||||
})),
|
||||
})
|
||||
return
|
||||
}
|
||||
if (endpoint === 'messages:media') {
|
||||
const message = smsMessages.find(
|
||||
(item) => item.id === request.body.id && item.message_type === 'voice',
|
||||
)
|
||||
response.json(
|
||||
message
|
||||
? {
|
||||
success: true,
|
||||
data: {
|
||||
mime: message.media_mime,
|
||||
payload: message.media_payload,
|
||||
},
|
||||
}
|
||||
: { success: false, error: 'message_not_found' },
|
||||
)
|
||||
return
|
||||
}
|
||||
if (endpoint === 'messages:send') {
|
||||
const body = String(request.body.body ?? '').trim()
|
||||
const phoneNumber = String(request.body.phoneNumber ?? '')
|
||||
const messageType = request.body.messageType ?? 'text'
|
||||
const isAttachment = ['image', 'gif', 'video'].includes(messageType)
|
||||
const attachmentId = String(request.body.mediaAssetId ?? '')
|
||||
if (
|
||||
!phoneNumber ||
|
||||
(messageType === 'text' && !body) ||
|
||||
(messageType === 'voice' && !request.body.mediaPayload) ||
|
||||
(isAttachment &&
|
||||
!attachmentAssets[messageType].has(attachmentId) &&
|
||||
!attachmentId.startsWith('https://'))
|
||||
) {
|
||||
response.json({ success: false, error: 'invalid_message' })
|
||||
return
|
||||
}
|
||||
const message = {
|
||||
body,
|
||||
created_at: new Date().toISOString().slice(0, 19).replace('T', ' '),
|
||||
direction: 'sent',
|
||||
id: `sms-${Date.now()}`,
|
||||
media_duration_ms:
|
||||
['voice', 'video'].includes(messageType)
|
||||
? request.body.mediaDurationMs ?? null
|
||||
: null,
|
||||
media_mime:
|
||||
messageType === 'voice'
|
||||
? request.body.mediaMime
|
||||
: messageType === 'image'
|
||||
? 'image/jpeg'
|
||||
: messageType === 'gif'
|
||||
? 'image/gif'
|
||||
: messageType === 'video'
|
||||
? 'video/mp4'
|
||||
: null,
|
||||
media_payload:
|
||||
messageType === 'voice'
|
||||
? request.body.mediaPayload
|
||||
: isAttachment
|
||||
? attachmentId
|
||||
: null,
|
||||
media_waveform:
|
||||
messageType === 'voice' ? request.body.mediaWaveform : null,
|
||||
message_type: messageType,
|
||||
media_asset_id: isAttachment ? attachmentId : null,
|
||||
read_at: null,
|
||||
recipient_number: phoneNumber,
|
||||
sender_number: '5551234567',
|
||||
}
|
||||
smsMessages.push(message)
|
||||
const { media_payload, ...publicMessage } = message
|
||||
response.json({ success: true, data: publicMessage })
|
||||
return
|
||||
}
|
||||
if (endpoint === 'messages:delete') {
|
||||
const phoneNumbers = new Set(
|
||||
Array.isArray(request.body.phoneNumbers)
|
||||
? request.body.phoneNumbers.map(String)
|
||||
: [],
|
||||
)
|
||||
for (let index = smsMessages.length - 1; index >= 0; index -= 1) {
|
||||
const message = smsMessages[index]
|
||||
const otherNumber =
|
||||
message.direction === 'sent'
|
||||
? message.recipient_number
|
||||
: message.sender_number
|
||||
if (phoneNumbers.has(otherNumber)) smsMessages.splice(index, 1)
|
||||
}
|
||||
response.json({ success: true })
|
||||
return
|
||||
}
|
||||
if (endpoint === 'contacts:list') {
|
||||
response.json({ success: true, data: contacts })
|
||||
return
|
||||
}
|
||||
if (endpoint === 'contacts:save') {
|
||||
const name = String(request.body.name ?? '').trim()
|
||||
const phoneNumber = String(request.body.phoneNumber ?? '').trim()
|
||||
if (!name || !phoneNumber) {
|
||||
response.json({ success: false, error: 'invalid_contact' })
|
||||
return
|
||||
}
|
||||
let contact = contacts.find((item) => item.id === request.body.id)
|
||||
if (contact) {
|
||||
contact.name = name
|
||||
contact.phone_number = phoneNumber
|
||||
contact.updated_at = new Date().toISOString().slice(0, 19).replace('T', ' ')
|
||||
} else {
|
||||
const now = new Date().toISOString().slice(0, 19).replace('T', ' ')
|
||||
contact = {
|
||||
created_at: now,
|
||||
id: `contact-${contactSequence++}`,
|
||||
name,
|
||||
phone_number: phoneNumber,
|
||||
updated_at: now,
|
||||
}
|
||||
contacts.push(contact)
|
||||
}
|
||||
response.json({ success: true, data: contact })
|
||||
return
|
||||
}
|
||||
if (endpoint === 'contacts:delete') {
|
||||
const index = contacts.findIndex((item) => item.id === request.body.id)
|
||||
if (index >= 0) contacts.splice(index, 1)
|
||||
response.json({ success: true })
|
||||
return
|
||||
}
|
||||
if (endpoint === 'account:login' || endpoint === 'account:register') {
|
||||
authenticated = true
|
||||
linkedAccount = {
|
||||
|
||||
Reference in New Issue
Block a user