onboarding: Show one-time modal to introduce inbox view.

To improve onboarding experience, this commit adds
a one-time modal which introduces the inbox view.

Users see this one-time modal on visiting the inbox view.

Fixes part of #29073.
This commit is contained in:
Prakhar Pratyush 2024-03-05 16:33:05 +05:30 committed by Tim Abbott
parent c9d25b2a95
commit 9a7634d527
6 changed files with 84 additions and 2 deletions

View File

@ -16,6 +16,7 @@ IGNORED_PHRASES = [
r"Cookie Bot", r"Cookie Bot",
r"DevAuthBackend", r"DevAuthBackend",
r"DSN", r"DSN",
r"Esc",
r"GCM", r"GCM",
r"GitHub", r"GitHub",
r"Gravatar", r"Gravatar",
@ -23,6 +24,7 @@ IGNORED_PHRASES = [
r"HTTP", r"HTTP",
r"ID", r"ID",
r"IDs", r"IDs",
r"Inbox",
r"IP", r"IP",
r"JSON", r"JSON",
r"Kerberos", r"Kerberos",

View File

@ -4,19 +4,23 @@ import _ from "lodash";
import render_inbox_row from "../templates/inbox_view/inbox_row.hbs"; import render_inbox_row from "../templates/inbox_view/inbox_row.hbs";
import render_inbox_stream_container from "../templates/inbox_view/inbox_stream_container.hbs"; import render_inbox_stream_container from "../templates/inbox_view/inbox_stream_container.hbs";
import render_inbox_view from "../templates/inbox_view/inbox_view.hbs"; import render_inbox_view from "../templates/inbox_view/inbox_view.hbs";
import render_introduce_zulip_view_modal from "../templates/introduce_zulip_view_modal.hbs";
import render_user_with_status_icon from "../templates/user_with_status_icon.hbs"; import render_user_with_status_icon from "../templates/user_with_status_icon.hbs";
import * as buddy_data from "./buddy_data"; import * as buddy_data from "./buddy_data";
import * as compose_closed_ui from "./compose_closed_ui"; import * as compose_closed_ui from "./compose_closed_ui";
import * as compose_state from "./compose_state"; import * as compose_state from "./compose_state";
import * as dialog_widget from "./dialog_widget";
import * as dropdown_widget from "./dropdown_widget"; import * as dropdown_widget from "./dropdown_widget";
import * as hash_util from "./hash_util"; import * as hash_util from "./hash_util";
import {$t_html} from "./i18n";
import {is_visible, set_visible} from "./inbox_util"; import {is_visible, set_visible} from "./inbox_util";
import * as keydown_util from "./keydown_util"; import * as keydown_util from "./keydown_util";
import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area"; import * as left_sidebar_navigation_area from "./left_sidebar_navigation_area";
import {localstorage} from "./localstorage"; import {localstorage} from "./localstorage";
import * as message_store from "./message_store"; import * as message_store from "./message_store";
import * as modals from "./modals"; import * as modals from "./modals";
import * as onboarding_steps from "./onboarding_steps";
import * as overlays from "./overlays"; import * as overlays from "./overlays";
import * as people from "./people"; import * as people from "./people";
import * as popovers from "./popovers"; import * as popovers from "./popovers";
@ -26,6 +30,7 @@ import * as stream_data from "./stream_data";
import * as sub_store from "./sub_store"; import * as sub_store from "./sub_store";
import * as unread from "./unread"; import * as unread from "./unread";
import * as unread_ops from "./unread_ops"; import * as unread_ops from "./unread_ops";
import {user_settings} from "./user_settings";
import * as user_status from "./user_status"; import * as user_status from "./user_status";
import * as user_topics from "./user_topics"; import * as user_topics from "./user_topics";
import * as user_topics_ui from "./user_topics_ui"; import * as user_topics_ui from "./user_topics_ui";
@ -92,6 +97,24 @@ export function show() {
set_visible, set_visible,
complete_rerender, complete_rerender,
}); });
if (onboarding_steps.ONE_TIME_NOTICES_TO_DISPLAY.has("intro_inbox_view_modal")) {
const html_body = render_introduce_zulip_view_modal({
zulip_view: "inbox",
current_home_view_and_escape_navigation_enabled:
user_settings.web_home_view === "inbox" &&
user_settings.web_escape_navigates_to_home_view,
});
dialog_widget.launch({
html_heading: $t_html({defaultMessage: "Welcome to your <b>inbox</b>!"}),
html_body,
html_submit_button: $t_html({defaultMessage: "Continue"}),
on_click() {},
single_footer_button: true,
focus_submit_on_open: true,
});
onboarding_steps.post_onboarding_step_as_read("intro_inbox_view_modal");
}
} }
export function hide() { export function hide() {

View File

@ -467,3 +467,18 @@
} }
} }
} }
#introduce-zulip-view-modal {
i {
vertical-align: middle;
}
.keyboard-button {
color: var(--color-hotkey-hint);
font-size: 12px;
font-weight: 500;
padding: 2px 4px;
border-radius: 3px;
border: 1px solid var(--color-hotkey-hint);
}
}

View File

@ -0,0 +1,38 @@
<div id="introduce-zulip-view-modal">
<p>
{{#if (eq zulip_view "inbox")}}
{{#tr}}The <b>inbox</b> view provides an overview of your conversations with unread messages.{{/tr}}
{{/if}}
{{#tr}}
In Zulip, a conversation is either a <z-link-direct-message>direct message</z-link-direct-message>
thread, or a <z-link-stream-topic>topic in a stream</z-link-stream-topic>.
{{#*inline "z-link-direct-message"}}<a href="/help/direct-messages" target="_blank" rel="noopener noreferrer">{{> @partial-block }}</a>{{/inline}}
{{#*inline "z-link-stream-topic"}}<a href="/help/streams-and-topics" target="_blank" rel="noopener noreferrer">{{> @partial-block }}</a>{{/inline}}
{{/tr}}
{{#if (eq zulip_view "inbox")}}
{{t 'The colored bars indicate which stream the conversation is in.' }}
{{/if}}
</p>
<p>
{{t 'Click on a conversation to view it. To return here, you can:'}}
<ul>
<li>{{#tr}}Use the <b>back</b> button in your browser or desktop app.{{/tr}}</li>
<li>
{{#if (eq zulip_view "inbox")}}
{{#tr}}
Click <z-icon-inbox></z-icon-inbox> <b>Inbox</b> in the left sidebar.
{{#*inline "z-icon-inbox"}}<i class="zulip-icon zulip-icon-inbox" aria-hidden="true"></i>{{/inline}}
{{/tr}}
{{/if}}
</li>
{{#if current_home_view_and_escape_navigation_enabled}}
<li>
{{#tr}}
Use <z-button>Esc</z-button> to go to your home view.
{{#*inline "z-button"}}<span class="keyboard-button">{{@partial-block}}</span>{{/inline}}
{{/tr}}
</li>
{{/if}}
</ul>
</p>
</div>

View File

@ -83,6 +83,9 @@ ONE_TIME_NOTICES: List[OneTimeNotice] = [
OneTimeNotice( OneTimeNotice(
name="visibility_policy_banner", name="visibility_policy_banner",
), ),
OneTimeNotice(
name="intro_inbox_view_modal",
),
] ]
# We would most likely implement new hotspots in the future that aren't # We would most likely implement new hotspots in the future that aren't

View File

@ -39,9 +39,10 @@ class TestGetNextOnboardingSteps(ZulipTestCase):
do_mark_onboarding_step_as_read(self.user, "intro_streams") do_mark_onboarding_step_as_read(self.user, "intro_streams")
do_mark_onboarding_step_as_read(self.user, "intro_compose") do_mark_onboarding_step_as_read(self.user, "intro_compose")
onboarding_steps = get_next_onboarding_steps(self.user) onboarding_steps = get_next_onboarding_steps(self.user)
self.assert_length(onboarding_steps, 2) self.assert_length(onboarding_steps, 3)
self.assertEqual(onboarding_steps[0]["name"], "visibility_policy_banner") self.assertEqual(onboarding_steps[0]["name"], "visibility_policy_banner")
self.assertEqual(onboarding_steps[1]["name"], "intro_topics") self.assertEqual(onboarding_steps[1]["name"], "intro_inbox_view_modal")
self.assertEqual(onboarding_steps[2]["name"], "intro_topics")
def test_all_onboarding_steps_done(self) -> None: def test_all_onboarding_steps_done(self) -> None:
with self.settings(TUTORIAL_ENABLED=True): with self.settings(TUTORIAL_ENABLED=True):