@plteam/chat-ui
Version:
CUI Kit is a free and open-source library for creating AI assistant chat interfaces, built with React, Material UI, and TypeScript
130 lines (129 loc) • 5.42 kB
JavaScript
import moment from 'moment/moment';
import { langReplace } from '../locale/langReplace';
import { capitalizeFirstLetter } from '../utils/stringUtils/capitalizeFirstLetter';
import { ObservableReactValue } from '../utils/observers';
import { ThreadListGroupItem } from './ThreadListGroupItem';
export class ThreadListCache {
groupValues = new ObservableReactValue({});
menuConfig = new ObservableReactValue(undefined);
audit = (locale, threads) => {
const currentMap = this.groupValues.value;
const pinnedThreads = threads.filter(t => t.pinnedAt.value != null);
const unpinnedThreads = threads.filter(t => t.pinnedAt.value == null);
const basicGroups = {
today: {
id: 'today',
timestamp: moment().startOf('day').unix(),
label: locale.historyToday,
},
yesterday: {
id: 'yesterday',
timestamp: moment().subtract(1, 'days').startOf('day').unix(),
label: locale.historyYesterday,
},
last7Days: {
id: 'last7Days',
timestamp: moment().subtract(7, 'days').startOf('day').unix(),
label: langReplace(locale.historyPreviousNDays, { days: 7 }),
},
last30Days: {
id: 'last30Days',
timestamp: moment().subtract(30, 'days').startOf('day').unix(),
label: langReplace(locale.historyPreviousNDays, { days: 30 }),
},
};
const basicKeys = Object.keys(basicGroups);
const startOfYear = moment().startOf('year').unix();
const results = {};
const threadsAffiliation = {};
if (pinnedThreads.length) {
results['__pinned__'] = {
id: '__pinned__',
label: locale.historyPinned,
timestamp: Number.MAX_SAFE_INTEGER,
};
threadsAffiliation['__pinned__'] = pinnedThreads;
}
unpinnedThreads.forEach((item) => {
const timestamp = item.timestamp.value;
let groupKey = 'other';
if (timestamp) {
const basicGroupKey = basicKeys.find(v => timestamp >= basicGroups[v].timestamp);
if (basicGroupKey) {
results[basicGroupKey] = { ...basicGroups[basicGroupKey] };
groupKey = basicGroupKey;
}
else if (timestamp >= startOfYear) {
const month = moment.unix(timestamp).startOf('month');
const monthEn = capitalizeFirstLetter(month.locale('en').format('MMMM'));
results[monthEn] = {
label: locale[`history${monthEn}`],
timestamp: month.unix(),
id: monthEn,
};
groupKey = monthEn;
}
else {
const year = moment.unix(timestamp).startOf('year');
const yearLang = year.format('YYYY');
const yearKey = `year${yearLang}`;
results[yearKey] = {
label: yearLang,
timestamp: year.unix(),
id: yearKey,
};
groupKey = yearKey;
}
}
else {
results['other'] = {
label: 'Other',
timestamp: 0,
id: 'Other',
};
}
if (!threadsAffiliation[groupKey]) {
threadsAffiliation[groupKey] = [];
}
threadsAffiliation[groupKey].push(item);
});
// Check the group for deleted threads in it
const gValues = Object.values(this.groupValues.value);
for (const gValue of gValues) {
const newThreads = [...gValue.threads.value];
let changed = false;
for (const thread of newThreads) {
const index = threads.findIndex(v => v.id === thread.id);
if (index === -1) {
changed = true;
newThreads.splice(index, 1);
}
}
if (changed) {
gValue.threads.value = newThreads;
}
}
let changed = false;
for (const key in results) {
let groupModel = currentMap[key];
if (!groupModel) {
changed = true;
groupModel = new ThreadListGroupItem(results[key]);
currentMap[key] = groupModel;
}
const comparator = key === '__pinned__'
? (a, b) => (b.pinnedAt.value ?? 0) - (a.pinnedAt.value ?? 0)
: undefined;
groupModel.checkList(threadsAffiliation[key] ?? [], comparator);
}
// Empty out groups that are no longer in results (e.g. a thread moved to pinned)
for (const key in currentMap) {
if (!(key in results)) {
currentMap[key].checkList([]);
}
}
if (changed) {
this.groupValues.value = { ...currentMap };
}
};
}