whatsapp/index.js
2025-05-06 19:49:49 +02:00

307 lines
9.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const { default: makeWASocket, useMultiFileAuthState, DisconnectReason, fetchLatestBaileysVersion, proto, generateWAMessageFromContent, generateWAMessageContent ,prepareWAMessageMedia} = require('@fizzxydev/baileys-pro');
const express = require('express');
const { Boom } = require('@hapi/boom');
const qrcode = require('qrcode');
const path = require('path');
const fs = require('fs');
const app = express();
app.use(express.json());
app.use(express.static('public'));
let sock;
let qrData = null;
let isConnected = false;
const initBaileys = async () => {
const { version } = await fetchLatestBaileysVersion();
const { state, saveCreds } = await useMultiFileAuthState('auth');
sock = makeWASocket({
version,
auth: state,
printQRInTerminal: false,
});
sock.ev.on('connection.update', async (update) => {
const { connection, lastDisconnect, qr } = update;
if (qr) {
qrData = await qrcode.toDataURL(qr);
isConnected = false;
}
if (connection === 'close') {
const shouldReconnect = lastDisconnect?.error?.output?.statusCode !== DisconnectReason.loggedOut;
if (shouldReconnect) {
console.log('🔁 Reconnexion...');
initBaileys();
} else {
console.log('❌ Déconnecté.');
}
} else if (connection === 'open') {
console.log('✅ Connecté à WhatsApp');
isConnected = true;
}
});
sock.ev.on('creds.update', saveCreds);
};
initBaileys();
app.use('/static', express.static(path.join(__dirname, 'public')));
app.get('/login', (req, res) => {
res.sendFile(path.join(__dirname, 'public', 'login.html'));
});
app.get('/api/qrcode', (req, res) => {
res.json({ qr: qrData, connected: isConnected });
});
app.post('/sendText', async (req, res) => {
const { phone, message } = req.body;
if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' });
try {
await sock.sendMessage(`${phone}@s.whatsapp.net`, { text: message });
res.json({ success: true });
} catch (e) {
res.status(500).json({ error: e.message });
}
});
app.post('/sendButtons', async (req, res) => {
const { phone } = req.body;
if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' });
try {
const content = {
message: {
interactiveMessage: proto.Message.InteractiveMessage.create({
body: { text: "Bienvenue sur notre service !" },
footer: { text: "Choisis une action ci-dessous" },
header: {
title: "Menu principal",
hasMediaAttachment: false
},
nativeFlowMessage: {
buttons: [
{
name: "cta_reply",
buttonParamsJson: JSON.stringify({
display_text: "📩 Contacter support",
id: "support_action"
})
},
{
name: "cta_url",
buttonParamsJson: JSON.stringify({
display_text: "🌐 Voir notre site",
url: "https://canguidev.fr",
merchant_url: "https://canguidev.fr"
})
},
{
name: "cta_call",
buttonParamsJson: JSON.stringify({
display_text: "📞 Appeler le support",
id: "+33612345678"
})
}
]
}
})
}
};
const msg = generateWAMessageFromContent(`${phone}@s.whatsapp.net`, content, {});
await sock.relayMessage(`${phone}@s.whatsapp.net`, msg.message, { messageId: msg.key.id });
res.json({ success: true });
} catch (e) {
console.error('❌ Erreur bouton actif :', e);
res.status(500).json({ error: e.message });
}
});
// Votre route POST
app.post('/sendInteractiveImage', async (req, res) => {
const { phone, caption, title, subtitle, footer } = req.body;
if (!sock || !isConnected) {
return res.status(400).json({ error: 'Non connecté à WhatsApp' });
}
try {
const imagePath = path.join(__dirname, 'public', 'logo-merlo-cs-FR.jpg');
const imageBuffer = fs.readFileSync(imagePath);
// Upload the image first
const uploadedImage = await prepareWAMessageMedia(
{ image: imageBuffer },
{ upload: sock.waUploadToServer }
);
const interactiveMessage = {
imageMessage: uploadedImage.imageMessage,
caption: caption || 'Description par défaut',
footer: footer || 'Pied de page',
buttons: [
{
buttonId: 'btn1',
buttonText: { displayText: '📄 Voir proposition' },
type: 1 // URL button
},
{
buttonId: 'btn2',
buttonText: { displayText: '🔧 Spécifications' },
type: 1 // URL button
}
]
};
await sock.sendMessage(`${phone}@s.whatsapp.net`, {
image: imageBuffer,
caption: caption,
footer: footer,
templateButtons: [
{
index: 1,
urlButton: {
displayText: '📄 Voir proposition',
url: 'https://merlo-ch.com/uploads/proposition/f_p_250505_0000136_00008_EB00001909.pdf'
}
},
{
index: 2,
urlButton: {
displayText: '🔧 Spécifications',
url: 'https://merlo-ch.com/uploads/proposition/d_p_250505_0000136_00008_EB00001909.pdf'
}
}
]
});
return res.json({ success: true });
} catch (e) {
console.error('❌ Erreur /sendInteractiveImage :', e);
return res.status(500).json({ error: e.message });
}
});
// app.post('/sendInteractiveImage', async (req, res) => {
// const { phone, caption, title, subtitle, footer } = req.body;
// if (!sock || !isConnected) return res.status(400).json({ error: 'Non connecté' });
// try {
// const imagePath = path.join(__dirname, 'public', 'logo-merlo-cs-FR.jpg');
// const resizedBuffer = fs.readFileSync(imagePath);
// await sock.sendMessage(`${phone}@s.whatsapp.net`, {
// image: resizedBuffer,
// caption: caption || 'Description par défaut',
// title: title || 'Titre par défaut',
// subtitle: subtitle || 'Sous-titre',
// footer: footer || 'Pied de page',
// media: true,
// interactiveButtons: [
// {
// name: 'cta_url',
// buttonParamsJson: JSON.stringify({
// display_text: 'Proposition',
// url: 'https://merlo-ch.com/uploads/proposition/f_p_250505_0000136_00008_EB00001909.pdf'
// })
// },
// {
// name: 'cta_url',
// buttonParamsJson: JSON.stringify({
// display_text: 'Spec machine',
// url: 'https://merlo-ch.com/uploads/proposition/d_p_250505_0000136_00008_EB00001909.pdf'
// })
// }
// ]
// });
// res.json({ success: true });
// } catch (e) {
// console.error('❌ Erreur interactive image :', e);
// res.status(500).json({ error: e.message });
// }
// });
app.post('/sendProductMessage', async (req, res) => {
// On vérifie sock et isConnected, pas client
if (!sock || !isConnected) {
return res.status(400).json({ error: 'Non connecté à WhatsApp' });
}
const {
phone,
productImageUrl,
productImageCount,
productTitle,
productDescription,
priceAmount1000,
currencyCode,
retailerId,
productUrl,
businessOwnerJid,
caption,
messageTitle,
footer,
interactiveButtons = [],
quoted
} = req.body;
try {
const jid = `${phone}@s.whatsapp.net`;
// Build product payload exactly comme avant
const productPayload = {
productImage: { url: productImageUrl },
productImageCount,
title: productTitle, // ici productTitle
description: productDescription,
priceAmount1000: priceAmount1000 * 1000, // ajustez si besoin
currencyCode,
retailerId,
url: productUrl
};
// Transformer les boutons
const buttons = interactiveButtons.map(btn => {
const params = {};
if (btn.id) params.id = btn.id;
if (btn.url) params.url = btn.url;
if (btn.display_text) params.display_text = btn.display_text;
return {
name: btn.name,
buttonParamsJson: JSON.stringify(params)
};
});
// **On utilise sock.sendMessage** et non client.sendMessage
await sock.sendMessage(
jid,
{
product: productPayload,
businessOwnerJid,
caption,
title: messageTitle,
footer,
media: true,
interactiveButtons: buttons
},
quoted ? { quoted } : {}
);
return res.json({ success: true });
} catch (e) {
console.error('❌ Erreur /sendProductMessage :', e);
return res.status(500).json({ error: e.message });
}
});
// 5) 404 et gestion des erreurs
app.use((req, res) => res.status(404).json({ error: 'Ressource introuvable' }));
app.use((err, req, res, next) => {
console.error('Middleware derreur :', err);
res.status(500).json({ error: err.message });
});
app.listen(3001, () => console.log('🚀 Serveur Baileys démarré sur http://localhost:3001'));