Skip to content

Commit

Permalink
render user join messages
Browse files Browse the repository at this point in the history
  • Loading branch information
Puyodead1 committed Sep 8, 2023
1 parent 05d9ea7 commit 1211093
Show file tree
Hide file tree
Showing 15 changed files with 212 additions and 151 deletions.
8 changes: 5 additions & 3 deletions src/components/Link.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import styled from "styled-components";

export const Link = styled.a`
export const Link = styled.a<{ color?: string }>`
// remove the default underline
text-decoration: none;
// set the color to the primary color
color: var(--primary-light);
color: ${(props) => props.color || "var(--primary-light)"};
cursor: pointer;
// remove the color when already visited because ew
&:visited {
color: var(--primary-light);
color: ${(props) => props.color || "var(--primary-light)"};
}
// when hovered, add underline
&:hover {
Expand Down
67 changes: 47 additions & 20 deletions src/components/messaging/Message.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@ import Moment from "react-moment";
import styled from "styled-components";
import { ContextMenuContext } from "../../contexts/ContextMenuContext";
import { useAppStore } from "../../stores/AppStore";
import { default as MessageObject } from "../../stores/objects/Message";
import QueuedMessage from "../../stores/objects/QueuedMessage";
import { MessageLike } from "../../stores/objects/Message";
import { calendarStrings } from "../../utils/i18n";
import Avatar from "../Avatar";
import { Link } from "../Link";
Expand All @@ -15,8 +14,6 @@ import AttachmentUploadProgress from "./AttachmentUploadProgress";
import MessageAttachment from "./MessageAttachment";
import MessageEmbed from "./MessageEmbed";

type MessageLike = MessageObject | QueuedMessage;

const MessageListItem = styled.li`
list-style: none;
`;
Expand Down Expand Up @@ -154,6 +151,51 @@ function Message({ message, isHeader, isSending, isFailed }: Props) {
// // setContextMenuOptions(items);
// }, [isSending, isFailed]);

// handles creating the message content based on the message type
const renderMessageContent = React.useCallback(() => {
switch (message.type) {
case MessageType.Default:
return (
<MessageContent sending={isSending} failed={isFailed}>
{message.content ? <Linkify>{message.content}</Linkify> : null}
{"attachments" in message
? message.attachments.map((attachment) => renderAttachment(attachment))
: null}
{"embeds" in message ? message.embeds.map((embed) => renderEmbed(embed)) : null}
</MessageContent>
);
case MessageType.UserJoin: {
// TODO: render only the join message and timestamp, will require a bit of refactoring
const msg = message.getJoinMessage();
const split = msg.split("{author}");
return (
<MessageContent
style={{
color: "var(--text-secondary)",
fontWeight: "var(--font-weight-regular)",
fontSize: "16px",
}}
>
{split[0]}
<Link color="var(--text)" style={{ fontWeight: "var(--font-weight-medium)" }}>
{message.author.username}
</Link>
{split[1]}
</MessageContent>
);
}
default:
return (
<div>
<div style={{ color: "var(--text-secondary)", fontSize: "12px" }}>
MessageType({MessageType[message.type]})
</div>
{message.content}
</div>
);
}
}, [message, isSending, isFailed, renderAttachment, renderEmbed]);

return (
<MessageListItem>
<Container
Expand Down Expand Up @@ -192,22 +234,7 @@ function Message({ message, isHeader, isSending, isFailed }: Props) {
</MessageHeader>
)}

{message.type === MessageType.Default ? (
<MessageContent sending={isSending} failed={isFailed}>
{message.content ? <Linkify>{message.content}</Linkify> : null}
{"attachments" in message
? message.attachments.map((attachment) => renderAttachment(attachment))
: null}
{"embeds" in message ? message.embeds.map((embed) => renderEmbed(embed)) : null}
</MessageContent>
) : (
<div>
<div style={{ color: "var(--text-secondary)", fontSize: "12px" }}>
MessageType({MessageType[message.type]})
</div>
{message.content ?? "No Content"}
</div>
)}
{renderMessageContent()}

{"files" in message && message.files?.length !== 0 && (
<div>
Expand Down
3 changes: 1 addition & 2 deletions src/components/messaging/MessageGroup.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { observer } from "mobx-react-lite";
import React from "react";
import styled from "styled-components";
import { QueuedMessageStatus } from "../../stores/MessageQueue";
import { default as MessageObject } from "../../stores/objects/Message";
import QueuedMessage from "../../stores/objects/QueuedMessage";
import QueuedMessage, { QueuedMessageStatus } from "../../stores/objects/QueuedMessage";
import Message from "./Message";

const Container = styled.div`
Expand Down
7 changes: 4 additions & 3 deletions src/components/messaging/MessageInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import useLogger from "../../hooks/useLogger";
import { useAppStore } from "../../stores/AppStore";
import Channel from "../../stores/objects/Channel";

import { RESTPostAPIChannelMessageJSONBody } from "@spacebarchat/spacebar-api-types/v9";
import { MessageType, RESTPostAPIChannelMessageJSONBody } from "@spacebarchat/spacebar-api-types/v9";
import { observer } from "mobx-react-lite";
import React, { useMemo } from "react";
import { BaseEditor, Descendant, Node, createEditor } from "slate";
import { HistoryEditor, withHistory } from "slate-history";
import { Editable, ReactEditor, Slate, withReact } from "slate-react";
import Guild from "../../stores/objects/Guild";
import User from "../../stores/objects/User";
import { Permissions } from "../../utils/Permissions";
import Snowflake from "../../utils/Snowflake";
import { HorizontalDivider } from "../Divider";
Expand Down Expand Up @@ -141,10 +140,12 @@ function MessageInput(props: Props) {
const nonce = Snowflake.generate();
const msg = app.queue.add({
id: nonce,
author: app.account! as unknown as User,
content,
channel: props.channel.id,
files: attachments,
timestamp: new Date().toISOString(),
type: MessageType.Default,
author: app.account!.raw,
});

if (shouldSend) {
Expand Down
3 changes: 2 additions & 1 deletion src/pages/LoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ import HCaptcha, { HeaderContainer } from "../components/HCaptcha";
import ForgotPasswordModal from "../components/modals/ForgotPasswordModal";
import useLogger from "../hooks/useLogger";
import { AUTH_NO_BRANDING, useAppStore } from "../stores/AppStore";
import { Globals, RouteSettings } from "../utils/Globals";
import { Globals } from "../utils/Globals";
import REST from "../utils/REST";
import { RouteSettings } from "../utils/constants";
import {
IAPILoginRequest,
IAPILoginResponse,
Expand Down
5 changes: 4 additions & 1 deletion src/stores/AccountStore.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { APIUser } from "@spacebarchat/spacebar-api-types/v9";
import {
APIUser,
CDNRoutes,
DefaultUserAvatarAssets,
ImageFormat,
Expand All @@ -23,10 +23,13 @@ export default class AccountStore {
@observable premiumType?: UserPremiumType.NitroClassic | UserPremiumType.Nitro | UserPremiumType.NitroBasic;
@observable flags?: UserFlags;
@observable publicFlags?: UserFlags;
@observable raw: APIUser;
// phone: string | null;
// nsfwAllowed: boolean | null;

constructor(user: APIUser) {
this.raw = user;

this.id = user.id;
this.username = user.username;
this.discriminator = user.discriminator;
Expand Down
2 changes: 1 addition & 1 deletion src/stores/AppStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default class AppStore {
@observable rest = new REST(this);
@observable experiments = new ExperimentsStore();
@observable presences = new PresenceStore(this);
@observable queue = new MessageQueue();
@observable queue = new MessageQueue(this);

constructor() {
makeAutoObservable(this);
Expand Down
22 changes: 5 additions & 17 deletions src/stores/MessageQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,14 @@ import { action, computed, makeAutoObservable, observable } from "mobx";

import type { IObservableArray } from "mobx";
import Snowflake from "../utils/Snowflake";
import QueuedMessage from "./objects/QueuedMessage";
import User from "./objects/User";

export enum QueuedMessageStatus {
SENDING = "sending",
FAILED = "failed",
}

export type QueuedMessageData = {
id: string;
channel: string;
author: User;
content: string;
files?: File[];
};
import AppStore from "./AppStore";
import type { QueuedMessageData } from "./objects/QueuedMessage";
import QueuedMessage, { QueuedMessageStatus } from "./objects/QueuedMessage";

export default class MessageQueue {
@observable private readonly messages: IObservableArray<QueuedMessage>;

constructor() {
constructor(private readonly app: AppStore) {
this.messages = observable.array([]);

makeAutoObservable(this);
Expand All @@ -36,7 +24,7 @@ export default class MessageQueue {
// status: QueuedMessageStatus.SENDING,
// type: MessageType.Default,
// });
const msg = new QueuedMessage(data);
const msg = new QueuedMessage(this.app, data);
this.messages.push(msg);
return msg;
}
Expand Down
113 changes: 37 additions & 76 deletions src/stores/objects/Message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,46 +16,21 @@ import type {
APIStickerItem,
APIUser,
MessageFlags,
MessageType,
Snowflake,
} from "@spacebarchat/spacebar-api-types/v9";
import { action, observable } from "mobx";
import AppStore from "../AppStore";
import User from "./User";
import MessageBase from "./MessageBase";
import QueuedMessage, { QueuedMessageData } from "./QueuedMessage";

export default class Message {
private readonly app: AppStore;
/**
* ID of the message
*/
id: Snowflake;
export type MessageLike = Message | QueuedMessage;
export type MessageLikeData = APIMessage | QueuedMessageData;

export default class Message extends MessageBase {
/**
* ID of the channel the message was sent in
*/
channel_id: Snowflake;
/**
* The author of this message (only a valid user in the case where the message is generated by a user or bot user)
*
* If the message is generated by a webhook, the author object corresponds to the webhook's id,
* username, and avatar. You can tell if a message is generated by a webhook by checking for the `webhook_id` property
*
* See https://discord.com/developers/docs/resources/user#user-object
*/
author: User;
/**
* Contents of the message
*
* The `MESSAGE_CONTENT` privileged gateway intent will become required after **August 31, 2022** for verified applications to receive a non-empty value from this field
*
* In the Discord Developers Portal, you need to enable the toggle of this intent of your application in **Bot > Privileged Gateway Intents**
*
* See https://support-dev.discord.com/hc/articles/4404772028055
*/
@observable content: string;
/**
* When this message was sent
*/
timestamp: Date;
/**
* When this message was edited (or null if never)
*/
Expand Down Expand Up @@ -141,12 +116,6 @@ export default class Message {
* If the message is generated by a webhook, this is the webhook's id
*/
webhook_id?: Snowflake;
/**
* Type of message
*
* See https://discord.com/developers/docs/resources/channel#message-object-message-types
*/
type: MessageType;
/**
* Sent with Rich Presence-related chat embeds
*
Expand Down Expand Up @@ -230,47 +199,39 @@ export default class Message {
*/
position?: number;

constructor(app: AppStore, message: APIMessage) {
this.app = app;
constructor(app: AppStore, data: APIMessage) {
super(app, data);

this.id = message.id;
this.channel_id = message.channel_id;
this.id = data.id;
this.channel_id = data.channel_id;
// this.member = message.member ? new GuildMember(message.member) : undefined;
this.content = message.content;
this.timestamp = new Date(message.timestamp);
this.edited_timestamp = message.edited_timestamp ? new Date(message.edited_timestamp) : null;
this.tts = message.tts;
this.mention_everyone = message.mention_everyone;
this.mentions = message.mentions; // TODO: user object?
this.mention_roles = message.mention_roles;
this.mention_channels = message.mention_channels;
this.attachments = message.attachments;
this.embeds = message.embeds;
this.reactions = message.reactions;
this.nonce = message.nonce;
this.pinned = message.pinned;
this.webhook_id = message.webhook_id;
this.type = message.type;
this.activity = message.activity;
this.application = message.application;
this.application_id = message.application_id;
this.message_reference = message.message_reference;
this.flags = message.flags;
this.referenced_message = message.referenced_message;
this.interaction = message.interaction;
this.thread = message.thread;
this.components = message.components;
this.sticker_items = message.sticker_items;
this.stickers = message.stickers;
this.position = message.position;

if (this.app.users.has(message.author.id)) {
this.author = this.app.users.get(message.author.id) as User;
} else {
const user = new User(message.author);
this.app.users.users.set(user.id, user);
this.author = user;
}
this.content = data.content;
this.timestamp = new Date(data.timestamp);
this.edited_timestamp = data.edited_timestamp ? new Date(data.edited_timestamp) : null;
this.tts = data.tts;
this.mention_everyone = data.mention_everyone;
this.mentions = data.mentions; // TODO: user object?
this.mention_roles = data.mention_roles;
this.mention_channels = data.mention_channels;
this.attachments = data.attachments;
this.embeds = data.embeds;
this.reactions = data.reactions;
this.nonce = data.nonce;
this.pinned = data.pinned;
this.webhook_id = data.webhook_id;
this.type = data.type;
this.activity = data.activity;
this.application = data.application;
this.application_id = data.application_id;
this.message_reference = data.message_reference;
this.flags = data.flags;
this.referenced_message = data.referenced_message;
this.interaction = data.interaction;
this.thread = data.thread;
this.components = data.components;
this.sticker_items = data.sticker_items;
this.stickers = data.stickers;
this.position = data.position;
}

@action
Expand Down
Loading

0 comments on commit 1211093

Please sign in to comment.