canove / whaticket-community

A very simple Ticket System based on WhatsApp messages, that allow multi-users in same WhatsApp account.
MIT License
1.65k stars 830 forks source link

VCARD #210

Closed janjrr closed 3 years ago

janjrr commented 3 years ago

I have a problem rendering the V-Card, how can I solve it? Captura de tela de 2021-07-23 10-42-13

alanddos commented 3 years ago

Tem que fazer as alterações algumas no back e no front para trazer o contato image

ertprs commented 3 years ago

Tem que fazer as alterações algumas no back e no front para trazer o contato image

Show como que vc fez isso?

alanddos commented 3 years ago

No Vcard. Extrai os dados do body da mensagem e salvo nos contatos assim que chega a mensagem em handleMessage: if (msg.type === "vcard") { try { const array = msg.body.split("\n"); const obj = []; let contact = ""; for (let index = 0; index < array.length; index++) { const v = array[index]; const values = v.split(":"); for (let ind = 0; ind < values.length; ind++) { if (values[ind].indexOf("+") !== -1) { obj.push({ number: values[ind] }); } if (values[ind].indexOf("FN") !== -1) { contact = values[ind + 1]; } } } for await (const ob of obj) { const cont = await CreateContactService({ name: contact, number: ob.number.replace(/\D/g, "") }); } } catch (error) { console.log(error); } }

No mult_vcard usei a mesma ideia extraindo os dados do array vCards e adicionando ao banco e altero o body para os ids adicionados ou encontrados, ps tenho que fazer esse final no vcard ainda para simplicar no front:

`if (msg.type === "multi_vcard") { try { const array = msg.vCards.toString().split("\n"); let name = ""; let number = ""; const obj = []; const conts = []; for (let index = 0; index < array.length; index++) { const v = array[index]; const values = v.split(":"); for (let ind = 0; ind < values.length; ind++) { if (values[ind].indexOf("+") !== -1) { number = values[ind]; } if (values[ind].indexOf("FN") !== -1) { name = values[ind + 1]; } if (name !== "" && number !== "") { obj.push({ name, number }); name = ""; number = ""; } } }

  // eslint-disable-next-line no-restricted-syntax
  for await (const ob of obj) {
    try {
      const cont = await CreateContactService({
        name: ob.name,
        number: ob.number.replace(/\D/g, "")
      });
      conts.push({
        id: cont.id,
        name: cont.name,
        number: cont.number
      });
    } catch (error) {
      if (error.message === "ERR_DUPLICATED_CONTACT") {
        const cont = await GetContactService({
          name: ob.name,
          number: ob.number.replace(/\D/g, ""),
          email: ""
        });
        conts.push({
          id: cont.id,
          name: cont.name,
          number: cont.number
        });
      }
    }
  }
  msg.body = JSON.stringify(conts);
} catch (error) {
  console.log(error);
}

}`

Em isValidMsg adiciona o multi

msg.type === "multi_vcard" ||

no handleMessage ainda adiona o novo formato em isFromMe

if ( !msg.hasMedia && msg.type !== "chat" && msg.type !== "vcard" && msg.type !== "multi_vcard") return;

Adcionei um serviço para buscar o contato por numero do jeito que eu queria

`import AppError from "../../errors/AppError"; import Contact from "../../models/Contact";

interface ExtraInfo { name: string; value: string; }

interface Request { name: string; number: string; email?: string; profilePicUrl?: string; extraInfo?: ExtraInfo[]; }

const GetContactService = async ({ name, number }: Request): Promise => { const numberExists = await Contact.findOne({ where: { number } });

if (!numberExists) { throw new AppError("CONTACT_NOT_FIND"); }

return numberExists; };

export default GetContactService;`

e no front adicionei um componente de visualização:

`import React, { PureComponent, useEffect, useState, useContext } from 'react'; import { useHistory } from "react-router-dom"; import toastError from "../../errors/toastError"; import api from "../../services/api";

import Avatar from "@material-ui/core/Avatar"; import Typography from "@material-ui/core/Typography"; import Grid from "@material-ui/core/Grid";

import { AuthContext } from "../../context/Auth/AuthContext";

import { Button, Divider, } from "@material-ui/core";

const VcardPreview = ({ contact, numbers }) => { const history = useHistory(); const { user } = useContext(AuthContext);

const [selectedContact, setContact] = useState({
    name: "",
    number: 0,
    profilePicUrl: ""
});

useEffect(() => {
    const delayDebounceFn = setTimeout(() => {
        const fetchContacts = async () => {
            try {
                let contactObj = {
                    name: contact,
                    number: numbers.replace(/\D/g, ""),
                    email: ""
                }
                const { data } = await api.post("/contact", contactObj);
                setContact(data)

            } catch (err) {
                console.log(err)
                toastError(err);
            }
        };
        fetchContacts();
    }, 500);
    return () => clearTimeout(delayDebounceFn);
}, []);

const handleNewChat = async () => {
    try {
        const { data: ticket } = await api.post("/tickets", {
            contactId: selectedContact.id,
            userId: user.id,
            status: "open",
        });
        history.push(`/tickets/${ticket.id}`);
    } catch (err) {
        toastError(err);
    }
}

return (
    <>
        <div style={{
            minWidth: "250px",
        }}>
            <Grid container spacing={1}>
                <Grid item xs={2}>
                    <Avatar src={selectedContact.profilePicUrl} />
                </Grid>
                <Grid item xs={9}>
                    <Typography style={{ marginTop: "12px", marginLeft: "10px" }} variant="subtitle1" color="primary" gutterBottom>
                        {selectedContact.name}
                    </Typography>
                </Grid>
                <Grid item xs={12}>
                    <Divider />
                    <Button
                        fullWidth
                        color="primary"
                        onClick={handleNewChat}
                        disabled={!selectedContact.number}
                    >Conversar</Button>
                    <Divider />
                </Grid>
            </Grid>
        </div>
    </>
);

};

export default VcardPreview; ` E alterei o messagesList para chamar o componente no proprio checkmessagemedia adicionando:

` const checkMessageMedia = (message) => { if (message.mediaType === "vcard") { let array = message.body.split("\n"); let obj = []; let contact = ""; for (let index = 0; index < array.length; index++) { const v = array[index]; let values = v.split(":"); for (let ind = 0; ind < values.length; ind++) { if (values[ind].indexOf("+") !== -1) { obj.push({ number: values[ind] }); } if (values[ind].indexOf("FN") !== -1) { contact = values[ind + 1]; } } }

  return <VcardPreview contact={contact} numbers={obj[0].number} />
}

if (message.mediaType === "multi_vcard") {
  let newBody = JSON.parse(message.body)
  return (
    <>
      {
        newBody.map(v => (
          <VcardPreview contact={v.name} numbers={v.number} />
        ))
      }
    </>
  )

}`

no mesmo messageList onde lista as mensagens adicionei tanto para fromMe quanto

{message.mediaType === "vcard" && checkMessageMedia(message)} {message.mediaType === "multi_vcard" && checkMessageMedia(message)}

Da para melhorar mas estou modificando as filas para aceitar subdepartamentos e não to tendo tempo.

ertprs commented 3 years ago

Show, muito bom!

Vou alterar os arquivos nesse Domingo e testar aqui.

Muito obrigado por compartilhar conosco.

Bom final de semana!

ricco-douro commented 3 years ago

Da para melhorar mas estou modificando as filas para aceitar subdepartamentos e não to tendo tempo.

Oi, @alanddos , tou interessado nisso. Valeu?

ertprs commented 3 years ago

`import AppError from "../../errors/AppError"; import Contact from "../../models/Contact";

interface ExtraInfo { name: string; value: string; }

interface Request { name: string; number: string; email?: string; profilePicUrl?: string; extraInfo?: ExtraInfo[]; }

const GetContactService = async ({ name, number }: Request): Promise => { const numberExists = await Contact.findOne({ where: { number } });

if (!numberExists) { throw new AppError("CONTACT_NOT_FIND"); }

return numberExists; };

export default GetContactService;`

Não deu certo, eu não consegui fazer isso.

image

alanddos commented 3 years ago

Da para melhorar mas estou modificando as filas para aceitar subdepartamentos e não to tendo tempo.

Oi, @alanddos , tou interessado nisso. Valeu?

import AppError from "../../errors/AppError"; import Contact from "../../models/Contact"; interface ExtraInfo { name: string; value: string; } interface Request { name: string; number: string; email?: string; profilePicUrl?: string; extraInfo?: ExtraInfo[]; } const GetContactService = async ({ name, number }: Request): Promise => { const numberExists = await Contact.findOne({ where: { number } }); if (!numberExists) { throw new AppError("CONTACT_NOT_FIND"); } return numberExists; }; export default GetContactService;

Não deu certo, eu não consegui fazer isso.

image

Parece que não esta retornando o contato, me chama amanha umas 10 hrs que te ajudo terminar ai.

dev-oneclick commented 3 years ago

Conseguiu resolver o problema?

import AppError from "../../errors/AppError"; import Contact from "../../models/Contact"; interface ExtraInfo { name: string; value: string; } interface Request { name: string; number: string; email?: string; profilePicUrl?: string; extraInfo?: ExtraInfo[]; } const GetContactService = async ({ name, number }: Request): Promise => { const numberExists = await Contact.findOne({ where: { number } }); if (!numberExists) { throw new AppError("CONTACT_NOT_FIND"); } return numberExists; }; export default GetContactService;

Não deu certo, eu não consegui fazer isso.

image

alanddos commented 3 years ago

Se alguém precisar de ajuda nisso chama la no discord, Alan Gonçalves#6714. Abraços!

ertprs commented 3 years ago

Alan Gonçalves#6714

Bom dia, enviei a solicitação de amizade para você lá.

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

presttec commented 3 years ago

Como sugestão,

Suba os arquivos completos. Que fica mais facil.

presttec commented 3 years ago

A menos que queira ganhar uma grana extra. Aí tem que deixar difícil. rs

presttec commented 3 years ago

@alanddos .

stale[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

AlefMartins commented 3 years ago

Alguém conseguiu colocar pra funcionar? se sim vou tentar aqui da forma que está aqui o git