Skip to content

Commit

Permalink
Load less chatlogs & refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
narze committed Sep 5, 2023
1 parent 846ba1b commit 04ab7a7
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 34 deletions.
15 changes: 7 additions & 8 deletions src/lib/commands/components/ChatMessage.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
import { fly } from 'svelte/transition';
import { decryptMessage } from '$lib/encryption';
import { firestore } from '$lib/firebase';
import { deleteDoc, doc } from 'firebase/firestore';
import { userStore } from '$lib/firebase-store';
import { db } from '../../db';
import { addToast } from '../../toasts';
import { db } from '$lib/db';
import { addToast } from '$lib/toasts';
import { userStore } from '$lib/stores/firebase-store';
import { deleteMessage } from '$lib/stores/messages';
export let message: Message;
export let components: Record<string, typeof SvelteComponent<any>>;
Expand Down Expand Up @@ -91,7 +90,7 @@
closeMenu();
}
async function deleteMessage() {
async function deleteChatMessage() {
closeMenu();
if (!confirm('Are you sure you want to delete this message?')) {
Expand All @@ -100,7 +99,7 @@
if ($user) {
try {
await deleteDoc(doc(firestore, `users/${$user!.uid}/messages/${message.id}`));
await deleteMessage($user, message.id);
} catch (e) {
console.error(e);
}
Expand Down Expand Up @@ -215,7 +214,7 @@
class="dropdown-content z-[1] menu m-1 shadow bg-base-100 rounded-box text-sm"
>
<li><button on:click={copyText}>Copy</button></li>
<li><button on:click={deleteMessage}>Delete</button></li>
<li><button on:click={deleteChatMessage}>Delete</button></li>
</ul>
</details>
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/lib/commands/components/Login.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@
import { sha256 } from '@noble/hashes/sha256';
import { decryptMessage, encodeBase64, encryptMessage } from '$lib/encryption';
import { auth, firestore } from '$lib/firebase';
import { collectionStore, userStore } from '$lib/firebase-store';
import { GoogleAuthProvider, signInWithPopup } from 'firebase/auth';
import { db } from '$lib/db';
import type { Log } from '~/src/routes/+page.svelte';
import { Timestamp, collection, doc, getDocs, updateDoc, writeBatch } from 'firebase/firestore';
import { Timestamp, collection, doc, getDocs, writeBatch } from 'firebase/firestore';
import { userStore } from '$lib/stores/firebase-store';
const provider = new GoogleAuthProvider();
const user = userStore();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
} from 'firebase/firestore';
import { writable } from 'svelte/store';

import { auth } from './firebase';
import { auth } from '../firebase';

/**
* The userStore is updated whenever the authentication state changes.
Expand Down
97 changes: 97 additions & 0 deletions src/lib/stores/messages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import type { User } from 'firebase/auth';
import {
type DocumentData,
type QueryDocumentSnapshot,
addDoc,
collection,
deleteDoc,
doc,
getDocs,
limit,
onSnapshot,
orderBy,
query,
startAfter
} from 'firebase/firestore';
import { writable } from 'svelte/store';
import type { Log } from '~/src/routes/+page.svelte';

import { firestore } from '../firebase';

const CHAT_MESSAGES_INITIAL_LIMIT = 15;

export const firebaseChatMessages = writable<Log[]>();

async function loadLatestMessages(user: User) {
const recentMessagesQuery = query(
collection(firestore, `users/${user.uid}/messages`),
orderBy('time', 'desc'),
limit(CHAT_MESSAGES_INITIAL_LIMIT)
);

const querySnapshot = await getDocs(recentMessagesQuery);

firebaseChatMessages.set(
querySnapshot.docs
.map((doc) => {
return {
...(doc.data() as Log),
id: doc.id
};
})
.reverse()
);

const newestDoc = querySnapshot.docs[0];
const oldestDoc = querySnapshot.docs[querySnapshot.docs.length - 1];

return { newestDoc, oldestDoc };
}

function listenToNewMessages(
user: User,
newestDoc: QueryDocumentSnapshot<DocumentData, DocumentData>
) {
const queryOptions = newestDoc ? [orderBy('time'), startAfter(newestDoc)] : [orderBy('time')];

const newMessagesQuery = query(
collection(firestore, `users/${user.uid}/messages`),
...queryOptions
);

const processedNewMessageIds = new Set();

onSnapshot(newMessagesQuery, (snapshot) => {
let newMessages: Log[] = [];

snapshot.docs.forEach((s) => {
if (!processedNewMessageIds.has(s.id)) {
processedNewMessageIds.add(s.id);
newMessages.push({ ...(s.data() as Log), id: s.id });
}
});

firebaseChatMessages.update((existingMessages) => [...existingMessages, ...newMessages]);
});
}

// TODO: implement
function loadMoreOlderMessages(count: number) {}

export async function loadMessages(user: User) {
const { newestDoc, oldestDoc } = await loadLatestMessages(user);

listenToNewMessages(user, newestDoc);
}

export async function addMessage(user: User, doc: any) {
return await addDoc(collection(firestore, `users/${user.uid}/messages`), doc);
}

export async function deleteMessage(user: User, docId: string) {
firebaseChatMessages.update((existingMessages) =>
existingMessages.filter((message) => message.id !== docId)
);

await deleteDoc(doc(firestore, `users/${user.uid}/messages/${docId}`));
}
2 changes: 1 addition & 1 deletion src/routes/+layout.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { userStore } from '../lib/firebase-store';
import { userStore } from '../lib/stores/firebase-store';
import type { LayoutLoad } from './$types';

export const load: LayoutLoad = async (event) => {
Expand Down
35 changes: 15 additions & 20 deletions src/routes/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@
import { onDestroy, tick } from 'svelte';
import ChatMessage from '$lib/commands/components/ChatMessage.svelte';
import type { BotMessageCallback, Components } from '$lib/commands';
import { firestore } from '$lib/firebase';
import { collectionStore } from '$lib/firebase-store';
import { Timestamp, collection, orderBy, query, type DocumentData } from 'firebase/firestore';
import { Timestamp } from 'firebase/firestore';
import type { PageData } from './$types';
import { liveQuery, type Observable } from 'dexie';
import { db } from '$lib/db';
import { fade } from 'svelte/transition';
import { addMessage, firebaseChatMessages, loadMessages } from '$lib/stores/messages';
export let data: PageData;
let { user } = data;
Expand Down Expand Up @@ -70,26 +69,22 @@
return messages;
}) satisfies Observable<Log[]>;
let messagesQuery: ReturnType<typeof query<DocumentData, DocumentData>>;
let messages: ReturnType<typeof collectionStore<Log>>;
let messagesCollection: ReturnType<typeof collectionStore<Log>>;
$: if ($user) {
messagesQuery = query(collection(firestore, `users/${$user.uid}/messages`), orderBy('time'));
messages = collectionStore<Log>(firestore, messagesQuery);
messagesCollection = collectionStore<Log>(firestore, `users/${$user.uid}/messages`);
loadMessages($user);
}
$: combinedMessages = $user
? [...($messages || []), ...$guestMessages].sort(
? [...($firebaseChatMessages || []), ...$guestMessages].sort(
(a, b) => a.time?.toDate().valueOf() - b.time?.toDate().valueOf()
)
: $guestMessages;
$: dbReady =
$user !== undefined && ($user ? $messages !== undefined : $guestMessages !== undefined);
$user !== undefined &&
($user ? $firebaseChatMessages !== undefined : $guestMessages !== undefined);
$: newLoggedInUser = $user && $messages !== undefined && $messages?.length === 0;
$: newLoggedInUser =
$user && $firebaseChatMessages !== undefined && $firebaseChatMessages?.length === 0;
$: newGuestUser = $user == null && $guestMessages !== undefined && $guestMessages?.length === 0;
let greeted = false;
Expand All @@ -107,7 +102,7 @@
greeted = true;
if ($user) {
messagesCollection.add({
addMessage($user, {
self: false,
message: `Hello ${$user.displayName}!`,
time: Timestamp.now(),
Expand Down Expand Up @@ -143,10 +138,10 @@
const debouncedScrollToBottom = debounce(scrollToBottom, 100);
$: if (chatDiv && ($messages?.length || $guestMessages?.length)) {
$: if (chatDiv && ($firebaseChatMessages?.length || $guestMessages?.length)) {
tick().then(() => {
if (
$messages?.[$messages.length - 1]?.self ||
$firebaseChatMessages?.[$firebaseChatMessages.length - 1]?.self ||
$guestMessages?.[$guestMessages.length - 1]?.self
) {
scrollToBottom(chatDiv, 'auto');
Expand Down Expand Up @@ -180,15 +175,15 @@
if (encryptionKey) {
const encryptedMessage = encryptMessage(message, encryptionKey);
await messagesCollection.add({
await addMessage($user, {
self: true,
message: encryptedMessage,
time: Timestamp.now(),
type: 'text',
encrypted: true
});
} else {
await messagesCollection.add({
await addMessage($user, {
self: true,
message,
time: Timestamp.now(),
Expand Down Expand Up @@ -219,7 +214,7 @@
const encryptedMessage = encryptMessage(message, encryptionKey);
const encryptedOptions = encryptMessage(options, encryptionKey);
await messagesCollection.add({
await addMessage($user, {
self: false,
message: encryptedMessage,
time: Timestamp.now(),
Expand All @@ -228,7 +223,7 @@
encrypted: true
});
} else {
await messagesCollection.add({
await addMessage($user, {
self: false,
message,
time: Timestamp.now(),
Expand Down
3 changes: 1 addition & 2 deletions src/routes/test/+page.svelte
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<script lang="ts">
import { firestore } from '$lib/firebase';
import { collectionStore } from '$lib/firebase-store';
import { addDoc, collection } from 'firebase/firestore';
import { collectionStore } from '$lib/stores/firebase-store';
interface Post {
message: string;
Expand Down

1 comment on commit 04ab7a7

@vercel
Copy link

@vercel vercel bot commented on 04ab7a7 Sep 5, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

chat-os – ./

chat-os-notnarze.vercel.app
chat-os-git-main-notnarze.vercel.app
chat.narze.live
chat-os.vercel.app

Please sign in to comment.