npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@liiift-studio/sales-portal

v3.1.9

Published

Sales dashboard and analytics components for Next.js type foundry sites — Stripe integration, MUI DataGrid, charts, CSV export, and multi-designer reporting.

Downloads

354

Readme

@liiift-studio/sales-portal

Drop-in sales dashboard and analytics components for Next.js type-foundry sites — designers log into their foundry's site and see their own typeface sales and revenue, pulled live from Stripe, with designer authentication via Sanity. Build the dashboard once, reuse it across every foundry site.

npm version license Next.js MUI

Architecture and data flow: a Next.js foundry site imports the sales-portal package, whose API handlers fetch sales data from Stripe and authenticate designers via Sanity CMS, keeping secrets server-side.

Internal package. UNLICENSED — published public on npm for convenient installation across Liiift Studio foundry sites, but all rights reserved; it is not licensed for use outside Liiift Studio projects.

Features

  • Designer authentication via Sanity CMS
  • Admin multi-designer view with sequential loading
  • Monthly and full-year sales data from Stripe (invoices + payment intents)
  • Interactive charts and data visualization (MUI X-Charts)
  • Spreadsheet-style data tables with sorting, filtering, and CSV export (MUI DataGrid)
  • Date range selection for custom export reports
  • Stripe balance reconciliation checks
  • Top performers analysis (typefaces and designers)
  • Typeface and license type breakdowns
  • Summary cards with key metrics
  • Login modal with two-column layout

How it works

Request lifecycle: 1 Login (LoginForm posts getDesignerInfo, Sanity verifies the account); 2 Fetch (sales widgets post getSales / getYearSales, Stripe returns invoices and payment intents); 3 Process (fees, refunds, and date ranges aggregated server-side); 4 Render (charts, summary cards, DataGrid and CSV export in the browser).

The package ships React/MUI components plus Next.js API handlers. Your site re-exports the handlers as API routes and renders <SalesPortalPage />. All Stripe and Sanity secrets stay server-side inside the API handlers — they are never exposed to the browser.

Installation

npm install @liiift-studio/sales-portal

Pages Router only. This package wires into pages/api/... route handlers and assumes the Next.js Pages Router.

Prerequisites

Peer dependencies required in your project:

{
  "@mui/material": "^5.10.0",
  "@mui/x-data-grid": "^8.0.0",
  "@mui/x-date-pickers": "^7.0.0",
  "@mui/x-charts": "^7.0.0",
  "react": "^18.0.0",
  "react-dom": "^18.0.0",
  "next": "^14.0.0",
  "dayjs": "^1.11.0",
  "slugify": "^1.6.0"
}

Compatibility

| Peer | Version | |------|---------| | @mui/material | ^5.10.0 (MUI v5; uses Box/flexbox, not Grid, so v5–v7 work) | | @mui/x-data-grid | ^8.0.0 | | @mui/x-date-pickers | ^7.0.0 | | @mui/x-charts | ^7.0.0 | | react / react-dom | ^18.0.0 | | next | ^14.0.0 (Pages Router) | | dayjs | ^1.11.0 | | slugify | ^1.6.0 |

Note @mui/x-data-grid is on major v8 while the other MUI X packages are on v7 — install the matching majors as listed above.

Quick Start

Everything below is for developers integrating the package. See SETUP.md for the full setup guide and a step-by-step checklist.

1. Create API route wrappers

Create these 5 files — all are required. The dashboard calls every endpoint, so a missing wrapper produces a 404 at runtime (the year-over-year view needs getYearSales):

pages/api/sales-portal/
  getDesignerInfo.js
  getDesigners.js
  getSales.js
  getYearSales.js
  getBalanceTransactions.js

Each file is a one-line re-export:

// pages/api/sales-portal/getSales.js
export { default, config } from '@liiift-studio/sales-portal/api/getSales';

2. Create the page

SalesPortalPage wraps its own MUI ThemeProvider with the exported salesTheme by default (pass includeTheme={false} to supply your own).

// pages/sales-portal.js
import { SalesPortalPage } from '@liiift-studio/sales-portal';

export default function SalesPortal() {
  return (
    <SalesPortalPage
      texts={{
        title: 'Sales Portal',
        dashboardTitle: 'Sales',
        dashboardSubtitle: 'by designer'
      }}
    />
  );
}

3. Configure Next.js

// next.config.js
const nextConfig = {
  transpilePackages: ['@mui/x-charts', '@liiift-studio/sales-portal'],
};

4. Set environment variables

# .env.local
SANITY_STUDIO_PROJECT_ID=your_project_id
SANITY_STUDIO_DATASET=production
SANITY_STUDIO_TOKEN=your_sanity_token
STRIPE_SECRET_KEY=your_stripe_secret_key

# Optional — defaults to 2022-04-01 if unset
SANITY_STUDIO_API_VERSION=2022-04-01

# Optional kill switch — set to the literal string "false" to disable the portal.
# Any other value (or unset) leaves it enabled.
SALES_PORTAL_ENABLED=true

Designer accounts (Sanity)

Authentication matches an account document in your Sanity dataset by email, password, and isDesigner. Each designer needs an account document with those fields for login to succeed. To grant access to the admin multi-designer view, set isAdmin: true on that designer's account document.

API Endpoints

| Endpoint | Method | Purpose | |----------|--------|---------| | getDesignerInfo | POST | Authenticate designer, return account data | | getDesigners | GET | List all designers (admin) | | getSales | POST | Fetch sales data for a month or date range | | getYearSales | POST | Fetch a full year of sales with year-level aggregates | | getBalanceTransactions | POST | Fetch Stripe balance transactions for reconciliation |

Component & Hook Exports

import {
  SalesPortalPage,     // Full page with login modal + dashboard
  LoginForm,           // Login modal component
  Sales,               // Individual designer sales dashboard
  SalesTable,          // Sales data table with CSV export
  DateRangeSalesTable, // Custom date range export table
  SalesChart,          // Revenue trend charts
  YearOverview,        // Full-year overview view
  SummaryCards,        // Key metrics cards (a.k.a. Insights)
  TopPerformers,       // Top typefaces/designers
  TypefaceList,        // Typeface breakdown
  LicenseTypeList,     // License type analysis
  PeriodComparison,    // Period comparison charts
  SalesErrorBoundary,  // Error boundary for dashboard sections
  salesTheme,          // MUI theme
  // Table helpers
  TableRowCells, getCellValue, COLUMNS,
  // Hooks
  useSalesDateQuery, useColumnSelection, useReconciliation,
} from '@liiift-studio/sales-portal';

API handlers are imported individually from the ./api/* subpath, e.g. import handler from '@liiift-studio/sales-portal/api/getSales'.

Architecture

@liiift-studio/sales-portal
  api/
    getDesignerInfo.ts        # Authenticate designer
    getDesigners.ts           # List designers (admin)
    getSales.ts               # Month / date-range sales
    getYearSales.ts           # Full-year sales + aggregates
    getBalanceTransactions.ts # Stripe balance transactions
    utils/
      clients.ts              # Shared Sanity + Stripe clients
      apiResponse.ts          # Standardized error/success responses
      authMiddleware.ts       # Request authentication
      dateUtils.ts            # UTC date range utilities
      salesDataProcessor.ts   # Core sales data pipeline
      stripeFetcher.ts        # Stripe API pagination
      feeCalculator.ts        # Fee distribution + rounding
      processors/             # Stripe invoice / payment-intent processors
  components/                 # React components (Box/flexbox, no MUI Grid)
  styles/                     # SCSS + MUI theme
  hooks/                      # Custom React hooks
  utils/                      # Client-side utilities

Currently deployed on

Contributing / Local Development

This is a published package built with tsup and tested with vitest. Type definitions are hand-maintained in index.d.ts (tsup runs with dts: false).

npm install          # install dev + peer tooling
npm run build        # bundle with tsup -> dist/
npm run dev          # tsup --watch (rebuild on change)
npm test             # run the vitest suite
npm run capture      # regenerate the README diagrams in assets/

When adding a new component/hook/util, register it as an entry in tsup.config.ts (or it won't be built) and add the matching export to index.ts and index.d.ts.

Test against a consumer site

Use the link:* scripts to npm link the package into a consumer for local testing before publishing (run npm run dev alongside so changes rebuild):

npm run link:tdf       # link into sites/tdf
npm run link:darden    # link into sites/darden
npm run link:positype  # link into sites/positype

Publishing

  1. Make and verify your changes (npm test, then test against a consumer site)
  2. Bump the version in package.json
  3. Commit and push to master
  4. Publish: npm publish (prepublishOnly runs the build automatically; publishConfig.access is already public)
  5. Foundry sites pick up the new version on their next deploy (they use ^ semver)

Before bumping, check the currently published version with npm view @liiift-studio/sales-portal version so the new number is ahead of npm.

License

UNLICENSED — internal Liiift Studio package. All rights reserved.