mirror of
https://github.com/irislib/iris-messenger.git
synced 2024-09-19 17:46:33 +00:00
Merge branch 'master' into production
This commit is contained in:
commit
c05b17e878
@ -61,7 +61,7 @@ npm run test
|
||||
```
|
||||
|
||||
</details>
|
||||
<br/>
|
||||
|
||||
[iris.to](https://iris.to) production version is in the [stable](https://github.com/irislib/iris-messenger/tree/stable) branch.
|
||||
|
||||
### Tauri (desktop app)
|
||||
|
21
src/js/components/ErrorBoundary.tsx
Normal file
21
src/js/components/ErrorBoundary.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import { Component } from 'preact';
|
||||
|
||||
export default class ErrorBoundary extends Component {
|
||||
state = { error: null };
|
||||
|
||||
static getDerivedStateFromError(error) {
|
||||
return { error: error.message };
|
||||
}
|
||||
|
||||
componentDidCatch(error) {
|
||||
console.error(error);
|
||||
this.setState({ error: error.message });
|
||||
}
|
||||
|
||||
render() {
|
||||
if (this.state.error) {
|
||||
return <p style="padding: 0 10px">Error: {this.state.error}</p>;
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ import { translate as t } from '../translations/Translation';
|
||||
|
||||
import Button from './buttons/Button';
|
||||
import EventComponent from './events/EventComponent';
|
||||
import ErrorBoundary from './ErrorBoundary';
|
||||
|
||||
const INITIAL_PAGE_SIZE = 20;
|
||||
|
||||
@ -122,7 +123,7 @@ class Feed extends Component {
|
||||
if (this.state.displayCount < this.state.sortedMessages.length) {
|
||||
if (
|
||||
this.props.scrollElement.scrollTop + this.props.scrollElement.clientHeight >=
|
||||
this.props.scrollElement.scrollHeight - 500
|
||||
this.props.scrollElement.scrollHeight - 1000
|
||||
) {
|
||||
this.setState({ displayCount: this.state.displayCount + INITIAL_PAGE_SIZE });
|
||||
}
|
||||
@ -176,6 +177,7 @@ class Feed extends Component {
|
||||
}
|
||||
|
||||
subscribe() {
|
||||
// TODO use LokiJS persistent dynamicviews so the result set is not recalculated all the time
|
||||
setTimeout(() => {
|
||||
this.unsub?.();
|
||||
let first = true;
|
||||
@ -218,6 +220,9 @@ class Feed extends Component {
|
||||
sort(a, b) {
|
||||
let aVal;
|
||||
let bVal;
|
||||
if (!a || !b) return 0;
|
||||
if (a && !b) return -1;
|
||||
if (!a && b) return 1;
|
||||
if (this.state.settings.sortBy === 'created_at') {
|
||||
aVal = a.created_at;
|
||||
bVal = b.created_at;
|
||||
@ -238,12 +243,11 @@ class Feed extends Component {
|
||||
getPostsAndRepliesByUser(pubkey, includeReplies) {
|
||||
this.unsub?.();
|
||||
// TODO apply filters
|
||||
const desc = this.state.settings.sortDirection === 'desc';
|
||||
const callback = () => {
|
||||
// throttle?
|
||||
const events = Events.db
|
||||
.chain()
|
||||
.find({ pubkey })
|
||||
.find({ pubkey, kind: 1 })
|
||||
.where((e) => {
|
||||
// TODO apply all filters from state.settings
|
||||
if (!includeReplies && e.tags.find((t) => t[0] === 'e')) {
|
||||
@ -257,58 +261,65 @@ class Feed extends Component {
|
||||
this.updateSortedMessages(events);
|
||||
};
|
||||
callback();
|
||||
this.unsub = PubSub.subscribe([{ kinds: [1, 3, 5, 7, 9735], limit: 100 }], callback, 'global');
|
||||
this.unsub = PubSub.subscribe([{ kinds: [1, 5, 7], authors: [pubkey] }], callback);
|
||||
}
|
||||
|
||||
getMessagesByEveryone() {
|
||||
this.unsub?.();
|
||||
const settings = this.state.settings;
|
||||
// TODO apply filters
|
||||
const desc = this.state.settings.sortDirection === 'desc';
|
||||
const callback = () => {
|
||||
// throttle?
|
||||
const events = Events.db
|
||||
.chain()
|
||||
.where((e) => {
|
||||
// TODO apply all filters from state.settings
|
||||
if (!this.state.settings.replies && e.tags.find((t) => t[0] === 'e')) {
|
||||
const dv = Events.db.addDynamicView('everyone');
|
||||
dv.applyFind({ kind: 1 });
|
||||
dv.applyWhere((e) => {
|
||||
if (!settings.replies && e.tags.find((t) => t[0] === 'e')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.data()
|
||||
.sort((a, b) => this.sort(a, b)) // why loki simplesort doesn't work?
|
||||
.map((e) => e.id);
|
||||
});
|
||||
const simpleSortDesc =
|
||||
settings.sortBy === 'created_at' ? settings.sortDirection === 'desc' : true;
|
||||
dv.applySimpleSort('created_at', { desc: simpleSortDesc });
|
||||
if (settings.sortBy !== 'created_at') {
|
||||
dv.applySort((a, b) => this.sort(a, b));
|
||||
}
|
||||
const callback = throttle(() => {
|
||||
const events = dv.data().map((e) => e.id);
|
||||
this.updateSortedMessages(events);
|
||||
};
|
||||
}, 1000);
|
||||
callback();
|
||||
this.unsub = PubSub.subscribe([{ kinds: [1, 3, 5, 7, 9735], limit: 100 }], callback, 'global');
|
||||
}
|
||||
|
||||
getMessagesByFollows() {
|
||||
this.unsub?.();
|
||||
const desc = this.state.settings.sortDirection === 'desc';
|
||||
const callback = () => {
|
||||
// throttle?
|
||||
const events = Events.db
|
||||
.chain()
|
||||
.where((e) => {
|
||||
// TODO apply all filters from state.settings
|
||||
if (!(SocialNetwork.followDistanceByUser.get(e.pubkey) <= 1)) {
|
||||
const dv = Events.db.addDynamicView('follows');
|
||||
dv.applyFind({ kind: 1 });
|
||||
dv.applyWhere((e) => {
|
||||
const followDistance = SocialNetwork.followDistanceByUser.get(e.pubkey);
|
||||
if (!followDistance || followDistance > 1) {
|
||||
return false;
|
||||
}
|
||||
if (!this.state.settings.replies && e.tags.find((t) => t[0] === 'e')) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.data()
|
||||
.sort((a, b) => this.sort(a, b)) // why loki simplesort doesn't work?
|
||||
.map((e) => e.id);
|
||||
});
|
||||
const simpleSortDesc =
|
||||
this.state.settings.sortBy === 'created_at'
|
||||
? this.state.settings.sortDirection === 'desc'
|
||||
: true;
|
||||
dv.applySimpleSort('created_at', { desc: simpleSortDesc });
|
||||
if (this.state.settings.sortBy !== 'created_at') {
|
||||
dv.applySort((a, b) => this.sort(a, b));
|
||||
}
|
||||
const callback = throttle(() => {
|
||||
// throttle?
|
||||
const events = dv.data().map((e) => e.id);
|
||||
this.updateSortedMessages(events);
|
||||
};
|
||||
}, 1000);
|
||||
|
||||
callback();
|
||||
this.unsub = PubSub.subscribe([{ kinds: [1, 3, 5, 7, 9735] }], callback);
|
||||
this.unsub = PubSub.subscribe([{ kinds: [1, 3, 5, 7, 9735] }], callback, 'global');
|
||||
}
|
||||
|
||||
updateParams(prevState) {
|
||||
@ -319,7 +330,7 @@ class Feed extends Component {
|
||||
} else {
|
||||
url.searchParams.delete('display');
|
||||
}
|
||||
window.history.replaceState({ ...window.history.state, state: this.state }, '', url);
|
||||
this.replaceState();
|
||||
}
|
||||
if (prevState.settings.replies !== this.state.settings.replies) {
|
||||
const url = new URL(window.location);
|
||||
@ -328,7 +339,7 @@ class Feed extends Component {
|
||||
} else {
|
||||
url.searchParams.delete('replies');
|
||||
}
|
||||
window.history.replaceState({ ...window.history.state, state: this.state }, '', url);
|
||||
this.replaceState();
|
||||
}
|
||||
if (prevState.settings.realtime !== this.state.settings.realtime) {
|
||||
const url = new URL(window.location);
|
||||
@ -337,10 +348,18 @@ class Feed extends Component {
|
||||
} else {
|
||||
url.searchParams.delete('realtime');
|
||||
}
|
||||
window.history.replaceState({ ...window.history.state, state: this.state }, '', url);
|
||||
this.replaceState();
|
||||
}
|
||||
}
|
||||
|
||||
replaceState = throttle(
|
||||
() => {
|
||||
window.history.replaceState({ ...window.history.state, state: this.state }, '');
|
||||
},
|
||||
1000,
|
||||
{ leading: true, trailing: true },
|
||||
);
|
||||
|
||||
componentDidUpdate(prevProps, prevState) {
|
||||
if (!prevProps.scrollElement && this.props.scrollElement) {
|
||||
this.addScrollHandler();
|
||||
@ -356,7 +375,7 @@ class Feed extends Component {
|
||||
this.subscribe();
|
||||
}
|
||||
this.handleScroll();
|
||||
window.history.replaceState({ ...window.history.state, state: this.state }, '');
|
||||
this.replaceState();
|
||||
if (!this.state.queuedMessages.length && prevState.queuedMessages.length) {
|
||||
Helpers.animateScrollTop('.main-view');
|
||||
}
|
||||
@ -544,9 +563,8 @@ class Feed extends Component {
|
||||
}[this.props.index];
|
||||
|
||||
const renderAs = this.state.settings.display === 'grid' ? 'NoteImage' : null;
|
||||
const messages = this.state.sortedMessages
|
||||
.slice(0, displayCount)
|
||||
.map((id) => (
|
||||
const messages = this.state.sortedMessages.slice(0, displayCount).map((id) => (
|
||||
<ErrorBoundary>
|
||||
<EventComponent
|
||||
notification={this.props.index === 'notifications'}
|
||||
key={id}
|
||||
@ -555,6 +573,7 @@ class Feed extends Component {
|
||||
renderAs={renderAs}
|
||||
feedOpenedAt={this.openedAt}
|
||||
/>
|
||||
</ErrorBoundary>
|
||||
));
|
||||
return (
|
||||
<div className="msg-feed">
|
||||
|
@ -29,7 +29,7 @@ export default class Menu extends Component {
|
||||
}
|
||||
|
||||
menuLinkClicked(e, a) {
|
||||
if (a.text === 'feeds') {
|
||||
if (a?.text === 'feeds') {
|
||||
this.handleFeedClick(e);
|
||||
}
|
||||
localState.get('toggleMenu').put(false);
|
||||
|
@ -51,8 +51,12 @@ const onClick = (event, noteId) => {
|
||||
|
||||
export default function NoteImage(props: { event: Event; fadeIn?: boolean }) {
|
||||
// get first image url from event content
|
||||
if (props.event.kind !== 1) {
|
||||
console.log('not a note', props.event);
|
||||
return null;
|
||||
}
|
||||
const attachments = [];
|
||||
const urls = props.event.content.match(/(https?:\/\/[^\s]+)/g);
|
||||
const urls = props.event.content?.match(/(https?:\/\/[^\s]+)/g);
|
||||
if (urls) {
|
||||
urls.forEach((url) => {
|
||||
let parsedUrl;
|
||||
@ -63,7 +67,7 @@ export default function NoteImage(props: { event: Event; fadeIn?: boolean }) {
|
||||
return;
|
||||
}
|
||||
if (parsedUrl.pathname.toLowerCase().match(/\.(jpg|jpeg|gif|png|webp)$/)) {
|
||||
attachments.push({ type: 'image', data: `${parsedUrl.href}` });
|
||||
attachments.push({ type: 'image', data: parsedUrl.href });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ const MAX_ZAPS_BY_NOTE = 1000;
|
||||
|
||||
const db = new Loki('iris');
|
||||
const events = db.addCollection('events', {
|
||||
indices: ['created_at', 'pubkey'],
|
||||
indices: ['created_at', 'pubkey', 'kind'],
|
||||
unique: ['id'],
|
||||
});
|
||||
|
||||
@ -105,34 +105,6 @@ const Events = {
|
||||
}
|
||||
}
|
||||
},
|
||||
deleteRepostedMsgsFromFeeds(event: Event, feeds: SortedLimitedEventSet[]) {
|
||||
const repostedEventId = this.getRepostedEventId(event);
|
||||
const repostedEvent = this.db.by('id', repostedEventId);
|
||||
// checking that someone isn't hiding posts from feeds with backdated reposts of them
|
||||
if (repostedEvent?.created_at < event.created_at) {
|
||||
const otherReposts = this.repostsByMessageId.get(repostedEventId);
|
||||
for (const feed of feeds) {
|
||||
feed.delete(repostedEventId);
|
||||
if (otherReposts) {
|
||||
for (const repostId of otherReposts) {
|
||||
if (repostId !== event.id) {
|
||||
feed.delete(repostId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
deleteRepliedMsgsFromFeeds(event: Event, feeds: SortedLimitedEventSet[]) {
|
||||
const replyingToEventId = this.getNoteReplyingTo(event);
|
||||
const replyingToEvent = this.db.by('id', replyingToEventId);
|
||||
// checking that someone isn't hiding posts from feeds with backdated replies to them
|
||||
if (replyingToEvent?.created_at < event.created_at) {
|
||||
for (const feed of feeds) {
|
||||
feed.delete(replyingToEventId);
|
||||
}
|
||||
}
|
||||
},
|
||||
getRepostedEventId(event: Event) {
|
||||
let id = event.tags?.find((tag) => tag[0] === 'e' && tag[3] === 'mention')?.[1];
|
||||
if (id) {
|
||||
@ -285,9 +257,11 @@ const Events = {
|
||||
},
|
||||
insert(event: Event) {
|
||||
try {
|
||||
delete event['$loki'];
|
||||
this.db.insert(event);
|
||||
} catch (e) {
|
||||
console.log('failed to insert event', e);
|
||||
console.log('failed to insert event', e, typeof e);
|
||||
// suppress error on duplicate insert. lokijs should throw a different error kind?
|
||||
}
|
||||
},
|
||||
handleMetadata(event: Event) {
|
||||
@ -421,13 +395,13 @@ const Events = {
|
||||
}
|
||||
return true;
|
||||
},
|
||||
handle(event: Event, force = false, saveToIdb = true) {
|
||||
handle(event: Event, force = false, saveToIdb = true): boolean {
|
||||
if (!event) return;
|
||||
if (!force && !!this.db.by('id', event.id)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!force && !this.acceptEvent(event)) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
// Accepting metadata so we still get their name. But should we instead save the name on our own list?
|
||||
// They might spam with 1 MB events and keep changing their name or something.
|
||||
@ -456,7 +430,7 @@ const Events = {
|
||||
switch (event.kind) {
|
||||
case 0:
|
||||
if (this.handleMetadata(event) === false) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
@ -475,7 +449,7 @@ const Events = {
|
||||
break;
|
||||
case 3:
|
||||
if (SocialNetwork.followEventByUser.get(event.pubkey)?.created_at >= event.created_at) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
this.maybeAddNotification(event);
|
||||
this.handleFollow(event);
|
||||
@ -516,12 +490,12 @@ const Events = {
|
||||
// TODO: don't save e.g. old profile & follow events
|
||||
// TODO since we're only querying relays since lastSeen, we need to store all beforeseen events and correctly query them on demand
|
||||
// otherwise feed will be incomplete
|
||||
const followDistance = SocialNetwork.followDistanceByUser.get(event.pubkey);
|
||||
if (saveToIdb) {
|
||||
const followDistance = SocialNetwork.followDistanceByUser.get(event.pubkey);
|
||||
if (followDistance <= 1) {
|
||||
// save all our own events and events from people we follow
|
||||
IndexedDB.saveEvent(event as Event & { id: string });
|
||||
} else if (followDistance <= 4) {
|
||||
} else if (followDistance <= 4 && [0, 3].includes(event.kind)) {
|
||||
// save profiles and follow events up to follow distance 4
|
||||
IndexedDB.saveEvent(event as Event & { id: string });
|
||||
}
|
||||
@ -530,12 +504,13 @@ const Events = {
|
||||
// go through subscriptions and callback if filters match
|
||||
for (const sub of PubSub.subscriptions.values()) {
|
||||
if (!sub.filters) {
|
||||
return;
|
||||
continue;
|
||||
}
|
||||
if (this.matchesOneFilter(event, sub.filters)) {
|
||||
if (this.matchFilters(event, sub.filters)) {
|
||||
sub.callback && sub.callback(event);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
},
|
||||
handleNextFutureEvent() {
|
||||
if (this.futureEventIds.size === 0) {
|
||||
@ -554,7 +529,7 @@ const Events = {
|
||||
}, (nextEvent.created_at - Date.now() / 1000) * 1000);
|
||||
},
|
||||
// if one of the filters matches, return true
|
||||
matchesOneFilter(event: Event, filters: Filter[]) {
|
||||
matchFilters(event: Event, filters: Filter[]) {
|
||||
for (const filter of filters) {
|
||||
if (this.matchFilter(event, filter)) {
|
||||
return true;
|
||||
|
@ -1,10 +1,10 @@
|
||||
import Dexie, { Table } from 'dexie';
|
||||
import { throttle } from 'lodash';
|
||||
|
||||
import { Event, Filter, matchFilter } from '../lib/nostr-tools';
|
||||
|
||||
import Events from './Events';
|
||||
import Key from './Key';
|
||||
import SocialNetwork from './SocialNetwork';
|
||||
export class MyDexie extends Dexie {
|
||||
events!: Table<Event & { id: string }>;
|
||||
|
||||
@ -21,38 +21,32 @@ const db = new MyDexie();
|
||||
export default {
|
||||
db,
|
||||
subscriptions: new Set<string>(),
|
||||
saveQueue: [] as Event[],
|
||||
clear() {
|
||||
return db.delete();
|
||||
},
|
||||
saveEvent(event: Event & { id: string }) {
|
||||
db.events
|
||||
.add(event)
|
||||
.catch('ConstraintError', () => {
|
||||
// fails if already exists
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error('error saving event', e);
|
||||
save: throttle((_this) => {
|
||||
const events = _this.saveQueue;
|
||||
_this.saveQueue = [];
|
||||
db.events.bulkAdd(events).catch((e) => {
|
||||
// lots of "already exists" errors
|
||||
// console.error('error saving events', e);
|
||||
});
|
||||
}, 500),
|
||||
saveEvent(event: Event & { id: string }) {
|
||||
this.saveQueue.push(event);
|
||||
this.save(this);
|
||||
},
|
||||
init() {
|
||||
const myPub = Key.getPubKey();
|
||||
let follows: string[];
|
||||
db.events
|
||||
.where({ pubkey: myPub })
|
||||
.each((event) => {
|
||||
Events.handle(event, false, false);
|
||||
})
|
||||
.then(() => {
|
||||
follows = Array.from(SocialNetwork.followedByUser.get(myPub) || []);
|
||||
return db.events
|
||||
.where('pubkey')
|
||||
.anyOf(follows)
|
||||
.each((event) => {
|
||||
Events.handle(event, false, false);
|
||||
});
|
||||
})
|
||||
.then(() => {
|
||||
// other follow events
|
||||
// are they loaded in correct order to build the WoT?
|
||||
return db.events.where({ kind: 3 }).each((event) => {
|
||||
Events.handle(event, false, false);
|
||||
});
|
||||
@ -62,7 +56,8 @@ export default {
|
||||
return db.events
|
||||
.orderBy('created_at')
|
||||
.reverse()
|
||||
.limit(3000)
|
||||
.filter((event) => event.kind === 1)
|
||||
.limit(5000)
|
||||
.each((event) => {
|
||||
Events.handle(event, false, false);
|
||||
});
|
||||
@ -71,16 +66,16 @@ export default {
|
||||
// other events to be loaded on demand
|
||||
},
|
||||
subscribe(filters: Filter[]) {
|
||||
const stringifiedFilters = JSON.stringify(filters);
|
||||
if (this.subscriptions.has(stringifiedFilters)) {
|
||||
return;
|
||||
}
|
||||
this.subscriptions.add(stringifiedFilters);
|
||||
const filter1 = filters.length === 1 ? filters[0] : undefined;
|
||||
let query: any = db.events;
|
||||
if (filter1.ids) {
|
||||
query = query.where('id').anyOf(filter1.ids);
|
||||
} else {
|
||||
const stringifiedFilters = JSON.stringify(filters);
|
||||
if (this.subscriptions.has(stringifiedFilters)) {
|
||||
return;
|
||||
}
|
||||
this.subscriptions.add(stringifiedFilters);
|
||||
if (filter1.authors) {
|
||||
query = query.where('pubkey').anyOf(filter1.authors);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import localForage from 'localforage';
|
||||
import { debounce } from 'lodash';
|
||||
import { debounce, throttle } from 'lodash';
|
||||
|
||||
import { Event } from '../lib/nostr-tools';
|
||||
|
||||
@ -7,40 +7,41 @@ import Events from './Events';
|
||||
import Key from './Key';
|
||||
import SocialNetwork from './SocialNetwork';
|
||||
|
||||
let latestByFollows;
|
||||
const getLatestByFollows = () => {
|
||||
if (latestByFollows) {
|
||||
return latestByFollows;
|
||||
}
|
||||
latestByFollows = Events.db.addDynamicView('latest_by_follows', { persist: true });
|
||||
latestByFollows.applyFind({ kind: 1 });
|
||||
latestByFollows.applySimpleSort('created_at', { desc: true });
|
||||
latestByFollows.applyWhere((event: Event) => {
|
||||
return SocialNetwork.followDistanceByUser.get(event.pubkey) <= 1;
|
||||
});
|
||||
return latestByFollows;
|
||||
};
|
||||
|
||||
let latestByEveryone;
|
||||
const getLatestByEveryone = () => {
|
||||
if (latestByEveryone) {
|
||||
return latestByEveryone;
|
||||
}
|
||||
latestByEveryone = Events.db.addDynamicView('latest_by_everyone', { persist: true });
|
||||
latestByEveryone.applyFind({ kind: 1 });
|
||||
latestByEveryone.applySimpleSort('created_at', { desc: true });
|
||||
return latestByEveryone;
|
||||
};
|
||||
|
||||
export default {
|
||||
loaded: false,
|
||||
saveEvents: debounce(() => {
|
||||
const latestMsgs = Events.db
|
||||
.chain()
|
||||
.simplesort('created_at')
|
||||
.where((e: Event) => {
|
||||
if (e.kind !== 1) {
|
||||
return false;
|
||||
}
|
||||
const followDistance = SocialNetwork.followDistanceByUser.get(e.pubkey);
|
||||
if (followDistance > 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.limit(100)
|
||||
.data();
|
||||
const latestMsgsByEveryone = Events.db
|
||||
.chain()
|
||||
.simplesort('created_at')
|
||||
.where((e: Event) => {
|
||||
if (e.kind !== 1) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.limit(100)
|
||||
.data();
|
||||
saveEvents: throttle(() => {
|
||||
const latestMsgs = getLatestByFollows().data().slice(0, 50);
|
||||
const latestMsgsByEveryone = getLatestByEveryone().data().slice(0, 50);
|
||||
const notifications = Events.notifications.eventIds
|
||||
.map((eventId: any) => {
|
||||
return Events.db.by('id', eventId);
|
||||
})
|
||||
.slice(0, 100);
|
||||
.slice(0, 50);
|
||||
let dms = [];
|
||||
for (const set of Events.directMessagesByUser.values()) {
|
||||
set.eventIds.forEach((eventId: any) => {
|
||||
@ -48,7 +49,7 @@ export default {
|
||||
});
|
||||
}
|
||||
dms = dms.slice(0, 100);
|
||||
const kvEvents = Array.from(Events.keyValueEvents.values()).slice(0, 100);
|
||||
const kvEvents = Array.from(Events.keyValueEvents.values()).slice(0, 50);
|
||||
|
||||
localForage.setItem('latestMsgs', latestMsgs);
|
||||
localForage.setItem('latestMsgsByEveryone', latestMsgsByEveryone);
|
||||
@ -56,6 +57,8 @@ export default {
|
||||
localForage.setItem('dms', dms);
|
||||
localForage.setItem('keyValueEvents', kvEvents);
|
||||
// TODO save own block and flag events
|
||||
console.log('saved latestMsgs', latestMsgs.length);
|
||||
console.log('saved latestMsgsByEveryone', latestMsgsByEveryone.length);
|
||||
}, 5000),
|
||||
|
||||
saveProfilesAndFollows: debounce(() => {
|
||||
@ -88,8 +91,8 @@ export default {
|
||||
);
|
||||
*/
|
||||
|
||||
localForage.setItem('profileEvents', profileEvents.slice(0, 100));
|
||||
localForage.setItem('followEvents', followEvents2.slice(0, 100));
|
||||
localForage.setItem('profileEvents', profileEvents.slice(0, 50));
|
||||
localForage.setItem('followEvents', followEvents2.slice(0, 50));
|
||||
}, 5000),
|
||||
|
||||
loadEvents: async function () {
|
||||
|
@ -11,6 +11,7 @@ import Events from '../nostr/Events';
|
||||
import Key from '../nostr/Key';
|
||||
import SocialNetwork from '../nostr/SocialNetwork';
|
||||
import { translate as t } from '../translations/Translation';
|
||||
import {route} from "preact-router";
|
||||
const bech32 = require('bech32-buffer');
|
||||
|
||||
const nostrLogin = async (event) => {
|
||||
@ -94,6 +95,7 @@ class Login extends Component {
|
||||
setTimeout(() => {
|
||||
// TODO remove setTimeout
|
||||
localState.get('loggedIn').put(true);
|
||||
route('/following');
|
||||
}, 100);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@ import { debounce } from 'lodash';
|
||||
import { createRef } from 'preact';
|
||||
|
||||
import Component from '../BaseComponent';
|
||||
import ErrorBoundary from '../components/ErrorBoundary';
|
||||
import Header from '../components/Header';
|
||||
|
||||
let isInitialLoad = true;
|
||||
@ -30,7 +31,7 @@ abstract class View extends Component {
|
||||
class={`main-view ${this.class}`}
|
||||
id={this.id}
|
||||
>
|
||||
{this.renderView()}
|
||||
<ErrorBoundary>{this.renderView()}</ErrorBoundary>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -18,7 +18,6 @@ class ChatList extends Component {
|
||||
sortedChats: [],
|
||||
};
|
||||
}
|
||||
|
||||
enableDesktopNotifications() {
|
||||
if (window.Notification) {
|
||||
Notification.requestPermission(() => {
|
||||
@ -39,9 +38,9 @@ class ChatList extends Component {
|
||||
const bEventIds = chats.get(b).eventIds;
|
||||
const aLatestEvent = aEventIds.length ? Events.db.by('id', aEventIds[0]) : null;
|
||||
const bLatestEvent = bEventIds.length ? Events.db.by('id', bEventIds[0]) : null;
|
||||
if (bLatestEvent.created_at > aLatestEvent.created_at) {
|
||||
if (bLatestEvent?.created_at > aLatestEvent?.created_at) {
|
||||
return 1;
|
||||
} else if (bLatestEvent.created_at < aLatestEvent.created_at) {
|
||||
} else if (bLatestEvent?.created_at < aLatestEvent?.created_at) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user