mirror of
https://github.com/sky-systems/sky_phone.git
synced 2026-09-01 18:58:58 +00:00
ENH - prioritize recent SMS contacts
This commit is contained in:
@@ -8,6 +8,7 @@ import type {
|
||||
SmsMessage,
|
||||
SmsOutgoingMessage,
|
||||
} from '@/types/messages'
|
||||
import { sortConversationsByRecency } from '@/utils/messages'
|
||||
import { nuiCall, type NuiResponse } from '@/utils/nui'
|
||||
|
||||
export const useMessagesStore = defineStore('messages', () => {
|
||||
@@ -23,10 +24,12 @@ export const useMessagesStore = defineStore('messages', () => {
|
||||
async function loadConversations(): Promise<boolean> {
|
||||
const response = await nuiCall<SmsConversation[]>('messages:conversations')
|
||||
if (response.success && response.data) {
|
||||
conversations.value = response.data.map((conversation) => ({
|
||||
...conversation,
|
||||
phoneNumber: String(conversation.phoneNumber),
|
||||
}))
|
||||
conversations.value = sortConversationsByRecency(
|
||||
response.data.map((conversation) => ({
|
||||
...conversation,
|
||||
phoneNumber: String(conversation.phoneNumber),
|
||||
})),
|
||||
)
|
||||
}
|
||||
else if (!response.success) conversations.value = []
|
||||
return response.success
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
import type { SmsConversation } from '@/types/messages'
|
||||
import {
|
||||
sortContactsByMessageRecency,
|
||||
sortConversationsByRecency,
|
||||
} from '@/utils/messages'
|
||||
|
||||
function conversation(
|
||||
phoneNumber: string,
|
||||
lastMessageAt: string,
|
||||
): SmsConversation {
|
||||
return {
|
||||
lastMessage: phoneNumber,
|
||||
lastMessageAt,
|
||||
lastMessageType: 'text',
|
||||
phoneNumber,
|
||||
unread: 0,
|
||||
}
|
||||
}
|
||||
|
||||
const conversations = [
|
||||
conversation('5550000001', '2026-08-12 10:00:00'),
|
||||
conversation('5550000002', '2026-08-12 12:00:00'),
|
||||
]
|
||||
|
||||
describe('SMS recency ordering', () => {
|
||||
it('places the conversation with the newest message first', () => {
|
||||
expect(
|
||||
sortConversationsByRecency(conversations).map(
|
||||
(item) => item.phoneNumber,
|
||||
),
|
||||
).toEqual(['5550000002', '5550000001'])
|
||||
})
|
||||
|
||||
it('places recently messaged contacts before unused contacts', () => {
|
||||
const contacts = [
|
||||
{ name: 'Unused', phone_number: '5550000003' },
|
||||
{ name: 'Older', phone_number: '5550000001' },
|
||||
{ name: 'Newest', phone_number: '5550000002' },
|
||||
]
|
||||
|
||||
expect(
|
||||
sortContactsByMessageRecency(contacts, conversations).map(
|
||||
(item) => item.name,
|
||||
),
|
||||
).toEqual(['Newest', 'Older', 'Unused'])
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,43 @@
|
||||
import type { SmsConversation } from '@/types/messages'
|
||||
import { parseDatabaseDate } from '@/utils/date'
|
||||
|
||||
function conversationTime(conversation: SmsConversation): number {
|
||||
const timestamp = parseDatabaseDate(conversation.lastMessageAt).getTime()
|
||||
return Number.isNaN(timestamp) ? 0 : timestamp
|
||||
}
|
||||
|
||||
export function sortConversationsByRecency(
|
||||
conversations: SmsConversation[],
|
||||
): SmsConversation[] {
|
||||
return conversations
|
||||
.map((conversation, index) => ({ conversation, index }))
|
||||
.sort(
|
||||
(left, right) =>
|
||||
conversationTime(right.conversation) -
|
||||
conversationTime(left.conversation) || left.index - right.index,
|
||||
)
|
||||
.map(({ conversation }) => conversation)
|
||||
}
|
||||
|
||||
export function sortContactsByMessageRecency<
|
||||
T extends { phone_number: string },
|
||||
>(contacts: T[], conversations: SmsConversation[]): T[] {
|
||||
const activity = new Map(
|
||||
conversations.map((conversation) => [
|
||||
conversation.phoneNumber,
|
||||
conversationTime(conversation),
|
||||
]),
|
||||
)
|
||||
return contacts
|
||||
.map((contact, index) => ({ contact, index }))
|
||||
.sort((left, right) => {
|
||||
const leftActivity = activity.get(left.contact.phone_number)
|
||||
const rightActivity = activity.get(right.contact.phone_number)
|
||||
if (leftActivity === undefined && rightActivity === undefined)
|
||||
return left.index - right.index
|
||||
if (leftActivity === undefined) return 1
|
||||
if (rightActivity === undefined) return -1
|
||||
return rightActivity - leftActivity || left.index - right.index
|
||||
})
|
||||
.map(({ contact }) => contact)
|
||||
}
|
||||
@@ -54,6 +54,7 @@ import { useMessagesStore } from '@/stores/messages'
|
||||
import { useMessageMediaStore } from '@/stores/messageMedia'
|
||||
import { usePhoneStore } from '@/stores/phone'
|
||||
import { parseDatabaseDate, type DatabaseDateValue } from '@/utils/date'
|
||||
import { sortContactsByMessageRecency } from '@/utils/messages'
|
||||
import type {
|
||||
GifSearchResult,
|
||||
SmsAttachmentType,
|
||||
@@ -139,8 +140,9 @@ const contactAvatarUrls = computed(
|
||||
)
|
||||
const contactSuggestions = computed(() => {
|
||||
const query = composerNumber.value.trim().toLocaleLowerCase(phone.lang)
|
||||
const contacts = calls.contacts.filter(
|
||||
(contact) => contact.canMessage !== false,
|
||||
const contacts = sortContactsByMessageRecency(
|
||||
calls.contacts.filter((contact) => contact.canMessage !== false),
|
||||
messages.conversations,
|
||||
)
|
||||
if (!query) return contacts.slice(0, 8)
|
||||
return contacts
|
||||
|
||||
Reference in New Issue
Block a user