mirror of
https://github.com/liamcottle/reticulum-meshchat.git
synced 2026-04-28 00:20:48 +00:00
move messages sidebar to own vue component
This commit is contained in:
parent
e8b4a498e3
commit
b540f20ccd
3 changed files with 258 additions and 159 deletions
|
|
@ -242,134 +242,13 @@
|
|||
</div>
|
||||
|
||||
<!-- messages sidebar -->
|
||||
<div v-if="tab === 'messages'" class="flex flex-col w-80 min-w-80">
|
||||
|
||||
<!-- tabs -->
|
||||
<div class="bg-white border-b border-r border-gray-200">
|
||||
<div class="-mb-px flex">
|
||||
<!-- Current: "border-blue-500 text-blue-600", Default: "border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700" -->
|
||||
<div @click="messagesTab = 'conversations'" class="w-full border-b-2 py-3 px-1 text-center text-sm font-medium cursor-pointer" :class="[ messagesTab === 'conversations' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700']">Conversations</div>
|
||||
<div @click="messagesTab = 'announces'" class="w-full border-b-2 py-3 px-1 text-center text-sm font-medium cursor-pointer" :class="[ messagesTab === 'announces' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700']">Announces</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- conversations -->
|
||||
<div v-if="messagesTab == 'conversations'" class="flex-1 flex flex-col bg-white border-r overflow-hidden">
|
||||
|
||||
<!-- search -->
|
||||
<div v-if="conversations.length > 0" class="p-1 border-b border-gray-300">
|
||||
<input v-model="conversationsSearchTerm" type="text" :placeholder="`Search ${conversations.length} Conversations...`" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
|
||||
</div>
|
||||
|
||||
<!-- peers -->
|
||||
<div class="flex h-full overflow-y-auto">
|
||||
<div v-if="searchedConversations.length > 0" class="w-full">
|
||||
<div @click="onConversationClick(conversation)" v-for="conversation of searchedConversations" class="flex cursor-pointer p-2 border-l-2" :class="[ conversation.destination_hash === selectedPeer?.destination_hash ? 'bg-gray-100 border-blue-500' : 'bg-white border-transparent hover:bg-gray-50 hover:border-gray-200' ]">
|
||||
<div class="my-auto mr-2">
|
||||
<div class="bg-gray-200 text-gray-500 p-2 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mr-auto">
|
||||
<div class="text-gray-900" :class="{ 'font-semibold': conversation.is_unread || conversation.failed_messages_count > 0 }">{{ conversation.name }}</div>
|
||||
<div class="text-gray-500 text-sm">{{ formatTimeAgo(conversation.updated_at) }}</div>
|
||||
</div>
|
||||
<div v-if="conversation.is_unread" class="my-auto ml-2 mr-2">
|
||||
<div class="bg-blue-500 rounded-full p-1"></div>
|
||||
</div>
|
||||
<div v-else-if="conversation.failed_messages_count" class="my-auto ml-2 mr-2">
|
||||
<div class="bg-red-500 rounded-full p-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mx-auto my-auto text-center leading-5">
|
||||
|
||||
<!-- no conversations at all -->
|
||||
<div v-if="conversations.length === 0" class="flex flex-col">
|
||||
<div class="mx-auto mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 13.5h3.86a2.25 2.25 0 0 1 2.012 1.244l.256.512a2.25 2.25 0 0 0 2.013 1.244h3.218a2.25 2.25 0 0 0 2.013-1.244l.256-.512a2.25 2.25 0 0 1 2.013-1.244h3.859m-19.5.338V18a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18v-4.162c0-.224-.034-.447-.1-.661L19.24 5.338a2.25 2.25 0 0 0-2.15-1.588H6.911a2.25 2.25 0 0 0-2.15 1.588L2.35 13.177a2.25 2.25 0 0 0-.1.661Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-semibold">No Conversations</div>
|
||||
<div>Discover peers on the Announces tab</div>
|
||||
</div>
|
||||
|
||||
<!-- is searching, but no results -->
|
||||
<div v-if="conversationsSearchTerm !== '' && conversations.length > 0" class="flex flex-col">
|
||||
<div class="mx-auto mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-semibold">No Search Results</div>
|
||||
<div>Your search didn't match any Conversations!</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- discover -->
|
||||
<div v-if="messagesTab == 'announces'" class="flex-1 flex flex-col bg-white border-r overflow-hidden">
|
||||
|
||||
<!-- search -->
|
||||
<div v-if="peersCount > 0" class="p-1 border-b border-gray-300">
|
||||
<input v-model="peersSearchTerm" type="text" :placeholder="`Search ${peersCount} Peers...`" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
|
||||
</div>
|
||||
|
||||
<!-- peers -->
|
||||
<div class="flex h-full overflow-y-auto">
|
||||
<div v-if="searchedPeers.length > 0" class="w-full">
|
||||
<div @click="onPeerClick(peer)" v-for="peer of searchedPeers" class="flex cursor-pointer p-2 border-l-2" :class="[ peer.destination_hash === selectedPeer?.destination_hash ? 'bg-gray-100 border-blue-500' : 'bg-white border-transparent hover:bg-gray-50 hover:border-gray-200' ]">
|
||||
<div class="my-auto mr-2">
|
||||
<div class="bg-gray-200 text-gray-500 p-2 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-900">{{ peer.name }}</div>
|
||||
<div class="text-gray-500 text-sm">{{ formatTimeAgo(peer.updated_at) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mx-auto my-auto text-center leading-5">
|
||||
|
||||
<!-- no peers at all -->
|
||||
<div v-if="peersCount === 0" class="flex flex-col">
|
||||
<div class="mx-auto mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-semibold">No Peers Discovered</div>
|
||||
<div>Waiting for someone to announce!</div>
|
||||
</div>
|
||||
|
||||
<!-- is searching, but no results -->
|
||||
<div v-if="peersSearchTerm !== '' && peersCount > 0" class="flex flex-col">
|
||||
<div class="mx-auto mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-semibold">No Search Results</div>
|
||||
<div>Your search didn't match any Peers!</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<MessagesSidebar
|
||||
v-if="tab === 'messages'"
|
||||
:conversations="conversations"
|
||||
:peers="peers"
|
||||
:selected-destination-hash="selectedPeer?.destination_hash"
|
||||
@conversation-click="onConversationClick"
|
||||
@peer-click="onPeerClick"/>
|
||||
|
||||
<!-- nomadnetwork sidebar -->
|
||||
<div v-if="tab === 'nomadnetwork'" class="flex flex-col w-80 min-w-80">
|
||||
|
|
@ -1212,10 +1091,12 @@
|
|||
|
||||
<script>
|
||||
import SidebarLink from "./SidebarLink.vue";
|
||||
import MessagesSidebar from "./messages/MessagesSidebar.vue";
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
MessagesSidebar,
|
||||
SidebarLink,
|
||||
},
|
||||
data() {
|
||||
|
|
@ -1245,7 +1126,6 @@ export default {
|
|||
|
||||
tab: "messages",
|
||||
peers: {},
|
||||
peersSearchTerm: "",
|
||||
selectedPeer: null,
|
||||
selectedPeerPath: null,
|
||||
|
||||
|
|
@ -1255,8 +1135,6 @@ export default {
|
|||
selectedNodePath: null,
|
||||
|
||||
conversations: [],
|
||||
conversationsSearchTerm: "",
|
||||
messagesTab: "conversations",
|
||||
|
||||
lxmfMessagesRequestSequence: 0,
|
||||
chatItems: [],
|
||||
|
|
@ -3119,26 +2997,6 @@ export default {
|
|||
isMobile() {
|
||||
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
|
||||
},
|
||||
peersCount() {
|
||||
return Object.keys(this.peers).length;
|
||||
},
|
||||
peersOrderedByLatestAnnounce() {
|
||||
const peers = Object.values(this.peers);
|
||||
return peers.sort(function(peerA, peerB) {
|
||||
// order by updated_at desc
|
||||
const peerAUpdatedAt = new Date(peerA.updated_at).getTime();
|
||||
const peerBUpdatedAt = new Date(peerB.updated_at).getTime();
|
||||
return peerBUpdatedAt - peerAUpdatedAt;
|
||||
});
|
||||
},
|
||||
searchedPeers() {
|
||||
return this.peersOrderedByLatestAnnounce.filter((peer) => {
|
||||
const search = this.peersSearchTerm.toLowerCase();
|
||||
const matchesAppData = peer.name.toLowerCase().includes(search);
|
||||
const matchesDestinationHash = peer.destination_hash.toLowerCase().includes(search);
|
||||
return matchesAppData || matchesDestinationHash;
|
||||
});
|
||||
},
|
||||
selectedPeerChatItems() {
|
||||
|
||||
// get all chat items related to the selected peer
|
||||
|
|
@ -3181,14 +3039,6 @@ export default {
|
|||
return matchesAppData || matchesDestinationHash;
|
||||
});
|
||||
},
|
||||
searchedConversations() {
|
||||
return this.conversations.filter((conversation) => {
|
||||
const search = this.conversationsSearchTerm.toLowerCase();
|
||||
const matchesName = conversation.name.toLowerCase().includes(search);
|
||||
const matchesDestinationHash = conversation.destination_hash.toLowerCase().includes(search);
|
||||
return matchesName || matchesDestinationHash;
|
||||
});
|
||||
},
|
||||
unreadConversationsCount() {
|
||||
return this.conversations.filter((conversation) => {
|
||||
return conversation.is_unread;
|
||||
|
|
|
|||
193
src/frontend/components/messages/MessagesSidebar.vue
Normal file
193
src/frontend/components/messages/MessagesSidebar.vue
Normal file
|
|
@ -0,0 +1,193 @@
|
|||
<template>
|
||||
<div class="flex flex-col w-80 min-w-80">
|
||||
|
||||
<!-- tabs -->
|
||||
<div class="bg-white border-b border-r border-gray-200">
|
||||
<div class="-mb-px flex">
|
||||
<div @click="tab = 'conversations'" class="w-full border-b-2 py-3 px-1 text-center text-sm font-medium cursor-pointer" :class="[ tab === 'conversations' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700']">Conversations</div>
|
||||
<div @click="tab = 'announces'" class="w-full border-b-2 py-3 px-1 text-center text-sm font-medium cursor-pointer" :class="[ tab === 'announces' ? 'border-blue-500 text-blue-600' : 'border-transparent text-gray-500 hover:border-gray-300 hover:text-gray-700']">Announces</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- conversations -->
|
||||
<div v-if="tab === 'conversations'" class="flex-1 flex flex-col bg-white border-r overflow-hidden">
|
||||
|
||||
<!-- search -->
|
||||
<div v-if="conversations.length > 0" class="p-1 border-b border-gray-300">
|
||||
<input v-model="conversationsSearchTerm" type="text" :placeholder="`Search ${conversations.length} Conversations...`" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
|
||||
</div>
|
||||
|
||||
<!-- peers -->
|
||||
<div class="flex h-full overflow-y-auto">
|
||||
<div v-if="searchedConversations.length > 0" class="w-full">
|
||||
<div @click="onConversationClick(conversation)" v-for="conversation of searchedConversations" class="flex cursor-pointer p-2 border-l-2" :class="[ conversation.destination_hash === selectedDestinationHash ? 'bg-gray-100 border-blue-500' : 'bg-white border-transparent hover:bg-gray-50 hover:border-gray-200' ]">
|
||||
<div class="my-auto mr-2">
|
||||
<div class="bg-gray-200 text-gray-500 p-2 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mr-auto">
|
||||
<div class="text-gray-900" :class="{ 'font-semibold': conversation.is_unread || conversation.failed_messages_count > 0 }">{{ conversation.name }}</div>
|
||||
<div class="text-gray-500 text-sm">{{ formatTimeAgo(conversation.updated_at) }}</div>
|
||||
</div>
|
||||
<div v-if="conversation.is_unread" class="my-auto ml-2 mr-2">
|
||||
<div class="bg-blue-500 rounded-full p-1"></div>
|
||||
</div>
|
||||
<div v-else-if="conversation.failed_messages_count" class="my-auto ml-2 mr-2">
|
||||
<div class="bg-red-500 rounded-full p-1"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mx-auto my-auto text-center leading-5">
|
||||
|
||||
<!-- no conversations at all -->
|
||||
<div v-if="conversations.length === 0" class="flex flex-col">
|
||||
<div class="mx-auto mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 13.5h3.86a2.25 2.25 0 0 1 2.012 1.244l.256.512a2.25 2.25 0 0 0 2.013 1.244h3.218a2.25 2.25 0 0 0 2.013-1.244l.256-.512a2.25 2.25 0 0 1 2.013-1.244h3.859m-19.5.338V18a2.25 2.25 0 0 0 2.25 2.25h15A2.25 2.25 0 0 0 21.75 18v-4.162c0-.224-.034-.447-.1-.661L19.24 5.338a2.25 2.25 0 0 0-2.15-1.588H6.911a2.25 2.25 0 0 0-2.15 1.588L2.35 13.177a2.25 2.25 0 0 0-.1.661Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-semibold">No Conversations</div>
|
||||
<div>Discover peers on the Announces tab</div>
|
||||
</div>
|
||||
|
||||
<!-- is searching, but no results -->
|
||||
<div v-if="conversationsSearchTerm !== '' && conversations.length > 0" class="flex flex-col">
|
||||
<div class="mx-auto mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-semibold">No Search Results</div>
|
||||
<div>Your search didn't match any Conversations!</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- discover -->
|
||||
<div v-if="tab === 'announces'" class="flex-1 flex flex-col bg-white border-r overflow-hidden">
|
||||
|
||||
<!-- search -->
|
||||
<div v-if="peersCount > 0" class="p-1 border-b border-gray-300">
|
||||
<input v-model="peersSearchTerm" type="text" :placeholder="`Search ${peersCount} Peers...`" class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5">
|
||||
</div>
|
||||
|
||||
<!-- peers -->
|
||||
<div class="flex h-full overflow-y-auto">
|
||||
<div v-if="searchedPeers.length > 0" class="w-full">
|
||||
<div @click="onPeerClick(peer)" v-for="peer of searchedPeers" class="flex cursor-pointer p-2 border-l-2" :class="[ peer.destination_hash === selectedDestinationHash ? 'bg-gray-100 border-blue-500' : 'bg-white border-transparent hover:bg-gray-50 hover:border-gray-200' ]">
|
||||
<div class="my-auto mr-2">
|
||||
<div class="bg-gray-200 text-gray-500 p-2 rounded">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 6a3.75 3.75 0 1 1-7.5 0 3.75 3.75 0 0 1 7.5 0ZM4.501 20.118a7.5 7.5 0 0 1 14.998 0A17.933 17.933 0 0 1 12 21.75c-2.676 0-5.216-.584-7.499-1.632Z" />
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div class="text-gray-900">{{ peer.name }}</div>
|
||||
<div class="text-gray-500 text-sm">{{ formatTimeAgo(peer.updated_at) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mx-auto my-auto text-center leading-5">
|
||||
|
||||
<!-- no peers at all -->
|
||||
<div v-if="peersCount === 0" class="flex flex-col">
|
||||
<div class="mx-auto mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.879 7.519c1.171-1.025 3.071-1.025 4.242 0 1.172 1.025 1.172 2.687 0 3.712-.203.179-.43.326-.67.442-.745.361-1.45.999-1.45 1.827v.75M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9 5.25h.008v.008H12v-.008Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-semibold">No Peers Discovered</div>
|
||||
<div>Waiting for someone to announce!</div>
|
||||
</div>
|
||||
|
||||
<!-- is searching, but no results -->
|
||||
<div v-if="peersSearchTerm !== '' && peersCount > 0" class="flex flex-col">
|
||||
<div class="mx-auto mb-1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-6 h-6">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
|
||||
</svg>
|
||||
</div>
|
||||
<div class="font-semibold">No Search Results</div>
|
||||
<div>Your search didn't match any Peers!</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Utils from "../../js/Utils";
|
||||
|
||||
export default {
|
||||
name: 'MessagesSidebar',
|
||||
props: {
|
||||
peers: Object,
|
||||
conversations: Array,
|
||||
selectedDestinationHash: String,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
tab: "conversations",
|
||||
conversationsSearchTerm: "",
|
||||
peersSearchTerm: "",
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
|
||||
},
|
||||
methods: {
|
||||
onConversationClick(conversation) {
|
||||
this.$emit("conversation-click", conversation);
|
||||
},
|
||||
onPeerClick(peer) {
|
||||
this.$emit("peer-click", peer);
|
||||
},
|
||||
formatTimeAgo: function(datetimeString) {
|
||||
return Utils.formatTimeAgo(datetimeString);
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
searchedConversations() {
|
||||
return this.conversations.filter((conversation) => {
|
||||
const search = this.conversationsSearchTerm.toLowerCase();
|
||||
const matchesName = conversation.name.toLowerCase().includes(search);
|
||||
const matchesDestinationHash = conversation.destination_hash.toLowerCase().includes(search);
|
||||
return matchesName || matchesDestinationHash;
|
||||
});
|
||||
},
|
||||
peersCount() {
|
||||
return Object.keys(this.peers).length;
|
||||
},
|
||||
peersOrderedByLatestAnnounce() {
|
||||
const peers = Object.values(this.peers);
|
||||
return peers.sort(function(peerA, peerB) {
|
||||
// order by updated_at desc
|
||||
const peerAUpdatedAt = new Date(peerA.updated_at).getTime();
|
||||
const peerBUpdatedAt = new Date(peerB.updated_at).getTime();
|
||||
return peerBUpdatedAt - peerAUpdatedAt;
|
||||
});
|
||||
},
|
||||
searchedPeers() {
|
||||
return this.peersOrderedByLatestAnnounce.filter((peer) => {
|
||||
const search = this.peersSearchTerm.toLowerCase();
|
||||
const matchesAppData = peer.name.toLowerCase().includes(search);
|
||||
const matchesDestinationHash = peer.destination_hash.toLowerCase().includes(search);
|
||||
return matchesAppData || matchesDestinationHash;
|
||||
});
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
|
@ -16,6 +16,62 @@ class Utils {
|
|||
|
||||
}
|
||||
|
||||
static parseSeconds(secondsToFormat) {
|
||||
secondsToFormat = Number(secondsToFormat);
|
||||
var days = Math.floor(secondsToFormat / (3600 * 24));
|
||||
var hours = Math.floor((secondsToFormat % (3600 * 24)) / 3600);
|
||||
var minutes = Math.floor((secondsToFormat % 3600) / 60);
|
||||
var seconds = Math.floor(secondsToFormat % 60);
|
||||
return {
|
||||
days: days,
|
||||
hours: hours,
|
||||
minutes: minutes,
|
||||
seconds: seconds,
|
||||
};
|
||||
}
|
||||
|
||||
static formatSeconds(seconds) {
|
||||
|
||||
const parsedSeconds = this.parseSeconds(seconds);
|
||||
|
||||
if(parsedSeconds.days > 0){
|
||||
if(parsedSeconds.days === 1){
|
||||
return "1 day ago";
|
||||
} else {
|
||||
return parsedSeconds.days + " days ago";
|
||||
}
|
||||
}
|
||||
|
||||
if(parsedSeconds.hours > 0){
|
||||
if(parsedSeconds.hours === 1){
|
||||
return "1 hour ago";
|
||||
} else {
|
||||
return parsedSeconds.hours + " hours ago";
|
||||
}
|
||||
}
|
||||
|
||||
if(parsedSeconds.minutes > 0){
|
||||
if(parsedSeconds.minutes === 1){
|
||||
return "a minute ago";
|
||||
} else {
|
||||
return parsedSeconds.minutes + " minutes ago";
|
||||
}
|
||||
}
|
||||
|
||||
if(parsedSeconds.seconds <= 1){
|
||||
return "a second ago";
|
||||
} else {
|
||||
return parsedSeconds.seconds + " seconds ago";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static formatTimeAgo(datetimeString) {
|
||||
const millisecondsAgo = Date.now() - new Date(datetimeString).getTime();
|
||||
const secondsAgo = Math.round(millisecondsAgo / 1000);
|
||||
return this.formatSeconds(secondsAgo);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Utils;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue