Skip to content

Commit

Permalink
Merge pull request #77 from nathsouzadev/add-social-bank
Browse files Browse the repository at this point in the history
[feat]add reply buttons
  • Loading branch information
nathsouzadev authored Jul 23, 2024
2 parents 2ed021e + eed77df commit 862d682
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 87 deletions.
1 change: 1 addition & 0 deletions .github/workflows/main.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ env:
BSKY_PASSWORD: 'BSKY_PASSWORD'
CLERK_WEBHOOK_SECRET: 'CLERK_WEBHOOK_SECRET'
WB_PHONE_NUMBER: '5521880881234'
BANK_URL: 'https://bank.com'

jobs:
lint:
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/prod.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ env:
BSKY_PASSWORD: 'BSKY_PASSWORD'
CLERK_WEBHOOK_SECRET: 'CLERK_WEBHOOK_SECRET'
WB_PHONE_NUMBER: '5521880881234'
BANK_URL: 'https://bank.com'

jobs:
lint:
Expand Down
144 changes: 115 additions & 29 deletions src/bank/bank.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Test, TestingModule } from '@nestjs/testing';
import { BankService } from './bank.service';
import { SocialService } from '../social/services/social.service';
import { CONTENT_BODY } from './constants/content';

describe('BankService', () => {
let service: BankService;
Expand Down Expand Up @@ -33,44 +34,129 @@ describe('BankService', () => {
const mockData = {
from: mockFrom,
phoneNumberId: mockPhoneNumberId,
contentReply: {
body: '/bank',
},
};

await service.handle(mockData);
expect(mockSocialService.replyToWhatsapp).toHaveBeenCalledWith({
...mockData,
message: '🤗 Bem vinda ao Social Bank!',
service: 'bank',
content: {
type: 'interactive',
recipient_type: 'individual',
interactive: {
type: 'button',
body: {
text: '🤗 Bem vinda ao Social Bank!',
},
footer: {
text: 'Social Bank é uma demo. Desenvolvido por @nathsouzadev',
},
action: {
buttons: [
{
type: 'reply',
reply: {
title: 'Ver saldo',
id: 'balance',
},
},
{
type: 'reply',
reply: {
title: 'Ver extrato',
id: 'extract',
},
},
],
},
content: CONTENT_BODY.WELLCOME,
});
});

it('should be reply with balance account', async () => {
jest
.spyOn(mockSocialService, 'replyToWhatsapp')
.mockImplementation(() => Promise.resolve(void 0));

const mockFrom = '5511444412345';
const mockPhoneNumberId = '5511432112345';
const mockData = {
from: mockFrom,
phoneNumberId: mockPhoneNumberId,
contentReply: {
type: 'button_reply',
button_reply: {
id: 'balance',
title: 'Ver saldo',
},
},
};

await service.handle(mockData);
expect(mockSocialService.replyToWhatsapp).toHaveBeenCalledWith({
...mockData,
message: 'Seu saldo é de R$ 1000,00',
service: 'bank',
content: CONTENT_BODY.BALANCE,
});
});

it('should be reply with purchase options', async () => {
jest
.spyOn(mockSocialService, 'replyToWhatsapp')
.mockImplementation(() => Promise.resolve(void 0));

const mockFrom = '5511444412345';
const mockPhoneNumberId = '5511432112345';
const mockData = {
from: mockFrom,
phoneNumberId: mockPhoneNumberId,
contentReply: {
type: 'button_reply',
button_reply: {
id: 'purchase',
title: 'Fazer uma compra',
},
},
};

await service.handle(mockData);
expect(mockSocialService.replyToWhatsapp).toHaveBeenCalledWith({
...mockData,
message: 'Escolha um item que deseja comprar',
service: 'bank',
content: CONTENT_BODY.PURCHASE,
});
});

it('should be reply with completed options', async () => {
jest
.spyOn(mockSocialService, 'replyToWhatsapp')
.mockImplementation(() => Promise.resolve(void 0));

const mockFrom = '5511444412345';
const mockPhoneNumberId = '5511432112345';
const mockData = {
from: mockFrom,
phoneNumberId: mockPhoneNumberId,
contentReply: {
type: 'button_reply',
button_reply: {
id: 'completed',
title: '🖥️ Monitor R$ 500.00',
},
},
};

await service.handle(mockData);
expect(mockSocialService.replyToWhatsapp).toHaveBeenCalledWith({
...mockData,
message: 'Compra realizada com sucesso',
service: 'bank',
content: CONTENT_BODY.PURCHASE_COMPLETED,
});
});

it('should be reply with refused options', async () => {
jest
.spyOn(mockSocialService, 'replyToWhatsapp')
.mockImplementation(() => Promise.resolve(void 0));

const mockFrom = '5511444412345';
const mockPhoneNumberId = '5511432112345';
const mockData = {
from: mockFrom,
phoneNumberId: mockPhoneNumberId,
contentReply: {
type: 'button_reply',
button_reply: {
id: 'refused',
title: '💻 PC R$ 2000.00',
},
},
};

await service.handle(mockData);
expect(mockSocialService.replyToWhatsapp).toHaveBeenCalledWith({
...mockData,
message: 'Compra recusada',
service: 'bank',
content: CONTENT_BODY.PURCHASE_REFUSED,
});
});
});
76 changes: 43 additions & 33 deletions src/bank/bank.service.ts
Original file line number Diff line number Diff line change
@@ -1,46 +1,56 @@
import { Injectable } from '@nestjs/common';
import { SocialService } from '../social/services/social.service';
import { BankMessageModel } from './model/message.model';
import { CONTENT_BODY } from './constants/content';

@Injectable()
export class BankService {
constructor(private readonly socialService: SocialService) {}

handle = async (data: BankMessageModel) =>
this.socialService.replyToWhatsapp({
handle = async (data: BankMessageModel) => {
if (Object.keys(data.contentReply).includes('button_reply')) {
const content = (() => {
switch (data.contentReply['button_reply'].id) {
case 'balance':
return {
message: `Seu saldo é de R$ 1000,00`,
content: CONTENT_BODY.BALANCE,
};
case 'purchase': {
return {
message: 'Escolha um item que deseja comprar',
content: CONTENT_BODY.PURCHASE,
};
}
case 'completed': {
return {
message: 'Compra realizada com sucesso',
content: CONTENT_BODY.PURCHASE_COMPLETED,
};
}
case 'refused': {
return {
message: 'Compra recusada',
content: CONTENT_BODY.PURCHASE_REFUSED,
};
}
}
})();

return this.socialService.replyToWhatsapp({
...data,
service: 'bank',
...content,
});
}

return this.socialService.replyToWhatsapp({
...data,
message: '🤗 Bem vinda ao Social Bank!',
service: 'bank',
content: {
type: 'interactive',
recipient_type: 'individual',
interactive: {
type: 'button',
body: {
text: '🤗 Bem vinda ao Social Bank!',
},
footer: {
text: 'Social Bank é uma demo. Desenvolvido por @nathsouzadev',
},
action: {
buttons: [
{
type: 'reply',
reply: {
title: 'Ver saldo',
id: 'balance',
},
},
{
type: 'reply',
reply: {
title: 'Ver extrato',
id: 'extract',
},
},
],
},
},
},
content: CONTENT_BODY.WELLCOME,
});
};

balance = () => 1000;
}
87 changes: 87 additions & 0 deletions src/bank/constants/content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { ButtonData } from 'src/social/model/whats-message.model';

const content = (data: {
type: string;
text: string;
buttons?: ButtonData[];
}) => {
const { type, text, buttons } = data;

return {
type,
recipient_type: 'individual',
interactive: {
type: 'button',
body: {
text: `${text} \nEscolha uma opção abaixo:`,
},
footer: {
text: 'Social Bank é uma demo. Desenvolvido por @nathsouzadev',
},
action: {
buttons: buttons ?? [
{
type: 'reply',
reply: {
title: 'Ver saldo',
id: 'balance',
},
},
{
type: 'reply',
reply: {
title: 'Fazer uma compra',
id: 'purchase',
},
},
],
},
},
};
};

export const CONTENT_BODY = {
WELLCOME: content({
type: 'interactive',
text: '🤗 Bem vinda ao Social Bank!',
}),
BALANCE: content({
type: 'interactive',
text: '💰💵 Seu saldo é de R$ 1000,00',
}),
PURCHASE: content({
type: 'interactive',
text: '🛒🛍️ O que deseja comprar?',
buttons: [
{
type: 'reply',
reply: {
title: '💻 PC R$ 2000.00',
id: 'refused',
},
},
{
type: 'reply',
reply: {
title: '🖥️ Monitor R$ 500.00',
id: 'completed',
},
},
{
type: 'reply',
reply: {
title: '🖲️ Mouse R$ 100.00',
id: 'completed',
},
},
],
}),
PURCHASE_COMPLETED: content({
type: 'interactive',
text: '🎉🎊 Compra realizada com sucesso!',
}),
PURCHASE_REFUSED: content({
type: 'interactive',
text: '❌🛒 Compra recusada!',
}),
};
20 changes: 16 additions & 4 deletions src/bank/model/message.model.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
interface TextContent {
body: string;
}

interface QuickReplyContent {
type: string;
button_reply: {
title: string;
id: string;
};
}

export interface BankMessageModel {
from: string;
phoneNumberId: string;
}
from: string;
phoneNumberId: string;
contentReply: TextContent | QuickReplyContent;
}
5 changes: 4 additions & 1 deletion src/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,8 @@ export default (): IConfig => ({
},
clerk: {
webhookSecret: process.env.CLERK_WEBHOOK_SECRET,
}
},
bank: {
url: process.env.BANK_URL,
},
});
3 changes: 3 additions & 0 deletions src/config/interface/bank.interface copy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface IBank {
url: string;
}
Loading

0 comments on commit 862d682

Please sign in to comment.