instagram_basic,{' '}
+ instagram_manage_messages
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ {h2({ children: 'Passo 2: Obter Token de Acesso' })}
+ {p({
+ children: (
+ <>
+ No{' '}
+
+ Meta for Developers
+
+ , crie um app e obtenha um token de acesso com as permissões
+ necessárias para gerenciar mensagens do Instagram.
+ >
+ )
+ })}
+
+ {h2({ children: 'Passo 3: Configurar Webhook' })}
+ {p({
+ children: (
+ <>
+ Configure um webhook para receber notificações de mensagens diretas:
+ >
+ )
+ })}
+
+ {pre({
+ children: `# URL do Webhook
+https://seu-servidor.com/webhook/instagram
+
+# Assine o evento: messages
+# Receberá notificações quando usuários enviarem DMs
+
+# Exemplo de payload recebido:
+{
+ "object": "instagram",
+ "entry": [{
+ "id": "INSTAGRAM_BUSINESS_ACCOUNT_ID",
+ "time": 1704116400,
+ "messaging": [{
+ "sender": { "id": "USER_ID" },
+ "recipient": { "id": "PAGE_ID" },
+ "timestamp": 1704116400,
+ "message": {
+ "mid": "MESSAGE_ID",
+ "text": "Qual é o horário de funcionamento?"
+ }
+ }]
+ }]
+}`
+ })}
+
+ {h2({ children: 'Passo 4: Integrar com Knowly API' })}
+ {p({
+ children: (
+ <>
+ Quando receber uma mensagem via webhook, consulte a API do Knowly e
+ envie a resposta de volta ao usuário:
+ >
+ )
+ })}
+
+ {p({
+ children: (
+ <>
+ Exemplo em Node.js:
+ >
+ )
+ })}
+
+ {pre({
+ children: `const express = require('express');
+const app = express();
+
+app.post('/webhook/instagram', async (req, res) => {
+ const { entry } = req.body;
+
+ // Processar cada mensagem recebida
+ for (const event of entry) {
+ for (const messaging of event.messaging) {
+ const senderId = messaging.sender.id;
+ const messageText = messaging.message?.text;
+
+ if (!messageText) continue;
+
+ // Consultar API do Knowly
+ const knowlyResponse = await fetch('https://api.knowly.dev.br/chat', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ },
+ body: JSON.stringify({
+ kb_key: 'knowly_c81a7410-4c69-45e2-b6c6-79205c3a99fd',
+ model: 'MISTRAL_SMALL',
+ prompt: messageText
+ })
+ });
+
+ const data = await knowlyResponse.json();
+ const aiResponse = data.response;
+
+ // Enviar resposta via Instagram Messaging API
+ await sendInstagramMessage(senderId, aiResponse);
+ }
+ }
+
+ res.sendStatus(200);
+});
+
+// Função para enviar mensagem pelo Instagram
+async function sendInstagramMessage(recipientId, message) {
+ const pageId = 'SEU_INSTAGRAM_BUSINESS_ACCOUNT_ID';
+
+ await fetch(\`https://graph.facebook.com/v18.0/\${pageId}/messages\`, {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'Authorization': 'Bearer SEU_TOKEN_INSTAGRAM'
+ },
+ body: JSON.stringify({
+ recipient: { id: recipientId },
+ message: { text: message }
+ })
+ });
+}
+
+// Endpoint de verificação do webhook (obrigatório)
+app.get('/webhook/instagram', (req, res) => {
+ const mode = req.query['hub.mode'];
+ const token = req.query['hub.verify_token'];
+ const challenge = req.query['hub.challenge'];
+
+ if (mode === 'subscribe' && token === 'SEU_TOKEN_DE_VERIFICACAO') {
+ res.status(200).send(challenge);
+ } else {
+ res.sendStatus(403);
+ }
+});`
+ })}
+
+ {p({
+ children: (
+ <>
+ Exemplo em Python:
+ >
+ )
+ })}
+
+ {pre({
+ children: `from flask import Flask, request
+import requests
+
+app = Flask(__name__)
+
+@app.route('/webhook/instagram', methods=['POST'])
+def instagram_webhook():
+ data = request.json
+
+ # Processar mensagens
+ for entry in data.get('entry', []):
+ for messaging in entry.get('messaging', []):
+ sender_id = messaging['sender']['id']
+ message_text = messaging.get('message', {}).get('text')
+
+ if not message_text:
+ continue
+
+ # Consultar API do Knowly
+ knowly_response = requests.post(
+ 'https://api.knowly.dev.br/chat',
+ headers={
+ 'Content-Type': 'application/json',
+ },
+ json={
+ 'kb_key': 'knowly_c81a7410-4c69-45e2-b6c6-79205c3a99fd',
+ 'model': 'MISTRAL_SMALL',
+ 'prompt': message_text
+ }
+ )
+
+ ai_response = knowly_response.json()['response']
+
+ # Enviar resposta pelo Instagram
+ send_instagram_message(sender_id, ai_response)
+
+ return '', 200
+
+def send_instagram_message(recipient_id, message):
+ page_id = 'SEU_INSTAGRAM_BUSINESS_ACCOUNT_ID'
+
+ requests.post(
+ f'https://graph.facebook.com/v18.0/{page_id}/messages',
+ headers={
+ 'Content-Type': 'application/json',
+ 'Authorization': 'Bearer SEU_TOKEN_INSTAGRAM'
+ },
+ json={
+ 'recipient': {'id': recipient_id},
+ 'message': {'text': message}
+ }
+ )
+
+@app.route('/webhook/instagram', methods=['GET'])
+def verify_webhook():
+ mode = request.args.get('hub.mode')
+ token = request.args.get('hub.verify_token')
+ challenge = request.args.get('hub.challenge')
+
+ if mode == 'subscribe' and token == 'SEU_TOKEN_DE_VERIFICACAO':
+ return challenge, 200
+ return '', 403`
+ })}
+
+ {h2({ children: 'Passo 5: Testar a Integração' })}
+ {ul({
+ children: (
+ <>
+ {li({
+ children: (
+ <>
+ Envie uma mensagem direta para sua conta Business do Instagram
+ >
+ )
+ })}
+ {li({
+ children: <>Verifique se o webhook está recebendo a notificação>
+ })}
+ {li({
+ children: (
+ <>
+ Confirme que a API do Knowly está retornando respostas
+ adequadas
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Valide se as respostas estão sendo enviadas corretamente ao
+ usuário
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ {h2({ children: 'Funcionalidades Avançadas' })}
+ {ul({
+ children: (
+ <>
+ {li({
+ children: (
+ <>
+ Respostas rápidas: Configure botões de
+ resposta rápida para melhorar a experiência
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Mídia: Envie imagens ou vídeos junto com as
+ respostas quando apropriado
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Templates: Use templates pré-aprovados para
+ respostas frequentes
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Horário comercial: Configure respostas
+ automáticas apenas fora do horário comercial
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ {h2({ children: 'Boas Práticas' })}
+ {ul({
+ children: (
+ <>
+ {li({
+ children: (
+ <>
+ Transparência: Informe aos usuários que estão
+ interagindo com um assistente automático
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Escalação: Ofereça opção de falar com
+ atendente humano quando necessário
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Tempo de resposta: Configure timeout adequado
+ (máx. 10 segundos)
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Monitoramento: Acompanhe métricas de
+ satisfação e qualidade das respostas
+ >
+ )
+ })}
+ {li({
+ children: (
+ <>
+ Políticas do Instagram: Respeite as
+ diretrizes de mensagens automatizadas da plataforma
+ >
+ )
+ })}
+ >
+ )
+ })}
+
+ {p({
+ children: (
+ <>
+ Com essa integração, você poderá responder automaticamente mensagens
+ diretas no Instagram, melhorando o engajamento com sua audiência e
+ fornecendo suporte instantâneo 24/7.
+ >
+ )
+ })}
+ + Três passos simples para transformar seus documentos em IA +
++
{content.content}
+ Escolha o plano perfeito para suas necessidades +
++ Tudo o que você precisa saber sobre o Knowly +
+- {message.content} -
-- {formatTime(message.timestamp)} -
+ {message.id === 'loading' ? ( ++ {message.content} +
++ {formatTime(message.timestamp)} +
+ > + )} {message.type === 'user' && ( diff --git a/src/features/sign-up/pages/sign-up-page.tsx b/src/features/sign-up/pages/sign-up-page.tsx index 7107a90..37d5ae0 100644 --- a/src/features/sign-up/pages/sign-up-page.tsx +++ b/src/features/sign-up/pages/sign-up-page.tsx @@ -27,11 +27,6 @@ import { zodResolver } from '@hookform/resolvers/zod' import { useForm } from 'react-hook-form' import { Checkbox } from '@/shared/components/checkbox' import { Label } from '@/shared/components/label' -import { - formatCNPJ, - formatCPF, - formatPhone -} from '@/shared/utils/format-documents' import toast from 'react-hot-toast' import { BackgroundBlobs } from '@/shared/components/background-blobs' import { motion } from 'framer-motion' @@ -41,6 +36,12 @@ import { containerVariants, cardVariants } from '@/shared/utils/animations' import { useCreateUserMutation } from '@/shared/hooks/use-user' import { AxiosError } from 'axios' import { useNavigate } from 'react-router-dom' +import { DOCUMENT_TYPE } from '@/shared/enums/document-type' +import { + handleCNPJChange, + handleCPFChange, + handlePhoneChange +} from '@/shared/utils/string-extensions' export function SignUpPage() { const [showPassword, setShowPassword] = useState(false) @@ -55,33 +56,9 @@ export function SignUpPage() { mode: 'onBlur' }) - const handleCPFChange = ( - value: string, - onChange: (value: string) => void - ) => { - const formattedValue = formatCPF(value) - onChange(formattedValue) - } - - const handleCNPJChange = ( - value: string, - onChange: (value: string) => void - ) => { - const formattedValue = formatCNPJ(value) - onChange(formattedValue) - } - - const handlePhoneChange = ( - value: string, - onChange: (value: string) => void - ) => { - const formattedValue = formatPhone(value) - onChange(formattedValue) - } - async function onSubmit(values: SignUpFormData) { try { - const isIndividual = values.documentType === 'individual' + const isIndividual = values.documentType === DOCUMENT_TYPE.INDIVIDUAL // Convert birthDate to seconds since epoch if provided const birthDateSeconds = values.birthDate @@ -196,9 +173,11 @@ export function SignUpPage() { >{knowledgeBase.createdAt.toLocaleDateString('pt-BR')}
+ Criada em: ++ {knowledgeBase.createdAt.toLocaleDateString('pt-BR')} +
{knowledgeBase.updatedAt.toLocaleDateString('pt-BR')}
++ {knowledgeBase.updatedAt.toLocaleDateString('pt-BR')} +
+
{knowledgeBase.files.length} arquivo {knowledgeBase.files.length !== 1 ? 's' : ''}
{knowledgeBase.totalSizeMB.toFixed(1)} MB
++ {knowledgeBase.totalSizeMB.toFixed(1)} MB +
Nenhum arquivo encontrado
{file.fileName}
-+
{formatFileSize(file.sizeMB)}