diff options
| author | Owen Jacobson <owen@grimoire.ca> | 2025-02-15 15:17:03 -0500 |
|---|---|---|
| committer | Owen Jacobson <owen@grimoire.ca> | 2025-02-21 17:49:38 -0500 |
| commit | fc0f1654a56d2247728a766f43e72ff169704888 (patch) | |
| tree | 945f44c9a90bf51de20c61a5a8c5ed82c2c05009 /ui/routes | |
| parent | 36cadfe00cacc6a6523f9862d3f7a08a9d0ce611 (diff) | |
Hoist global state access out of individual components.
Access to "global" (maybe "external?") state is now handled at the top level of the component hierarchy, in `+page.svelte`, `+layout.svelte`, and their associated scripts. State is otherwise passed down through props, and changes are passed up through callbacks.
This is - hopefully - groundwork for refactoring state management a bit. I wanted to move access to state out to a smaller number of places, so that I have fewer places to update to implement reconnect logic. My broader goal is to make it easier to refactor these kinds of external side effects, as well, though no such changes are in this branch.
This change also makes testing a mile easier, since tests can interact with props and callbacks instead of emulating the whole HTTP request stack and the Pilcrow API. This change removes do-very-little tests.
Diffstat (limited to 'ui/routes')
| -rw-r--r-- | ui/routes/(app)/+layout.svelte | 16 | ||||
| -rw-r--r-- | ui/routes/(app)/ch/[channel]/+page.svelte | 28 | ||||
| -rw-r--r-- | ui/routes/(app)/me/+page.svelte | 31 | ||||
| -rw-r--r-- | ui/routes/(login)/invite/[invite]/+page.svelte | 18 | ||||
| -rw-r--r-- | ui/routes/(login)/login/+page.svelte | 18 | ||||
| -rw-r--r-- | ui/routes/(login)/setup/+page.svelte | 18 |
6 files changed, 74 insertions, 55 deletions
diff --git a/ui/routes/(app)/+layout.svelte b/ui/routes/(app)/+layout.svelte index 6339abd..02f7d19 100644 --- a/ui/routes/(app)/+layout.svelte +++ b/ui/routes/(app)/+layout.svelte @@ -5,7 +5,7 @@ import { getContext, onDestroy, onMount } from 'svelte'; import TinyGesture from 'tinygesture'; - import { boot, subscribeToEvents } from '$lib/apiServer'; + import * as api from '$lib/apiServer.js'; import { channelsList, currentUser, logins, messages, onEvent } from '$lib/store'; import ChannelList from '$lib/components/ChannelList.svelte'; @@ -58,20 +58,20 @@ return; } gesture = new TinyGesture(window); - gesture.on('swiperight', (event) => { + gesture.on('swiperight', () => { pageContext.showMenu = true; }); - gesture.on('swipeleft', (event) => { + gesture.on('swipeleft', () => { pageContext.showMenu = false; }); } onMount(async () => { - let response = await boot(); + let response = await api.boot(); switch (response.status) { case 200: onBooted(response.data); - events = subscribeToEvents(response.data.resume_point); + events = api.subscribeToEvents(response.data.resume_point); events.onmessage = onEvent.fromMessage; break; case 401: @@ -109,6 +109,10 @@ event.returnValue = ''; return ''; } + + async function createChannel(name) { + await api.createChannel(name); + } </script> <svelte:window {onbeforeunload} /> @@ -125,7 +129,7 @@ <nav id="sidebar" data-expanded={pageContext.showMenu}> <ChannelList active={channel} channels={enrichedChannels} /> <div class="create-channel"> - <CreateChannelForm /> + <CreateChannelForm {createChannel} /> </div> </nav> <main> diff --git a/ui/routes/(app)/ch/[channel]/+page.svelte b/ui/routes/(app)/ch/[channel]/+page.svelte index 84cb0ae..8de9859 100644 --- a/ui/routes/(app)/ch/[channel]/+page.svelte +++ b/ui/routes/(app)/ch/[channel]/+page.svelte @@ -3,10 +3,22 @@ import { page } from '$app/state'; import ActiveChannel from '$lib/components/ActiveChannel.svelte'; import MessageInput from '$lib/components/MessageInput.svelte'; - import { channelsList, messages } from '$lib/store'; + import { channelsList, currentUser, logins, messages } from '$lib/store'; + import * as api from '$lib/apiServer'; let channel = $derived(page.params.channel); - let messageRuns = $derived($messages.inChannel(channel)); + let messageRuns = $derived( + $messages.inChannel(channel).map(({ sender, messages }) => { + let senderName = $derived($logins.get(sender)); + let ownMessage = $derived($currentUser !== null && $currentUser.id === sender); + + return { + sender: senderName, + ownMessage, + messages + }; + }) + ); let activeChannel; function inView(parentElement, element) { @@ -63,13 +75,21 @@ clearTimeout(lastReadCallback); // Fine if lastReadCallback is null still. lastReadCallback = setTimeout(setLastRead, 2 * 1000); } + + async function sendMessage(message) { + await api.postToChannel(channel, message); + } + + async function deleteMessage(id) { + await api.deleteMessage(id); + } </script> <svelte:window onkeydown={handleKeydown} /> <div class="active-channel" {onscroll} bind:this={activeChannel}> - <ActiveChannel {messageRuns} /> + <ActiveChannel {messageRuns} {deleteMessage} /> </div> <div class="create-message"> - <MessageInput {channel} /> + <MessageInput {sendMessage} /> </div> diff --git a/ui/routes/(app)/me/+page.svelte b/ui/routes/(app)/me/+page.svelte index 14a9db8..ab214e9 100644 --- a/ui/routes/(app)/me/+page.svelte +++ b/ui/routes/(app)/me/+page.svelte @@ -2,10 +2,35 @@ import LogOut from '$lib/components/LogOut.svelte'; import Invites from '$lib/components/Invites.svelte'; import ChangePassword from '$lib/components/ChangePassword.svelte'; + + import { goto } from '$app/navigation'; + import * as api from '$lib/apiServer.js'; + import { currentUser } from '$lib/store'; + + let invites = $state([]); + + async function logOut() { + const response = await api.logOut(); + if (200 <= response.status && response.status < 300) { + currentUser.set(null); + await goto('/login'); + } + } + + async function changePassword(currentPassword, newPassword) { + await api.changePassword(currentPassword, newPassword); + } + + async function createInvite() { + let response = await api.createInvite(); + if (response.status === 200) { + invites.push(response.data); + } + } </script> -<ChangePassword /> +<ChangePassword {changePassword} /> <hr /> -<Invites /> +<Invites {invites} {createInvite} /> <hr /> -<LogOut /> +<LogOut {logOut} /> diff --git a/ui/routes/(login)/invite/[invite]/+page.svelte b/ui/routes/(login)/invite/[invite]/+page.svelte index 0c01286..04341e5 100644 --- a/ui/routes/(login)/invite/[invite]/+page.svelte +++ b/ui/routes/(login)/invite/[invite]/+page.svelte @@ -1,26 +1,16 @@ <script> import { goto } from '$app/navigation'; - import { acceptInvite } from '$lib/apiServer'; + import * as api from '$lib/apiServer'; import LogIn from '$lib/components/LogIn.svelte'; let { data } = $props(); - let username = $state(''), - password = $state(''); - let pending = false; - let disabled = $derived(pending); - - async function onSubmit(event, inviteId) { - event.preventDefault(); - pending = true; - const response = await acceptInvite(inviteId, username, password); + async function acceptInvite(inviteId, username, password) { + const response = await api.acceptInvite(inviteId, username, password); if (200 <= response.status && response.status < 300) { - username = ''; - password = ''; await goto('/'); } - pending = false; } </script> @@ -32,5 +22,5 @@ <div class="invite-text"> <p>Hi there! {invite.issuer} invites you to the conversation.</p> </div> - <LogIn {disabled} bind:username bind:password onsubmit={(event) => onSubmit(event, invite.id)} /> + <LogIn logIn={async (username, password) => acceptInvite(invite.id, username, password)} /> {/await} diff --git a/ui/routes/(login)/login/+page.svelte b/ui/routes/(login)/login/+page.svelte index 9157cef..b1f7cf2 100644 --- a/ui/routes/(login)/login/+page.svelte +++ b/ui/routes/(login)/login/+page.svelte @@ -1,25 +1,15 @@ <script> import { goto } from '$app/navigation'; - import { logIn } from '$lib/apiServer'; + import * as api from '$lib/apiServer'; import LogIn from '$lib/components/LogIn.svelte'; - let username = '', - password = ''; - let pending = false; - $: disabled = pending; - - async function onSubmit(event) { - event.preventDefault(); - pending = true; - const response = await logIn(username, password); + async function logIn(username, password) { + const response = await api.logIn(username, password); if (200 <= response.status && response.status < 300) { - username = ''; - password = ''; await goto('/'); } - pending = false; } </script> -<LogIn {disabled} bind:username bind:password onsubmit={onSubmit} /> +<LogIn {logIn} /> diff --git a/ui/routes/(login)/setup/+page.svelte b/ui/routes/(login)/setup/+page.svelte index c63f198..0b5a824 100644 --- a/ui/routes/(login)/setup/+page.svelte +++ b/ui/routes/(login)/setup/+page.svelte @@ -1,25 +1,15 @@ <script> import { goto } from '$app/navigation'; - import { setup } from '$lib/apiServer'; + import * as api from '$lib/apiServer'; import LogIn from '$lib/components/LogIn.svelte'; - let username = $state(''), - password = $state(''); - let pending = false; - let disabled = $derived(pending); - - async function onSubmit(event) { - event.preventDefault(); - pending = true; - const response = await setup(username, password); + async function logIn(username, password) { + const response = await api.setup(username, password); if (200 <= response.status && response.status < 300) { - username = ''; - password = ''; await goto('/'); } - pending = false; } </script> -<LogIn {disabled} bind:username bind:password legend="set up" onsubmit={onSubmit} /> +<LogIn legend="set up" {logIn} /> |
