npub.email/src/routes/+page.svelte

137 lines
No EOL
4.2 KiB
Svelte

<script lang="ts">
import { ndk, pageIcon, pageTitle } from '$lib/stores.svelte';
import Icon from '@iconify/svelte';
import MailboxFolderItems from '../components/MailboxFolderItems.svelte';
import { decryptSealedMessageIntoReadableType } from '$lib/utils.svelte';
import { Letter } from '$lib/letter';
import { FolderLabel } from '$lib/folderLabel';
import type { NDKEvent, NDKEventId } from '@nostr-dev-kit/ndk';
import { LetterToFolderMapping } from '$lib/letterToFolderMapping';
import IconButton from '../components/IconButton.svelte';
import FoldersListSidebar from '../components/FoldersListSidebar.svelte';
import { onMount } from 'svelte';
let sidebarOpen = $state(false);
let messages = $ndk.storeSubscribe([{
kinds: [1059],
'#p': [$ndk.activeUser.pubkey]
}], {
closeOnEose: false,
groupable: false,
groupableDelay: 0
});
let letters = $state<Letter[]>([]);
let activeFolder = $state('inbox');
let folders = $state([
{ id: 'inbox', name: 'Inbox', icon: 'solar:inbox-bold-duotone' },
{ id: 'sent', name: 'Sent', icon: 'fa:send' },
{ id: 'trash', name: 'Trash', icon: 'eos-icons:trash' }
]);
async function decryptMessages(messages: NDKEvent[]) {
const currentMessages = messages;
const decryptedFolders = [
{ id: 'inbox', name: 'Inbox', icon: 'solar:inbox-bold-duotone' },
{ id: 'sent', name: 'Sent', icon: 'fa:send' },
{ id: 'trash', name: 'Trash', icon: 'formkit:trash' }
];
const allLetters = [];
let allLettersInFolders: NDKEventId[] = [];
const letterLabels = new Map<string, NDKEventId[]>();
for (const message of currentMessages) {
const msg = await decryptSealedMessageIntoReadableType(message);
if ((msg instanceof Letter)) {
allLetters.push(msg);
} else if (msg instanceof FolderLabel) {
decryptedFolders.push(msg);
} else if (msg instanceof LetterToFolderMapping) {
if (!letterLabels.has(msg.folder))
letterLabels.set(msg.folder, []);
for (const folderId of letterLabels.keys()) {
// check if letter is in a folder, if so remove it and move it to the new folder
if (letterLabels.get(folderId)!.includes(msg.message)) {
letterLabels.get(folderId)!.splice(letterLabels.get(folderId)!.indexOf(msg.message), 1);
break;
}
}
allLettersInFolders.push(msg.message);
letterLabels.set(msg.folder, letterLabels.get(msg.folder)!.concat(msg.message));
}
}
letters = allLetters.filter(letter => {
if (activeFolder === 'sent')
return letter.from.pubkey === $ndk.activeUser.pubkey;
if (activeFolder === 'inbox' && letter.from.pubkey !== $ndk.activeUser.pubkey)
return !allLettersInFolders.includes(letter.id);
if (!letterLabels.has(activeFolder))
return false;
return letterLabels.get(activeFolder)!.includes(letter.id);
});
folders = decryptedFolders;
}
messages.subscribe((m: NDKEvent) => decryptMessages(m));
function changeFolder(newFolder: string) {
letters = [];
activeFolder = newFolder;
$pageTitle = folders.find(f => f.id === newFolder)!.name;
$pageIcon = folders.find(f => f.id === newFolder)!.icon;
decryptMessages($messages);
}
let moveFolderDialogOpen = $state(false);
onMount(() => {
$pageTitle = 'Inbox';
$pageIcon = 'solar:inbox-bold-duotone';
});
</script>
<div class="actions">
<IconButton icon="mynaui:sidebar-solid" onclick={() => sidebarOpen = !sidebarOpen} text="Sidebar" />
<IconButton icon="mdi:folder-move-outline" onclick={() => moveFolderDialogOpen = true} text="Move Letters" />
</div>
<div class="content" class:sidebar-open={sidebarOpen}>
<FoldersListSidebar bind:folders bind:sidebarOpen {changeFolder} />
<div class="folder-view">
{#if letters.length === 0}
<Icon icon="eos-icons:loading" width="5em" />
<br />
<p>
If you have letters, they will appear here, please wait...
</p>
{:else}
<MailboxFolderItems bind:moveFolderDialogOpen foldersList={folders}
folder={folders.find(f => f.id === activeFolder)} {letters} />
{/if}
</div>
</div>
<style>
.content {
display: flex;
gap: 0;
transition: gap 0.3s ease;
&.sidebar-open {
gap: var(--spacing-sm);
}
}
.folder-view {
flex-grow: 1;
}
.actions {
display: flex;
gap: var(--spacing-sm);
margin-bottom: var(--spacing-sm);
}
</style>