Initial commit
This commit is contained in:
86
src/lib/whatsapp.ts
Normal file
86
src/lib/whatsapp.ts
Normal file
@ -0,0 +1,86 @@
|
||||
import { appendLog, readJsonFile, writeJsonFile } from './storage'
|
||||
|
||||
type FlowState = Record<string, { step: string; name?: string }>
|
||||
|
||||
function normalizeNumber(number?: string | null) {
|
||||
return (number || '').replace(/\D+/g, '')
|
||||
}
|
||||
|
||||
export async function sendTextMessage(to: string, message: string) {
|
||||
const apiVersion = process.env.WHATSAPP_API_VERSION || 'v23.0'
|
||||
const phoneNumberId = process.env.WHATSAPP_PHONE_NUMBER_ID || ''
|
||||
const accessToken = process.env.WHATSAPP_ACCESS_TOKEN || ''
|
||||
const url = `https://graph.facebook.com/${apiVersion}/${phoneNumberId}/messages`
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
Authorization: `Bearer ${accessToken}`,
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
messaging_product: 'whatsapp',
|
||||
to,
|
||||
type: 'text',
|
||||
text: { preview_url: false, body: message },
|
||||
}),
|
||||
})
|
||||
|
||||
const payload = await response.json().catch(async () => ({ raw: await response.text() }))
|
||||
|
||||
appendLog({ type: 'outgoing_message', to, message, response: payload, success: response.ok, created_at: new Date().toISOString() })
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Gagal kirim pesan ke WhatsApp')
|
||||
}
|
||||
|
||||
return payload
|
||||
}
|
||||
|
||||
export async function handleWebhook(payload: any) {
|
||||
appendLog({ type: 'webhook_received', payload, created_at: new Date().toISOString() })
|
||||
|
||||
for (const entry of payload.entry || []) {
|
||||
for (const change of entry.changes || []) {
|
||||
const value = change.value || {}
|
||||
|
||||
for (const message of value.messages || []) {
|
||||
await handleIncomingMessage(message)
|
||||
}
|
||||
|
||||
for (const status of value.statuses || []) {
|
||||
appendLog({ type: 'message_status', status, created_at: new Date().toISOString() })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function handleIncomingMessage(message: any) {
|
||||
const from = message.from || ''
|
||||
appendLog({ type: 'incoming_message', from, message, created_at: new Date().toISOString() })
|
||||
|
||||
if (normalizeNumber(from) !== normalizeNumber(process.env.WA_TEST_NUMBER)) {
|
||||
appendLog({ type: 'ignored_message', reason: 'sender_not_test_number', from, created_at: new Date().toISOString() })
|
||||
return
|
||||
}
|
||||
|
||||
const body = (message.text?.body || '').trim()
|
||||
const state = readJsonFile<FlowState>('flow-state.json', {})
|
||||
const step = state[from]?.step || 'idle'
|
||||
|
||||
if (body.toLowerCase() === 'daftar' && step === 'idle') {
|
||||
state[from] = { step: 'waiting_name' }
|
||||
writeJsonFile('flow-state.json', state)
|
||||
await sendTextMessage(from, 'Silakan kirim nama Anda.')
|
||||
return
|
||||
}
|
||||
|
||||
if (step === 'waiting_name' && body) {
|
||||
state[from] = { step: 'completed', name: body }
|
||||
writeJsonFile('flow-state.json', state)
|
||||
await sendTextMessage(from, `Terima kasih ${body}, data testing diterima.`)
|
||||
return
|
||||
}
|
||||
|
||||
await sendTextMessage(from, 'Kirim "daftar" untuk mulai flow testing.')
|
||||
}
|
||||
Reference in New Issue
Block a user