Overview
Home shortcuts are icon tiles on the home screen for high-frequency actions (POS, scan, create invoice). Register them once during PluginModule.register() via the base-frontend shortcut store — not through AppRegistry.
- Import useHomeShortcutStore and ShortcutItem from @quan-erp/base-frontend
- Call useHomeShortcutStore().getState().add({…}) inside register()
- Wrap the icon in <ShortcutItem>
- Keep id unique across all plugins (prefer `${metadata.name}/…`)
1. Register a shortcut
Add shortcuts in frontend/src/index.tsx during register(). Provide pluginName, a unique id, displayName, a ShortcutItem-wrapped icon, and either toLink and/or onClick.
TSXfrontend/src/index.tsx
1import { ShoppingCart } from "lucide-react";
2import { ShortcutItem, useHomeShortcutStore } from "@quan-erp/base-frontend";
3import type { AppRegistryState, PluginModule } from "@quan-erp/shared-types";
4import metadata from "../module.metadata.json" with { type: "json" };
5
6const Plugin: PluginModule = {
7 register(_AppRegistry: AppRegistryState) {
8 useHomeShortcutStore().getState().add({
9 pluginName: metadata.name,
10 id: `${metadata.name}/pos`,
11 displayName: "POS",
12 component: (
13 <ShortcutItem>
14 <ShoppingCart size={25} />
15 </ShortcutItem>
16 ),
17 toLink: `/${metadata.name}/pos`,
18 async onClick() {
19 // optional — dialogs, scans, side effects
20 },
21 });
22 },
23};
24
25export default Plugin;2. Properties
Each add() entry configures one home tile.
- pluginName — must equal module.metadata.json name
- id — unique across plugins; recommended `${metadata.name}/feature`
- displayName — label under the icon
- component — ReactNode; must wrap the icon in <ShortcutItem>
- toLink — optional route under the plugin namespace (e.g. `/${metadata.name}/pos`)
- onClick — optional async handler for dialogs, scanners, or custom navigation
3. Navigation patterns
Use toLink for normal route jumps. Use onClick when the shortcut opens a dialog, starts a scan flow, or needs logic before navigate. You can combine both when useful.
- Keep toLink under your plugin path namespace to avoid collisions
- Align toLink with a real AppRegistry.route / menu path
- Prefer IconPark / lucide icons sized ~25 for visual consistency
TSonClick-only (e.g. scan)
1useHomeShortcutStore().getState().add({
2 pluginName: metadata.name,
3 id: `${metadata.name}/scan`,
4 displayName: "Scan",
5 component: (
6 <ShortcutItem>
7 <ScanIcon size={25} />
8 </ShortcutItem>
9 ),
10 async onClick() {
11 // open scanner / dialog — no toLink required
12 },
13});Critical rules
- Register only in register() — not inside page components on mount
- component must use ShortcutItem; bare icons break home layout styling
- ids must be unique across installed plugins
- pluginName must match metadata.name
- Use for high-frequency actions — not every menu item
Checklist
- Import ShortcutItem + useHomeShortcutStore from @quan-erp/base-frontend
- add() in register() with pluginName, id, displayName, component
- Wrap icon in <ShortcutItem>
- Set toLink and/or onClick
- Verify tile after quan-erp watch and install
Common failures
- Tile missing — add() not called, wrong pluginName, or plugin not installed
- Broken icon layout — missing ShortcutItem wrapper
- Click does nothing — neither toLink nor onClick set, or route path mismatch
- Duplicate / colliding tiles — non-unique id across plugins
- Wrong destination — toLink not aligned with AppRegistry.route path