Skip to content

Commit

Permalink
mark channel as read on open
Browse files Browse the repository at this point in the history
  • Loading branch information
Puyodead1 committed Jul 18, 2024
1 parent 329a14c commit 2f6a56d
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 6 deletions.
4 changes: 2 additions & 2 deletions src/components/ChannelList/ChannelListItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { useNavigate } from "react-router-dom";
import styled from "styled-components";
import { ContextMenuContext } from "../../contexts/ContextMenuContext";
import { modalController } from "../../controllers/modals";
import { useAppStore } from "../../hooks/useAppStore";
import Channel from "../../stores/objects/Channel";
import { Permissions } from "../../utils/Permissions";
import Icon from "../Icon";
import SidebarPill from "../SidebarPill";
import Floating from "../floating/Floating";
import FloatingTrigger from "../floating/FloatingTrigger";
import { useAppStore } from "../../hooks/useAppStore";

const ListItem = styled.div<{ isCategory?: boolean }>`
padding: ${(props) => (props.isCategory ? "16px 8px 0 0" : "1px 8px 0 0")};
Expand Down Expand Up @@ -90,7 +90,7 @@ function ChannelListItem({ channel, isCategory, active }: Props) {
alignItems: "center",
}}
>
<SidebarPill type={channel.hasUnread() ? "unread" : "none"} />
<SidebarPill type={channel.unread ? "unread" : "none"} />
{channel.channelIcon && !isCategory && (
<Icon
icon={channel.channelIcon}
Expand Down
6 changes: 5 additions & 1 deletion src/components/messaging/Chat.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { runInAction } from "mobx";
import { observer } from "mobx-react-lite";
import React from "react";
import React, { useEffect } from "react";
import styled from "styled-components";
import { useAppStore } from "../../hooks/useAppStore";
import useLogger from "../../hooks/useLogger";
Expand Down Expand Up @@ -57,6 +57,10 @@ function ChatContent({ channel, guild }: Props2) {
const app = useAppStore();
const readstate = app.readStateStore.get(channel.id);

useEffect(() => {
channel.markAsRead();
}, [channel, guild]);

return (
<Container>
<MessageList guild={guild} channel={channel} before={readstate?.lastMessageId} />
Expand Down
19 changes: 19 additions & 0 deletions src/stores/GatewayConnectionStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ export default class GatewayConnectionStore {
this.dispatchHandlers.set(GatewayDispatchEvents.ChannelCreate, this.onChannelCreate);
this.dispatchHandlers.set(GatewayDispatchEvents.ChannelUpdate, this.onChannelUpdate);
this.dispatchHandlers.set(GatewayDispatchEvents.ChannelDelete, this.onChannelDelete);
// @ts-expect-error missing event in typings
this.dispatchHandlers.set("MESSAGE_ACK", this.onMessageAck);

this.dispatchHandlers.set(GatewayDispatchEvents.MessageCreate, this.onMessageCreate);
this.dispatchHandlers.set(GatewayDispatchEvents.MessageUpdate, this.onMessageUpdate);
Expand Down Expand Up @@ -633,6 +635,23 @@ export default class GatewayConnectionStore {
guild.removeChannel(data.id);
};

private onMessageAck = (data: { channel_id: string; message_id: string; version: number }) => {
// get readstate for channel
const readstate = this.app.readStateStore.get(data.channel_id);
if (!readstate) {
this.logger.warn(`[MessageAck] Readstate not found for channel ${data.channel_id}`);
return;
}

runInAction(() => {
readstate.lastMessageId = data.message_id;
});

this.logger.debug(
`[MessageAck] Updated last message id for channel readstate ${data.channel_id} to ${data.message_id}`,
);
};

private onMessageCreate = (data: GatewayMessageCreateDispatchData) => {
const guild = this.app.guilds.get(data.guild_id!);
if (!guild) {
Expand Down
22 changes: 21 additions & 1 deletion src/stores/objects/Channel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,8 @@ export default class Channel {
return listId;
}

hasUnread() {
@computed
get unread() {
const readState = this.app.readStateStore.get(this.id);
if (!readState) {
// this.logger.warn(`Failed to find readstate for channel ${this.id}`); // this just causes unnecessary spam
Expand All @@ -320,4 +321,23 @@ export default class Channel {

return readState.lastMessageId !== this.lastMessageId;
}

markAsRead() {
const readState = this.app.readStateStore.get(this.id);
if (!readState) {
this.logger.warn(`Failed to find readstate for channel ${this.id}`); // this just causes unnecessary spam
return;
}

this.app.rest
.post(Routes.channelMessage(this.id, readState.lastMessageId) + "/ack", {
mention_count: readState.mentionCount,
})
.then((r) => {
this.logger.debug(`Acked ${this.lastMessageId} for channel ${this.id}`, r);
})
.catch((e) => {
this.logger.error(`Failed to ack ${this.lastMessageId} for channel ${this.id}`, e);
});
}
}
7 changes: 5 additions & 2 deletions src/stores/objects/ReadState.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { APIReadState } from "@spacebarchat/spacebar-api-types/v9";
import { type APIReadState } from "@spacebarchat/spacebar-api-types/v9";
import { action, observable } from "mobx";
import Logger from "../../utils/Logger";
import AppStore from "../AppStore";

export default class ReadState {
private readonly logger: Logger;
private readonly app: AppStore;

id: string;
Expand All @@ -11,9 +13,10 @@ export default class ReadState {
@observable mentionCount: number | null;

constructor(app: AppStore, data: APIReadState) {
this.logger = new Logger("ReadState");
this.app = app;

this.id = data.id;
this.id = data.id; // channel id
this.lastMessageId = data.last_message_id;
this.lastPinTimestamp = data.last_pin_timestamp;
this.mentionCount = data.mention_count;
Expand Down

0 comments on commit 2f6a56d

Please sign in to comment.