npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

worthwhile-chat-app

v0.1.4

Published

<!-- # Vue 3 + Vite

Readme

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

# 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:

<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:

<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

{
  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:

<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:

<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>