51 lines
1.5 KiB
TypeScript
51 lines
1.5 KiB
TypeScript
import { getPlan, type PlanId } from './plans';
|
|
|
|
export type OrgRole = 'owner' | 'admin' | 'member';
|
|
export const ORG_ROLES: OrgRole[] = ['owner', 'admin', 'member'];
|
|
|
|
export function isOrgRole(value: unknown): value is OrgRole {
|
|
return value === 'owner' || value === 'admin' || value === 'member';
|
|
}
|
|
|
|
export function roleRank(role: OrgRole): number {
|
|
return role === 'owner' ? 3 : role === 'admin' ? 2 : 1;
|
|
}
|
|
|
|
export function canManageMembers(role: unknown): boolean {
|
|
return isOrgRole(role) && roleRank(role) >= 2;
|
|
}
|
|
|
|
export function canManageBilling(role: unknown): boolean {
|
|
return role === 'owner';
|
|
}
|
|
|
|
export function seatLimit(plan: unknown): number {
|
|
return getPlan(plan).limits.seats;
|
|
}
|
|
|
|
/** True when one more member may be added (the count is checked before the insert). */
|
|
export function withinSeats(plan: unknown, currentMembers: number): boolean {
|
|
return currentMembers < seatLimit(plan);
|
|
}
|
|
|
|
export const FEATURES = {
|
|
free: ['dashboard', 'members', 'billing'],
|
|
pro: ['dashboard', 'members', 'billing', 'reports'],
|
|
} as const;
|
|
|
|
export type Feature = 'dashboard' | 'members' | 'billing' | 'reports';
|
|
|
|
export function canUseFeature(plan: unknown, feature: Feature): boolean {
|
|
const id = (getPlan(plan).id ?? 'free') as PlanId;
|
|
return (FEATURES[id] as readonly string[]).includes(feature);
|
|
}
|
|
|
|
export function slugifyOrg(name: string): string {
|
|
return name
|
|
.toLowerCase()
|
|
.trim()
|
|
.replace(/[^a-z0-9]+/g, '-')
|
|
.replace(/^-+|-+$/g, '')
|
|
.slice(0, 40);
|
|
}
|