mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 13:08:40 +08:00
This does a handful of things to improve the livestream chat experience: 1. RSVP prompt replaces the default join button. A new chat-channel-preview-card-content plugin outlet in core chat lets the calendar plugin's livestream-rsvp connector fill the redesigned preview card's content slots. For users who can RSVP, it swaps the default join button for a going button for the event. 2. Pinned reference message linking back to the event topic. When a livestream channel is created, a system message is posted and pinned, and its id is stored in a new `reference_message_id` column. It's hidden via CSS when the chat is embedded in that same topic because it would be redundant. 3. Access control for private events. `chat_channel_id` is only serialized to users who can access the event's chat (invitees/invited groups, or admins) 4. If the channel is already open and expanded in the chat drawer, the embedded chat (and the livestream page layout) are suppressed. 5. Livestream channels are created with the spiral calendar emoji 🗓️ as their icon. I also converted core chat's preview card from viewport media queries to container queries so its layout responds to the width of the chat column it's rendered in rather than the viewport. With livestream sidebar <img width="2962" height="1726" alt="image" src="https://github.com/user-attachments/assets/71dc3d3f-35e5-4a0d-9103-92a03d4bb08e" /> Isolated chat when you're not in the livestream topic <img width="2560" height="1726" alt="image" src="https://github.com/user-attachments/assets/51cef0b8-85b4-4be8-a4f3-bf669f4be4fb" /> --------- Co-authored-by: Martin Brennan <martin@discourse.org>
161 lines
5.9 KiB
Text
Vendored
161 lines
5.9 KiB
Text
Vendored
import { getOwner } from "@ember/owner";
|
|
import { render } from "@ember/test-helpers";
|
|
import { module, test } from "qunit";
|
|
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
|
import { i18n } from "discourse-i18n";
|
|
import ChatChannelCard from "discourse/plugins/chat/discourse/components/chat-channel-card";
|
|
import ChatChannelPreviewCard from "discourse/plugins/chat/discourse/components/chat-channel-preview-card";
|
|
import ChatFabricators from "discourse/plugins/chat/discourse/lib/fabricators";
|
|
import { LIVESTREAM_CHAT_CONTEXT } from "discourse/plugins/discourse-calendar/discourse/components/livestream/embeddable-chat-channel";
|
|
|
|
module("Discourse Calendar | Component | LivestreamRsvp", function (hooks) {
|
|
setupRenderingTest(hooks);
|
|
|
|
hooks.beforeEach(function () {
|
|
this.channel = new ChatFabricators(getOwner(this)).channel({
|
|
chatable_type: "Category",
|
|
});
|
|
this.channel.title = "livestream chat";
|
|
this.channel.meta = { can_join_chat_channel: true };
|
|
this.currentUser.set("has_chat_enabled", true);
|
|
this.siteSettings.chat_enabled = true;
|
|
|
|
this.setLivestreamTopic = (overrides = {}) => {
|
|
this.channel.livestreamTopic = {
|
|
id: 1,
|
|
title: "Watching the birds",
|
|
slug: "watching-the-birds",
|
|
url: "/t/watching-the-birds/1",
|
|
event_id: 99,
|
|
can_update_attendance: true,
|
|
watching_invitee_status: null,
|
|
...overrides,
|
|
};
|
|
};
|
|
});
|
|
|
|
test("replaces the join button with a linked RSVP message for livestream channels", async function (assert) {
|
|
this.setLivestreamTopic();
|
|
|
|
await render(
|
|
<template><ChatChannelPreviewCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert
|
|
.dom(".livestream-rsvp__message a[href='/t/watching-the-birds/1']")
|
|
.exists("links to the livestream topic");
|
|
assert
|
|
.dom(".chat-channel-preview-card__actions .livestream-rsvp__going-button")
|
|
.exists("renders the RSVP button in the preview card actions");
|
|
assert.dom(".toggle-channel-membership-button.-join").doesNotExist();
|
|
});
|
|
|
|
test("does not link the topic when rendered within the livestream topic", async function (assert) {
|
|
this.setLivestreamTopic();
|
|
|
|
await render(
|
|
<template>
|
|
<ChatChannelPreviewCard
|
|
@channel={{this.channel}}
|
|
@context={{LIVESTREAM_CHAT_CONTEXT}}
|
|
/>
|
|
</template>
|
|
);
|
|
|
|
assert
|
|
.dom(".livestream-rsvp__message")
|
|
.hasText(i18n("discourse_calendar.livestream.chat.rsvp_to_event"));
|
|
assert.dom(".livestream-rsvp__message a").doesNotExist();
|
|
});
|
|
|
|
test("keeps the default join button when the user cannot join the event", async function (assert) {
|
|
this.setLivestreamTopic({ can_update_attendance: false });
|
|
|
|
await render(
|
|
<template><ChatChannelPreviewCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert.dom(".toggle-channel-membership-button.-join").exists();
|
|
assert.dom(".livestream-rsvp__going-button").doesNotExist();
|
|
});
|
|
|
|
test("keeps the default join button when the user is already going", async function (assert) {
|
|
this.setLivestreamTopic({ watching_invitee_status: "going" });
|
|
|
|
await render(
|
|
<template><ChatChannelPreviewCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert.dom(".toggle-channel-membership-button.-join").exists();
|
|
assert.dom(".livestream-rsvp__going-button").doesNotExist();
|
|
});
|
|
|
|
test("keeps the default join button for regular channels", async function (assert) {
|
|
await render(
|
|
<template><ChatChannelPreviewCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert.dom(".toggle-channel-membership-button.-join").exists();
|
|
assert.dom(".livestream-rsvp__going-button").doesNotExist();
|
|
});
|
|
|
|
test("does not render the RSVP replacement when the livestream topic is absent", async function (assert) {
|
|
this.channel.livestreamTopic = undefined;
|
|
|
|
await render(
|
|
<template><ChatChannelPreviewCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert.dom(".livestream-rsvp").doesNotExist();
|
|
assert.dom(".livestream-rsvp__message").doesNotExist();
|
|
assert.dom(".livestream-rsvp__going-button").doesNotExist();
|
|
assert.dom(".toggle-channel-membership-button.-join").exists();
|
|
});
|
|
|
|
module("browse channels card", function () {
|
|
test("replaces the join button with the RSVP button for livestream channels", async function (assert) {
|
|
this.setLivestreamTopic();
|
|
|
|
await render(
|
|
<template><ChatChannelCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert
|
|
.dom(".chat-channel-card__cta .livestream-rsvp__going-button")
|
|
.exists("renders the RSVP button in the card CTA");
|
|
assert.dom(".toggle-channel-membership-button.-join").doesNotExist();
|
|
});
|
|
|
|
test("keeps the default join button when the user cannot join the event", async function (assert) {
|
|
this.setLivestreamTopic({ can_update_attendance: false });
|
|
|
|
await render(
|
|
<template><ChatChannelCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert.dom(".toggle-channel-membership-button.-join").exists();
|
|
assert.dom(".livestream-rsvp__going-button").doesNotExist();
|
|
});
|
|
|
|
test("keeps the default join button for regular channels", async function (assert) {
|
|
await render(
|
|
<template><ChatChannelCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert.dom(".toggle-channel-membership-button.-join").exists();
|
|
assert.dom(".livestream-rsvp__going-button").doesNotExist();
|
|
});
|
|
|
|
test("keeps the leave button for existing chat members", async function (assert) {
|
|
this.setLivestreamTopic();
|
|
this.channel.currentUserMembership = { following: true };
|
|
|
|
await render(
|
|
<template><ChatChannelCard @channel={{this.channel}} /></template>
|
|
);
|
|
|
|
assert.dom(".toggle-channel-membership-button.-leave").exists();
|
|
assert.dom(".livestream-rsvp__going-button").doesNotExist();
|
|
});
|
|
});
|
|
});
|