Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion CHANGELOG.json
Original file line number Diff line number Diff line change
Expand Up @@ -483,5 +483,28 @@
}
]
}
]
],
"unreleased": {
"highlights": [
{
"description": "`@plexusone/invites`: pages for SystemForge invite-gated sign-up, an operator page for invite codes, email invites, the waitlist and member allowances, and a member page to invite people"
}
],
"added": [
{
"description": "`createInvitesApi`: a typed client for SystemForge's invite API, with snake_case wire types and `ApiError`"
},
{
"description": "`InviteAdminPage`: codes, email invites, waitlist, allowances and joined accounts, with new codes and links shown once and inline revoke"
},
{
"description": "`InvitePeoplePage`: a member's allowance, create and copy an invite link, and revoke unused ones"
}
],
"documentation": [
{
"description": "`@plexusone/invites` package page"
}
]
}
}
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ and this changelog is generated by [Structured Changelog](https://github.com/gro

## [Unreleased]

### Highlights

- `@plexusone/invites`: pages for SystemForge invite-gated sign-up, an operator page for invite codes, email invites, the waitlist and member allowances, and a member page to invite people

### Added

- `createInvitesApi`: a typed client for SystemForge's invite API, with snake_case wire types and `ApiError`
- `InviteAdminPage`: codes, email invites, waitlist, allowances and joined accounts, with new codes and links shown once and inline revoke
- `InvitePeoplePage`: a member's allowance, create and copy an invite link, and revoke unused ones

### Documentation

- `@plexusone/invites` package page

## [v0.4.0] - 2026-10-20

### Highlights
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Alphabetical; see [Packages](docs/packages/index.md) for how they depend on each
| `@plexusone/console` | Organization console pages | [![npm](https://img.shields.io/npm/v/@plexusone/console)](https://www.npmjs.com/package/@plexusone/console) |
| `@plexusone/design-tokens` | Design system tokens | [![npm](https://img.shields.io/npm/v/@plexusone/design-tokens)](https://www.npmjs.com/package/@plexusone/design-tokens) |
| `@plexusone/host` | App and shell contracts, createHost | [![npm](https://img.shields.io/npm/v/@plexusone/host)](https://www.npmjs.com/package/@plexusone/host) |
| `@plexusone/invites` | Invite-gated sign-up pages | [![npm](https://img.shields.io/npm/v/@plexusone/invites)](https://www.npmjs.com/package/@plexusone/invites) |
| `@plexusone/pages` | Pre-built pages | [![npm](https://img.shields.io/npm/v/@plexusone/pages)](https://www.npmjs.com/package/@plexusone/pages) |
| `@plexusone/shell` | Application shell | [![npm](https://img.shields.io/npm/v/@plexusone/shell)](https://www.npmjs.com/package/@plexusone/shell) |
| `@plexusone/telemetry` | Event instrumentation | [![npm](https://img.shields.io/npm/v/@plexusone/telemetry)](https://www.npmjs.com/package/@plexusone/telemetry) |
Expand Down
14 changes: 14 additions & 0 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,20 @@ and this changelog is generated by [Structured Changelog](https://github.com/gro

## [Unreleased]

### Highlights

- `@plexusone/invites`: pages for SystemForge invite-gated sign-up, an operator page for invite codes, email invites, the waitlist and member allowances, and a member page to invite people

### Added

- `createInvitesApi`: a typed client for SystemForge's invite API, with snake_case wire types and `ApiError`
- `InviteAdminPage`: codes, email invites, waitlist, allowances and joined accounts, with new codes and links shown once and inline revoke
- `InvitePeoplePage`: a member's allowance, create and copy an invite link, and revoke unused ones

### Documentation

- `@plexusone/invites` package page

## [v0.4.0] - 2026-10-20

### Highlights
Expand Down
1 change: 1 addition & 0 deletions docs/packages/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ share one copy. Every package also needs React 19.
| [@plexusone/console](console.md) | The organization console | `consoleApp`, `consoleSessionClient`, `Connections`, `Connect` |
| [@plexusone/design-tokens](design-tokens.md) | Design system | Colors, typography, spacing |
| [@plexusone/host](host.md) | Hosting applications | `AppModule`, `Shell`, `createHost`, `DevShell` |
| [@plexusone/invites](invites.md) | Invite-gated sign-up pages | `InviteAdminPage`, `InvitePeoplePage`, `createInvitesApi` |
| [@plexusone/pages](pages.md) | Pre-built pages | `LoginPage`, `ErrorPage`, `OrganizationSettingsPage` |
| [@plexusone/shell](shell.md) | Application chrome | `AppShell`, `ProductSwitcher`, `OrganizationSwitcher`, `ProfileMenu` |
| [@plexusone/telemetry](telemetry.md) | Instrumentation | `TelemetryProvider`, `ErrorBoundary` |
Expand Down
77 changes: 77 additions & 0 deletions docs/packages/invites.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# @plexusone/invites

Pages for SystemForge's invite-gated sign-up: an operator page to manage
invite codes, email invites, the waitlist and member allowances, and a member
page to invite people. Both call SystemForge's invite API (`signupapi`); see
SystemForge's [invite-gated sign-up guide](https://plexusone.github.io/systemforge/guides/invite-gated-signup/).

```bash
pnpm add @plexusone/invites @plexusone/ui
```

## Use the pages

The pages are plain components: route them in your application wherever they
belong. They are not an `AppModule`, because invites are platform-wide, not
organization-scoped.

```tsx
import { createInvitesApi, InviteAdminPage, InvitePeoplePage } from '@plexusone/invites';

// Where the host serves the invite API: behind its own session...
const invites = createInvitesApi('/invites/api');
// ...or on SystemAuth with Options.SignupAPI:
// createInvitesApi('https://auth.example.com/signup-invites/api');

<Route path="/admin/invites" element={<InviteAdminPage api={invites} />} />
<Route path="/invite" element={<InvitePeoplePage api={invites} />} />
```

Requests carry the browser's cookies, so the API must be same-origin with the
page or allow credentialed requests from it. The pages use Tailwind classes
from `@plexusone/ui`'s preset; add the package's `dist` to your Tailwind
sources.

## InvitePeoplePage

For any signed-in person:

- how many people they can still invite, from their allowance;
- **Create invite link**, disabled when none are left, which shows the new
link once with a copy button;
- their links with status and expiry, and **Revoke** (asked inline) for a link
nobody has used, which gives the slot back.

| Prop | Type | Description |
| ------- | ------------ | ---------------------------------- |
| `api` | `InvitesApi` | The client from `createInvitesApi` |
| `title` | `string` | Heading; default "Invite people" |

## InviteAdminPage

For platform administrators; anyone else sees the API's refusal. Sections:

| Section | Does |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Invite codes** | Create a code with a label, how many people it admits, expiry and note; the code and link are shown once. List codes with uses and status; revoke |
| **Email invites** | Invite pasted addresses, with a note and expiry; list with status; revoke |
| **Waitlist** | Select entries (or everyone not yet invited) and invite them; remove an entry |
| **Member allowances** | Set how many people a member may invite, by email, or return them to the default |
| **Joined** | Accounts admitted by codes and email invites, with the code or member that brought them |

| Prop | Type | Description |
| ------- | ------------ | ---------------------------------- |
| `api` | `InvitesApi` | The client from `createInvitesApi` |
| `title` | `string` | Heading; default "Invites" |

## API client

`createInvitesApi(baseUrl)` returns an `InvitesApi` with one method per
route: `settings`, `myInvites`, `createMyCode`, `revokeMyCode`, and for
administrators `invites`, `addInvites`, `revokeInvite`, `codes`,
`createCode`, `revokeCode`, `waitlist`, `inviteFromWaitlist`,
`removeFromWaitlist`, `allowances`, `setAllowance` and `joined`. A failed
call throws `ApiError` with the HTTP status and the API's message. Wire types
(`InviteCode`, `CreatedCode`, `EmailInvite`, `WaitlistEntry`, `Allowance`,
`JoinedAccount`, `MyInvites`, `InviteSettings`) are snake_case, as the API
sends them.
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ nav:
- '@plexusone/console': packages/console.md
- '@plexusone/design-tokens': packages/design-tokens.md
- '@plexusone/host': packages/host.md
- '@plexusone/invites': packages/invites.md
- '@plexusone/pages': packages/pages.md
- '@plexusone/shell': packages/shell.md
- '@plexusone/telemetry': packages/telemetry.md
Expand Down
61 changes: 61 additions & 0 deletions packages/invites/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"name": "@plexusone/invites",
"version": "0.1.0",
"description": "Pages for SystemForge invite-gated sign-up: an operator page for invite codes, email invites, the waitlist and member allowances, and a member page to invite people",
"homepage": "https://plexusone.github.io/systemforge-web/packages/invites/",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./package.json": "./package.json"
},
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"lint": "eslint src/",
"typecheck": "tsc --noEmit"
},
"peerDependencies": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"@plexusone/ui": "workspace:^"
},
"devDependencies": {
"@plexusone/ui": "workspace:*",
"@testing-library/react": "^16.0.0",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.0.0",
"react": "^19.0.0",
"react-dom": "^19.0.0",
"tsup": "^8.0.1",
"typescript": "^5.3.3"
},
"keywords": [
"systemforge",
"invites",
"signup",
"waitlist",
"react"
],
"author": "SystemForge Team",
"license": "MIT",
"repository": {
"type": "git",
"url": "https://github.com/plexusone/systemforge-web.git",
"directory": "packages/invites"
},
"bugs": {
"url": "https://github.com/plexusone/systemforge-web/issues"
}
}
Loading
Loading