summaryrefslogtreecommitdiff
path: root/hi-ui
diff options
context:
space:
mode:
authorOwen Jacobson <owen@grimoire.ca>2024-10-05 20:12:25 -0400
committerOwen Jacobson <owen@grimoire.ca>2024-10-05 20:23:54 -0400
commit8edd5625ad5dde0ef1637d5c89e9901b3ee65d73 (patch)
tree2dfa09776511bdae04e116a478a605957d2db2fe /hi-ui
parentbc514e0ea5f0a553f15ab8275961907877181520 (diff)
Provide named operations for stored state.
Diffstat (limited to 'hi-ui')
-rw-r--r--hi-ui/src/apiServer.js37
-rw-r--r--hi-ui/src/lib/ActiveChannel.svelte12
-rw-r--r--hi-ui/src/lib/Channel.svelte4
-rw-r--r--hi-ui/src/lib/ChannelList.svelte4
-rw-r--r--hi-ui/src/lib/CreateChannelForm.svelte2
-rw-r--r--hi-ui/src/lib/MessageInput.svelte4
-rw-r--r--hi-ui/src/store.js8
-rw-r--r--hi-ui/src/store/channels.js71
-rw-r--r--hi-ui/src/store/messages.js35
9 files changed, 127 insertions, 50 deletions
diff --git a/hi-ui/src/apiServer.js b/hi-ui/src/apiServer.js
index 5e521de..6273576 100644
--- a/hi-ui/src/apiServer.js
+++ b/hi-ui/src/apiServer.js
@@ -1,5 +1,5 @@
import axios from 'axios';
-import { activeChannel, channelsList, events } from './store';
+import { activeChannel, channelsList, messages } from './store';
export const apiServer = axios.create({
baseURL: '/api/',
@@ -39,7 +39,6 @@ export async function deleteMessage(messageId) {
export function subscribeToEvents() {
const evtSource = new EventSource("/api/events");
- events.update(() => []);
// TODO: this should process all incoming events and store them.
// TODO: eventually we'll need to handle expiring old info, so as not to use
// infinite browser memory.
@@ -61,39 +60,15 @@ export function subscribeToEvents() {
case 'created':
break;
case 'message':
- events.update((value) => {
- const eventList = [...value, data];
- eventList.sort((a, b) => a.at - b.at);
- return eventList;
- });
+ messages.update((value) => value.addMessage(data));
break;
case 'message_deleted':
- events.update((value) => {
- const eventList = value.map((el) => {
- if (el.message?.id === data.message) {
- el.message.body = '&laquo;&hellip;&raquo;';
- return el
- } else {
- return el;
- }
- });
- return eventList;
- });
+ messages.update((value) => value.deleteMessage(data.channel.id, data.message));
break;
case 'deleted':
- activeChannel.update((value) => {
- if (value?.id === data.channel) {
- return null;
- }
- return value;
- });
- channelsList.update((value) => {
- const channelIndex = value.map((e) => e.id).indexOf(data.channel);
- if (channelIndex !== -1) {
- value.splice(channelIndex, 1);
- }
- return value;
- });
+ activeChannel.update((value) => value.deleteChannel(data.channel));
+ channelsList.update((value) => value.deleteChannel(data.channel));
+ messages.update((value) => value.deleteChannel(data.channel));
break;
default:
break;
diff --git a/hi-ui/src/lib/ActiveChannel.svelte b/hi-ui/src/lib/ActiveChannel.svelte
index 84f9119..d2d92fb 100644
--- a/hi-ui/src/lib/ActiveChannel.svelte
+++ b/hi-ui/src/lib/ActiveChannel.svelte
@@ -1,15 +1,9 @@
<script>
- import { activeChannel, events } from '../store';
+ import { activeChannel, messages } from '../store';
import Message from './Message.svelte';
let container;
- $: messages = $events.filter(
- (ev) => (
- ev.type === 'message'
- && $activeChannel !== null
- && ev.channel.id === $activeChannel.id
- )
- );
+ $: messageList = $activeChannel.isSet() ? $messages.inChannel($activeChannel.get()) : [];
// TODO: eventually, store scroll height/last unread in channel? scroll there?
@@ -19,7 +13,7 @@
</script>
<div class="container" bind:this={container}>
- {#each messages as message}
+ {#each messageList as message}
<div use:scroll>
<Message {...message} />
</div>
diff --git a/hi-ui/src/lib/Channel.svelte b/hi-ui/src/lib/Channel.svelte
index 7826c46..ad07594 100644
--- a/hi-ui/src/lib/Channel.svelte
+++ b/hi-ui/src/lib/Channel.svelte
@@ -6,11 +6,11 @@
let active = false;
activeChannel.subscribe((value) => {
- active = value ? value.id == id : false;
+ active = value.is(id);
});
function activate() {
- activeChannel.update(() => ({ id, name }));
+ activeChannel.update((value) => value.set(id));
}
</script>
diff --git a/hi-ui/src/lib/ChannelList.svelte b/hi-ui/src/lib/ChannelList.svelte
index 9f88e24..5577d94 100644
--- a/hi-ui/src/lib/ChannelList.svelte
+++ b/hi-ui/src/lib/ChannelList.svelte
@@ -9,12 +9,12 @@
let loading = true;
channelsList.subscribe((value) => {
- channels = value;
+ channels = value.channels;
});
onMount(async () => {
let channels = await listChannels();
- channelsList.update(() => channels.data);
+ channelsList.update((value) => value.setChannels(channels.data));
loading = false;
});
</script>
diff --git a/hi-ui/src/lib/CreateChannelForm.svelte b/hi-ui/src/lib/CreateChannelForm.svelte
index 70dc13d..aa415fd 100644
--- a/hi-ui/src/lib/CreateChannelForm.svelte
+++ b/hi-ui/src/lib/CreateChannelForm.svelte
@@ -10,7 +10,7 @@
disabled = true;
const response = await createChannel(name);
if (200 <= response.status && response.status < 300) {
- channelsList.update((value) => [...value, response.data]);
+ channelsList.update((value) => value.addChannel(response.data));
name = '';
}
disabled = false;
diff --git a/hi-ui/src/lib/MessageInput.svelte b/hi-ui/src/lib/MessageInput.svelte
index 9a8475c..b899221 100644
--- a/hi-ui/src/lib/MessageInput.svelte
+++ b/hi-ui/src/lib/MessageInput.svelte
@@ -8,12 +8,12 @@
let self;
let input;
- $: disabled = $activeChannel == null;
+ $: disabled = !$activeChannel.isSet();
async function handleSubmit(event) {
disabled = true;
// TODO try/catch:
- await postToChannel($activeChannel?.id, input);
+ await postToChannel($activeChannel.get(), input);
input = '';
disabled = false;
await tick();
diff --git a/hi-ui/src/store.js b/hi-ui/src/store.js
index a9d9421..4e6b4f1 100644
--- a/hi-ui/src/store.js
+++ b/hi-ui/src/store.js
@@ -1,6 +1,8 @@
import { writable } from 'svelte/store';
+import { ActiveChannel, Channels } from './store/channels';
+import { Messages } from './store/messages';
export const currentUser = writable(null);
-export const activeChannel = writable(null);
-export const channelsList = writable([]);
-export const events = writable([]);
+export const activeChannel = writable(new ActiveChannel());
+export const channelsList = writable(new Channels());
+export const messages = writable(new Messages());
diff --git a/hi-ui/src/store/channels.js b/hi-ui/src/store/channels.js
new file mode 100644
index 0000000..20702cc
--- /dev/null
+++ b/hi-ui/src/store/channels.js
@@ -0,0 +1,71 @@
+export class Channels {
+ constructor() {
+ this.channels = [];
+ }
+
+ setChannels(channels) {
+ this.channels = [...channels];
+ this.sort();
+ return this;
+ }
+
+ addChannel(channel) {
+ this.channels = [...this.channels, channel];
+ this.sort();
+ return this;
+ }
+
+ deleteChannel(id) {
+ const channelIndex = this.channels.map((e) => e.id).indexOf(id);
+ if (channelIndex !== -1) {
+ this.channels.splice(channelIndex, 1);
+ }
+ return this;
+ }
+
+ sort() {
+ this.channels.sort((a, b) => {
+ if (a.name < b.name) {
+ return -1;
+ } else if (a.name > b.name) {
+ return 1;
+ }
+ return 0;
+ });
+ }
+}
+
+export class ActiveChannel {
+ constructor() {
+ this.channel = null;
+ }
+
+ isSet() {
+ return this.channel !== null;
+ }
+
+ get() {
+ return this.channel;
+ }
+
+ is(id) {
+ return this.channel === id;
+ }
+
+ set(id) {
+ this.channel = id;
+ return this;
+ }
+
+ deleteChannel(id) {
+ if (this.is(id)) {
+ return this.clear();
+ }
+ return this;
+ }
+
+ clear() {
+ this.channel = null;
+ return this;
+ }
+}
diff --git a/hi-ui/src/store/messages.js b/hi-ui/src/store/messages.js
new file mode 100644
index 0000000..d1f19d3
--- /dev/null
+++ b/hi-ui/src/store/messages.js
@@ -0,0 +1,35 @@
+export class Messages {
+ constructor() {
+ this.channels = {};
+ }
+
+ inChannel(channel) {
+ return this.channels[channel] || [];
+ }
+
+ addMessage(message) {
+ let {
+ channel,
+ ...payload
+ } = message;
+ let channel_id = channel.id;
+ this.updateChannel(channel_id, (messages) => [...messages, payload]);
+ return this;
+ }
+
+ deleteMessage(channel, message) {
+ let messages = this.messages(channel).filter((msg) => msg.message.id != message);
+ this.channels[channel] = messages;
+ }
+
+ deleteChannel(id) {
+ delete this.channels[id];
+ return this;
+ }
+
+ updateChannel(channel, callback) {
+ let messages = callback(this.inChannel(channel));
+ messages.sort((a, b) => a.at - b.at);
+ this.channels[channel] = messages;
+ }
+}