Revert "feat: WhatsApp notification helper + phase 4 migration (recheck_round, WhatsApp settings)"

This reverts commit b6845f5bb5.
This commit is contained in:
2026-07-11 18:47:08 +08:00
parent dfca872629
commit 121433ddf8
4 changed files with 1 additions and 116 deletions
+1 -6
View File
@@ -3,12 +3,7 @@ export const dynamic = 'force-dynamic'
import { NextRequest, NextResponse } from 'next/server'
import { createClient } from '@/lib/supabase/server'
const ALLOWED_KEYS = [
'ANTHROPIC_API_KEY',
'VOYAGE_API_KEY',
'META_WHATSAPP_PHONE_NUMBER_ID',
'META_WHATSAPP_ACCESS_TOKEN',
] as const
const ALLOWED_KEYS = ['ANTHROPIC_API_KEY', 'VOYAGE_API_KEY'] as const
type SettingKey = typeof ALLOWED_KEYS[number]
async function requireAdmin(supabase: Awaited<ReturnType<typeof createClient>>) {
-42
View File
@@ -1,42 +0,0 @@
export async function sendWhatsAppMessage(
phoneNumber: string,
templateName: string,
parameters: string[],
phoneNumberId: string,
accessToken: string,
): Promise<void> {
const sanitized = phoneNumber.replace(/[^0-9]/g, '')
if (!sanitized) return
const body = {
messaging_product: 'whatsapp',
to: sanitized,
type: 'template',
template: {
name: templateName,
language: { code: 'en_US' },
components: [
{
type: 'body',
parameters: parameters.map(text => ({ type: 'text', text })),
},
],
},
}
const res = await fetch(
`https://graph.facebook.com/v19.0/${phoneNumberId}/messages`,
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${accessToken}`,
},
body: JSON.stringify(body),
}
)
if (!res.ok) {
throw new Error(`WhatsApp API error: ${res.status}`)
}
}
@@ -1,10 +0,0 @@
-- Add effectiveness recheck round tracking to capa_actions
ALTER TABLE capa_actions
ADD COLUMN IF NOT EXISTS effectiveness_recheck_round INT NOT NULL DEFAULT 0;
-- WhatsApp and effectiveness recheck credentials for Settings UI
INSERT INTO app_settings (key, value, updated_at, updated_by)
VALUES
('META_WHATSAPP_PHONE_NUMBER_ID', '', now(), NULL),
('META_WHATSAPP_ACCESS_TOKEN', '', now(), NULL)
ON CONFLICT (key) DO NOTHING;
-58
View File
@@ -1,58 +0,0 @@
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { sendWhatsAppMessage } from '@/lib/notifications/whatsapp'
const fetchMock = vi.fn()
vi.stubGlobal('fetch', fetchMock)
describe('sendWhatsAppMessage', () => {
beforeEach(() => fetchMock.mockClear())
it('posts to Meta Graph API with correct template structure', async () => {
fetchMock.mockResolvedValueOnce(
new Response('{"messages":[{"id":"wamid.abc"}]}', { status: 200 })
)
await sendWhatsAppMessage(
'60123456789',
'ims_incident_alert',
['SETIA-202407-0001', 'injury', 'Warehouse A'],
'test-phone-id',
'test-token'
)
expect(fetchMock).toHaveBeenCalledOnce()
const [url, opts] = fetchMock.mock.calls[0]
expect(url).toBe('https://graph.facebook.com/v19.0/test-phone-id/messages')
expect(opts.method).toBe('POST')
expect(opts.headers['Authorization']).toBe('Bearer test-token')
const body = JSON.parse(opts.body)
expect(body.messaging_product).toBe('whatsapp')
expect(body.to).toBe('60123456789')
expect(body.type).toBe('template')
expect(body.template.name).toBe('ims_incident_alert')
expect(body.template.language.code).toBe('en_US')
expect(body.template.components[0].parameters).toHaveLength(3)
expect(body.template.components[0].parameters[0]).toEqual({ type: 'text', text: 'SETIA-202407-0001' })
})
it('throws on non-2xx response', async () => {
fetchMock.mockResolvedValueOnce(
new Response('{"error":{"message":"Invalid token"}}', { status: 400 })
)
await expect(
sendWhatsAppMessage('60123456789', 'ims_incident_alert', ['a'], 'pid', 'tok')
).rejects.toThrow('WhatsApp API error: 400')
})
it('returns immediately without calling fetch when phoneNumber is empty', async () => {
await sendWhatsAppMessage('', 'ims_incident_alert', ['a'], 'pid', 'tok')
expect(fetchMock).not.toHaveBeenCalled()
})
it('sanitizes phone number — strips spaces, dashes, and plus sign', async () => {
fetchMock.mockResolvedValueOnce(
new Response('{"messages":[{"id":"x"}]}', { status: 200 })
)
await sendWhatsAppMessage('+60 12-345 6789', 'ims_incident_alert', ['a'], 'pid', 'tok')
const body = JSON.parse(fetchMock.mock.calls[0][1].body)
expect(body.to).toBe('60123456789')
})
})