Skip to content

Commit

Permalink
types: Migrated todo_widget.js to todo_widget.ts.
Browse files Browse the repository at this point in the history
This commit migrates the todo_widget.js file to todo_widget.ts file.
The file extension is also modified in tests-js-with-node file.
  • Loading branch information
Wr4th100 committed Mar 23, 2024
1 parent 29ca4ba commit 63d95f7
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 34 deletions.
2 changes: 1 addition & 1 deletion tools/test-js-with-node
Expand Up @@ -246,7 +246,7 @@ EXEMPT_FILES = make_set(
"web/src/subscriber_api.ts",
"web/src/timerender.ts",
"web/src/tippyjs.ts",
"web/src/todo_widget.js",
"web/src/todo_widget.ts",
"web/src/topic_list.ts",
"web/src/topic_popover.js",
"web/src/tutorial.js",
Expand Down
126 changes: 93 additions & 33 deletions web/src/todo_widget.js → web/src/todo_widget.ts
@@ -1,50 +1,100 @@
import $ from "jquery";
import assert from "minimalistic-assert";
import {z} from "zod";

import type {InboundData} from "../shared/src/poll_data";
import render_widgets_todo_widget from "../templates/widgets/todo_widget.hbs";
import render_widgets_todo_widget_tasks from "../templates/widgets/todo_widget_tasks.hbs";

import * as blueslip from "./blueslip";
import {$t} from "./i18n";
import type {Message} from "./message_store";
import {page_params} from "./page_params";
import * as people from "./people";

// Any single user should send add a finite number of tasks
// to a todo list. We arbitrarily pick this value.
const MAX_IDX = 1000;

type Task = {
completed: boolean;
task: string;
desc: string;
idx: number;
key: string;
};

export type NewTaskOutboundData = {
type: string;
task: string;
desc: string;
key: number;
completed: boolean;
};
export type StrikeOutboundData = {
type: string;
key: string;
};
export type TodoHandle = {
[key: string]: {
outbound: (...args: string[]) => InboundData | undefined;
inbound: (sender_id: number, data: InboundData) => void;
};
new_task: {
outbound: (task: string, desc: string) => NewTaskOutboundData | undefined;
inbound: (sender_id: number, data: InboundData) => void;
};
strike: {
outbound: (key: string) => StrikeOutboundData;
inbound: (sender_id: number, data: InboundData) => void;
};
};

const inbount_new_task_schema = z.object({
key: z.number(),
task: z.string(),
desc: z.string(),
completed: z.boolean(),
type: z.literal("new_task"),
});

const inbound_strike_schema = z.object({
key: z.string(),
type: z.literal("strike"),
});

export class TaskData {
task_map = new Map();
task_map = new Map<string, Task>();
my_idx = 1;
me: number;

constructor({current_user_id}) {
constructor({current_user_id}: {current_user_id: number}) {
this.me = current_user_id;
}

get_widget_data() {
get_widget_data(): {all_tasks: Task[]} {
const all_tasks = [...this.task_map.values()];

const widget_data = {
all_tasks,
};

return widget_data;
}

name_in_use(name) {
name_in_use(name: string): boolean {
for (const item of this.task_map.values()) {
if (item.task === name) {
return true;
}
}

return false;
}

handle = {
// eslint-disable-next-line @typescript-eslint/member-ordering
handle: TodoHandle = {
new_task: {
outbound: (task, desc) => {
outbound: (task: string, desc: string) => {
this.my_idx += 1;
const event = {
const event: NewTaskOutboundData = {
type: "new_task",
key: this.my_idx,
task,
Expand All @@ -58,13 +108,14 @@ export class TaskData {
return undefined;
},

inbound: (sender_id, data) => {
inbound: (sender_id: number, data: InboundData): void => {
const safe_data = inbount_new_task_schema.parse(data);
// All messages readers may add tasks.
// for legacy reasons, the inbound idx is
// called key in the event
const idx = data.key;
const task = data.task;
const desc = data.desc;
const idx = safe_data.key;
const task = safe_data.task;
const desc = safe_data.desc;

if (!Number.isInteger(idx) || idx < 0 || idx > MAX_IDX) {
blueslip.warn("todo widget: bad type for inbound task idx");
Expand All @@ -82,14 +133,14 @@ export class TaskData {
}

const key = idx + "," + sender_id;
const completed = data.completed;
const completed = safe_data.completed;

const task_data = {
task,
desc,
idx,
key,
completed,
completed: Boolean(completed),
};

if (!this.name_in_use(task)) {
Expand All @@ -104,18 +155,18 @@ export class TaskData {
},

strike: {
outbound(key) {
const event = {
outbound(key: string) {
const event: StrikeOutboundData = {
type: "strike",
key,
};

return event;
},

inbound: (_sender_id, data) => {
// All message readers may strike/unstrike todo tasks.
const key = data.key;
inbound: (_sender_id: number, data: InboundData): void => {
const safe_data = inbound_strike_schema.parse(data);
const key = safe_data.key;
if (typeof key !== "string") {
blueslip.warn("todo widget: bad type for inbound strike key");
return;
Expand All @@ -133,33 +184,41 @@ export class TaskData {
},
};

handle_event(sender_id, data) {
handle_event(sender_id: number, data: InboundData): void {
const type = data.type;
if (this.handle[type] && this.handle[type].inbound) {
if (this.handle[type]?.inbound !== undefined) {
this.handle[type].inbound(sender_id, data);
} else {
blueslip.warn(`todo widget: unknown inbound type: ${type}`);
}
}
}

export function activate(opts) {
const $elem = opts.$elem;
export function activate(opts: {
$elem: JQuery;
callback: (data: NewTaskOutboundData | StrikeOutboundData | undefined) => void;
message: Message;
}): void {
const $elem: JQuery = opts.$elem;
const callback = opts.callback;

const task_data = new TaskData({
current_user_id: people.my_current_user_id(),
});

function render() {
function render(): void {
const html = render_widgets_todo_widget();
$elem.html(html);

$elem.find("button.add-task").on("click", (e) => {
e.stopPropagation();
$elem.find(".widget-error").text("");
const task = $elem.find("input.add-task").val().trim();
const desc = $elem.find("input.add-desc").val().trim();
const taskValue = $elem?.find<HTMLInputElement>("input.add-task")?.val();
assert(taskValue !== undefined, "taskValue is undefined");
const task = taskValue.trim();
const descValue = $elem?.find<HTMLInputElement>("input.add-desc")?.val();
assert(descValue !== undefined, "descValue is undefined");
const desc = descValue.trim();

if (task === "") {
return;
Expand All @@ -175,11 +234,13 @@ export function activate(opts) {
}

const data = task_data.handle.new_task.outbound(task, desc);
callback(data);
if (data) {
callback(data);
}
});
}

function render_results() {
function render_results(): void {
const widget_data = task_data.get_widget_data();
const html = render_widgets_todo_widget_tasks(widget_data);
$elem.find("ul.todo-widget").html(html);
Expand All @@ -199,13 +260,12 @@ export function activate(opts) {
return;
}
const key = $(e.target).attr("data-key");

const data = task_data.handle.strike.outbound(key);
const data = task_data.handle.strike.outbound(key ?? "");
callback(data);
});
}

$elem.handle_events = function (events) {
$elem.handle_events = function (events): void {
for (const event of events) {
task_data.handle_event(event.sender_id, event.data);
}
Expand Down

0 comments on commit 63d95f7

Please sign in to comment.