105 lines
3.0 KiB
TypeScript
105 lines
3.0 KiB
TypeScript
import { useCallback, useMemo } from 'react';
|
|
import { useMatrixClient } from './useMatrixClient';
|
|
import { useAccountData } from './useAccountData';
|
|
|
|
const PAARROT_EMOJI_USAGE_EVENT = 'paarrot.favemojis';
|
|
const MAX_TRACKED_EMOJIS = 50;
|
|
|
|
export type EmojiUsageData = {
|
|
[shortcode: string]: {
|
|
count: number;
|
|
lastUsed: number;
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Hook for tracking emoji usage and storing favorites in Matrix account data
|
|
* Stores emoji usage stats under paarrot.favemojis in user's account data
|
|
*/
|
|
export function useEmojiUsage() {
|
|
const mx = useMatrixClient();
|
|
const event = useAccountData(PAARROT_EMOJI_USAGE_EVENT);
|
|
|
|
const emojiUsage = useMemo((): EmojiUsageData => {
|
|
const content = event?.getContent<EmojiUsageData>();
|
|
return content || {};
|
|
}, [event]);
|
|
|
|
/**
|
|
* Track emoji usage (max 1 per message as per spec)
|
|
* @param shortcode - Emoji shortcode (e.g., 'thumbsup', 'smile')
|
|
*/
|
|
const trackEmojiUsage = useCallback(
|
|
async (shortcode: string) => {
|
|
const now = Date.now();
|
|
const currentUsage = { ...emojiUsage };
|
|
|
|
// Update or create emoji entry
|
|
currentUsage[shortcode] = {
|
|
count: (currentUsage[shortcode]?.count || 0) + 1,
|
|
lastUsed: now,
|
|
};
|
|
|
|
// Keep only top MAX_TRACKED_EMOJIS by usage count
|
|
const entries = Object.entries(currentUsage);
|
|
if (entries.length > MAX_TRACKED_EMOJIS) {
|
|
entries.sort((a, b) => b[1].count - a[1].count);
|
|
const topEmojis = entries.slice(0, MAX_TRACKED_EMOJIS);
|
|
const newUsage: EmojiUsageData = {};
|
|
topEmojis.forEach(([key, value]) => {
|
|
newUsage[key] = value;
|
|
});
|
|
await mx.setAccountData(PAARROT_EMOJI_USAGE_EVENT, newUsage);
|
|
} else {
|
|
await mx.setAccountData(PAARROT_EMOJI_USAGE_EVENT, currentUsage);
|
|
}
|
|
},
|
|
[mx, emojiUsage]
|
|
);
|
|
|
|
/**
|
|
* Get most used emoji shortcode
|
|
* @returns Shortcode of most used emoji, or undefined if none tracked
|
|
*/
|
|
const getMostUsedEmoji = useCallback((): string | undefined => {
|
|
const entries = Object.entries(emojiUsage);
|
|
if (entries.length === 0) return undefined;
|
|
|
|
// Sort by count descending, then by lastUsed descending
|
|
entries.sort((a, b) => {
|
|
if (b[1].count !== a[1].count) {
|
|
return b[1].count - a[1].count;
|
|
}
|
|
return b[1].lastUsed - a[1].lastUsed;
|
|
});
|
|
|
|
return entries[0][0];
|
|
}, [emojiUsage]);
|
|
|
|
/**
|
|
* Get top N most used emojis
|
|
* @param count - Number of top emojis to return
|
|
* @returns Array of shortcodes sorted by usage
|
|
*/
|
|
const getTopEmojis = useCallback(
|
|
(count: number = 10): string[] => {
|
|
const entries = Object.entries(emojiUsage);
|
|
entries.sort((a, b) => {
|
|
if (b[1].count !== a[1].count) {
|
|
return b[1].count - a[1].count;
|
|
}
|
|
return b[1].lastUsed - a[1].lastUsed;
|
|
});
|
|
return entries.slice(0, count).map(([shortcode]) => shortcode);
|
|
},
|
|
[emojiUsage]
|
|
);
|
|
|
|
return {
|
|
emojiUsage,
|
|
trackEmojiUsage,
|
|
getMostUsedEmoji,
|
|
getTopEmojis,
|
|
};
|
|
}
|