slackapi / node-tasks-app

Tasks App is a sample Task Management app built on the Slack Platform.
MIT License
99 stars 50 forks source link

[FEATURE] Using partials and conditionals for UI #88

Open raycharius opened 2 years ago

raycharius commented 2 years ago

Is there an existing request for this?

Have you read our code of conduct?

Feature as a user story

I recently released an update to the slack-block-builder library that includes helper functions for inline conditionals, which can be helpful in a few places here, for example:

const { Modal, Blocks, Elements } = require('slack-block-builder');

module.exports = (prefilledTitle, currentUser) => {
  const textInput = (taskTitle) => {
    if (taskTitle) {
      return Elements.TextInput({
        placeholder: 'Do this thing',
        actionId: 'taskTitle',
        initialValue: taskTitle,
      });
    }
    return Elements.TextInput({
      placeholder: 'Do this thing',
      actionId: 'taskTitle',
    });
  };

  return Modal({ title: 'Create new task', submit: 'Create', callbackId: 'new-task-modal' })
    .blocks(
      Blocks.Input({ label: 'New task', blockId: 'taskTitle' }).element(
        textInput(prefilledTitle),
      ),
      Blocks.Input({ label: 'Assign user', blockId: 'taskAssignUser' }).element(
        Elements.UserSelect({
          actionId: 'taskAssignUser',
        }).initialUser(currentUser),
      ),
      Blocks.Input({ label: 'Due date', blockId: 'taskDueDate', optional: true }).element(
        Elements.DatePicker({
          actionId: 'taskDueDate',
        }),
      ),
      Blocks.Input({ label: 'Time', blockId: 'taskDueTime', optional: true }).element(
        Elements.TimePicker({
          actionId: 'taskDueTime',
        }),
      ),
    ).buildToJSON();
};

This can easily become the following:

const { Modal, Blocks, Elements, setIfTruthy } = require('slack-block-builder');

module.exports = (prefilledTitle, currentUser) => Modal({
  title: 'Create new task',
  submit: 'Create',
  callbackId: 'new-task-modal',
})
  .blocks(
    Blocks.Input({ label: 'New task', blockId: 'taskTitle' }).element(
      Elements.TextInput({
        placeholder: 'Do this thing',
        actionId: 'taskTitle',
        initialValue: setIfTruthy(prefilledTitle, prefilledTitle),
      })
    ),
    Blocks.Input({ label: 'Assign user', blockId: 'taskAssignUser' }).element(
      Elements.UserSelect({
        actionId: 'taskAssignUser',
      }).initialUser(currentUser),
    ),
    Blocks.Input({ label: 'Due date', blockId: 'taskDueDate', optional: true }).element(
      Elements.DatePicker({
        actionId: 'taskDueDate',
      }),
    ),
    Blocks.Input({ label: 'Time', blockId: 'taskDueTime', optional: true }).element(
      Elements.TimePicker({
        actionId: 'taskDueTime',
      }),
    ),
  ).buildToJSON();

It gets rid of the if, the duplicated copy, and keeps the view's code similar to the view itself. There are a few other similar places.

Another idea was to include partials, which was something we touched on during the talk around Tasks App at Frontiers:

module.exports = (openTasks) => HomeTab({
  callbackId: 'tasks-home',
  privateMetaData: 'open',
}).blocks(
  partials.homeTabNavigation({ isOpenTasks: true }),
  openTasks.length === 0
    ? partials.emptyTaskListContent({
      title: 'No open tasks',
      message: 'Looks like you\'ve got nothing to do.',
    })
    : partials.openTaskListContent(openTasks),
).buildToJSON();

Let me know what you think – happy to send over a PR!