mirror of
https://github.com/spacebarchat/client.git
synced 2024-11-22 02:12:38 +01:00
mark channel as read on open
This commit is contained in:
parent
329a14ccf5
commit
2f6a56d65e
@ -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")};
|
||||
@ -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}
|
||||
|
@ -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";
|
||||
@ -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} />
|
||||
|
@ -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);
|
||||
@ -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) {
|
||||
|
@ -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
|
||||
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user