# worthwhile-chat-app

Latest version **0.1.4** (published 2022-12-22) · 0 weekly downloads

## Install

```sh
npm install worthwhile-chat-app
pnpm add worthwhile-chat-app
yarn add worthwhile-chat-app
bun add worthwhile-chat-app
```

## Health

**Score 15/100 (F)** — status: abandoned.

Positive: esm support; no vulnerabilities.

Warnings: low downloads; no types; low quality score; pre 1.0.

Negative: abandoned; low maintenance score.

## Facts

| | |
|---|---|
| Version | 0.1.4 |
| Published | 2022-12-22 |
| First published | 2022-12-20 |
| Weekly downloads | 0 |
| TypeScript types | none |
| Module format | ESM + CommonJS |
| Dependencies | 6 |
| Unpacked size | 597.8 KB |
| Known vulnerabilities | 0 |
| Install scripts | no |
| Maintainers | steph544 |

## Links

- npm: https://www.npmjs.com/package/worthwhile-chat-app
- npm.io page: https://npm.io/package/worthwhile-chat-app

## Dependencies (6)

- [vue](https://npm.io/package/vue.md) ^3.2.16
- [lodash](https://npm.io/package/lodash.md) ^4.17.21
- [moment](https://npm.io/package/moment.md) ^2.29.4
- [bootstrap-icons](https://npm.io/package/bootstrap-icons.md) ^1.8.3
- [socket.io-client](https://npm.io/package/socket.io-client.md) ^4.5.4
- [eslint-plugin-cypress](https://npm.io/package/eslint-plugin-cypress.md) ^2.12.1

## Recent versions

- 0.1.4 (latest) — 2022-12-22
- 0.1.3 — 2022-12-22
- 0.1.2 — 2022-12-22
- 0.1.1 — 2022-12-22
- 0.1.0 — 2022-12-22
- 0.0.9 — 2022-12-22
- 0.0.8 — 2022-12-22
- 0.0.7 — 2022-12-21
- 0.0.6 — 2022-12-21
- 0.0.5 — 2022-12-21
- 0.0.4 — 2022-12-21
- 0.0.3 — 2022-12-21
- 0.0.2 — 2022-12-20
- 0.0.1 — 2022-12-20

## README

<!-- # Vue 3 + Vite

This template should help get you started developing with Vue 3 in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.

## Recommended IDE Setup

- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur) + [TypeScript Vue Plugin (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.vscode-typescript-vue-plugin). -->
# Name
Worthwhile Chat App 

# Description
Worthwhile Chat App is a real-time Vue Chat Application that uses Socket.io, Tailwind, and Vite to allow communication between two users. 

# Features
* Compatible with Vue framework 
* Customizable Real-time Chat Messaging 
* Editable Messages 
* Message Timestamps
* Real-time typing indicator
* Customizable text and background colors
* Inbox Message List (List of the existing chats for the user)

## Table of Contents 
* Installation 
* Usage
* Props data structure 
* Required Methods
  
## Installation


```bash
# Using npm
npm install --save worthwhile-chat-app
```

## Usage
There are two components in this package: 
* InboxMessages
* MessageList
  
You can import both as custom components in your Vue Project. Example Usage for InboxMessages: 

```javascript
<script>
import { useUser } from "@/stores/userStore";
import { useMessage } from "@/stores/messageStore";
import { useInvitation } from "@/stores/invitationStore";
import { InboxMessages } from "worthwhile-chat-app";

export default {
  name: "InboxMessagesChat",
  components: { InboxMessages },
  data() {
    return {
      messages: [],
      userStore: useUser(),
      invitationStore: useInvitation(),
      messageStore: useMessage(),
      sender: {},
      port: null,
    };
  },
  computed: {
    currentMessages() {
      return this.messageStore.messages;
    },
  },
  mounted() {
    if (this.messageStore?.selectedMessageInvitationInfo) {
      this.sender = {
        invitation_id: this.messageStore?.selectedMessageInvitationInfo.invitation_id,
        sender_name: this.userStore?.currentUser?.name,
        sender_image: "https://picsum.photos/200/300",
        userOne: {
          userOne_id: this.messageStore?.selectedMessageInvitationInfo?.userOne.userOne_id,
          name: this.messageStore?.selectedMessageInvitationInfo?.userOne.name,
          phone: this.messageStore?.selectedMessageInvitationInfo?.userOne.phone,
          email: this.messageStore?.selectedMessageInvitationInfo?.userOne.email,
        },
        userTwo: {
          userTwo_id: this.messageStore?.selectedMessageInvitationInfo?.userTwo.userTwo_id,
          name: this.messageStore?.selectedMessageInvitationInfo?.userTwo.name,
          phone: this.messageStore?.selectedMessageInvitationInfo?.userTwo.phone,
          email: this.messageStore?.selectedMessageInvitationInfo?.userTwo.email,
        },
        message: this.message,
        status: "active",
        read: false,
        edited: false,
      };
    }
    this.port = 4000;
  },
  methods: {
    createNewMessage(sender) {
      this.messageStore.createMessage(sender);
    },
    getAllMessages() {
      this.messageStore
        .readMessages(
          this.messageStore.selectedMessageInvitationInfo?.invitation_id,
          "invitation_id"
        )
        .then(() => {
          this.messageStore.messages.forEach((message) => this.messages.push(message));
        });
    },
    updateMessage(messageId, newMessage, messageItem) {
      const updatedMessage = {
        message: newMessage.message,
        edited: true,
      };

      this.messageStore.updateMessage(messageId, updatedMessage, messageItem).then(() => {
        this.getAllMessages();
        this.$nextTick(() => {
          document.getElementById(`${messageItem._id}`).scrollIntoView({
            behavior: "smooth",
            block: "center",
            inline: "center",
          });
        });
      });

      this.editedMessage = null;
      this.newMessage = null;
      this.hovered = null;
    },
  },
};
</script>
<template>
  <div class="overflow-y-scroll">
    <InboxMessages
      :port="port"
      :chatroom="messageStore.selectedMessageInvitationInfo?.invitation_id"
      :current-user="userStore.currentUser"
      :selected-message="messageStore.selectedMessageInvitationInfo"
      :sender-information="sender"
      :existing-messages="currentMessages"
      @get-all-messages="getAllMessages"
      @create-new-message="createNewMessage"
      @update-message="updateMessage"
    />
  </div>
</template>
<style lang="scss">
.message-height {
  height: 100vh;
  box-sizing: border-box;
  @media screen and (min-width: 768px) {
    height: calc(100vh - 300px);
  }
}
</style>

```
Example Usage of MessageList Component:
```javascript
<script setup>
import { onMounted, computed } from "vue";
import { useView } from "@/stores/viewStore";
import { useMessage } from "@/stores/messageStore";
import { useUser } from "@/stores/userStore";
import _ from "lodash";
import { MessageList } from "worthwhile-chat-app";
const viewStore = useView();
const messageStore = useMessage();
const userStore = useUser();

onMounted(() => {
  messageStore.readMessages(userStore.currentUser._id, userStore.userType);
});

const messageList = computed(() => {
  return _.uniqBy(messageStore.messageList, "invitation_id");
});

function getMessages(message) {
  if (viewStore.isMobile) {
    userStore.showFilterPanel = !userStore.showFilterPanel;
  }
  console.log("get messages", message);

  messageStore.selectedMessageInvitationInfo = {
    invitation_id: message.invitation_id,
    userOne: {
      userOne_id: message.userOne.userOne_id,
      name: message.userOne.name,
      phone: message.userOne.phone,
      email: message.userOne.email,
    },
    userTwo: {
      userTwo_id: message.userTwo.userTwo_id,
      name: message.userTwo.name,
      phone: message.userTwo.phone,
      email: message.userTwo.email,
    },
    sender_name: message.sender_name,
    sender_image: message.sender_image,
  };
  messageStore.readMessages(message.invitation_id, "invitation_id");
  viewStore.search = "messages";
}

function getAllUserMessages() {
  messageStore.readMessages(userStore.currentUser._id, userStore.userType);
}
</script>
<template>
  <MessageList
    :message-list="messageList"
    identifier-id="invitation_id"
    user-one="userOne"
    user-two="userTwo"
    message-background-color="bg-gray-100"
    max-width="max-width: 75px"
    name-color="text-gray-900"
    identifier-color="text-gray-900"
    :user-one-identifier="userStore.isUserOne"
    :current-user="userStore.currentUser"
    @get-all-user-messages="getAllUserMessages"
    @get-messages="getMessages"
  />
</template>

```

## Required Props and Data Structures

### InboxMessages Component

The following props are required: 
  | Props              | Type   | Required 
|--------------------|--------|----------|
| port               | String | true     |
| chatroom           | String | true     |
| current-user       | Object | true     |
| selected-chat   | [Object, String] | true     |
| sender-information | Object | true     |
| token              | String | true     |
| roles              | Array  | false    |
| userId             | String | true     |
| existing-messages  | Array  | true     |

(1) ```port``` (ex: http://localhost:4000)

(2) ```chatroom``` Identifies which room the users will join. You will want this to be something in common between the users, such as a request ID that joins the two users. 

(3) ```current-user``` This is an object with the currentUser information. See data structure below.

(4) ```selected-chat``` This is the indicator for which specific chat is selected. It can be either an Object or String. The component simply checks if it exists. 

(5)```sender-information``` This is an object with the sender information. See data structure below.

(6) ```existing-messages``` This is an array of all the messages that have already been persisted to the database. 

### Data Structure for InboxMessages Props
The following only illustrates what is required for the component to work correctly. Including more properties in the object will not break the code. 

**Current User**

```
{
  name: {
    first: "First",
    last: "Last"
  }
}
```

**Sender Information**

```javascript
{
  invitation_id: "68asdfasdf6842",
  sender_name: this.userStore?.currentUser?.name,
  sender_image: "https://picsum.photos/200/300",
  userOne: {
    userOne_id: this.messageStore?.selectedMessageInvitationInfo?.userOne.userOne_id,
    name: {
      first: "First",
      last: "Last"
    },
    phone: this.messageStore?.selectedMessageInvitationInfo?.userOne.phone,
    email: this.messageStore?.selectedMessageInvitationInfo?.userOne.email,
  },
  userTwo: {
    userTwo_id: this.messageStore?.selectedMessageInvitationInfo?.userTwo.userTwo_id,
    name: {
      first: "First",
      last: "Last"
    },
    phone: this.messageStore?.selectedMessageInvitationInfo?.userTwo.phone,
    email: this.messageStore?.selectedMessageInvitationInfo?.userTwo.email,
  },
}
```
** Object should have ```_id``` and ```updatedAt``` properties as well, this should be automatically assigned in Mongo. If not, you will need to also include those. 
  
(1) ```invitation_id``` This can be named anything, this is what identifies the common identifier between the two parties. This property will need to be the same name as the ```identifierId``` prop for MessageList component and a String value.
(2) ```userOne``` This can be named anything, this property will be the identifier for User One (will need to be the name as ```userOne``` prop for MessageList component)
(3) ```userTwo``` This can be named anything, this property will be the identifier for User Two (will need to be the name as ```userTwo``` prop for MessageList component)

### InboxMessages Component

The following props are required: 

  | Props              | Type   | Required 
|--------------------|--------|----------|
| chat-list          | Array   | true |
| identifier-id          | String  | true |
| user-one-identifier   | Boolean | true |
| current-user          | Object  | true |
| user-one              | String  | true |
| user-two              | String  | true |
| message-background-color* | String  | false |
| hover-message-background-color* | String  | false |
| max-width             | String  | false|
| name-color*            | String  | false|
| identifier-color*      | String  | false|

**must be Tailwind values (ex. text-gray-100)

(1) ```chat-list``` is the filtered list of chats that for the current user.  

(2) ```identifier-id``` is a String value and must equal the name of the property that was assigned in the SenderInformation object in the InboxMessages component. This would be the 'invitation_id' in the SenderInformation data structure example.

(3) ```user-one-identifier``` is a Boolean value that identifies userOne from userTwo. For example, pass a computed property that checks if userOne is the userOne versus the professional. 

(4) ```current-user``` This is an object with the currentUser information. This should be the same current-user value that was passed to InboxMessages Component. See data structure below.

(5) ```userOne``` This must match the property name that was used in the SenderInformation Object in the InboxMessages Component. For example, 'userOne'.

(6) ```userTwo``` This must match the property name that was used in the SenderInformation Object in the InboxMessages Component. For example, 'userTwo'.

(7) ```message-background-color``` This is an optional background color for each item in the chat-list

(8)  ```hover-message-background-color``` This is an optional hover background color for each item in the chat-list

(9) ```max-width``` Sets the max-width for each chat list item. For example, pass in "max-width: 75px"

(10) ```name-color``` Sets the color of the Sender name. 

(10) ```identifier-color``` Sets the color of the identifierId property. 

### Data Structure for MessageList Props

**Current User**

```
{
  name: {
    first: "First",
    last: "Last"
  }
}
```

## Required Methods to pass to Components 
### InboxMessages 
You must pass the following methods to InboxMessages:

@get-all-messages="YourMethod"
*_This function should send a GET request for all the existing messages from the database. Then you will want to update the ```existing-messages``` property that you're passing to InboxMessages Component with this response data._ 

@create-new-message="YourMethod"
@update-message="YourMethod"

*_See comments below in Example Usage for descriptions_

**Example Usage:**
```javascript
<script>
   getAllMessages() {
      this.messageStore
        .readMessages(
          this.messageStore.selectedMessageInvitationInfo?.invitation_id,
          "invitation_id"
        )
        .then(() => {
          this.messageStore.messages.forEach((message) => this.messages.push(message));
        });
    },

    //*_This function should send a POST request 
    //to create a new message in the database._ 
    createNewMessage(sender) {
      this.messageStore.createMessage(sender);
    },

    //This function should send a PUT request 
    //to update a message in the database.
    updateMessage(messageId, newMessage, messageItem) {
      const updatedMessage = {
        message: newMessage.message,
        edited: true,
      };

      this.messageStore.updateMessage(messageId, updatedMessage, messageItem).then(() => {
        this.getAllMessages();
        this.$nextTick(() => {
          document.getElementById(`${messageItem._id}`).scrollIntoView({
            behavior: "smooth",
            block: "center",
            inline: "center",
          });
        });
      });
    }
</script>
<template>
  <div class="overflow-y-scroll">
    <InboxMessages
      :port="port"
      :chatroom="messageStore.selectedMessageInvitationInfo?.invitation_id"
      :current-user="userStore.currentUser"
      :selected-chat="messageStore.selectedMessageInvitationInfo"
      :sender-information="sender"
      :token="userStore.token"
      :roles="userStore.currentUser.roles"
      :user-id="userStore.currentUser._id"
      :existing-messages="currentMessages"
      @get-all-messages="getAllMessages"
      @create-new-message="createNewMessage"
      @update-message="updateMessage"
    />
  </div>
</template>   

```

### MessageList
You must pass the following methods to MessageList:

@get-all-user-messages="YourMethod"
@get-messages="YourMethod"

*_See comments in example usage below for descriptions_

**Important** The messageList prop needs to be filtered prior to passing it as a prop. You will want to filter it so that the messageList does not include all messages, but only surfaces one message per chat. See messageList function below for an example.

**Example Usage:**
```javascript
<template>
  import _ from "lodash";

  //This returns only one message per unique invitation_id
  const messageList = computed(() => {
    return _.uniqBy(messageStore.messageList, "invitation_id");
  });

  //This function should send a GET request to the 
  //database that queries for all messages that are
  //tied to the selected chat list item

  function getMessages(message) {
    messageStore.selectedMessageInvitationInfo = {
      invitation_id: message.invitation_id,
      userOne: {
        userOne_id: message.userOne.userOne_id,
        name: message.userOne.name,
        phone: message.userOne.phone,
        email: message.userOne.email,
      },
      userTwo: {
        userTwo_id: message.userTwo.userTwo_id,
        name: message.userTwo.name,
        phone: message.userTwo.phone,
        email: message.userTwo.email,
      },
      sender_name: message.sender_name,
      sender_image: message.sender_image,
    };
    messageStore.readMessages(message.invitation_id, "invitation_id");
    viewStore.search = "messages";
  }

  //This function should search for all 
  //messages in the database that includes the current user

  function getAllUserMessages() {
    messageStore.readMessages(userStore.currentUser._id, userStore.userType);
  }

  <MessageList
    :chat-list="messageList"
    identifier-id="invitation_id"
    user-one="userOne"
    user-two="userTwo"
    message-background-color="bg-gray-100"
    max-width="max-width: 75px"
    name-color="text-gray-900"
    identifier-color="text-gray-900"
    :user-one-identifier="userStore.isuserOne"
    :current-user="userStore.currentUser"
    @get-all-user-messages="getAllUserMessages"
    @get-messages="getMessages"
  />
</template>
```

---
_Source: https://npm.io/package/worthwhile-chat-app · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
