chore: pre-chore

This commit is contained in:
Leifer Mendez
2023-02-04 18:03:57 +01:00
parent 99b9b17f52
commit 2ecc41f3f0
82 changed files with 411 additions and 904 deletions

View File

@@ -1,4 +1,4 @@
#!/usr/bin/env sh
. "$(dirname -- "$0")/_/husky.sh"
npx --no -- commitlint --edit
npm run lint:fix && npx --no -- commitlint --edit

View File

@@ -1,5 +1,5 @@
packages/**/lib
packages/docs/*.json
packages/docs/
**/.git
**/.svn
**/.hg

View File

@@ -8,8 +8,7 @@ const { addKeyword, addAnswer, addChild, toSerialize } = require('./io/methods')
* @param {*} args
* @returns
*/
const createBot = async ({ flow, database, provider }, args = {}) =>
new CoreClass(flow, database, provider, args)
const createBot = async ({ flow, database, provider }, args = {}) => new CoreClass(flow, database, provider, args)
/**
* Crear instancia de clase Io (Flow)
@@ -29,8 +28,7 @@ const createFlow = (args) => {
*/
const createProvider = (providerClass = class {}, args = null) => {
const providerInstance = new providerClass(args)
if (!providerClass.prototype instanceof ProviderClass)
throw new Error('El provider no implementa ProviderClass')
if (!providerClass.prototype instanceof ProviderClass) throw new Error('El provider no implementa ProviderClass')
return providerInstance
}

View File

@@ -17,15 +17,10 @@ const addAnswer =
* @returns
*/
const getAnswerOptions = () => ({
media:
typeof options?.media === 'string' ? `${options?.media}` : null,
media: typeof options?.media === 'string' ? `${options?.media}` : null,
buttons: Array.isArray(options?.buttons) ? options.buttons : [],
capture:
typeof options?.capture === 'boolean'
? options?.capture
: false,
child:
typeof options?.child === 'string' ? `${options?.child}` : null,
capture: typeof options?.capture === 'boolean' ? options?.capture : false,
child: typeof options?.child === 'string' ? `${options?.child}` : null,
delay: typeof options?.delay === 'number' ? options?.delay : 0,
})
@@ -49,8 +44,7 @@ const addAnswer =
* Esta funcion aplana y busca los callback anidados de los hijos
* @returns
*/
const getCbFromNested = () =>
flatObject(Array.isArray(nested) ? nested : [nested])
const getCbFromNested = () => flatObject(Array.isArray(nested) ? nested : [nested])
const callback = typeof cb === 'function' ? cb : () => null

View File

@@ -20,8 +20,7 @@ class ProviderClass extends EventEmitter {
*/
sendMessage = async (userId, message) => {
if (NODE_ENV !== 'production')
console.log('[sendMessage]', { userId, message })
if (NODE_ENV !== 'production') console.log('[sendMessage]', { userId, message })
return message
}
}

View File

@@ -2,13 +2,7 @@ const { test } = require('uvu')
const assert = require('uvu/assert')
const FlowClass = require('../io/flow.class')
const MockProvider = require('../../../__mocks__/mock.provider')
const {
createBot,
CoreClass,
createFlow,
createProvider,
ProviderClass,
} = require('../index')
const { createBot, CoreClass, createFlow, createProvider, ProviderClass } = require('../index')
class MockFlow {
allCallbacks = { ref: () => 1 }
@@ -100,20 +94,13 @@ test(`[Bot] Eventos 'require_action,ready,auth_failure,message '`, async () => {
await createBot(setting)
/// Escuchamos eventos
mockProvider.on(
'require_action',
(r) => (responseEvents['require_action'] = r)
)
mockProvider.on('require_action', (r) => (responseEvents['require_action'] = r))
mockProvider.on('ready', (r) => (responseEvents['ready'] = r))
mockProvider.on('auth_failure', (r) => (responseEvents['auth_failure'] = r))
mockProvider.on('message', (r) => (responseEvents['message'] = r))
/// Emitimos eventos
mockProvider.delaySendMessage(
0,
'require_action',
MOCK_EVENTS.require_action
)
mockProvider.delaySendMessage(0, 'require_action', MOCK_EVENTS.require_action)
mockProvider.delaySendMessage(0, 'ready', MOCK_EVENTS.ready)
mockProvider.delaySendMessage(0, 'auth_failure', MOCK_EVENTS.auth_failure)
mockProvider.delaySendMessage(0, 'message', MOCK_EVENTS.message)
@@ -121,21 +108,12 @@ test(`[Bot] Eventos 'require_action,ready,auth_failure,message '`, async () => {
await delay(0)
/// Testeamos eventos
assert.is(
JSON.stringify(responseEvents.require_action),
JSON.stringify(MOCK_EVENTS.require_action)
)
assert.is(JSON.stringify(responseEvents.require_action), JSON.stringify(MOCK_EVENTS.require_action))
assert.is(responseEvents.ready, MOCK_EVENTS.ready)
assert.is(
JSON.stringify(responseEvents.auth_failure),
JSON.stringify(MOCK_EVENTS.auth_failure)
)
assert.is(JSON.stringify(responseEvents.auth_failure), JSON.stringify(MOCK_EVENTS.auth_failure))
assert.is(
JSON.stringify(responseEvents.message),
JSON.stringify(MOCK_EVENTS.message)
)
assert.is(JSON.stringify(responseEvents.message), JSON.stringify(MOCK_EVENTS.message))
})
test(`[Bot] Probando Flujos Internos`, async () => {
@@ -166,20 +144,13 @@ test(`[Bot] Probando Flujos Internos`, async () => {
await createBot(setting)
/// Escuchamos eventos
mockProvider.on(
'require_action',
(r) => (responseEvents['require_action'] = r)
)
mockProvider.on('require_action', (r) => (responseEvents['require_action'] = r))
mockProvider.on('ready', (r) => (responseEvents['ready'] = r))
mockProvider.on('auth_failure', (r) => (responseEvents['auth_failure'] = r))
mockProvider.on('message', (r) => (responseEvents['message'] = r))
/// Emitimos eventos
mockProvider.delaySendMessage(
0,
'require_action',
MOCK_EVENTS.require_action
)
mockProvider.delaySendMessage(0, 'require_action', MOCK_EVENTS.require_action)
mockProvider.delaySendMessage(0, 'ready', MOCK_EVENTS.ready)
mockProvider.delaySendMessage(0, 'auth_failure', MOCK_EVENTS.auth_failure)
mockProvider.delaySendMessage(0, 'message', MOCK_EVENTS.message)
@@ -187,21 +158,12 @@ test(`[Bot] Probando Flujos Internos`, async () => {
await delay(0)
/// Testeamos eventos
assert.is(
JSON.stringify(responseEvents.require_action),
JSON.stringify(MOCK_EVENTS.require_action)
)
assert.is(JSON.stringify(responseEvents.require_action), JSON.stringify(MOCK_EVENTS.require_action))
assert.is(responseEvents.ready, MOCK_EVENTS.ready)
assert.is(
JSON.stringify(responseEvents.auth_failure),
JSON.stringify(MOCK_EVENTS.auth_failure)
)
assert.is(JSON.stringify(responseEvents.auth_failure), JSON.stringify(MOCK_EVENTS.auth_failure))
assert.is(
JSON.stringify(responseEvents.message),
JSON.stringify(MOCK_EVENTS.message)
)
assert.is(JSON.stringify(responseEvents.message), JSON.stringify(MOCK_EVENTS.message))
})
test(`[Bot] Probando Flujos Nested`, async () => {
@@ -234,20 +196,13 @@ test(`[Bot] Probando Flujos Nested`, async () => {
botInstance.sendProviderAndSave('xxxxx', 'xxxxx')
botInstance.continue('xxxxx', 'xxxxx')
/// Escuchamos eventos
mockProvider.on(
'require_action',
(r) => (responseEvents['require_action'] = r)
)
mockProvider.on('require_action', (r) => (responseEvents['require_action'] = r))
mockProvider.on('ready', (r) => (responseEvents['ready'] = r))
mockProvider.on('auth_failure', (r) => (responseEvents['auth_failure'] = r))
mockProvider.on('message', (r) => (responseEvents['message'] = r))
/// Emitimos eventos
mockProvider.delaySendMessage(
0,
'require_action',
MOCK_EVENTS.require_action
)
mockProvider.delaySendMessage(0, 'require_action', MOCK_EVENTS.require_action)
mockProvider.delaySendMessage(0, 'ready', MOCK_EVENTS.ready)
mockProvider.delaySendMessage(0, 'auth_failure', MOCK_EVENTS.auth_failure)
mockProvider.delaySendMessage(0, 'message', MOCK_EVENTS.message)
@@ -255,21 +210,12 @@ test(`[Bot] Probando Flujos Nested`, async () => {
await delay(0)
/// Testeamos eventos
assert.is(
JSON.stringify(responseEvents.require_action),
JSON.stringify(MOCK_EVENTS.require_action)
)
assert.is(JSON.stringify(responseEvents.require_action), JSON.stringify(MOCK_EVENTS.require_action))
assert.is(responseEvents.ready, MOCK_EVENTS.ready)
assert.is(
JSON.stringify(responseEvents.auth_failure),
JSON.stringify(MOCK_EVENTS.auth_failure)
)
assert.is(JSON.stringify(responseEvents.auth_failure), JSON.stringify(MOCK_EVENTS.auth_failure))
assert.is(
JSON.stringify(responseEvents.message),
JSON.stringify(MOCK_EVENTS.message)
)
assert.is(JSON.stringify(responseEvents.message), JSON.stringify(MOCK_EVENTS.message))
})
test.run()

View File

@@ -35,10 +35,7 @@ test('Debere probar toSerialize', () => {
const ARRANGE = {
keyword: ['hola!', 'ole'],
}
const MAIN_CTX = addKeyword(ARRANGE.keyword)
.addAnswer('Segundo!')
.addAnswer('Segundo!')
.toJson()
const MAIN_CTX = addKeyword(ARRANGE.keyword).addAnswer('Segundo!').addAnswer('Segundo!').toJson()
const [ANSWER_A] = MAIN_CTX
@@ -71,9 +68,7 @@ test('Debere probar la anidación', () => {
answer_A: 'Bienvenido',
answer_B: 'Continuar',
}
const MAIN_CTX = addKeyword(ARRANGE.keyword)
.addAnswer(ARRANGE.answer_A)
.addAnswer(ARRANGE.answer_B)
const MAIN_CTX = addKeyword(ARRANGE.keyword).addAnswer(ARRANGE.answer_A).addAnswer(ARRANGE.answer_B)
assert.is(MAIN_CTX.ctx.answer, ARRANGE.answer_B)
})
@@ -107,10 +102,7 @@ test('Debere probar error las addAnswer', () => {
})
test('Obtener toJson', () => {
const [ctxA, ctxB, ctxC] = addKeyword('hola')
.addAnswer('pera!')
.addAnswer('chao')
.toJson()
const [ctxA, ctxB, ctxC] = addKeyword('hola').addAnswer('pera!').addAnswer('chao').toJson()
assert.is(ctxA.keyword, 'hola')
assert.match(ctxA.ref, /^key_/)

View File

@@ -1,4 +1,3 @@
const delay = (miliseconds) =>
new Promise((res) => setTimeout(res, miliseconds))
const delay = (miliseconds) => new Promise((res) => setTimeout(res, miliseconds))
module.exports = { delay }

View File

@@ -3,9 +3,7 @@ const flatObject = (listArray = []) => {
if (!listArray.length) return {}
const cbNestedObj = cbNestedList
.map(({ ctx }) => ctx?.callbacks)
.filter((i) => !!i)
const cbNestedObj = cbNestedList.map(({ ctx }) => ctx?.callbacks).filter((i) => !!i)
const queueCb = cbNestedObj.reduce((acc, current) => {
const getKeys = Object.keys(current)
const parse = getKeys.map((icb, i) => ({

View File

@@ -16,9 +16,6 @@ const generateRef = (prefix = false) => {
* @returns
*/
const generateRefSerialize = ({ index, answer, keyword }) =>
crypto
.createHash('md5')
.update(JSON.stringify({ index, answer, keyword }))
.digest('hex')
crypto.createHash('md5').update(JSON.stringify({ index, answer, keyword })).digest('hex')
module.exports = { generateRef, generateRefSerialize }

View File

@@ -4,9 +4,7 @@ const printer = (message, title) => {
if (NODE_ENV !== 'test') {
// console.clear()
if (title) console.log(bgRed(`${title}`))
console.log(
yellow(Array.isArray(message) ? message.join('\n') : message)
)
console.log(yellow(Array.isArray(message) ? message.join('\n') : message))
console.log(``)
}
}

View File

@@ -5,15 +5,9 @@ const checkNodeVersion = () => {
return new Promise((resolve, reject) => {
console.log(bgCyan('🚀 Revisando tu Node.js'))
const version = process.version
const majorVersion = parseInt(
version.replace('v', '').split('.').shift()
)
const majorVersion = parseInt(version.replace('v', '').split('.').shift())
if (majorVersion < 16) {
console.error(
red(
`🔴 Se require Node.js 16 o superior. Actualmente esta ejecutando Node.js ${version}`
)
)
console.error(red(`🔴 Se require Node.js 16 o superior. Actualmente esta ejecutando Node.js ${version}`))
console.log(``)
reject('ERROR_NODE')
}

View File

@@ -2,10 +2,7 @@ const rimraf = require('rimraf')
const { yellow } = require('kleur')
const { join } = require('path')
const PATH_WW = [
join(process.cwd(), '.wwebjs_auth'),
join(process.cwd(), 'session.json'),
]
const PATH_WW = [join(process.cwd(), '.wwebjs_auth'), join(process.cwd(), 'session.json')]
const cleanSession = () => {
const queue = []

View File

@@ -23,11 +23,7 @@ const JSON_TEMPLATE = {
const PATH_CONFIG = join(process.cwd(), 'config.json')
const jsonConfig = () => {
return writeFile(
PATH_CONFIG,
JSON.stringify(JSON_TEMPLATE, null, 2),
'utf-8'
)
return writeFile(PATH_CONFIG, JSON.stringify(JSON_TEMPLATE, null, 2), 'utf-8')
}
module.exports = { jsonConfig }

View File

@@ -20,13 +20,9 @@ const installDeps = (pkgManager, packageList) => {
const installSingle = (pkgInstall) => () => {
new Promise((resolve) => {
try {
childProcess = spawn(
pkgManager,
[PKG_OPTION[pkgManager], pkgInstall],
{
stdio: 'inherit',
}
)
childProcess = spawn(pkgManager, [PKG_OPTION[pkgManager], pkgInstall], {
stdio: 'inherit',
})
childProcess.on('error', (e) => {
console.error(e)

View File

@@ -30,9 +30,7 @@ const startInteractive = async () => {
await nextSteps()
} catch (e) {
console.error(bgRed(`Ups! 🙄 algo no va bien.`))
console.error(
bgRed(`Revisa los requerimientos minimos en la documentacion`)
)
console.error(bgRed(`Revisa los requerimientos minimos en la documentacion`))
}
}
@@ -82,8 +80,7 @@ const nextSteps = async () => {
const { outDir = '', providerDb = [], providerWs = [] } = response
const createApp = async (templateName = null) => {
if (!templateName)
throw new Error('TEMPLATE_NAME_INVALID: ', templateName)
if (!templateName) throw new Error('TEMPLATE_NAME_INVALID: ', templateName)
const possiblesPath = [
join(__dirname, '..', '..', 'starters', 'apps', templateName),
@@ -115,11 +112,7 @@ const nextSteps = async () => {
const vendorProvider = async () => {
const [answer] = providerWs
if (!providerWs.length) {
console.log(
red(
`Debes seleccionar un proveedor de whatsapp. Tecla [Space] para seleccionar`
)
)
console.log(red(`Debes seleccionar un proveedor de whatsapp. Tecla [Space] para seleccionar`))
process.exit(1)
}
return answer
@@ -132,11 +125,7 @@ const nextSteps = async () => {
const dbProvider = async () => {
const [answer] = providerDb
if (!providerDb.length) {
console.log(
red(
`Debes seleccionar un proveedor de base de datos. Tecla [Space] para seleccionar`
)
)
console.log(red(`Debes seleccionar un proveedor de base de datos. Tecla [Space] para seleccionar`))
process.exit(1)
}
return answer

View File

@@ -38,10 +38,8 @@ class DialogFlowCXContext extends CoreClass {
* */
}
if (!this.optionsDX.location.length)
throw new Error('LOCATION_NO_ENCONTRADO')
if (!this.optionsDX.agentId.length)
throw new Error('AGENTID_NO_ENCONTRADO')
if (!this.optionsDX.location.length) throw new Error('LOCATION_NO_ENCONTRADO')
if (!this.optionsDX.agentId.length) throw new Error('AGENTID_NO_ENCONTRADO')
const rawJson = readFileSync(GOOGLE_ACCOUNT_PATH, 'utf-8')
const { project_id, private_key, client_email } = JSON.parse(rawJson)
@@ -86,9 +84,7 @@ class DialogFlowCXContext extends CoreClass {
},
}
const [single] = (await this.sessionClient.detectIntent(reqDialog)) || [
null,
]
const [single] = (await this.sessionClient.detectIntent(reqDialog)) || [null]
const listMessages = single.queryResult.responseMessages.map((res) => {
if (res.message == 'text') {
@@ -96,17 +92,11 @@ class DialogFlowCXContext extends CoreClass {
}
if (res.message == 'payload') {
const {
media = null,
buttons = [],
answer = '',
} = res.payload.fields
const buttonsArray = buttons?.listValue?.values?.map(
(btnValue) => {
const { stringValue } = btnValue.structValue.fields.body
return { body: stringValue }
}
)
const { media = null, buttons = [], answer = '' } = res.payload.fields
const buttonsArray = buttons?.listValue?.values?.map((btnValue) => {
const { stringValue } = btnValue.structValue.fields.body
return { body: stringValue }
})
return {
answer: answer?.stringValue,
options: {

View File

@@ -5,8 +5,7 @@ const DialogCXFlowClass = require('./dialogflow-cx.class')
* @param {*} args
* @returns
*/
const createBotDialog = async ({ database, provider }, _options) =>
new DialogCXFlowClass(database, provider, _options)
const createBotDialog = async ({ database, provider }, _options) => new DialogCXFlowClass(database, provider, _options)
module.exports = {
createBotDialog,

View File

@@ -65,10 +65,7 @@ class DialogFlowContext extends CoreClass {
* para evitar este problema.
* https://github.com/codigoencasa/bot-whatsapp/pull/140
*/
const session = this.sessionClient.projectAgentSessionPath(
this.projectId,
from
)
const session = this.sessionClient.projectAgentSessionPath(this.projectId, from)
const reqDialog = {
session,
queryInput: {
@@ -79,15 +76,11 @@ class DialogFlowContext extends CoreClass {
},
}
const [single] = (await this.sessionClient.detectIntent(reqDialog)) || [
null,
]
const [single] = (await this.sessionClient.detectIntent(reqDialog)) || [null]
const { queryResult } = single
const msgPayload = queryResult?.fulfillmentMessages?.find(
(a) => a.message === 'payload'
)
const msgPayload = queryResult?.fulfillmentMessages?.find((a) => a.message === 'payload')
// Revisamos si el dialogFlow tiene multimedia
if (msgPayload && msgPayload?.payload) {

View File

@@ -5,8 +5,7 @@ const DialogFlowClass = require('./dialogflow.class')
* @param {*} args
* @returns
*/
const createBotDialog = async ({ database, provider }) =>
new DialogFlowClass(database, provider)
const createBotDialog = async ({ database, provider }) => new DialogFlowClass(database, provider)
module.exports = {
createBotDialog,

View File

@@ -5,8 +5,7 @@ const MockClass = require('./mock.class')
* @param {*} args
* @returns
*/
const createBotMock = async ({ database, provider }) =>
new MockClass(database, provider)
const createBotMock = async ({ database, provider }) => new MockClass(database, provider)
module.exports = {
createBotMock,

View File

@@ -24,12 +24,7 @@ class MongoAdapter {
}
getPrevByNumber = async (from) => {
const result = await this.db
.collection('history')
.find({ from })
.sort({ _id: -1 })
.limit(1)
.toArray()
const result = await this.db.collection('history').find({ from }).sort({ _id: -1 }).limit(1).toArray()
return result[0]
}

View File

@@ -1,76 +1,66 @@
const mysql = require("mysql2");
const mysql = require('mysql2')
class MyslAdapter {
db;
listHistory = [];
credentials = { host: null, user: null, database: null, password: null };
db
listHistory = []
credentials = { host: null, user: null, database: null, password: null }
constructor(_credentials) {
this.credentials = _credentials;
this.init().then();
}
constructor(_credentials) {
this.credentials = _credentials
this.init().then()
}
async init() {
this.db = mysql.createConnection(this.credentials);
async init() {
this.db = mysql.createConnection(this.credentials)
await this.db.connect(async (error) => {
if (!error) {
console.log(`Solicitud de conexión a base de datos exitosa`);
await this.checkTableExists();
}
await this.db.connect(async (error) => {
if (!error) {
console.log(`Solicitud de conexión a base de datos exitosa`)
await this.checkTableExists()
}
if (error) {
console.log(`Solicitud de conexión fallida ${error.stack}`);
}
});
}
if (error) {
console.log(`Solicitud de conexión fallida ${error.stack}`)
}
})
}
getPrevByNumber = (from) =>
new Promise((resolve, reject) => {
const sql = `SELECT * FROM history WHERE phone=${from} ORDER BY id DESC`;
this.db.query(sql, (error, rows) => {
if (error) {
reject(error);
}
getPrevByNumber = (from) =>
new Promise((resolve, reject) => {
const sql = `SELECT * FROM history WHERE phone=${from} ORDER BY id DESC`
this.db.query(sql, (error, rows) => {
if (error) {
reject(error)
}
if (rows.length) {
const [row] = rows;
row.options = JSON.parse(row.options);
resolve(row);
}
if (rows.length) {
const [row] = rows
row.options = JSON.parse(row.options)
resolve(row)
}
if (!rows.length) {
resolve(null);
}
});
});
if (!rows.length) {
resolve(null)
}
})
})
save = (ctx) => {
const values = [
[
ctx.ref,
ctx.keyword,
ctx.answer,
ctx.refSerialize,
ctx.from,
JSON.stringify(ctx.options),
],
];
const sql =
"INSERT INTO history (ref, keyword, answer, refSerialize, phone, options ) values ?";
save = (ctx) => {
const values = [[ctx.ref, ctx.keyword, ctx.answer, ctx.refSerialize, ctx.from, JSON.stringify(ctx.options)]]
const sql = 'INSERT INTO history (ref, keyword, answer, refSerialize, phone, options ) values ?'
this.db.query(sql, [values], (err) => {
if (err) throw err;
console.log("Guardado en DB...", values);
});
this.listHistory.push(ctx);
};
this.db.query(sql, [values], (err) => {
if (err) throw err
console.log('Guardado en DB...', values)
})
this.listHistory.push(ctx)
}
createTable = () =>
new Promise((resolve) => {
const tableName = "history";
createTable = () =>
new Promise((resolve) => {
const tableName = 'history'
const sql = `CREATE TABLE ${tableName}
const sql = `CREATE TABLE ${tableName}
(id INT AUTO_INCREMENT PRIMARY KEY,
ref varchar(255) NOT NULL,
keyword varchar(255) NOT NULL,
@@ -78,29 +68,29 @@ class MyslAdapter {
refSerialize varchar(255) NOT NULL,
phone varchar(255) NOT NULL,
options longtext NOT NULL)
CHARACTER SET utf8mb4 COLLATE utf8mb4_General_ci`;
CHARACTER SET utf8mb4 COLLATE utf8mb4_General_ci`
this.db.query(sql, (err) => {
if (err) throw err;
console.log(`Tabla ${tableName} creada correctamente `);
resolve(true);
});
});
this.db.query(sql, (err) => {
if (err) throw err
console.log(`Tabla ${tableName} creada correctamente `)
resolve(true)
})
})
checkTableExists = () =>
new Promise((resolve) => {
const sql = "SHOW TABLES LIKE 'history'";
checkTableExists = () =>
new Promise((resolve) => {
const sql = "SHOW TABLES LIKE 'history'"
this.db.query(sql, (err, rows) => {
if (err) throw err;
this.db.query(sql, (err, rows) => {
if (err) throw err
if (!rows.length) {
this.createTable();
}
if (!rows.length) {
this.createTable()
}
resolve(!!rows.length);
});
});
resolve(!!rows.length)
})
})
}
module.exports = MyslAdapter;
module.exports = MyslAdapter

View File

@@ -8,6 +8,5 @@
font-family: IBMPlexMono-Regular;
src: url(IBMPlexMono-Regular-subset.woff2) format('woff2'),
url(IBMPlexMono-Regular-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+2C, U+2E, U+41-43, U+46, U+49, U+4B-4F, U+53-55, U+58,
U+61-65, U+67-69, U+6C-76;
unicode-range: U+20, U+2C, U+2E, U+41-43, U+46, U+49, U+4B-4F, U+53-55, U+58, U+61-65, U+67-69, U+6C-76;
}

View File

@@ -8,6 +8,6 @@
font-family: IBMPlexMono-SemiBold;
src: url(IBMPlexMono-SemiBold-subset.woff2) format('woff2'),
url(IBMPlexMono-SemiBold-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+24, U+2E, U+30, U+38, U+39, U+41, U+42, U+44, U+47,
U+4E, U+4F, U+52-55, U+57, U+59, U+65, U+68, U+6F, U+72, U+74;
unicode-range: U+20, U+24, U+2E, U+30, U+38, U+39, U+41, U+42, U+44, U+47, U+4E, U+4F, U+52-55, U+57, U+59, U+65,
U+68, U+6F, U+72, U+74;
}

View File

@@ -6,9 +6,8 @@
@font-face {
font-family: Pally-Variable;
src: url(Pally-Variable-subset.woff2) format('woff2'),
url(Pally-Variable-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+24, U+2C, U+2E, U+30, U+33, U+39, U+41-43, U+46,
U+49-4D, U+53, U+55, U+58, U+61-65, U+67-69, U+6B-77, U+79;
src: url(Pally-Variable-subset.woff2) format('woff2'), url(Pally-Variable-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+24, U+2C, U+2E, U+30, U+33, U+39, U+41-43, U+46, U+49-4D, U+53, U+55, U+58, U+61-65, U+67-69,
U+6B-77, U+79;
font-weight: 400 700;
}

View File

@@ -8,6 +8,5 @@
font-family: SourceSerifPro-Regular;
src: url(SourceSerifPro-Regular-subset.woff2) format('woff2'),
url(SourceSerifPro-Regular-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+2C, U+2E, U+41-44, U+49, U+4A, U+4C, U+53, U+55,
U+61-65, U+67-69, U+6B-76, U+79;
unicode-range: U+20, U+2C, U+2E, U+41-44, U+49, U+4A, U+4C, U+53, U+55, U+61-65, U+67-69, U+6B-76, U+79;
}

View File

@@ -6,9 +6,8 @@
@font-face {
font-family: Synonym-Variable;
src: url(Synonym-Variable-subset.woff2) format('woff2'),
url(Synonym-Variable-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+24, U+2C, U+2E, U+30, U+33, U+35, U+41-44, U+46, U+47,
U+49, U+4B-4F, U+53-55, U+57-59, U+61, U+63-65, U+67-69, U+6C-76;
src: url(Synonym-Variable-subset.woff2) format('woff2'), url(Synonym-Variable-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+24, U+2C, U+2E, U+30, U+33, U+35, U+41-44, U+46, U+47, U+49, U+4B-4F, U+53-55, U+57-59, U+61,
U+63-65, U+67-69, U+6C-76;
font-weight: 400 700;
}

View File

@@ -6,8 +6,7 @@
@font-face {
font-family: TenorSans-Regular;
src: url(TenorSans-Regular-subset.woff2) format('woff2'),
url(TenorSans-Regular-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+24, U+2E, U+30, U+36, U+46, U+49, U+4A, U+53, U+54,
U+61, U+63, U+65, U+69, U+6B, U+6E, U+6F, U+72-75, U+79;
src: url(TenorSans-Regular-subset.woff2) format('woff2'), url(TenorSans-Regular-subset.zopfli.woff) format('woff');
unicode-range: U+20, U+24, U+2E, U+30, U+36, U+46, U+49, U+4A, U+53, U+54, U+61, U+63, U+65, U+69, U+6B, U+6E, U+6F,
U+72-75, U+79;
}

View File

@@ -56,10 +56,7 @@ export const DigitalOcean = () => (
h-3.1V2h3.2V14.9z M361.9,21.1v1.1c0,4.4,2.6,6.6,6.2,6.6c3.7,0,6.5-2.5,6.5-7.2c0-4.6-2.8-7.1-6.5-7.1
C364.5,14.5,361.9,16.8,361.9,21.1z"
/>
<path
class="st0"
d="M386.3,40.9l4.6-10.7L383.2,12h3.6l5.8,14.5l5.8-14.5h3.6l-12.2,28.9H386.3z"
/>
<path class="st0" d="M386.3,40.9l4.6-10.7L383.2,12h3.6l5.8,14.5l5.8-14.5h3.6l-12.2,28.9H386.3z" />
</g>
</g>
<g id="XMLID_2369_">
@@ -111,14 +108,7 @@ export const DigitalOcean = () => (
c1.2,1.2,2.6,1.8,4.3,1.8c1.7,0,3.1-0.6,4.3-1.8c1.2-1.2,1.8-2.6,1.8-4.3c0-1.7-0.6-3.1-1.8-4.2
C225.7,46.5,224.3,45.9,222.6,45.9z"
/>
<rect
id="XMLID_276_"
x="217.6"
y="63"
class="st0"
width="9.8"
height="39.1"
/>
<rect id="XMLID_276_" x="217.6" y="63" class="st0" width="9.8" height="39.1" />
<path
id="XMLID_273_"
class="st0"
@@ -128,14 +118,7 @@ export const DigitalOcean = () => (
c3.5-3.6,5.3-8.4,5.3-14.2V63h-9.7V66.3z M260.6,89.4c-1.7,2-3.9,2.9-6.8,2.9c-2.8,0-5-0.9-6.7-2.9c-1.7-1.9-2.5-4.5-2.5-7.7
c0-3.2,0.9-5.8,2.5-7.7c1.7-1.9,3.9-2.9,6.7-2.9c2.8,0,5,1,6.8,2.9c1.7,2,2.6,4.6,2.6,7.7C263.2,84.9,262.3,87.5,260.6,89.4z"
/>
<rect
id="XMLID_272_"
x="281.3"
y="63"
class="st0"
width="9.8"
height="39.1"
/>
<rect id="XMLID_272_" x="281.3" y="63" class="st0" width="9.8" height="39.1" />
<path
id="XMLID_271_"
class="st0"
@@ -149,14 +132,7 @@ export const DigitalOcean = () => (
d="M312.7,52.5H303V63h-5.6v9h5.6v16.2c0,5.1,1,8.7,3,10.8c2,2.1,5.6,3.2,10.6,3.2
c1.6,0,3.2-0.1,4.8-0.2l0.4,0v-9l-3.4,0.2c-2.3,0-3.9-0.4-4.7-1.2c-0.8-0.8-1.1-2.6-1.1-5.2V72h9.2v-9h-9.2V52.5z"
/>
<rect
id="XMLID_269_"
x="368"
y="46.6"
class="st0"
width="9.8"
height="55.5"
/>
<rect id="XMLID_269_" x="368" y="46.6" class="st0" width="9.8" height="55.5" />
<path
id="XMLID_268_"
class="st0"

View File

@@ -5,14 +5,7 @@ import logoSrc from '~/assets/images/chatbot-whatsapp.png?width=64&height=64&png
export default component$(() => (
<span class="self-center ml-2 text-2xl md:text-xl font-bold text-gray-900 whitespace-nowrap dark:text-white flex items-center">
<img
src={logoSrc}
class="inline-block mr-1"
width={32}
height={32}
alt="Qwind Logo"
loading="lazy"
/>
<img src={logoSrc} class="inline-block mr-1" width={32} height={32} alt="Qwind Logo" loading="lazy" />
Chatbot
</span>
))

View File

@@ -1,11 +1,5 @@
export const Netlify = () => (
<svg
xmlns="http://www.w3.org/2000/svg"
width={147}
height={40}
role="img"
fill="currentColor"
>
<svg xmlns="http://www.w3.org/2000/svg" width={147} height={40} role="img" fill="currentColor">
<g fill-rule="evenodd">
<path d="M53.37 12.978l.123 2.198c1.403-1.7 3.245-2.55 5.525-2.55 3.951 0 5.962 2.268 6.032 6.804v12.568H60.79V19.676c0-1.207-.26-2.1-.78-2.681-.52-.58-1.371-.87-2.552-.87-1.719 0-3 .78-3.84 2.338v13.535h-4.262v-19.02h4.016zM77.748 32.35c-2.7 0-4.89-.852-6.567-2.557-1.678-1.705-2.517-3.976-2.517-6.812v-.527c0-1.898.365-3.595 1.096-5.089.73-1.494 1.757-2.657 3.078-3.49 1.321-.831 2.794-1.247 4.42-1.247 2.583 0 4.58.826 5.988 2.478 1.41 1.653 2.114 3.99 2.114 7.014v1.723h-12.4c.13 1.57.652 2.812 1.57 3.726.918.914 2.073 1.371 3.464 1.371 1.952 0 3.542-.79 4.77-2.373l2.297 2.198c-.76 1.136-1.774 2.018-3.042 2.645-1.269.627-2.692.94-4.27.94zm-.508-16.294c-1.17 0-2.113.41-2.832 1.23-.72.82-1.178 1.963-1.377 3.428h8.12v-.317c-.094-1.43-.474-2.51-1.14-3.243-.667-.732-1.59-1.098-2.771-1.098zm16.765-7.7v4.623h3.35v3.164h-3.35V26.76c0 .726.144 1.25.43 1.573.286.322.798.483 1.535.483a6.55 6.55 0 0 0 1.49-.176v3.305c-.97.27-1.905.404-2.806.404-3.273 0-4.91-1.81-4.91-5.431V16.142H86.62v-3.164h3.122V8.355h4.261zm11.137 23.643h-4.262v-27h4.262v27zm9.172 0h-4.262v-19.02h4.262v19.02zm-4.525-23.96c0-.655.207-1.2.622-1.634.416-.433 1.009-.65 1.78-.65.772 0 1.368.217 1.79.65.42.434.63.979.63 1.635 0 .644-.21 1.18-.63 1.608-.422.428-1.018.642-1.79.642-.771 0-1.364-.214-1.78-.642-.415-.427-.622-.964-.622-1.608zm10.663 23.96V16.142h-2.894v-3.164h2.894v-1.74c0-2.11.584-3.738 1.753-4.887 1.17-1.148 2.806-1.722 4.91-1.722.749 0 1.544.105 2.386.316l-.105 3.34a8.375 8.375 0 0 0-1.631-.14c-2.035 0-3.052 1.048-3.052 3.146v1.687h3.858v3.164h-3.858v15.856h-4.261zm17.87-6.117l3.858-12.903h4.542l-7.54 21.903c-1.158 3.199-3.122 4.799-5.893 4.799-.62 0-1.304-.106-2.052-.317v-3.305l.807.053c1.075 0 1.885-.196 2.429-.589.543-.392.973-1.051 1.289-1.977l.613-1.635-6.664-18.932h4.595l4.016 12.903z" />
<path

View File

@@ -13,10 +13,7 @@ export const RouterHead = component$(() => {
<title>{head.title}</title>
<link rel="canonical" href={loc.href} />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" />
{head.meta.map((m) => (

View File

@@ -34,14 +34,8 @@ export const Social = () => {
content="https://campaign.codigoencasa.com"
/>
<meta property="og:site_name" content="campaign.codigoencasa.com" /> */}
<meta
property="og:image"
content="https://i.imgur.com/0HpzsEm.png"
></meta>
<meta
property="og:image:secure_url"
content="https://i.imgur.com/0HpzsEm.png"
/>
<meta property="og:image" content="https://i.imgur.com/0HpzsEm.png"></meta>
<meta property="og:image:secure_url" content="https://i.imgur.com/0HpzsEm.png" />
<meta property="og:image:type" content="image/png"></meta>
<meta property="og:image:width" content="1200"></meta>
<meta property="og:image:height" content="630"></meta>
@@ -52,10 +46,7 @@ export const Social = () => {
name="twitter:title"
content="💻 Conviértete en un Programador Backend aprendiendo todo de Cloud y Nodejs"
/>
<meta
name="twitter:image"
content="https://i.imgur.com/0HpzsEm.png"
/>
<meta name="twitter:image" content="https://i.imgur.com/0HpzsEm.png" />
</>
)
}

View File

@@ -27,9 +27,7 @@ export default component$((props: ItemProps) => {
// TODO:
document.body.classList.toggle('overflow-hidden')
document.getElementById('header')?.classList.toggle('h-screen')
document
.querySelector('#header nav')
?.classList.toggle('hidden')
document.querySelector('#header nav')?.classList.toggle('hidden')
}}
>
<IconMenu class={iconClass} />

View File

@@ -10,16 +10,13 @@ interface ItemProps {
export default component$((props: ItemProps) => {
const { iconClass } = props
const store = useStore({
theme:
(typeof window !== 'undefined' && window?.localStorage?.theme) ||
undefined,
theme: (typeof window !== 'undefined' && window?.localStorage?.theme) || undefined,
})
useClientEffect$(() => {
store.theme =
window.localStorage.theme === 'dark' ||
(!('theme' in window.localStorage) &&
window.matchMedia('(prefers-color-scheme: dark)').matches)
(!('theme' in window.localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
? 'dark'
: 'light'
})
@@ -42,11 +39,7 @@ export default component$((props: ItemProps) => {
}
}}
>
{store.theme == 'dark' ? (
<IconMoon class={iconClass} />
) : (
<IconSun class={iconClass} />
)}
{store.theme == 'dark' ? <IconMoon class={iconClass} /> : <IconSun class={iconClass} />}
</button>
)
})

View File

@@ -7,9 +7,7 @@ export const IconArrowDownRight = (props: ItemProps) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
class={`icon icon-tabler icon-tabler-arrow-down-right ${
className || 'w-5 h-5'
}`}
class={`icon icon-tabler icon-tabler-arrow-down-right ${className || 'w-5 h-5'}`}
width="24"
height="24"
viewBox="0 0 24 24"

View File

@@ -8,9 +8,7 @@ export const IconMenu = (props: ItemProps) => {
<svg
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
class={`icon icon-tabler icon-tabler-menu ${
className || 'w-5 h-5'
}`}
class={`icon icon-tabler icon-tabler-menu ${className || 'w-5 h-5'}`}
preserveAspectRatio="xMidYMid meet"
viewBox="0 0 24 24"
>

View File

@@ -7,9 +7,7 @@ export const IconMoon = (props: ItemProps) => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
class={`icon icon-tabler icon-tabler-moon ${
className || 'w-5 h-5'
}`}
class={`icon icon-tabler icon-tabler-moon ${className || 'w-5 h-5'}`}
width="24"
height="24"
viewBox="0 0 24 24"

View File

@@ -23,9 +23,7 @@ export default component$(
<div class="pt-2 space-y-4 justify-center flex">
<figcaption class="text-sm">
<div class={'font-semibold truncate'}>
{props.user.login}
</div>
<div class={'font-semibold truncate'}>{props.user.login}</div>
</figcaption>
</div>
</figure>

View File

@@ -32,8 +32,7 @@ export default component$((props: { users: User[] }) => {
Super estrellas
</h2>
<p class="max-w-3xl mx-auto sm:text-center text-xl text-gray-600 dark:text-slate-400">
Todo es posible gracias a el mayor recursos de todos, el
recurso humano. Tu tambien puedes{' '}
Todo es posible gracias a el mayor recursos de todos, el recurso humano. Tu tambien puedes{' '}
<a class={'font-semibold'} href="/docs/contributing">
formar parte
</a>

View File

@@ -15,8 +15,8 @@ export default component$(() => {
📄 Editar esta pagina
</a>
<p class={'text-xs'}>
Forma parte de esta comunidad mejorando la documentación
siente libre de poder agregar o editar lo que quieras
Forma parte de esta comunidad mejorando la documentación siente libre de poder agregar o editar
lo que quieras
</p>
</li>
</ul>

View File

@@ -56,13 +56,9 @@ export default component$(() => {
<IconArrowDownRight class="w-7 h-7 text-primary-600 inline-block" />
{question}
</div>
{answer
.split('\n\n')
.map((paragraph) => (
<p class="text-gray-700 dark:text-gray-400 mb-2">
{paragraph}
</p>
))}
{answer.split('\n\n').map((paragraph) => (
<p class="text-gray-700 dark:text-gray-400 mb-2">{paragraph}</p>
))}
</div>
))}
</div>

View File

@@ -50,13 +50,11 @@ export default component$(() => {
Caracteristicas
</p>
<h2 class="text-4xl md:text-5xl font-bold leading-tighter tracking-tighter mb-4 font-heading">
Nuestras principales{' '}
<span class="whitespace-nowrap">funciones</span>
Nuestras principales <span class="whitespace-nowrap">funciones</span>
</h2>
<p class="max-w-3xl mx-auto sm:text-center text-xl text-gray-600 dark:text-slate-400">
El secreto es mantener los procesos repetitivos en
procesos automatizados simples, por eso te mostramos en
que destacamos.
El secreto es mantener los procesos repetitivos en procesos automatizados simples, por eso te
mostramos en que destacamos.
</p>
</div>
<div class="grid mx-auto space-y-6 md:grid-cols-2 md:space-y-0">
@@ -70,12 +68,8 @@ export default component$(() => {
</div>
</div>
<div>
<h3 class="mb-3 text-xl font-bold">
{title}
</h3>
<p class="text-gray-600 dark:text-slate-400">
{description}
</p>
<h3 class="mb-3 text-xl font-bold">{title}</h3>
<p class="text-gray-600 dark:text-slate-400">{description}</p>
</div>
</div>
))}

View File

@@ -9,36 +9,24 @@ import { src as placeholder } from '~/assets/images/chatbot-whatsapp.png?width=4
export default component$(() => {
return (
<section
class={` from-white via-purple-50 to-sky-100 dark:bg-none mt-[-95px]`}
>
<section class={` from-white via-purple-50 to-sky-100 dark:bg-none mt-[-95px]`}>
<div class="max-w-6xl mx-auto px-4 sm:px-6 md:flex md:h-screen 2xl:h-auto pt-[72px]">
<div class="py-12 md:py-12 lg:py-16 block md:flex text-center md:text-left">
<div class="pb-12 md:pb-0 md:py-0 max-w-5xl mx-auto md:pr-16 flex items-center basis-[56%]">
<div>
<h1 class="text-5xl md:text-[3.48rem] font-bold leading-tighter tracking-tighter mb-4 font-heading px-4 md:px-0">
Crear chatbot{' '}
<span class="sm:whitespace-nowrap text-[#25b637]">
WhatsApp
</span>
<br class="hidden lg:block" />{' '}
<span class="lg:inline">en minutos</span>
Crear chatbot <span class="sm:whitespace-nowrap text-[#25b637]">WhatsApp</span>
<br class="hidden lg:block" /> <span class="lg:inline">en minutos</span>
</h1>
<div class="max-w-3xl mx-auto">
<p class="text-xl text-gray-600 mb-8 dark:text-slate-400">
<span class="font-semibold ">
Con esta libreria,{' '}
</span>
<span class="font-semibold ">Con esta libreria, </span>
<span class="font-semibold ">
puedes configurar respuestas
automatizadas para preguntas frecuentes
puedes configurar respuestas automatizadas para preguntas frecuentes
</span>{' '}
, recibir y responder mensajes de manera
automatizada, y hacer un seguimiento de las
interacciones con los clientes. Además,
nuestro Chatbot se integra fácilmente con
otros sistemas y herramientas que ya esté
utilizando en su negocio.
, recibir y responder mensajes de manera automatizada, y hacer un seguimiento de las
interacciones con los clientes. Además, nuestro Chatbot se integra fácilmente con
otros sistemas y herramientas que ya esté utilizando en su negocio.
</p>
<div class="max-w-xs sm:max-w-md flex flex-nowrap flex-col sm:flex-col gap-4 m-auto md:m-0 justify-center md:justify-start">
@@ -48,10 +36,7 @@ export default component$(() => {
</code>
</div>
<div class="flex w-full sm:w-auto gap-3">
<a
href="/docs"
class="btn bg-gray-50 dark:bg-transparent"
>
<a href="/docs" class="btn bg-gray-50 dark:bg-transparent">
Ver documentación
</a>
<a

View File

@@ -32,14 +32,9 @@ export default component$((props: { users: User[] }) => {
Miembros
</h2>
<p class="max-w-3xl mx-auto sm:text-center text-xl text-gray-600 dark:text-slate-400">
Conviértete en un miembro destacado y forma parte del
proyecto y disfruta de manera adelantada de las
actualizaciones{' '}
<a
class={'font-semibold'}
target={'_blank'}
href="https://opencollective.com/bot-whatsapp"
>
Conviértete en un miembro destacado y forma parte del proyecto y disfruta de manera adelantada
de las actualizaciones{' '}
<a class={'font-semibold'} target={'_blank'} href="https://opencollective.com/bot-whatsapp">
Únete
</a>
</p>

View File

@@ -5,55 +5,45 @@ import { DocumentationCtx } from '~/contexts'
/**
* options = [] array con la lista de opciones de la documentacion
*/
export default component$(
({ options = [] }: { options: DocumentationCtx[] }) => {
return (
<div>
{options.map((item, i) => (
<UlCompoent key={i} title={item.title} list={item.list} />
))}
</div>
)
}
)
export default component$(({ options = [] }: { options: DocumentationCtx[] }) => {
return (
<div>
{options.map((item, i) => (
<UlCompoent key={i} title={item.title} list={item.list} />
))}
</div>
)
})
export const UlCompoent = component$(
(porps: { title: string; list: { link: string; name: string }[] }) => {
return (
<ul>
<li class="mt-2 lg:mt-2">
<h5 class="mb-8 lg:mb-3 font-semibold text-slate-900 dark:text-slate-200">
{porps.title}
</h5>
<LiComponent list={porps.list} />
export const UlCompoent = component$((porps: { title: string; list: { link: string; name: string }[] }) => {
return (
<ul>
<li class="mt-2 lg:mt-2">
<h5 class="mb-8 lg:mb-3 font-semibold text-slate-900 dark:text-slate-200">{porps.title}</h5>
<LiComponent list={porps.list} />
</li>
</ul>
)
})
export const LiComponent = component$((porps: { list: { link: string; name: string }[] }) => {
const location = useLocation()
const currentPage = location.pathname
return (
<ul class="space-y-6 lg:space-y-2 border-l border-slate-100 dark:border-slate-800">
{porps.list.map((opt) => (
<li>
<Link
class={[
currentPage === `${opt.link}/` ? 'font-semibold' : '',
'block border-l pl-4 -ml-px border-transparent hover:border-slate-400 dark:hover:border-slate-500 text-slate-700 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-300 ',
]}
href={opt.link}
>
{opt.name}
</Link>
</li>
</ul>
)
}
)
export const LiComponent = component$(
(porps: { list: { link: string; name: string }[] }) => {
const location = useLocation()
const currentPage = location.pathname
return (
<ul class="space-y-6 lg:space-y-2 border-l border-slate-100 dark:border-slate-800">
{porps.list.map((opt) => (
<li>
<Link
class={[
currentPage === `${opt.link}/`
? 'font-semibold'
: '',
'block border-l pl-4 -ml-px border-transparent hover:border-slate-400 dark:hover:border-slate-500 text-slate-700 hover:text-slate-900 dark:text-slate-400 dark:hover:text-slate-300 ',
]}
href={opt.link}
>
{opt.name}
</Link>
</li>
))}
</ul>
)
}
)
))}
</ul>
)
})

View File

@@ -1,74 +1,63 @@
import { component$ } from '@builder.io/qwik'
export const ButtonLink = component$(
(props: { name: string; link: string; direction: 'left' | 'right' }) => {
const ArrowRight = () => (
<svg
viewBox="0 0 3 6"
class="ml-3 w-auto h-1.5 text-slate-400 overflow-visible group-hover:text-slate-600 dark:group-hover:text-slate-300"
>
<path
d="M0 0L3 3L0 6"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
)
export const ButtonLink = component$((props: { name: string; link: string; direction: 'left' | 'right' }) => {
const ArrowRight = () => (
<svg
viewBox="0 0 3 6"
class="ml-3 w-auto h-1.5 text-slate-400 overflow-visible group-hover:text-slate-600 dark:group-hover:text-slate-300"
>
<path
d="M0 0L3 3L0 6"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
)
const ArrowLeft = () => (
<svg
viewBox="0 0 3 6"
class="mr-3 w-auto h-1.5 text-slate-400 overflow-visible group-hover:text-slate-600 dark:group-hover:text-slate-300"
>
<path
d="M3 0L0 3L3 6"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
)
const ArrowLeft = () => (
<svg
viewBox="0 0 3 6"
class="mr-3 w-auto h-1.5 text-slate-400 overflow-visible group-hover:text-slate-600 dark:group-hover:text-slate-300"
>
<path
d="M3 0L0 3L3 6"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
></path>
</svg>
)
return (
<a
class="group flex items-center hover:text-slate-900 dark:hover:text-white"
href={props.link}
>
{props.direction === 'left' ? (
<>
<ArrowLeft />
{props.name}
</>
) : (
<>
{props.name}
<ArrowRight />
</>
)}
</a>
)
}
)
return (
<a class="group flex items-center hover:text-slate-900 dark:hover:text-white" href={props.link}>
{props.direction === 'left' ? (
<>
<ArrowLeft />
{props.name}
</>
) : (
<>
{props.name}
<ArrowRight />
</>
)}
</a>
)
})
export default component$(
(props: { pages: ({ name: string; link: string } | null)[] }) => {
const { pages } = props
return (
<div class="text-sm leading-6 mt-12">
<div class="mb-10 text-slate-700 font-semibold flex justify-between items-center dark:text-slate-200">
{pages[0] ? (
<ButtonLink direction="left" {...pages[0]} />
) : null}
{pages[1] ? (
<ButtonLink direction="right" {...pages[1]} />
) : null}
</div>
export default component$((props: { pages: ({ name: string; link: string } | null)[] }) => {
const { pages } = props
return (
<div class="text-sm leading-6 mt-12">
<div class="mb-10 text-slate-700 font-semibold flex justify-between items-center dark:text-slate-200">
{pages[0] ? <ButtonLink direction="left" {...pages[0]} /> : null}
{pages[1] ? <ButtonLink direction="right" {...pages[1]} /> : null}
</div>
)
}
)
</div>
)
})

View File

@@ -5,33 +5,25 @@ export default component$(() => {
<div class="px-4 py-8 md:py-16 sm:px-6 mx-auto md:px-24 lg:px-8 lg:py-20 max-w-6xl">
<div class="grid grid-cols-2 row-gap-8 md:grid-cols-4">
<div class="text-center md:border-r dark:md:border-slate-500 mb-10 md:mb-0">
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">
132K
</div>
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">132K</div>
<p class="text-sm font-medium tracking-widest text-gray-800 dark:text-slate-400 uppercase lg:text-base">
Downloads
</p>
</div>
<div class="text-center md:border-r dark:md:border-slate-500 mb-10 md:mb-0">
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">
24.8K
</div>
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">24.8K</div>
<p class="text-sm font-medium tracking-widest text-gray-800 dark:text-slate-400 uppercase lg:text-base">
Stars
</p>
</div>
<div class="text-center md:border-r dark:md:border-slate-500 font-heading">
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1]">
10.3K
</div>
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1]">10.3K</div>
<p class="text-sm font-medium tracking-widest text-gray-800 dark:text-slate-400 uppercase lg:text-base">
Forks
</p>
</div>
<div class="text-center">
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">
48.4K
</div>
<div class="text-4xl font-bold lg:text-5xl xl:text-6xl text-[#039de1] font-heading">48.4K</div>
<p class="text-sm font-medium tracking-widest text-gray-800 dark:text-slate-400 uppercase lg:text-base">
Users
</p>

View File

@@ -13,5 +13,4 @@ export interface User {
avatar_url: string
}
export const GlobalStore =
createContext<DocumentationCtx[]>('documentation-site')
export const GlobalStore = createContext<DocumentationCtx[]>('documentation-site')

View File

@@ -1,14 +1,5 @@
import {
component$,
useContextProvider,
useStore,
useStyles$,
} from '@builder.io/qwik'
import {
QwikCityProvider,
RouterOutlet,
ServiceWorkerRegister,
} from '@builder.io/qwik-city'
import { component$, useContextProvider, useStore, useStyles$ } from '@builder.io/qwik'
import { QwikCityProvider, RouterOutlet, ServiceWorkerRegister } from '@builder.io/qwik-city'
import { RouterHead } from '~/components/core/RouterHead'
import { DarkThemeLauncher } from '~/components/core/DarkThemeLauncher'
@@ -78,10 +69,7 @@ export default component$(() => {
<QwikCityProvider>
<head>
<meta charSet="utf-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1"
/>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="manifest" href="/manifest.json" />
<RouterHead />

View File

@@ -4,11 +4,10 @@ import Navigation from '../../../components/widgets/Navigation'
# DataBase (Base de datos)
<Alert>
⚡ Dependiendo del tipo de conector que utlices puede que necesites pasar
algunas configuracion adicional como **user, host, password** para esos
casos te recomendamos guiarte de los
**[starters](https://github.com/codigoencasa/bot-whatsapp/tree/dev/starters/apps)**
o si gustas puedes editar esta documentación para ir agregando más info
⚡ Dependiendo del tipo de conector que utlices puede que necesites pasar algunas configuracion adicional como
**user, host, password** para esos casos te recomendamos guiarte de los
**[starters](https://github.com/codigoencasa/bot-whatsapp/tree/dev/starters/apps)** o si gustas puedes editar esta
documentación para ir agregando más info
</Alert>
Es la pieza encargada de mantener el **"estado"** de una conversación, para mayor facilidad la libreria te proporcia diferentes conectores que se de adapten mejor a tu desarrollo

View File

@@ -22,12 +22,7 @@ Tan sencillo como decir **palabra/s clave** y **mensaje a responder**
Ambos metodos **[addKeyword](https://github.com/codigoencasa/bot-whatsapp/blob/dev/packages/bot/io/methods/addKeyword.js)** y el **[addAnswer](https://github.com/codigoencasa/bot-whatsapp/blob/dev/packages/bot/io/methods/addAnswer.js)** tienen una serie opciones disponibles
```js
const {
createBot,
createProvider,
createFlow,
addKeyword,
} = require('@bot-whatsapp/bot')
const { createBot, createProvider, createFlow, addKeyword } = require('@bot-whatsapp/bot')
const flowPrincipal = addKeyword(['hola', 'alo'])
.addAnswer(['Hola, bienvenido a mi tienda', '¿Como puedo ayudarte?'])
@@ -39,11 +34,10 @@ const flowPrincipal = addKeyword(['hola', 'alo'])
## Provider (Proveedor)
<Alert>
⚡ Dependiendo del tipo de proveedor que utlices puede que necesites pasar
algunas configuracion adicional como **token, api, etc.** para esos casos te
recomendamos guiarte de los
**[starters](https://github.com/codigoencasa/bot-whatsapp/tree/dev/starters/apps)**
o si gustas puedes editar esta documentación para ir agregando más info
⚡ Dependiendo del tipo de proveedor que utlices puede que necesites pasar algunas configuracion adicional como
**token, api, etc.** para esos casos te recomendamos guiarte de los
**[starters](https://github.com/codigoencasa/bot-whatsapp/tree/dev/starters/apps)** o si gustas puedes editar esta
documentación para ir agregando más info
</Alert>
Es la pieza que conectara tu flujo con Whatsapp. En este chatbot tenemos varios proveedores disponibles la mayoria gratis pero tambien tenemos integracion la api oficial de whatsapp o twilio
@@ -71,11 +65,10 @@ Los proveedores disponibles hasta el momento son los siguientes:
## DataBase (Base de datos)
<Alert>
⚡ Dependiendo del tipo de conector que utlices puede que necesites pasar
algunas configuracion adicional como **user, host, password** para esos
casos te recomendamos guiarte de los
**[starters](https://github.com/codigoencasa/bot-whatsapp/tree/dev/starters/apps)**
o si gustas puedes editar esta documentación para ir agregando más info
⚡ Dependiendo del tipo de conector que utlices puede que necesites pasar algunas configuracion adicional como
**user, host, password** para esos casos te recomendamos guiarte de los
**[starters](https://github.com/codigoencasa/bot-whatsapp/tree/dev/starters/apps)** o si gustas puedes editar esta
documentación para ir agregando más info
</Alert>
Es la pieza encargada de mantener el **"estado"** de una conversación, para mayor facilidad la libreria te proporcia diferentes conectores que se de adapten mejor a tu desarrollo

View File

@@ -5,12 +5,7 @@ import Navigation from '../../../components/widgets/Navigation'
Si copias y pegas este codigo y tu entorno de trabajo cumple con todos los requesitos te debe funcionar abajo explico muy por encima
```js
const {
createBot,
createProvider,
createFlow,
addKeyword,
} = require('@bot-whatsapp/bot')
const { createBot, createProvider, createFlow, addKeyword } = require('@bot-whatsapp/bot')
const WebWhatsappProvider = require('@bot-whatsapp/provider/web-whatsapp')
const MockAdapter = require('@bot-whatsapp/database/mock')
@@ -42,12 +37,7 @@ main()
En esta parte solo estamos declaramos las dependencias que vamos a utilizar. Si quieres saber a fondo cada una de las funciones te recomiendo pasarte por la seccion de **[conceptos](/docs/concepts)**
```js
const {
createBot,
createProvider,
createFlow,
addKeyword,
} = require('@bot-whatsapp/bot')
const { createBot, createProvider, createFlow, addKeyword } = require('@bot-whatsapp/bot')
const WebWhatsappProvider = require('@bot-whatsapp/provider/web-whatsapp')
const MockAdapter = require('@bot-whatsapp/database/mock')

View File

@@ -9,12 +9,7 @@ Tan sencillo como decir **palabra/s clave** y **mensaje a responder**
Ambos metodos **[addKeyword](https://github.com/codigoencasa/bot-whatsapp/blob/dev/packages/bot/io/methods/addKeyword.js)** y el **[addAnswer](https://github.com/codigoencasa/bot-whatsapp/blob/dev/packages/bot/io/methods/addAnswer.js)** tienen una serie opciones disponibles
```js
const {
createBot,
createProvider,
createFlow,
addKeyword,
} = require('@bot-whatsapp/bot')
const { createBot, createProvider, createFlow, addKeyword } = require('@bot-whatsapp/bot')
const flowPrincipal = addKeyword(['hola', 'alo'])
.addAnswer(['Hola, bienvenido a mi tienda', '¿Como puedo ayudarte?'])
@@ -81,37 +76,21 @@ Esta funcion se utliza para responder un mensaje despues del `addKeyword()`
```js
const { addKeyword } = require('@bot-whatsapp/bot')
const flowString = addKeyword('hola').addAnswer(
'Este mensaje se enviara 1 segundo despues',
{
delay: 1000,
}
)
const flowString = addKeyword('hola').addAnswer('Este mensaje se enviara 1 segundo despues', {
delay: 1000,
})
const flowString = addKeyword('hola').addAnswer(
'Este mensaje envia una imagen',
{
media: 'https://i.imgur.com/0HpzsEm.png',
}
)
const flowString = addKeyword('hola').addAnswer('Este mensaje envia una imagen', {
media: 'https://i.imgur.com/0HpzsEm.png',
})
const flowString = addKeyword('hola').addAnswer(
'Este mensaje envia tres botones',
{
buttons: [
{ body: 'Boton 1' },
{ body: 'Boton 2' },
{ body: 'Boton 3' },
],
}
)
const flowString = addKeyword('hola').addAnswer('Este mensaje envia tres botones', {
buttons: [{ body: 'Boton 1' }, { body: 'Boton 2' }, { body: 'Boton 3' }],
})
const flowString = addKeyword('hola').addAnswer(
'Este mensaje espera una respueta del usuario',
{
capture: true,
}
)
const flowString = addKeyword('hola').addAnswer('Este mensaje espera una respueta del usuario', {
capture: true,
})
```
---
@@ -123,13 +102,9 @@ Este argumento se utiliza para obtener el contexto de la conversación
```js
const { addKeyword } = require('@bot-whatsapp/bot')
const flowString = addKeyword('hola').addAnswer(
'Indica cual es tu email',
null,
(ctx) => {
console.log('👉 Informacion del contexto: ', ctx)
}
)
const flowString = addKeyword('hola').addAnswer('Indica cual es tu email', null, (ctx) => {
console.log('👉 Informacion del contexto: ', ctx)
})
```
---
@@ -143,13 +118,9 @@ se repetira el mensaje `Indica cual es tu email`
```js
const { addKeyword } = require('@bot-whatsapp/bot')
const flowString = addKeyword('hola').addAnswer(
'Indica cual es tu email',
null,
(ctx, { fallBack }) => {
if (!ctx.body.includes('@')) return fallBack()
}
)
const flowString = addKeyword('hola').addAnswer('Indica cual es tu email', null, (ctx, { fallBack }) => {
if (!ctx.body.includes('@')) return fallBack()
})
```
---

View File

@@ -4,10 +4,9 @@ import Navigation from '../../components/widgets/Navigation'
# Introducción
<Alert>
**Atención** estás leyendo la documentación de la **versión v2** de esta
librería, si vienes de la versión anterior te recomendamos pasarte por la
sección de **[migración](/docs/migration/)** para que puedas disfrutar de
las nuevas características.
**Atención** estás leyendo la documentación de la **versión v2** de esta librería, si vienes de la versión anterior
te recomendamos pasarte por la sección de **[migración](/docs/migration/)** para que puedas disfrutar de las nuevas
características.
</Alert>
## ¿Qué es esto?
@@ -34,10 +33,7 @@ npm create bot-whatsapp@latest
muted
playsinline
>
<source
src="https://leifer-landing-page.s3.us-east-2.amazonaws.com/console.webm"
type="video/webm"
/>
<source src="https://leifer-landing-page.s3.us-east-2.amazonaws.com/console.webm" type="video/webm" />
</video>
</div>

View File

@@ -28,10 +28,7 @@ El **CLI** te hace una revisión previa, de versión de Node y sistema operativo
muted
playsinline
>
<source
src="https://leifer-landing-page.s3.us-east-2.amazonaws.com/console.webm"
type="video/webm"
/>
<source src="https://leifer-landing-page.s3.us-east-2.amazonaws.com/console.webm" type="video/webm" />
</video>
</div>
@@ -54,10 +51,8 @@ Cada plantilla tiene sus dependencias necesarias basadas en tu previa selección
```
<Alert>
📄 Si deseas cambiar tu **proveedor o tu motor** de base de datos no es
necesario volver ejecutar el CLI (lo puedes hacer sin problema) aunque
tambien basta con solo modificar un par de lineas. [Ver
explicación](/docs/essential)
📄 Si deseas cambiar tu **proveedor o tu motor** de base de datos no es necesario volver ejecutar el CLI (lo puedes
hacer sin problema) aunque tambien basta con solo modificar un par de lineas. [Ver explicación](/docs/essential)
</Alert>
---

View File

@@ -27,11 +27,7 @@ export default component$(() => {
<NavBar options={store} />
</div>
<div class={'lg:pl-[14.5rem] lg:pr-[14.5rem]'}>
<div
class={
'slot max-w-3xl mx-auto relative z-20 p-5 xl:max-w-none'
}
>
<div class={'slot max-w-3xl mx-auto relative z-20 p-5 xl:max-w-none'}>
<Slot />
</div>
</div>
@@ -54,8 +50,7 @@ export const head: DocumentHead = {
meta: [
{
name: 'description',
content:
'Crear chatbot WhatsApp en minutos — Servicio de chatbot para whatspp gratis proyecto OpenSource',
content: 'Crear chatbot WhatsApp en minutos — Servicio de chatbot para whatspp gratis proyecto OpenSource',
},
],
}

View File

@@ -49,11 +49,7 @@ En la **_versión (legacy)_** se implementas los flujos de esta manera, en dos a
"title": "¿Que te interesa ver?",
"message": "Abajo unos botons",
"footer": "",
"buttons": [
{ "body": "Telefonos" },
{ "body": "Computadoras" },
{ "body": "Otros" }
]
"buttons": [{ "body": "Telefonos" }, { "body": "Computadoras" }, { "body": "Otros" }]
}
},
"catalogo": {
@@ -70,51 +66,28 @@ En esta versión es mucho más sencillo, abajo encontrarás un ejemplo del mismo
```js
//app.js
const {
createBot,
createProvider,
createFlow,
addKeyword,
addChild,
} = require('@bot-whatsapp/bot')
const { createBot, createProvider, createFlow, addKeyword, addChild } = require('@bot-whatsapp/bot')
const BaileysProvider = require('@bot-whatsapp/provider/baileys') //Provider
const MockAdapter = require('@bot-whatsapp/database/mock') //Base de datos
/**
* Declarando flujos principales.
*/
const flowHola = addKeyword(['hola', 'ola', 'alo']).addAnswer(
'Bienvenido a tu tienda online!'
)
const flowHola = addKeyword(['hola', 'ola', 'alo']).addAnswer('Bienvenido a tu tienda online!')
const flowAdios = addKeyword(['adios', 'bye'])
.addAnswer('Que te vaya bien!!')
.addAnswer('Hasta luego!')
const flowAdios = addKeyword(['adios', 'bye']).addAnswer('Que te vaya bien!!').addAnswer('Hasta luego!')
const flowProductos = addKeyword(['productos', 'info']).addAnswer(
'Te envio una imagen',
{
buttons: [
{ body: 'Telefonos' },
{ body: 'Computadoras' },
{ body: 'Otros' },
],
}
)
const flowProductos = addKeyword(['productos', 'info']).addAnswer('Te envio una imagen', {
buttons: [{ body: 'Telefonos' }, { body: 'Computadoras' }, { body: 'Otros' }],
})
const flowCatalogo = addKeyword(['imagen', 'foto']).addAnswer(
'Te envio una imagen',
{ media: 'https://media2.giphy.com/media/VQJu0IeULuAmCwf5SL/giphy.gif' }
)
const flowCatalogo = addKeyword(['imagen', 'foto']).addAnswer('Te envio una imagen', {
media: 'https://media2.giphy.com/media/VQJu0IeULuAmCwf5SL/giphy.gif',
})
const main = async () => {
const adapterDB = new MockAdapter()
const adapterFlow = createFlow([
flowHola,
flowAdios,
flowProductos,
flowCatalogo,
]) //Se crean los flujos.
const adapterFlow = createFlow([flowHola, flowAdios, flowProductos, flowCatalogo]) //Se crean los flujos.
const adapterProvider = createProvider(BaileysProvider)
createBot({
flow: adapterFlow,

View File

@@ -49,17 +49,15 @@ Qwik is a new kind of web framework that can deliver instant loading web applica
<div class="card">
<h3>Instant-on</h3>
<p>
Unlike other frameworks, Qwik is resumable which means Qwik
applications require 0 hydration. This allows Qwik apps to have
instant-on interactivity, regardless of size or complexity
Unlike other frameworks, Qwik is resumable which means Qwik applications require 0 hydration. This allows
Qwik apps to have instant-on interactivity, regardless of size or complexity
</p>
</div>
<div class="card">
<h3>Optimized for speed</h3>
<p>
Qwik has unprecedented performance, offering sub-second full page
loads even on mobile devices. Qwik achieves this by delivering pure
HTML, and incrementally loading JS only as-needed.
Qwik has unprecedented performance, offering sub-second full page loads even on mobile devices. Qwik
achieves this by delivering pure HTML, and incrementally loading JS only as-needed.
</p>
</div>
</div>

View File

@@ -4,11 +4,10 @@ import Navigation from '../../../components/widgets/Navigation'
# Proveedores
<Alert>
⚡ Dependiendo del tipo de proveedor que utlices puede que necesites pasar
algunas configuracion adicional como **token, api, etc.** para esos casos te
recomendamos guiarte de los
**[starters](https://github.com/codigoencasa/bot-whatsapp/tree/dev/starters/apps)**
o si gustas puedes editar esta documentación para ir agregando más info
⚡ Dependiendo del tipo de proveedor que utlices puede que necesites pasar algunas configuracion adicional como
**token, api, etc.** para esos casos te recomendamos guiarte de los
**[starters](https://github.com/codigoencasa/bot-whatsapp/tree/dev/starters/apps)** o si gustas puedes editar esta
documentación para ir agregando más info
</Alert>
Es la pieza que conectara tu flujo con Whatsapp. En este chatbot tenemos varios proveedores disponibles la mayoria gratis pero tambien tenemos integracion la api oficial de whatsapp o twilio

View File

@@ -59,10 +59,7 @@ En el **archivo principal** del bot donde estás implementando la función del a
- **jwtToken:** Lo puedes encontrar en la pagina anterior
- **verifyToken:** Puedes escribir lo que quieras es como una palabra clave
<Alert>
En el ejemplo de abajo puedes ver como una sugerencia de como puede ser
utilizando variables de entorno
</Alert>
<Alert>En el ejemplo de abajo puedes ver como una sugerencia de como puede ser utilizando variables de entorno</Alert>
```js
const main = async () => {

View File

@@ -5,10 +5,7 @@ import Navigation from '../../../../components/widgets/Navigation'
Twilio es una plataforma de desarrollo que permite a los desarrolladores construir aplicaciones de comunicación en la nube y sistemas web. Las API de comunicaciones de Twilio permiten a las empresas proporcionar la experiencia de comunicación adecuada para sus clientes dentro de la web y las aplicaciones móviles. Al usar las API de Twilio, los desarrolladores pueden agregar rápidamente esta funcionalidad a una aplicación, como mensajes de voz, videollamadas, mensajes de texto y más.
<Alert>
Twilio te proporciona una cuenta **Sandbox** para que puedas probar
gratuitamente el servicio
</Alert>
<Alert>Twilio te proporciona una cuenta **Sandbox** para que puedas probar gratuitamente el servicio</Alert>
### Requerimientos
@@ -66,10 +63,7 @@ En el **archivo principal** del bot donde estás implementando la función del a
- **ACC_VENDOR:** Es el numero de whatsapp (si ya tienes el plan de pago de Twilio usa el numero que compraste), si aun estas en modo
sandbox utliza el numero proporcionado en el paso numero 2
<Alert>
En el ejemplo de abajo puedes ver como una sugerencia de como puede ser
utilizando variables de entorno
</Alert>
<Alert>En el ejemplo de abajo puedes ver como una sugerencia de como puede ser utilizando variables de entorno</Alert>
```js
const main = async () => {

View File

@@ -13,8 +13,7 @@ import { GITHUB_TOKEN } from './docs/constant'
// import { SearchModal } from '~/components/widgets/SearchModal'
export const onGet: RequestHandlerNetlify = async ({ platform }) => {
const CHECK_GITHUB_TOKEN =
(platform as any)?.['GITHUB_TOKEN'] ?? GITHUB_TOKEN
const CHECK_GITHUB_TOKEN = (platform as any)?.['GITHUB_TOKEN'] ?? GITHUB_TOKEN
const dataGithub = await fetchGithub(CHECK_GITHUB_TOKEN)
const dataOpenCollective = await fetchOpenCollective()
return {
@@ -52,8 +51,7 @@ export const head: DocumentHead = {
meta: [
{
name: 'description',
content:
'Crear chatbot WhatsApp en minutos — Servicio de chatbot para whatspp gratis proyecto OpenSource',
content: 'Crear chatbot WhatsApp en minutos — Servicio de chatbot para whatspp gratis proyecto OpenSource',
},
],
}

View File

@@ -3,17 +3,14 @@
* @returns
*/
export const fetchGithub = async (token: string) => {
const data = await fetch(
`https://api.github.com/repos/codigoencasa/bot-whatsapp/contributors`,
{
method: 'GET',
headers: {
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
},
}
)
const data = await fetch(`https://api.github.com/repos/codigoencasa/bot-whatsapp/contributors`, {
method: 'GET',
headers: {
Accept: 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28',
Authorization: `Bearer ${token}`,
},
})
const listUsers = await data.json()
return listUsers.map((u: any) => ({
...u,

View File

@@ -3,12 +3,9 @@
* @returns
*/
export const fetchOpenCollective = async () => {
const data = await fetch(
`https://opencollective.com/bot-whatsapp/members/users.json?limit=22&offset=0`,
{
method: 'GET',
}
)
const data = await fetch(`https://opencollective.com/bot-whatsapp/members/users.json?limit=22&offset=0`, {
method: 'GET',
})
const listUsers = await data.json()
return listUsers.map((u: any) => ({
html_url: u.profile,

View File

@@ -76,9 +76,7 @@ module.exports = {
a: {
fontWeight: theme('fontWeight.semibold'),
textDecoration: 'none',
borderBottom: `1px solid ${theme(
'colors.sky.300'
)}`,
borderBottom: `1px solid ${theme('colors.sky.300')}`,
},
'a:hover': {
borderBottomWidth: '2px',

View File

@@ -3,11 +3,7 @@
"scope": "javascriptreact,typescriptreact",
"prefix": "q:onGet",
"description": "onGet function for a route index",
"body": [
"export const onGet: RequestHandler = (request) => {",
" $0",
"};"
]
"body": ["export const onGet: RequestHandler = (request) => {", " $0", "};"]
},
"onGet (typed)": {
"scope": "javascriptreact,typescriptreact",

View File

@@ -56,24 +56,13 @@
"scope": "javascriptreact,typescriptreact",
"prefix": "q:useTask",
"description": "useTask$() function hook",
"body": [
"useTask$(({ track }) => {",
" track(() => $1);",
" $0",
"});",
""
]
"body": ["useTask$(({ track }) => {", " track(() => $1);", " $0", "});", ""]
},
"useResource": {
"scope": "javascriptreact,typescriptreact",
"prefix": "q:useResource",
"description": "useResource$() declaration",
"body": [
"const $1 = useResource$(({ track, cleanup }) => {",
" $0",
"});",
""
]
"body": ["const $1 = useResource$(({ track, cleanup }) => {", " $0", "});", ""]
},
"useServerMount": {
"scope": "javascriptreact,typescriptreact",

View File

@@ -5,14 +5,9 @@ const polka = require('polka')
const HTTP_PORT = process.env.PORT || 3000
const QR_FILE = process.env.QR_FILE ?? 'bot'
const PUBLIC_URL =
process.env.PUBLIC_URL ??
process.env.RAILWAY_STATIC_URL ??
'http://localhost'
const PUBLIC_URL = process.env.PUBLIC_URL ?? process.env.RAILWAY_STATIC_URL ?? 'http://localhost'
const dir = [join(__dirname, 'dist'), join(__dirname, '..', 'dist')].find((i) =>
existsSync(i)
)
const dir = [join(__dirname, 'dist'), join(__dirname, '..', 'dist')].find((i) => existsSync(i))
const serve = require('serve-static')(dir)
/**
@@ -32,14 +27,8 @@ const start = (args) => {
console.log(``)
console.log(bgYellow(`🚩 ESCANEAR QR 🚩`))
console.log(cyan(`Existen varias maneras de escanear el QR code`))
console.log(
cyan(`- Tambien puedes visitar `),
yellow(`${publicSite}:${port}`)
)
console.log(
cyan(`- Se ha creado un archivo que finaliza `),
yellow('qr.png')
)
console.log(cyan(`- Tambien puedes visitar `), yellow(`${publicSite}:${port}`))
console.log(cyan(`- Se ha creado un archivo que finaliza `), yellow('qr.png'))
console.log(``)
}

View File

@@ -8,28 +8,18 @@ export default component$(() => {
return (
<header>
<div class="logo">
<a
href="https://github.com/codigoencasa/bot-whatsapp"
target="_blank"
title="qwik"
>
<a href="https://github.com/codigoencasa/bot-whatsapp" target="_blank" title="qwik">
<BotLogo />
</a>
</div>
<ul>
<li>
<a
href="https://github.com/codigoencasa/bot-whatsapp"
target="_blank"
>
<a href="https://github.com/codigoencasa/bot-whatsapp" target="_blank">
Docs
</a>
</li>
<li>
<a
href="https://github.com/codigoencasa/bot-whatsapp/tree/main/starters/apps"
target="_blank"
>
<a href="https://github.com/codigoencasa/bot-whatsapp/tree/main/starters/apps" target="_blank">
Examples
</a>
</li>

View File

@@ -1,11 +1,5 @@
export const QwikLogo = () => (
<svg
width="100"
height="35"
viewBox="0 0 167 53"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<svg width="100" height="35" viewBox="0 0 167 53" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M81.9545 46.5859H75.5513V35.4045C73.4363 36.8579 71.0496 37.5749 68.4884 37.5749C65.0151 37.5749 62.4344 36.6253 60.8239 34.6487C59.2134 32.6915 58.3984 29.2034 58.3984 24.2231C58.3984 19.1266 59.3492 15.5997 61.2702 13.5456C63.23 11.4721 66.3734 10.4644 70.7004 10.4644C74.7946 10.4644 78.5201 11.0264 81.9545 12.131V46.5859ZM75.5513 16.278C74.096 15.8323 72.4661 15.6191 70.7004 15.6191C68.5272 15.6191 66.9749 16.1811 66.1017 17.3244C65.2479 18.4871 64.7823 20.6962 64.7823 23.9712C64.7823 27.0524 65.1897 29.1065 66.0435 30.2304C66.8973 31.335 68.3719 31.897 70.5452 31.897C73.3781 31.897 75.5513 30.7343 75.5513 29.2809V16.278Z"
fill="black"

View File

@@ -1,9 +1,4 @@
import {
component$,
useClientEffect$,
useStore,
useStylesScoped$,
} from '@builder.io/qwik'
import { component$, useClientEffect$, useStore, useStylesScoped$ } from '@builder.io/qwik'
import style from './qr.css?inline'
export const QR = component$(() => {
@@ -20,12 +15,7 @@ export const QR = component$(() => {
return (
<div>
<img
width={350}
height={350}
src={'qr.png?time=' + state.count}
alt="QR"
/>
<img width={350} height={350} src={'qr.png?time=' + state.count} alt="QR" />
</div>
)
})

View File

@@ -10,10 +10,7 @@ export const RouterHead = component$(() => {
<title>{head.title}</title>
<link rel="canonical" href={loc.href} />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
{head.meta.map((m) => (

View File

@@ -15,8 +15,7 @@
body {
background-color: #fafafa;
font-family: 'Inter', sans-serif, ui-sans-serif, system-ui, -apple-system,
BlinkMacSystemFont, sans-serif;
font-family: 'Inter', sans-serif, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
padding: 20px 20px 40px 20px;
}

View File

@@ -12,8 +12,7 @@
.page .btn-link {
background: white;
box-shadow: rgb(0 0 0 / 16%) 0px 10px 36px 0px,
rgb(0 0 0 / 6%) 0px 0px 0px 1px;
box-shadow: rgb(0 0 0 / 16%) 0px 10px 36px 0px, rgb(0 0 0 / 6%) 0px 0px 0px 1px;
padding: 10px;
border-radius: 5px;
font-weight: 600;

View File

@@ -15,19 +15,13 @@ export default component$(() => {
<div class={'qr-section intructions'}>
<h1>Whatsapp QR</h1>
<p>
Con esta libreria, puedes configurar respuestas
automatizadas para preguntas frecuentes, recibir y responder
mensajes de manera automatizada, y hacer un seguimiento de
las interacciones con los clientes. <br /> Además, nuestro
Chatbot se integra fácilmente con otros sistemas y
herramientas que ya esté utilizando en su negocio.
Con esta libreria, puedes configurar respuestas automatizadas para preguntas frecuentes, recibir y
responder mensajes de manera automatizada, y hacer un seguimiento de las interacciones con los
clientes. <br /> Además, nuestro Chatbot se integra fácilmente con otros sistemas y herramientas que
ya esté utilizando en su negocio.
</p>
<div class={'qr-section links'}>
<a
class={'btn-link '}
target="_blank"
href="https://bot-whatsapp.netlify.app/"
>
<a class={'btn-link '} target="_blank" href="https://bot-whatsapp.netlify.app/">
Ver documentación
</a>
<a
@@ -37,11 +31,7 @@ export default component$(() => {
>
Ver videos
</a>
<a
class={'btn-link '}
target="_blank"
href="https://opencollective.com/bot-whatsapp"
>
<a class={'btn-link '} target="_blank" href="https://opencollective.com/bot-whatsapp">
Comprar café
</a>
</div>

View File

@@ -56,15 +56,11 @@ class MetaProvider extends ProviderClass {
sendMessageMeta = async (body) => {
try {
const response = await axios.post(
`${URL}/${this.numberId}/messages`,
body,
{
headers: {
Authorization: `Bearer ${this.jwtToken}`,
},
}
)
const response = await axios.post(`${URL}/${this.numberId}/messages`, body, {
headers: {
Authorization: `Bearer ${this.jwtToken}`,
},
})
return response.data
} catch (error) {
return Promise.resolve(error)
@@ -106,8 +102,7 @@ class MetaProvider extends ProviderClass {
*/
sendMessage = async (number, message, { options }) => {
if (options?.buttons?.length) return console.log('Envio de botones')
if (options?.media)
return this.sendMedia(number, message, options.media)
if (options?.media) return this.sendMedia(number, message, options.media)
this.sendtext(number, message)
}

View File

@@ -81,9 +81,7 @@ class MetaWebHookServer extends EventEmitter {
* @returns
*/
buildHTTPServer = () => {
this.metaServer
.use(urlencoded({ extended: true }))
.get('/webhook', this.verifyToken)
this.metaServer.use(urlencoded({ extended: true })).get('/webhook', this.verifyToken)
this.metaServer
.use(urlencoded({ extended: true }))
@@ -99,9 +97,7 @@ class MetaWebHookServer extends EventEmitter {
this.metaServer.listen(this.metaPort, () => {
console.log(``)
console.log(`[meta]: Agregar esta url "WHEN A MESSAGE COMES IN"`)
console.log(
`[meta]: POST http://localhost:${this.metaPort}/webhook`
)
console.log(`[meta]: POST http://localhost:${this.metaPort}/webhook`)
console.log(`[meta]: Más información en la documentacion`)
console.log(``)
})

View File

@@ -86,12 +86,8 @@ class TwilioProvider extends ProviderClass {
*/
sendButtons = async () => {
console.log(``)
console.log(
`[NOTA]: Actualmente enviar botons con Twilio esta en desarrollo`
)
console.log(
`[NOTA]: https://www.twilio.com/es-mx/docs/whatsapp/buttons`
)
console.log(`[NOTA]: Actualmente enviar botons con Twilio esta en desarrollo`)
console.log(`[NOTA]: https://www.twilio.com/es-mx/docs/whatsapp/buttons`)
console.log(``)
}
@@ -104,10 +100,8 @@ class TwilioProvider extends ProviderClass {
*/
sendMessage = async (number, message, { options }) => {
number = parseNumber(number)
if (options?.buttons?.length)
this.sendButtons(number, message, options.buttons)
if (options?.media)
return this.sendMedia(number, message, options.media)
if (options?.buttons?.length) this.sendButtons(number, message, options.buttons)
if (options?.media) return this.sendMedia(number, message, options.media)
return this.vendor.messages.create({
body: message,
from: `whatsapp:+${this.vendorNumber}`,

View File

@@ -51,9 +51,7 @@ class TwilioWebHookServer extends EventEmitter {
this.twilioServer.listen(this.twilioPort, () => {
console.log(``)
console.log(`[Twilio]: Agregar esta url "WHEN A MESSAGE COMES IN"`)
console.log(
`[Twilio]: POST http://localhost:${this.twilioPort}/twilio-hook`
)
console.log(`[Twilio]: POST http://localhost:${this.twilioPort}/twilio-hook`)
console.log(`[Twilio]: Más información en la documentacion`)
console.log(``)
})

View File

@@ -4,11 +4,7 @@ const { createWriteStream } = require('fs')
const { Console } = require('console')
const mime = require('mime-types')
const {
venomCleanNumber,
venomGenerateImage,
venomisValidNumber,
} = require('./utils')
const { venomCleanNumber, venomGenerateImage, venomisValidNumber } = require('./utils')
const logger = new Console({
stdout: createWriteStream(`${process.cwd()}/venom.log`),
@@ -108,8 +104,7 @@ class VenomProvider extends ProviderClass {
const listEvents = this.busEvents()
for (const { event, func } of listEvents) {
if (this.vendor[event])
this.vendor[event]((payload) => func(payload))
if (this.vendor[event]) this.vendor[event]((payload) => func(payload))
}
}
@@ -122,16 +117,13 @@ class VenomProvider extends ProviderClass {
* @returns
*/
sendButtons = async (number, message, buttons = []) => {
const NOTE_VENOM_BUTTON = [
`Actualmente VENOM tiene problemas con la API`,
`para el envio de Botones`,
].join('\n')
const NOTE_VENOM_BUTTON = [`Actualmente VENOM tiene problemas con la API`, `para el envio de Botones`].join(
'\n'
)
console.log(`[NOTA]: ${NOTE_VENOM_BUTTON}`)
const buttonToStr = [message]
.concat(buttons.map((btn) => `${btn.body}`))
.join(`\n`)
const buttonToStr = [message].concat(buttons.map((btn) => `${btn.body}`)).join(`\n`)
return this.vendor.sendText(number, buttonToStr)
// return this.vendor.sendButtons(number, "Title", buttons1, "Description");
}
@@ -194,12 +186,9 @@ class VenomProvider extends ProviderClass {
const fileDownloaded = await generalDownload(mediaUrl)
const mimeType = mime.lookup(fileDownloaded)
if (mimeType.includes('image'))
return this.sendImage(number, fileDownloaded, text)
if (mimeType.includes('video'))
return this.sendVideo(number, fileDownloaded, text)
if (mimeType.includes('audio'))
return this.sendAudio(number, fileDownloaded)
if (mimeType.includes('image')) return this.sendImage(number, fileDownloaded, text)
if (mimeType.includes('video')) return this.sendVideo(number, fileDownloaded, text)
if (mimeType.includes('audio')) return this.sendAudio(number, fileDownloaded)
return this.sendFile(number, fileDownloaded, text)
}
@@ -213,10 +202,8 @@ class VenomProvider extends ProviderClass {
*/
sendMessage = async (userId, message, { options }) => {
const number = venomCleanNumber(userId)
if (options?.buttons?.length)
return this.sendButtons(number, message, options.buttons)
if (options?.media)
return this.sendMedia(number, options.media, message)
if (options?.buttons?.length) return this.sendButtons(number, message, options.buttons)
if (options?.media) return this.sendMedia(number, options.media, message)
return this.vendor.sendText(number, message)
}
}