@planningcenter/topbar
TypeScript icon, indicating that this package has built-in type declarations

9.9.0 • Public • Published

TOPBAR

The shared Planning Center product Topbar

In general, it is responsible for a number of things that are shared across our apps.

Usage

To a limited extent, each product can customize the display of these items as they see fit. For the majority of the products, implementation is very similar. You can view product-specific examples below.

Disabling the notifications inbox

The global determination of whether the notifications inbox is enabled or disabled is controlled via a People flipper flag. However, if your app needs to disable the notifications inbox for whatever reason, set window.notificationsDisabled = true when your app renders and we'll honor that setting. Because settings and flags are cached for one load cycle, it will take a fresh reload from the user to have the disable override to take effect.

Shared Jolt connections

New in v7.3 is the admin notifications inbox feature. Visually, this is a bell in the topbar that, when clicked, will display a dropdown containing notifications from every app in their account. Because a notification can be sent to a user as they are working on a page, topbar subscribes to a special notifications channel for the current user that provides push updates to the dropdown.

For a handful of reasons (not least of which is because we pay per Jolt connection), if the current page of an app is already using a Jolt connection, topbar would like to piggy-back on that connection for its own subscription. Note that this connection sharing is entirely optional for the parent app, but strongly encouraged. If a Jolt connection is not shared with topbar, it will gladly initiate its own connection specifically for its purposes.

To reuse your app's Jolt connection, topbar requires a Promise that resolves into a Jolt client connection. If nothing is passed—or if a Promise is passed that resolves to undefined or void—topbar will initiate its own connection.

Topbar hooks into pco-page-expired and will disconnect when the session is invalidated (i.e. logged out in a different tab). This occurs for topbar-created jolt instances as well as jolt instances provided to topbar via the joltPromise prop. CSRF tokens are invalidated when the session is invalidated. Non-GET APIv2 requests (i.e. auth/subscribe) require a valid CSRF token and will never succeed in that state.

Example

As an example, we'll use what Services has done for the v7.3 alpha. As a layout partial, they attach two Jolt-related things to window:

  1. joltListener (an instance of their own wrapper around the jolt-client library)
  2. joltListenerPromise (a jolt-client instance that has gone through (or will go through asynchronously) the connection and authorization process)
<script>
  window.joltListener = new window.JoltListener()
  window.joltListenerPromise = window.joltListener.connect()
</script>

In their Topbar implementation component, they then create the function that provides topbar the required Promise...

const waitForWindowJolt = async () =>
  window.joltListenerPromise.then(listener => {
    if (listener && listener.jolt) {
      return listener.jolt
    }
  })

...and passes that function in for the JoltPromise prop to topbar. Topbar can then use this Promise to determine whether or not it needs to create its own connection or piggyback on one provided.

The implementation details for your app can be decided by you and dependent on your apps current usage of Jolt.

Upgrade

yarn add @planningcenter/topbar

Develop

cd ~/Code/planningcenter/design/planningcenter/topbar
npm i
npm run dev

The dev script starts a server at http://localhost:9000.

The dev/dev.tsx is the main dev environment component.

Local App Development

If you are working on a new feature or run into a specific bug in your application and need to inspect the problem locally before publishing, you can use yalc to install and run the Topbar package locally.

To get started:

  1. In /topbar: yalc publish
  2. In your product: yalc add @planningcenter/topbar

When you make topbar changes, run yalc publish --push to update your product.

When you're done, in your product directory run yalc remove @planningcenter/topbar.

If you are not seeing published updates after running yalc publish --push or things break in your app after running yalc remove @planningcenter/topbar then in your product you will want to be running bin/webpack-dev-server. From experience, we have seen that the People app will automatically reload while running bin/webpack-dev-server. Unfortunately, in the Services app we have had to restart bin/webpack-dev-server every time for a change to come in. This may change depending on what app you're adding your yalc changes to.

Debugging Jolt

The jolt-client library has the ability to log debug information to the console. This functionality is configured when creating a client and is disabled by default. If you are passing your own Jolt client object into Topbar via props, you can configure it as required before providing it to Topbar. If you are relying on Topbar to create its own Jolt connection and would like to enable logging, pass enableJoltLogging={true} as a prop to whichever topbar components you are using you are using (AppsProvider/Tasks/Toolbar).

Toolbar

Toolbar lives alongside Topbar on the right side of the viewport. It is responsible for the global concerns of Profile, Help Desk, Tasks, Notifications, and Core Messaging.

Contributing

Tool implementations are self-contained modules that live in the modules/toolbar/tools/ directory.

A tool module is required to have a named export which adheres to the following ToolbarTool interface.

interface ToolbarTool {
  component: unknown // A React component. Stronger typing is in the works.
  icon: string
  name: string
}
  • component: the React component that will be rendered into the drawer when the tool is selected.
  • icon: the name of the tapestry-react icon that will be rendered as the button in Toolbar.
  • name: the formal name of the tool. For now, this is only surfaced for accessibility concerns on the tool's toolbar Button.

Example

The following example implements an example tool using the shared DrawerHeader and DrawerHeading components.

  • DrawerHeader handles the placement and styling of the close button.
  • DrawerHeading handles the styling of the drawer heading.
// tool_name.tsx

import { DrawerHeader, DrawerHeading } from "../components"

import { ToolbarTool } from "../types"

function ToolComponent({ closeDrawer }) {
  return (
    <>
      <DrawerHeader closeDrawer={closeDrawer}>
        <DrawerHeading>Tool name</DrawerHeading>
      </DrawerHeader>
      {/* Tool drawer content implementation */}
    </>
  )
}

const ToolName: ToolbarTool = {
  component: ToolComponent,
  icon: "general.toolbarIconName",
  name: "Tool name",
}

export { ToolName }

Migrate

These migration docs will guide you thru the process of updating to recent major releases.

Changelog

This is a limited history. Topbar releases often require a coordinated effort across products and no app can stay an outdated version for very long. So, this CHANGELOG is a little lazy.

CHANGELOG

Story

If you like history, here are the initial release notes with technical considerations and trade-offs.

STORY

Example product implementations

Readme

Keywords

none

Package Sidebar

Install

npm i @planningcenter/topbar

Weekly Downloads

1,421

Version

9.9.0

License

UNLICENSED

Unpacked Size

3.24 MB

Total Files

256

Last publish

Collaborators

  • kylemellander
  • jonsuh
  • keola
  • timmorgan
  • danott