diff --git a/docs/subsystems/input-pills.md b/docs/subsystems/input-pills.md index 60b3961241..ef7a5d3327 100644 --- a/docs/subsystems/input-pills.md +++ b/docs/subsystems/input-pills.md @@ -26,7 +26,7 @@ var pills = input_pill.create({ }); ``` -You can look at `web/src/user_pill.js` to see how the above +You can look at `web/src/user_pill.ts` to see how the above methods are implemented. Essentially you just need to convert from raw data (like an email) to structured data (like an object with display_value, email, and user_id for a user), and vice @@ -46,7 +46,7 @@ source: function () { }, ``` -And then in `user_pill.js`... +And then in `user_pill.ts`... ```js export function typeahead_source(pill_widget) { diff --git a/web/src/input_pill.ts b/web/src/input_pill.ts index 973ee2a7fd..72c8f50c9f 100644 --- a/web/src/input_pill.ts +++ b/web/src/input_pill.ts @@ -17,7 +17,7 @@ export type InputPillItem = { type: string; img_src?: string; deactivated?: boolean; - status_emoji_info?: EmojiRenderingDetails & {emoji_alt_code: boolean}; // TODO: Move this in user_status.js + status_emoji_info?: EmojiRenderingDetails & {emoji_alt_code?: boolean}; // TODO: Move this in user_status.js should_add_guest_user_indicator?: boolean; } & T; @@ -56,7 +56,7 @@ type InputPillRenderingDetails = { img_src?: string; deactivated?: boolean; has_status?: boolean; - status_emoji_info?: EmojiRenderingDetails & {emoji_alt_code: boolean}; + status_emoji_info?: EmojiRenderingDetails & {emoji_alt_code?: boolean}; should_add_guest_user_indicator?: boolean; }; diff --git a/web/src/user_pill.js b/web/src/user_pill.ts similarity index 74% rename from web/src/user_pill.js rename to web/src/user_pill.ts index 9bf608f86a..aa8e39d901 100644 --- a/web/src/user_pill.js +++ b/web/src/user_pill.ts @@ -1,13 +1,25 @@ import * as blueslip from "./blueslip"; +import type {InputPillContainer, InputPillItem} from "./input_pill"; import * as input_pill from "./input_pill"; import {page_params} from "./page_params"; +import type {User} from "./people"; import * as people from "./people"; import * as user_status from "./user_status"; // This will be used for pills for things like composing // direct messages or adding users to a stream/group. -export function create_item_from_email(email, current_items) { +type UserPill = { + user_id?: number; + email: string; +}; + +type UserPillWidget = InputPillContainer; + +export function create_item_from_email( + email: string, + current_items: InputPillItem[], +): InputPillItem | undefined { // For normal Zulip use, we need to validate the email for our realm. const user = people.get_by_email(email); @@ -45,7 +57,7 @@ export function create_item_from_email(email, current_items) { // We must supply display_value for the widget to work. Everything // else is for our own use in callbacks. - const item = { + const item: InputPillItem = { type: "user", display_value: user.full_name, user_id: user.user_id, @@ -64,11 +76,11 @@ export function create_item_from_email(email, current_items) { return item; } -export function get_email_from_item(item) { +export function get_email_from_item(item: InputPillItem): string { return item.email; } -export function append_person(opts) { +export function append_person(opts: {person: User; pill_widget: UserPillWidget}): void { const person = opts.person; const pill_widget = opts.pill_widget; const avatar_url = people.small_avatar_url_for_person(person); @@ -88,15 +100,12 @@ export function append_person(opts) { pill_widget.clear_text(); } -export function get_user_ids(pill_widget) { +export function get_user_ids(pill_widget: UserPillWidget): number[] { const items = pill_widget.items(); - let user_ids = items.map((item) => item.user_id); - user_ids = user_ids.filter(Boolean); // be defensive about undefined users - - return user_ids; + return items.flatMap((item) => item.user_id ?? []); // be defensive about undefined users } -export function has_unconverted_data(pill_widget) { +export function has_unconverted_data(pill_widget: UserPillWidget): boolean { // This returns true if we either have text that hasn't been // turned into pills or email-only pills (for Zephyr). if (pill_widget.is_pending()) { @@ -109,18 +118,18 @@ export function has_unconverted_data(pill_widget) { return has_unknown_items; } -export function typeahead_source(pill_widget, exclude_bots) { +export function typeahead_source(pill_widget: UserPillWidget, exclude_bots?: boolean): User[] { const users = exclude_bots ? people.get_realm_active_human_users() : people.get_realm_users(); return filter_taken_users(users, pill_widget); } -export function filter_taken_users(items, pill_widget) { +export function filter_taken_users(items: User[], pill_widget: UserPillWidget): User[] { const taken_user_ids = get_user_ids(pill_widget); items = items.filter((item) => !taken_user_ids.includes(item.user_id)); return items; } -export function append_user(user, pills) { +export function append_user(user: User, pills: UserPillWidget): void { if (user) { append_person({ pill_widget: pills, @@ -131,7 +140,12 @@ export function append_user(user, pills) { } } -export function create_pills($pill_container, pill_config) { +export function create_pills( + $pill_container: JQuery, + pill_config?: { + show_user_status_emoji?: boolean; + }, +): input_pill.InputPillContainer { const pills = input_pill.create({ $container: $pill_container, pill_config,