Skip to content

Carry Over Todos

You can enhance the basic todo script from the guide so that unfinished items from the previous todo list carry over to the new one:

TypeScript
async function () {
  const { quote } = zeta.v1.element;
  const { openNote } = zeta.v1.ui;
  const { get } = zeta.v1.http;
  const { _ } = zeta.v1.common;

  const {
    getNoteIdByTitle,
    getNodesByTag,
    getNote,
  } = zeta.v1.query;

  const {
    createNote,
    updateNote,
    tagNote,
  } = zeta.v1.api;

  const todayNoteTitle = `Todo ${
    new Date().toLocaleDateString("sv")
  }`;

  const todayNoteId = await getNoteIdByTitle(
    todayNoteTitle
  );

  // If a todo list already exists
  // for today, simply open it.
  if (todayNoteId) {
    openNote(todayNoteId);

    return;
  }

  const nodes = getNodesByTag("Todo");
  const notes = [];

  // Fetch all previous todo lists.
  for await (const node of nodes) {
    if (
      node.type === "Note" &&
      /^Todo \d{4}-\d{2}-\d{2}$/.test(node.title)
    ) {
      const date = node.title.slice(5);
      const time = new Date(date).getTime();

      notes.push({
        id: node.id,
        time,
      });
    }
  }

  const { data } = await get([
    "https://api.quotable.io/quotes/random",
    "?tags=inspirational",
  ].join(""));

  const res = data[0];

  const inspirationalQuote =
    quote(`"${res.content}" - ${res.author}`);

  // If there are no previous todo lists,
  // just create a new one and open it.
  if (!notes.length) {
    const newNoteId = createNote({
      title: todayNoteTitle,
      content: inspirationalQuote,
    });

    tagNote(newNoteId, "Todo");
    openNote(newNoteId);

    return;
  }

  // Get the latest todo list note ID.
  const oldNoteId = _.sortBy(
    notes,
    ({ time }) => time
  )[notes.length - 1].id;

  const { content } = await getNote(oldNoteId);

  let isParentDone = false;

  // Partition todos by whether
  // the top-level todo is done.
  const [
    oldContent,
    newContent,
  ] = _.partition(
    content,
    (element) => {
      if (element.type !== "Todo") {
        return true;
      }

      if (element.data.indent > 0) {
        return isParentDone;
      }

      isParentDone = element.data.done;

      return isParentDone;
    }
  );

  // Only keep finished items
  // in the latest todo list.
  updateNote(oldNoteId, {
    content: oldContent,
  });

  // Create a new note by carrying
  // over all the unfinished items.
  const newNoteId = createNote({
    title: todayNoteTitle,

    content: [
      inspirationalQuote,
      ...newContent,
    ],
  });

  tagNote(newNoteId, "Todo");
  openNote(newNoteId);
}

Now, running todo() in a code cell will move unfinished items from the previous todo list to the new todo list for today.