availsync 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.adal/skills/stripe-best-practices/SKILL.md +42 -0
- package/.adal/skills/stripe-best-practices/references/billing.md +36 -0
- package/.adal/skills/stripe-best-practices/references/connect.md +48 -0
- package/.adal/skills/stripe-best-practices/references/payments.md +79 -0
- package/.adal/skills/stripe-best-practices/references/security.md +109 -0
- package/.adal/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.adal/skills/stripe-projects/SKILL.md +139 -0
- package/.adal/skills/upgrade-stripe/SKILL.md +185 -0
- package/.agents/skills/stripe-best-practices/SKILL.md +42 -0
- package/.agents/skills/stripe-best-practices/references/billing.md +36 -0
- package/.agents/skills/stripe-best-practices/references/connect.md +48 -0
- package/.agents/skills/stripe-best-practices/references/payments.md +79 -0
- package/.agents/skills/stripe-best-practices/references/security.md +109 -0
- package/.agents/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.agents/skills/stripe-projects/SKILL.md +139 -0
- package/.agents/skills/upgrade-stripe/SKILL.md +185 -0
- package/.augment/skills/stripe-best-practices/SKILL.md +42 -0
- package/.augment/skills/stripe-best-practices/references/billing.md +36 -0
- package/.augment/skills/stripe-best-practices/references/connect.md +48 -0
- package/.augment/skills/stripe-best-practices/references/payments.md +79 -0
- package/.augment/skills/stripe-best-practices/references/security.md +109 -0
- package/.augment/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.augment/skills/stripe-projects/SKILL.md +139 -0
- package/.augment/skills/upgrade-stripe/SKILL.md +185 -0
- package/.bob/skills/stripe-best-practices/SKILL.md +42 -0
- package/.bob/skills/stripe-best-practices/references/billing.md +36 -0
- package/.bob/skills/stripe-best-practices/references/connect.md +48 -0
- package/.bob/skills/stripe-best-practices/references/payments.md +79 -0
- package/.bob/skills/stripe-best-practices/references/security.md +109 -0
- package/.bob/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.bob/skills/stripe-projects/SKILL.md +139 -0
- package/.bob/skills/upgrade-stripe/SKILL.md +185 -0
- package/.claude/settings.local.json +7 -0
- package/.claude/skills/stripe-best-practices/SKILL.md +42 -0
- package/.claude/skills/stripe-best-practices/references/billing.md +36 -0
- package/.claude/skills/stripe-best-practices/references/connect.md +48 -0
- package/.claude/skills/stripe-best-practices/references/payments.md +79 -0
- package/.claude/skills/stripe-best-practices/references/security.md +109 -0
- package/.claude/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.claude/skills/stripe-projects/SKILL.md +139 -0
- package/.claude/skills/upgrade-stripe/SKILL.md +185 -0
- package/.codebuddy/skills/stripe-best-practices/SKILL.md +42 -0
- package/.codebuddy/skills/stripe-best-practices/references/billing.md +36 -0
- package/.codebuddy/skills/stripe-best-practices/references/connect.md +48 -0
- package/.codebuddy/skills/stripe-best-practices/references/payments.md +79 -0
- package/.codebuddy/skills/stripe-best-practices/references/security.md +109 -0
- package/.codebuddy/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.codebuddy/skills/stripe-projects/SKILL.md +139 -0
- package/.codebuddy/skills/upgrade-stripe/SKILL.md +185 -0
- package/.commandcode/skills/stripe-best-practices/SKILL.md +42 -0
- package/.commandcode/skills/stripe-best-practices/references/billing.md +36 -0
- package/.commandcode/skills/stripe-best-practices/references/connect.md +48 -0
- package/.commandcode/skills/stripe-best-practices/references/payments.md +79 -0
- package/.commandcode/skills/stripe-best-practices/references/security.md +109 -0
- package/.commandcode/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.commandcode/skills/stripe-projects/SKILL.md +139 -0
- package/.commandcode/skills/upgrade-stripe/SKILL.md +185 -0
- package/.continue/skills/stripe-best-practices/SKILL.md +42 -0
- package/.continue/skills/stripe-best-practices/references/billing.md +36 -0
- package/.continue/skills/stripe-best-practices/references/connect.md +48 -0
- package/.continue/skills/stripe-best-practices/references/payments.md +79 -0
- package/.continue/skills/stripe-best-practices/references/security.md +109 -0
- package/.continue/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.continue/skills/stripe-projects/SKILL.md +139 -0
- package/.continue/skills/upgrade-stripe/SKILL.md +185 -0
- package/.cortex/skills/stripe-best-practices/SKILL.md +42 -0
- package/.cortex/skills/stripe-best-practices/references/billing.md +36 -0
- package/.cortex/skills/stripe-best-practices/references/connect.md +48 -0
- package/.cortex/skills/stripe-best-practices/references/payments.md +79 -0
- package/.cortex/skills/stripe-best-practices/references/security.md +109 -0
- package/.cortex/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.cortex/skills/stripe-projects/SKILL.md +139 -0
- package/.cortex/skills/upgrade-stripe/SKILL.md +185 -0
- package/.crush/skills/stripe-best-practices/SKILL.md +42 -0
- package/.crush/skills/stripe-best-practices/references/billing.md +36 -0
- package/.crush/skills/stripe-best-practices/references/connect.md +48 -0
- package/.crush/skills/stripe-best-practices/references/payments.md +79 -0
- package/.crush/skills/stripe-best-practices/references/security.md +109 -0
- package/.crush/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.crush/skills/stripe-projects/SKILL.md +139 -0
- package/.crush/skills/upgrade-stripe/SKILL.md +185 -0
- package/.env.example +20 -0
- package/.factory/skills/stripe-best-practices/SKILL.md +42 -0
- package/.factory/skills/stripe-best-practices/references/billing.md +36 -0
- package/.factory/skills/stripe-best-practices/references/connect.md +48 -0
- package/.factory/skills/stripe-best-practices/references/payments.md +79 -0
- package/.factory/skills/stripe-best-practices/references/security.md +109 -0
- package/.factory/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.factory/skills/stripe-projects/SKILL.md +139 -0
- package/.factory/skills/upgrade-stripe/SKILL.md +185 -0
- package/.goose/skills/stripe-best-practices/SKILL.md +42 -0
- package/.goose/skills/stripe-best-practices/references/billing.md +36 -0
- package/.goose/skills/stripe-best-practices/references/connect.md +48 -0
- package/.goose/skills/stripe-best-practices/references/payments.md +79 -0
- package/.goose/skills/stripe-best-practices/references/security.md +109 -0
- package/.goose/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.goose/skills/stripe-projects/SKILL.md +139 -0
- package/.goose/skills/upgrade-stripe/SKILL.md +185 -0
- package/.iflow/skills/stripe-best-practices/SKILL.md +42 -0
- package/.iflow/skills/stripe-best-practices/references/billing.md +36 -0
- package/.iflow/skills/stripe-best-practices/references/connect.md +48 -0
- package/.iflow/skills/stripe-best-practices/references/payments.md +79 -0
- package/.iflow/skills/stripe-best-practices/references/security.md +109 -0
- package/.iflow/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.iflow/skills/stripe-projects/SKILL.md +139 -0
- package/.iflow/skills/upgrade-stripe/SKILL.md +185 -0
- package/.junie/skills/stripe-best-practices/SKILL.md +42 -0
- package/.junie/skills/stripe-best-practices/references/billing.md +36 -0
- package/.junie/skills/stripe-best-practices/references/connect.md +48 -0
- package/.junie/skills/stripe-best-practices/references/payments.md +79 -0
- package/.junie/skills/stripe-best-practices/references/security.md +109 -0
- package/.junie/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.junie/skills/stripe-projects/SKILL.md +139 -0
- package/.junie/skills/upgrade-stripe/SKILL.md +185 -0
- package/.kilocode/skills/stripe-best-practices/SKILL.md +42 -0
- package/.kilocode/skills/stripe-best-practices/references/billing.md +36 -0
- package/.kilocode/skills/stripe-best-practices/references/connect.md +48 -0
- package/.kilocode/skills/stripe-best-practices/references/payments.md +79 -0
- package/.kilocode/skills/stripe-best-practices/references/security.md +109 -0
- package/.kilocode/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.kilocode/skills/stripe-projects/SKILL.md +139 -0
- package/.kilocode/skills/upgrade-stripe/SKILL.md +185 -0
- package/.kiro/skills/stripe-best-practices/SKILL.md +42 -0
- package/.kiro/skills/stripe-best-practices/references/billing.md +36 -0
- package/.kiro/skills/stripe-best-practices/references/connect.md +48 -0
- package/.kiro/skills/stripe-best-practices/references/payments.md +79 -0
- package/.kiro/skills/stripe-best-practices/references/security.md +109 -0
- package/.kiro/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.kiro/skills/stripe-projects/SKILL.md +139 -0
- package/.kiro/skills/upgrade-stripe/SKILL.md +185 -0
- package/.kode/skills/stripe-best-practices/SKILL.md +42 -0
- package/.kode/skills/stripe-best-practices/references/billing.md +36 -0
- package/.kode/skills/stripe-best-practices/references/connect.md +48 -0
- package/.kode/skills/stripe-best-practices/references/payments.md +79 -0
- package/.kode/skills/stripe-best-practices/references/security.md +109 -0
- package/.kode/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.kode/skills/stripe-projects/SKILL.md +139 -0
- package/.kode/skills/upgrade-stripe/SKILL.md +185 -0
- package/.mcpjam/skills/stripe-best-practices/SKILL.md +42 -0
- package/.mcpjam/skills/stripe-best-practices/references/billing.md +36 -0
- package/.mcpjam/skills/stripe-best-practices/references/connect.md +48 -0
- package/.mcpjam/skills/stripe-best-practices/references/payments.md +79 -0
- package/.mcpjam/skills/stripe-best-practices/references/security.md +109 -0
- package/.mcpjam/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.mcpjam/skills/stripe-projects/SKILL.md +139 -0
- package/.mcpjam/skills/upgrade-stripe/SKILL.md +185 -0
- package/.mux/skills/stripe-best-practices/SKILL.md +42 -0
- package/.mux/skills/stripe-best-practices/references/billing.md +36 -0
- package/.mux/skills/stripe-best-practices/references/connect.md +48 -0
- package/.mux/skills/stripe-best-practices/references/payments.md +79 -0
- package/.mux/skills/stripe-best-practices/references/security.md +109 -0
- package/.mux/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.mux/skills/stripe-projects/SKILL.md +139 -0
- package/.mux/skills/upgrade-stripe/SKILL.md +185 -0
- package/.neovate/skills/stripe-best-practices/SKILL.md +42 -0
- package/.neovate/skills/stripe-best-practices/references/billing.md +36 -0
- package/.neovate/skills/stripe-best-practices/references/connect.md +48 -0
- package/.neovate/skills/stripe-best-practices/references/payments.md +79 -0
- package/.neovate/skills/stripe-best-practices/references/security.md +109 -0
- package/.neovate/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.neovate/skills/stripe-projects/SKILL.md +139 -0
- package/.neovate/skills/upgrade-stripe/SKILL.md +185 -0
- package/.nixpacksignore +14 -0
- package/.openhands/skills/stripe-best-practices/SKILL.md +42 -0
- package/.openhands/skills/stripe-best-practices/references/billing.md +36 -0
- package/.openhands/skills/stripe-best-practices/references/connect.md +48 -0
- package/.openhands/skills/stripe-best-practices/references/payments.md +79 -0
- package/.openhands/skills/stripe-best-practices/references/security.md +109 -0
- package/.openhands/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.openhands/skills/stripe-projects/SKILL.md +139 -0
- package/.openhands/skills/upgrade-stripe/SKILL.md +185 -0
- package/.pi/skills/stripe-best-practices/SKILL.md +42 -0
- package/.pi/skills/stripe-best-practices/references/billing.md +36 -0
- package/.pi/skills/stripe-best-practices/references/connect.md +48 -0
- package/.pi/skills/stripe-best-practices/references/payments.md +79 -0
- package/.pi/skills/stripe-best-practices/references/security.md +109 -0
- package/.pi/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.pi/skills/stripe-projects/SKILL.md +139 -0
- package/.pi/skills/upgrade-stripe/SKILL.md +185 -0
- package/.pochi/skills/stripe-best-practices/SKILL.md +42 -0
- package/.pochi/skills/stripe-best-practices/references/billing.md +36 -0
- package/.pochi/skills/stripe-best-practices/references/connect.md +48 -0
- package/.pochi/skills/stripe-best-practices/references/payments.md +79 -0
- package/.pochi/skills/stripe-best-practices/references/security.md +109 -0
- package/.pochi/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.pochi/skills/stripe-projects/SKILL.md +139 -0
- package/.pochi/skills/upgrade-stripe/SKILL.md +185 -0
- package/.qoder/skills/stripe-best-practices/SKILL.md +42 -0
- package/.qoder/skills/stripe-best-practices/references/billing.md +36 -0
- package/.qoder/skills/stripe-best-practices/references/connect.md +48 -0
- package/.qoder/skills/stripe-best-practices/references/payments.md +79 -0
- package/.qoder/skills/stripe-best-practices/references/security.md +109 -0
- package/.qoder/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.qoder/skills/stripe-projects/SKILL.md +139 -0
- package/.qoder/skills/upgrade-stripe/SKILL.md +185 -0
- package/.qwen/skills/stripe-best-practices/SKILL.md +42 -0
- package/.qwen/skills/stripe-best-practices/references/billing.md +36 -0
- package/.qwen/skills/stripe-best-practices/references/connect.md +48 -0
- package/.qwen/skills/stripe-best-practices/references/payments.md +79 -0
- package/.qwen/skills/stripe-best-practices/references/security.md +109 -0
- package/.qwen/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.qwen/skills/stripe-projects/SKILL.md +139 -0
- package/.qwen/skills/upgrade-stripe/SKILL.md +185 -0
- package/.roo/skills/stripe-best-practices/SKILL.md +42 -0
- package/.roo/skills/stripe-best-practices/references/billing.md +36 -0
- package/.roo/skills/stripe-best-practices/references/connect.md +48 -0
- package/.roo/skills/stripe-best-practices/references/payments.md +79 -0
- package/.roo/skills/stripe-best-practices/references/security.md +109 -0
- package/.roo/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.roo/skills/stripe-projects/SKILL.md +139 -0
- package/.roo/skills/upgrade-stripe/SKILL.md +185 -0
- package/.trae/skills/stripe-best-practices/SKILL.md +42 -0
- package/.trae/skills/stripe-best-practices/references/billing.md +36 -0
- package/.trae/skills/stripe-best-practices/references/connect.md +48 -0
- package/.trae/skills/stripe-best-practices/references/payments.md +79 -0
- package/.trae/skills/stripe-best-practices/references/security.md +109 -0
- package/.trae/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.trae/skills/stripe-projects/SKILL.md +139 -0
- package/.trae/skills/upgrade-stripe/SKILL.md +185 -0
- package/.vibe/skills/stripe-best-practices/SKILL.md +42 -0
- package/.vibe/skills/stripe-best-practices/references/billing.md +36 -0
- package/.vibe/skills/stripe-best-practices/references/connect.md +48 -0
- package/.vibe/skills/stripe-best-practices/references/payments.md +79 -0
- package/.vibe/skills/stripe-best-practices/references/security.md +109 -0
- package/.vibe/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.vibe/skills/stripe-projects/SKILL.md +139 -0
- package/.vibe/skills/upgrade-stripe/SKILL.md +185 -0
- package/.windsurf/skills/stripe-best-practices/SKILL.md +42 -0
- package/.windsurf/skills/stripe-best-practices/references/billing.md +36 -0
- package/.windsurf/skills/stripe-best-practices/references/connect.md +48 -0
- package/.windsurf/skills/stripe-best-practices/references/payments.md +79 -0
- package/.windsurf/skills/stripe-best-practices/references/security.md +109 -0
- package/.windsurf/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.windsurf/skills/stripe-projects/SKILL.md +139 -0
- package/.windsurf/skills/upgrade-stripe/SKILL.md +185 -0
- package/.zencoder/skills/stripe-best-practices/SKILL.md +42 -0
- package/.zencoder/skills/stripe-best-practices/references/billing.md +36 -0
- package/.zencoder/skills/stripe-best-practices/references/connect.md +48 -0
- package/.zencoder/skills/stripe-best-practices/references/payments.md +79 -0
- package/.zencoder/skills/stripe-best-practices/references/security.md +109 -0
- package/.zencoder/skills/stripe-best-practices/references/treasury.md +16 -0
- package/.zencoder/skills/stripe-projects/SKILL.md +139 -0
- package/.zencoder/skills/upgrade-stripe/SKILL.md +185 -0
- package/AUDIT.md +95 -0
- package/BLOCKERS.md +0 -0
- package/COOLIFY.md +51 -0
- package/MCP_SETUP.md +23 -0
- package/PRODUCTION_CHECKLIST.md +246 -0
- package/README.md +47 -0
- package/ROADMAP.md +91 -0
- package/docs/superpowers/plans/2026-05-11-availsync-frontend-sales-flow.md +2445 -0
- package/frontend/.env.example +2 -0
- package/frontend/app/admin/layout.tsx +13 -0
- package/frontend/app/admin/page.tsx +747 -0
- package/frontend/app/app/activity/page.tsx +257 -0
- package/frontend/app/app/agents/[agentId]/page.tsx +21 -0
- package/frontend/app/app/agents/page.tsx +1155 -0
- package/frontend/app/app/audit/page.tsx +225 -0
- package/frontend/app/app/availability/page.tsx +840 -0
- package/frontend/app/app/holds/page.tsx +262 -0
- package/frontend/app/app/layout.tsx +19 -0
- package/frontend/app/app/onboarding/page.tsx +10 -0
- package/frontend/app/app/onboarding/verify/page.tsx +309 -0
- package/frontend/app/app/page.tsx +508 -0
- package/frontend/app/app/settings/page.tsx +399 -0
- package/frontend/app/app/work/page.tsx +426 -0
- package/frontend/app/changelog/page.tsx +93 -0
- package/frontend/app/checkout/page.tsx +25 -0
- package/frontend/app/docs/api/page.tsx +157 -0
- package/frontend/app/docs/page.tsx +296 -0
- package/frontend/app/docs/pilot/page.tsx +127 -0
- package/frontend/app/docs/quickstart/page.tsx +318 -0
- package/frontend/app/docs/reliability/page.tsx +78 -0
- package/frontend/app/docs/sdk/node/page.tsx +166 -0
- package/frontend/app/globals.css +57 -0
- package/frontend/app/icon.png +0 -0
- package/frontend/app/layout.tsx +87 -0
- package/frontend/app/login/page.tsx +14 -0
- package/frontend/app/page.tsx +47 -0
- package/frontend/app/pricing/page.tsx +66 -0
- package/frontend/app/privacy/page.tsx +52 -0
- package/frontend/app/robots.ts +26 -0
- package/frontend/app/security/page.tsx +74 -0
- package/frontend/app/signup/page.tsx +14 -0
- package/frontend/app/sitemap.ts +14 -0
- package/frontend/app/terms/page.tsx +51 -0
- package/frontend/components/brand/AvailsyncLogo.tsx +56 -0
- package/frontend/components/checkout/CheckoutClient.tsx +100 -0
- package/frontend/components/dashboard/AgentForm.tsx +59 -0
- package/frontend/components/dashboard/AppShell.tsx +291 -0
- package/frontend/components/dashboard/AvailabilityChecker.tsx +117 -0
- package/frontend/components/dashboard/AvailabilityWindowForm.tsx +40 -0
- package/frontend/components/dashboard/HoldForm.tsx +133 -0
- package/frontend/components/dashboard/MetricCard.tsx +10 -0
- package/frontend/components/login/LoginForm.tsx +95 -0
- package/frontend/components/marketing/AgentCoordinationStory.tsx +1530 -0
- package/frontend/components/marketing/Faq.tsx +41 -0
- package/frontend/components/marketing/Hero.tsx +73 -0
- package/frontend/components/marketing/HowItWorks.tsx +28 -0
- package/frontend/components/marketing/ObserveModeTeaser.tsx +41 -0
- package/frontend/components/marketing/PricingTeaser.tsx +23 -0
- package/frontend/components/marketing/ProblemSolution.tsx +36 -0
- package/frontend/components/marketing/SiteFooter.tsx +59 -0
- package/frontend/components/marketing/SiteHeader.tsx +45 -0
- package/frontend/components/marketing/UseCases.tsx +27 -0
- package/frontend/components/onboarding/OnboardingClient.tsx +278 -0
- package/frontend/components/pricing/PricingCards.tsx +65 -0
- package/frontend/components/privacy/CookieConsent.tsx +230 -0
- package/frontend/components/privacy/CookieSettingsButton.tsx +15 -0
- package/frontend/components/seo/JsonLd.tsx +10 -0
- package/frontend/components/signup/SignupForm.tsx +55 -0
- package/frontend/components/ui/Badge.tsx +23 -0
- package/frontend/components/ui/Button.tsx +37 -0
- package/frontend/components/ui/Card.tsx +11 -0
- package/frontend/components/ui/ConfirmDialog.tsx +77 -0
- package/frontend/components/ui/EmptyState.tsx +24 -0
- package/frontend/components/ui/Input.tsx +14 -0
- package/frontend/components/ui/KeyDisplay.tsx +49 -0
- package/frontend/components/ui/Select.tsx +14 -0
- package/frontend/components/ui/Skeleton.tsx +24 -0
- package/frontend/components/ui/Tabs.tsx +19 -0
- package/frontend/components/ui/Textarea.tsx +14 -0
- package/frontend/components/ui/Toast.tsx +78 -0
- package/frontend/components/waitlist/WaitlistDialog.tsx +128 -0
- package/frontend/lib/api.ts +1282 -0
- package/frontend/lib/billing.ts +6 -0
- package/frontend/lib/cookieConsent.ts +113 -0
- package/frontend/lib/format.ts +16 -0
- package/frontend/lib/plans.ts +62 -0
- package/frontend/lib/schemas.ts +108 -0
- package/frontend/lib/seo.ts +376 -0
- package/frontend/lib/setupGuides.ts +630 -0
- package/frontend/lib/storage.ts +30 -0
- package/frontend/next-env.d.ts +6 -0
- package/frontend/next.config.mjs +13 -0
- package/frontend/package-lock.json +14409 -0
- package/frontend/package.json +41 -0
- package/frontend/playwright.config.ts +20 -0
- package/frontend/postcss.config.mjs +8 -0
- package/frontend/public/.gitkeep +0 -0
- package/frontend/public/brand/availsync-logo-board.png +0 -0
- package/frontend/public/brand/availsync-logo-dark.png +0 -0
- package/frontend/public/brand/availsync-mark-dark.png +0 -0
- package/frontend/public/brand/availsync-wordmark-dark.png +0 -0
- package/frontend/public/marketing/hero-agent-coordination.png +0 -0
- package/frontend/tailwind.config.ts +53 -0
- package/frontend/tests/smoke.spec.ts +89 -0
- package/frontend/tsconfig.json +23 -0
- package/jest.config.js +7 -0
- package/nixpacks.toml +11 -0
- package/package.json +53 -0
- package/packages/mcp/LICENSE +21 -0
- package/packages/mcp/README.md +60 -0
- package/packages/mcp/jest.config.cjs +8 -0
- package/packages/mcp/package.json +54 -0
- package/packages/mcp/src/helpers.ts +38 -0
- package/packages/mcp/src/index.test.ts +60 -0
- package/packages/mcp/src/index.ts +387 -0
- package/packages/mcp/tsconfig.json +20 -0
- package/packages/mcp/tsconfig.test.json +12 -0
- package/packages/node/LICENSE +21 -0
- package/packages/node/README.md +120 -0
- package/packages/node/jest.config.cjs +8 -0
- package/packages/node/package.json +46 -0
- package/packages/node/src/index.test.ts +360 -0
- package/packages/node/src/index.ts +402 -0
- package/packages/node/tsconfig.json +20 -0
- package/packages/node/tsconfig.test.json +12 -0
- package/plan.md +923 -0
- package/skills/stripe-best-practices/SKILL.md +42 -0
- package/skills/stripe-best-practices/references/billing.md +36 -0
- package/skills/stripe-best-practices/references/connect.md +48 -0
- package/skills/stripe-best-practices/references/payments.md +79 -0
- package/skills/stripe-best-practices/references/security.md +109 -0
- package/skills/stripe-best-practices/references/treasury.md +16 -0
- package/skills/stripe-projects/SKILL.md +139 -0
- package/skills/upgrade-stripe/SKILL.md +185 -0
- package/skills-lock.json +20 -0
- package/src/core/availability.ts +178 -0
- package/src/core/conflict.ts +209 -0
- package/src/core/work.ts +490 -0
- package/src/db/client.ts +17 -0
- package/src/db/migrations/001_init.sql +88 -0
- package/src/db/migrations/002_stripe.sql +2 -0
- package/src/db/migrations/003_workspace_auth.sql +19 -0
- package/src/db/migrations/004_agent_mcp_status.sql +2 -0
- package/src/db/migrations/005_hold_event_actor.sql +4 -0
- package/src/db/migrations/006_agent_activity.sql +35 -0
- package/src/db/migrations/007_work_coordination.sql +60 -0
- package/src/db/migrations/008_work_claim_leases.sql +20 -0
- package/src/db/migrations/009_billing_subscription_state.sql +23 -0
- package/src/db/migrations/010_agent_api_key_prefix.sql +10 -0
- package/src/db/migrations/011_org_verified_and_work_event_retention.sql +11 -0
- package/src/db/migrations/012_agent_enforcement_mode.sql +12 -0
- package/src/db/migrations/013_support_tickets.sql +21 -0
- package/src/db/migrations/014_paid_plan_waitlist.sql +23 -0
- package/src/db/migrations/015_agent_last_seen.sql +2 -0
- package/src/db/migrations.ts +164 -0
- package/src/db/run-migrations.ts +13 -0
- package/src/index.ts +183 -0
- package/src/lib/activity.ts +137 -0
- package/src/lib/apiKeys.ts +32 -0
- package/src/lib/appInfo.ts +26 -0
- package/src/lib/billingConfig.ts +3 -0
- package/src/lib/env.ts +75 -0
- package/src/lib/logger.ts +8 -0
- package/src/lib/plans.ts +204 -0
- package/src/mcp/server.js +5 -0
- package/src/mcp/server.ts +350 -0
- package/src/middleware/auth.ts +342 -0
- package/src/middleware/requestId.ts +16 -0
- package/src/routes/account.ts +168 -0
- package/src/routes/activity.ts +126 -0
- package/src/routes/admin.ts +514 -0
- package/src/routes/audit.ts +68 -0
- package/src/routes/auth.ts +203 -0
- package/src/routes/availability.ts +325 -0
- package/src/routes/billing.ts +406 -0
- package/src/routes/conflicts.ts +131 -0
- package/src/routes/holds.ts +437 -0
- package/src/routes/mcp.ts +57 -0
- package/src/routes/metrics.ts +39 -0
- package/src/routes/onboarding.ts +273 -0
- package/src/routes/orgs.ts +981 -0
- package/src/routes/preferences.ts +132 -0
- package/src/routes/session.ts +16 -0
- package/src/routes/support.ts +77 -0
- package/src/routes/value.ts +186 -0
- package/src/routes/waitlist.ts +63 -0
- package/src/routes/work.ts +1578 -0
- package/src/server.ts +36 -0
- package/src/types/index.ts +109 -0
- package/tests/integration/activity.route.test.ts +103 -0
- package/tests/integration/admin.route.test.ts +143 -0
- package/tests/integration/agent-keys.route.test.ts +237 -0
- package/tests/integration/availability.route.test.ts +125 -0
- package/tests/integration/billing.route.test.ts +393 -0
- package/tests/integration/conflicts.route.test.ts +131 -0
- package/tests/integration/flows.test.ts +154 -0
- package/tests/integration/helpers.ts +134 -0
- package/tests/integration/holds.route.test.ts +185 -0
- package/tests/integration/metrics.route.test.ts +100 -0
- package/tests/integration/onboarding.verify.route.test.ts +163 -0
- package/tests/integration/preferences.route.test.ts +53 -0
- package/tests/integration/session.route.test.ts +97 -0
- package/tests/integration/system.route.test.ts +92 -0
- package/tests/integration/value.route.test.ts +235 -0
- package/tests/integration/work.route.test.ts +745 -0
- package/tests/setup.ts +4 -0
- package/tests/smoke.sh +62 -0
- package/tests/unit/auth.test.ts +114 -0
- package/tests/unit/availability.test.ts +149 -0
- package/tests/unit/conflict.test.ts +118 -0
- package/tests/unit/env.test.ts +69 -0
- package/tests/unit/migrations.test.ts +135 -0
- package/tests/unit/request-id.test.ts +37 -0
- package/tmp-mobile-agents.png +0 -0
- package/tmp-next-mobile.err.log +10 -0
- package/tmp-next-mobile.log +5 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { Check } from 'lucide-react';
|
|
4
|
+
import { useState } from 'react';
|
|
5
|
+
import { Button } from '@/components/ui/Button';
|
|
6
|
+
import { Card } from '@/components/ui/Card';
|
|
7
|
+
import { billingUpgradesEnabled } from '@/lib/billing';
|
|
8
|
+
import { plans } from '@/lib/plans';
|
|
9
|
+
import { WaitlistDialog } from '@/components/waitlist/WaitlistDialog';
|
|
10
|
+
|
|
11
|
+
export function PricingCards() {
|
|
12
|
+
const upgradesEnabled = billingUpgradesEnabled();
|
|
13
|
+
const [waitlistPlan, setWaitlistPlan] = useState<'individual' | 'team' | null>(null);
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<div id="waitlist" className="grid gap-4 md:grid-cols-3">
|
|
17
|
+
{plans.map((plan) => {
|
|
18
|
+
const paidWaitlist = plan.id !== 'free' && !upgradesEnabled;
|
|
19
|
+
return (
|
|
20
|
+
<Card className={plan.id === 'individual' ? 'border-accent bg-surface-raised' : ''} key={plan.id}>
|
|
21
|
+
<div className="flex items-center justify-between gap-3">
|
|
22
|
+
<p className="text-label font-semibold uppercase text-text-tertiary">{plan.name}</p>
|
|
23
|
+
{paidWaitlist && (
|
|
24
|
+
<span className="rounded border border-border bg-bg px-2 py-1 text-label text-text-tertiary">
|
|
25
|
+
Waitlist
|
|
26
|
+
</span>
|
|
27
|
+
)}
|
|
28
|
+
</div>
|
|
29
|
+
<p className="mt-4 text-4xl font-semibold text-text-primary">
|
|
30
|
+
{paidWaitlist ? 'Waitlist' : plan.price}
|
|
31
|
+
{!paidWaitlist && <span className="text-base text-text-tertiary">{plan.period}</span>}
|
|
32
|
+
</p>
|
|
33
|
+
<p className="mt-3 min-h-14 text-body leading-6 text-text-secondary">
|
|
34
|
+
{paidWaitlist ? `${plan.description} Paid upgrades are in private pilot.` : plan.description}
|
|
35
|
+
</p>
|
|
36
|
+
<Button
|
|
37
|
+
className="mt-6 w-full"
|
|
38
|
+
href={paidWaitlist ? undefined : plan.href}
|
|
39
|
+
onClick={paidWaitlist ? () => setWaitlistPlan(plan.id as 'individual' | 'team') : undefined}
|
|
40
|
+
>
|
|
41
|
+
{paidWaitlist ? 'Join waitlist' : plan.cta}
|
|
42
|
+
</Button>
|
|
43
|
+
<div className="mt-6 space-y-3">
|
|
44
|
+
{plan.features.map((feature) => (
|
|
45
|
+
<p className="flex gap-2 text-body text-text-secondary" key={feature}>
|
|
46
|
+
<Check className="h-4 w-4 text-success" />
|
|
47
|
+
{feature}
|
|
48
|
+
</p>
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
</Card>
|
|
52
|
+
);
|
|
53
|
+
})}
|
|
54
|
+
</div>
|
|
55
|
+
{waitlistPlan && (
|
|
56
|
+
<WaitlistDialog
|
|
57
|
+
open
|
|
58
|
+
plan={waitlistPlan}
|
|
59
|
+
source="pricing"
|
|
60
|
+
onClose={() => setWaitlistPlan(null)}
|
|
61
|
+
/>
|
|
62
|
+
)}
|
|
63
|
+
</>
|
|
64
|
+
);
|
|
65
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useEffect, useRef, useState } from 'react';
|
|
4
|
+
import { X } from 'lucide-react';
|
|
5
|
+
import {
|
|
6
|
+
getCookieConsent,
|
|
7
|
+
OPEN_COOKIE_SETTINGS_EVENT,
|
|
8
|
+
setCookieConsent,
|
|
9
|
+
type CookieConsent as StoredCookieConsent,
|
|
10
|
+
} from '@/lib/cookieConsent';
|
|
11
|
+
|
|
12
|
+
type PreferenceState = {
|
|
13
|
+
analytics: boolean;
|
|
14
|
+
marketing: boolean;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
const defaultPreferences: PreferenceState = {
|
|
18
|
+
analytics: false,
|
|
19
|
+
marketing: false,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
function preferencesFromConsent(consent: StoredCookieConsent | null): PreferenceState {
|
|
23
|
+
return {
|
|
24
|
+
analytics: consent?.categories.analytics ?? false,
|
|
25
|
+
marketing: consent?.categories.marketing ?? false,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function CookieConsent() {
|
|
30
|
+
const [loaded, setLoaded] = useState(false);
|
|
31
|
+
const [showBanner, setShowBanner] = useState(false);
|
|
32
|
+
const [showModal, setShowModal] = useState(false);
|
|
33
|
+
const [preferences, setPreferences] = useState<PreferenceState>(defaultPreferences);
|
|
34
|
+
const modalRef = useRef<HTMLDivElement>(null);
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
const existing = getCookieConsent();
|
|
38
|
+
setPreferences(preferencesFromConsent(existing));
|
|
39
|
+
setShowBanner(!existing);
|
|
40
|
+
setLoaded(true);
|
|
41
|
+
|
|
42
|
+
const openSettings = () => {
|
|
43
|
+
const latest = getCookieConsent();
|
|
44
|
+
setPreferences(preferencesFromConsent(latest));
|
|
45
|
+
setShowBanner(false);
|
|
46
|
+
setShowModal(true);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
window.addEventListener(OPEN_COOKIE_SETTINGS_EVENT, openSettings);
|
|
50
|
+
return () => window.removeEventListener(OPEN_COOKIE_SETTINGS_EVENT, openSettings);
|
|
51
|
+
}, []);
|
|
52
|
+
|
|
53
|
+
useEffect(() => {
|
|
54
|
+
if (!showModal) return;
|
|
55
|
+
|
|
56
|
+
modalRef.current?.focus();
|
|
57
|
+
const onKeyDown = (event: KeyboardEvent) => {
|
|
58
|
+
if (event.key === 'Escape') setShowModal(false);
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
window.addEventListener('keydown', onKeyDown);
|
|
62
|
+
return () => window.removeEventListener('keydown', onKeyDown);
|
|
63
|
+
}, [showModal]);
|
|
64
|
+
|
|
65
|
+
function save(nextPreferences: PreferenceState) {
|
|
66
|
+
setCookieConsent(nextPreferences);
|
|
67
|
+
setPreferences(nextPreferences);
|
|
68
|
+
setShowBanner(false);
|
|
69
|
+
setShowModal(false);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!loaded) return null;
|
|
73
|
+
|
|
74
|
+
return (
|
|
75
|
+
<>
|
|
76
|
+
{showBanner && (
|
|
77
|
+
<section
|
|
78
|
+
aria-label="Cookie notice"
|
|
79
|
+
className="fixed inset-x-0 bottom-0 z-[80] border-t border-border bg-bg/96 px-4 py-4 text-text-primary shadow-[0_-18px_60px_rgba(0,0,0,0.45)] backdrop-blur"
|
|
80
|
+
>
|
|
81
|
+
<div className="mx-auto flex max-w-6xl flex-col gap-4 md:flex-row md:items-center md:justify-between">
|
|
82
|
+
<div className="max-w-2xl">
|
|
83
|
+
<p className="text-heading font-semibold">Cookies on Availsync</p>
|
|
84
|
+
<p className="mt-1 text-body leading-6 text-text-secondary">
|
|
85
|
+
We use necessary cookies for login and security. Optional analytics and marketing
|
|
86
|
+
cookies stay off unless you allow them.
|
|
87
|
+
</p>
|
|
88
|
+
</div>
|
|
89
|
+
<div className="grid gap-2 sm:grid-cols-3 md:flex md:shrink-0">
|
|
90
|
+
<button
|
|
91
|
+
className="min-h-11 rounded border border-border px-4 text-body font-medium text-text-secondary transition hover:border-border-focus hover:text-text-primary"
|
|
92
|
+
onClick={() => setShowModal(true)}
|
|
93
|
+
>
|
|
94
|
+
Manage preferences
|
|
95
|
+
</button>
|
|
96
|
+
<button
|
|
97
|
+
className="min-h-11 rounded border border-border px-4 text-body font-medium text-text-secondary transition hover:border-border-focus hover:text-text-primary"
|
|
98
|
+
onClick={() => save({ analytics: false, marketing: false })}
|
|
99
|
+
>
|
|
100
|
+
Reject optional
|
|
101
|
+
</button>
|
|
102
|
+
<button
|
|
103
|
+
className="min-h-11 rounded bg-accent px-4 text-body font-medium text-white transition hover:bg-accent-hover"
|
|
104
|
+
onClick={() => save({ analytics: true, marketing: true })}
|
|
105
|
+
>
|
|
106
|
+
Accept all
|
|
107
|
+
</button>
|
|
108
|
+
</div>
|
|
109
|
+
</div>
|
|
110
|
+
</section>
|
|
111
|
+
)}
|
|
112
|
+
|
|
113
|
+
{showModal && (
|
|
114
|
+
<div className="fixed inset-0 z-[90] flex items-end justify-center bg-black/60 p-3 sm:items-center sm:p-6">
|
|
115
|
+
<div
|
|
116
|
+
aria-labelledby="cookie-preferences-title"
|
|
117
|
+
aria-modal="true"
|
|
118
|
+
className="max-h-[calc(100dvh-24px)] w-full max-w-xl overflow-y-auto rounded border border-border bg-surface p-5 text-text-primary shadow-2xl outline-none"
|
|
119
|
+
ref={modalRef}
|
|
120
|
+
role="dialog"
|
|
121
|
+
tabIndex={-1}
|
|
122
|
+
>
|
|
123
|
+
<div className="flex items-start justify-between gap-4">
|
|
124
|
+
<div>
|
|
125
|
+
<p className="text-label uppercase text-text-tertiary">Privacy controls</p>
|
|
126
|
+
<h2 className="mt-1 text-title font-semibold" id="cookie-preferences-title">
|
|
127
|
+
Cookie preferences
|
|
128
|
+
</h2>
|
|
129
|
+
</div>
|
|
130
|
+
<button
|
|
131
|
+
aria-label="Close cookie preferences"
|
|
132
|
+
className="flex min-h-10 min-w-10 items-center justify-center rounded border border-border text-text-secondary transition hover:border-border-focus hover:text-text-primary"
|
|
133
|
+
onClick={() => setShowModal(false)}
|
|
134
|
+
>
|
|
135
|
+
<X aria-hidden="true" className="h-4 w-4" />
|
|
136
|
+
</button>
|
|
137
|
+
</div>
|
|
138
|
+
|
|
139
|
+
<p className="mt-4 text-body leading-6 text-text-secondary">
|
|
140
|
+
Necessary cookies keep login and security working. Optional categories are prepared
|
|
141
|
+
for future analytics and marketing, but no third-party tracking is loaded in this
|
|
142
|
+
slice.
|
|
143
|
+
</p>
|
|
144
|
+
|
|
145
|
+
<div className="mt-5 space-y-3">
|
|
146
|
+
<div className="rounded border border-border bg-bg p-4">
|
|
147
|
+
<div className="flex items-start justify-between gap-4">
|
|
148
|
+
<div>
|
|
149
|
+
<h3 className="text-heading font-semibold">Necessary</h3>
|
|
150
|
+
<p className="mt-1 text-body leading-6 text-text-secondary">
|
|
151
|
+
Required for dashboard sessions, security, and saving this preference.
|
|
152
|
+
</p>
|
|
153
|
+
</div>
|
|
154
|
+
<span className="rounded bg-success/15 px-2 py-1 text-label font-medium uppercase text-success">
|
|
155
|
+
Always on
|
|
156
|
+
</span>
|
|
157
|
+
</div>
|
|
158
|
+
</div>
|
|
159
|
+
|
|
160
|
+
<label className="block rounded border border-border bg-bg p-4">
|
|
161
|
+
<span className="flex items-start justify-between gap-4">
|
|
162
|
+
<span>
|
|
163
|
+
<span className="block text-heading font-semibold">Analytics</span>
|
|
164
|
+
<span className="mt-1 block text-body leading-6 text-text-secondary">
|
|
165
|
+
Helps measure product usage if analytics is added later.
|
|
166
|
+
</span>
|
|
167
|
+
</span>
|
|
168
|
+
<input
|
|
169
|
+
checked={preferences.analytics}
|
|
170
|
+
className="mt-1 h-5 w-5 accent-accent"
|
|
171
|
+
onChange={(event) =>
|
|
172
|
+
setPreferences((current) => ({
|
|
173
|
+
...current,
|
|
174
|
+
analytics: event.target.checked,
|
|
175
|
+
}))
|
|
176
|
+
}
|
|
177
|
+
type="checkbox"
|
|
178
|
+
/>
|
|
179
|
+
</span>
|
|
180
|
+
</label>
|
|
181
|
+
|
|
182
|
+
<label className="block rounded border border-border bg-bg p-4">
|
|
183
|
+
<span className="flex items-start justify-between gap-4">
|
|
184
|
+
<span>
|
|
185
|
+
<span className="block text-heading font-semibold">Marketing</span>
|
|
186
|
+
<span className="mt-1 block text-body leading-6 text-text-secondary">
|
|
187
|
+
Allows campaign attribution or ad pixels if they are added later.
|
|
188
|
+
</span>
|
|
189
|
+
</span>
|
|
190
|
+
<input
|
|
191
|
+
checked={preferences.marketing}
|
|
192
|
+
className="mt-1 h-5 w-5 accent-accent"
|
|
193
|
+
onChange={(event) =>
|
|
194
|
+
setPreferences((current) => ({
|
|
195
|
+
...current,
|
|
196
|
+
marketing: event.target.checked,
|
|
197
|
+
}))
|
|
198
|
+
}
|
|
199
|
+
type="checkbox"
|
|
200
|
+
/>
|
|
201
|
+
</span>
|
|
202
|
+
</label>
|
|
203
|
+
</div>
|
|
204
|
+
|
|
205
|
+
<div className="mt-5 grid gap-2 sm:grid-cols-3">
|
|
206
|
+
<button
|
|
207
|
+
className="min-h-11 rounded border border-border px-4 text-body font-medium text-text-secondary transition hover:border-border-focus hover:text-text-primary"
|
|
208
|
+
onClick={() => save({ analytics: false, marketing: false })}
|
|
209
|
+
>
|
|
210
|
+
Reject optional
|
|
211
|
+
</button>
|
|
212
|
+
<button
|
|
213
|
+
className="min-h-11 rounded border border-border px-4 text-body font-medium text-text-secondary transition hover:border-border-focus hover:text-text-primary"
|
|
214
|
+
onClick={() => save(preferences)}
|
|
215
|
+
>
|
|
216
|
+
Save choices
|
|
217
|
+
</button>
|
|
218
|
+
<button
|
|
219
|
+
className="min-h-11 rounded bg-accent px-4 text-body font-medium text-white transition hover:bg-accent-hover"
|
|
220
|
+
onClick={() => save({ analytics: true, marketing: true })}
|
|
221
|
+
>
|
|
222
|
+
Accept all
|
|
223
|
+
</button>
|
|
224
|
+
</div>
|
|
225
|
+
</div>
|
|
226
|
+
</div>
|
|
227
|
+
)}
|
|
228
|
+
</>
|
|
229
|
+
);
|
|
230
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { OPEN_COOKIE_SETTINGS_EVENT } from '@/lib/cookieConsent';
|
|
4
|
+
|
|
5
|
+
export function CookieSettingsButton({ className }: { className?: string }) {
|
|
6
|
+
return (
|
|
7
|
+
<button
|
|
8
|
+
className={className}
|
|
9
|
+
onClick={() => window.dispatchEvent(new Event(OPEN_COOKIE_SETTINGS_EVENT))}
|
|
10
|
+
type="button"
|
|
11
|
+
>
|
|
12
|
+
Cookie settings
|
|
13
|
+
</button>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { useRouter, useSearchParams } from 'next/navigation';
|
|
5
|
+
import { createOrg } from '@/lib/api';
|
|
6
|
+
import { Button } from '@/components/ui/Button';
|
|
7
|
+
import { Input } from '@/components/ui/Input';
|
|
8
|
+
|
|
9
|
+
export function SignupForm() {
|
|
10
|
+
const router = useRouter();
|
|
11
|
+
const searchParams = useSearchParams();
|
|
12
|
+
const [name, setName] = useState('');
|
|
13
|
+
const [error, setError] = useState('');
|
|
14
|
+
const [loading, setLoading] = useState(false);
|
|
15
|
+
|
|
16
|
+
async function onSubmit(event: React.FormEvent) {
|
|
17
|
+
event.preventDefault();
|
|
18
|
+
setError('');
|
|
19
|
+
setLoading(true);
|
|
20
|
+
try {
|
|
21
|
+
const org = await createOrg(name);
|
|
22
|
+
router.push(`/app/onboarding?orgId=${org.id}&plan=${searchParams.get('plan') || 'free'}`);
|
|
23
|
+
} catch (err) {
|
|
24
|
+
setError(err instanceof Error ? err.message : 'Could not create organization');
|
|
25
|
+
} finally {
|
|
26
|
+
setLoading(false);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return (
|
|
31
|
+
<div className="mt-8 grid gap-4">
|
|
32
|
+
<form className="rounded border border-border bg-surface p-5" onSubmit={onSubmit}>
|
|
33
|
+
<label className="text-label uppercase text-text-tertiary" htmlFor="org-name">
|
|
34
|
+
Organization name
|
|
35
|
+
</label>
|
|
36
|
+
<Input
|
|
37
|
+
id="org-name"
|
|
38
|
+
required
|
|
39
|
+
value={name}
|
|
40
|
+
onChange={(event) => setName(event.target.value)}
|
|
41
|
+
/>
|
|
42
|
+
{error && <p className="mt-3 text-body text-error">{error}</p>}
|
|
43
|
+
<Button className="mt-5 w-full" disabled={loading} type="submit">
|
|
44
|
+
{loading ? 'Creating...' : 'Create organization'}
|
|
45
|
+
</Button>
|
|
46
|
+
</form>
|
|
47
|
+
<p className="text-body text-text-secondary">
|
|
48
|
+
Already have a workspace?{' '}
|
|
49
|
+
<a className="font-semibold text-accent" href="/login">
|
|
50
|
+
Sign in
|
|
51
|
+
</a>
|
|
52
|
+
</p>
|
|
53
|
+
</div>
|
|
54
|
+
);
|
|
55
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const variants = {
|
|
2
|
+
success: 'bg-success/15 text-success',
|
|
3
|
+
warning: 'bg-warning/15 text-warning',
|
|
4
|
+
error: 'bg-error/15 text-error',
|
|
5
|
+
neutral: 'bg-border text-text-secondary',
|
|
6
|
+
accent: 'bg-accent/15 text-accent',
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export function Badge({
|
|
10
|
+
variant = 'neutral',
|
|
11
|
+
children,
|
|
12
|
+
}: {
|
|
13
|
+
variant?: keyof typeof variants;
|
|
14
|
+
children: React.ReactNode;
|
|
15
|
+
}) {
|
|
16
|
+
return (
|
|
17
|
+
<span
|
|
18
|
+
className={`inline-flex items-center rounded px-1.5 py-0.5 text-[11px] font-medium leading-4 ${variants[variant]}`}
|
|
19
|
+
>
|
|
20
|
+
{children}
|
|
21
|
+
</span>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import Link from 'next/link';
|
|
2
|
+
import { type ButtonHTMLAttributes, type ReactNode } from 'react';
|
|
3
|
+
import { twMerge } from 'tailwind-merge';
|
|
4
|
+
|
|
5
|
+
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
6
|
+
variant?: 'primary' | 'secondary' | 'ghost';
|
|
7
|
+
href?: string;
|
|
8
|
+
children: ReactNode;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const variants = {
|
|
12
|
+
primary: 'bg-accent text-white hover:bg-accent-hover',
|
|
13
|
+
secondary: 'bg-surface-raised text-text-primary border border-border hover:border-border-focus',
|
|
14
|
+
ghost: 'bg-transparent text-text-secondary hover:bg-surface-raised hover:text-text-primary',
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export function Button({ variant = 'primary', href, className, children, ...props }: ButtonProps) {
|
|
18
|
+
const classes = twMerge(
|
|
19
|
+
'inline-flex min-h-10 items-center justify-center gap-2 rounded px-4 text-body font-medium transition duration-150 disabled:cursor-not-allowed disabled:opacity-60 active:scale-[0.98]',
|
|
20
|
+
variants[variant],
|
|
21
|
+
className,
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
if (href) {
|
|
25
|
+
return (
|
|
26
|
+
<Link className={classes} href={href}>
|
|
27
|
+
{children}
|
|
28
|
+
</Link>
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<button className={classes} {...props}>
|
|
34
|
+
{children}
|
|
35
|
+
</button>
|
|
36
|
+
);
|
|
37
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type HTMLAttributes } from 'react';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
export function Card({ className, ...props }: HTMLAttributes<HTMLDivElement>) {
|
|
5
|
+
return (
|
|
6
|
+
<div
|
|
7
|
+
className={twMerge('rounded border border-border bg-surface p-5', className)}
|
|
8
|
+
{...props}
|
|
9
|
+
/>
|
|
10
|
+
);
|
|
11
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { X } from 'lucide-react';
|
|
5
|
+
|
|
6
|
+
export function ConfirmDialog({
|
|
7
|
+
title,
|
|
8
|
+
description,
|
|
9
|
+
confirmText,
|
|
10
|
+
confirmLabel = 'Confirm',
|
|
11
|
+
onConfirm,
|
|
12
|
+
onCancel,
|
|
13
|
+
destructive = false,
|
|
14
|
+
}: {
|
|
15
|
+
title: string;
|
|
16
|
+
description: string;
|
|
17
|
+
confirmText?: string;
|
|
18
|
+
confirmLabel?: string;
|
|
19
|
+
onConfirm: () => void;
|
|
20
|
+
onCancel: () => void;
|
|
21
|
+
destructive?: boolean;
|
|
22
|
+
}) {
|
|
23
|
+
const [input, setInput] = useState('');
|
|
24
|
+
const canConfirm = confirmText ? input === confirmText : true;
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<div className="fixed inset-0 z-50 flex items-center justify-center">
|
|
28
|
+
<div className="absolute inset-0 bg-black/60" onClick={onCancel} />
|
|
29
|
+
<div className="relative w-full max-w-md rounded-lg bg-surface border border-border p-5">
|
|
30
|
+
<button
|
|
31
|
+
onClick={onCancel}
|
|
32
|
+
className="absolute top-3 right-3 text-text-tertiary hover:text-text-secondary"
|
|
33
|
+
>
|
|
34
|
+
<X className="h-4 w-4" />
|
|
35
|
+
</button>
|
|
36
|
+
|
|
37
|
+
<h3 className="text-heading font-medium text-text-primary mb-2">{title}</h3>
|
|
38
|
+
<p className="text-body text-text-secondary mb-4">{description}</p>
|
|
39
|
+
|
|
40
|
+
{confirmText && (
|
|
41
|
+
<div className="mb-4">
|
|
42
|
+
<p className="text-body text-text-secondary mb-2">
|
|
43
|
+
Type <span className="font-mono text-text-primary">{confirmText}</span> to
|
|
44
|
+
confirm:
|
|
45
|
+
</p>
|
|
46
|
+
<input
|
|
47
|
+
value={input}
|
|
48
|
+
onChange={(e) => setInput(e.target.value)}
|
|
49
|
+
className="w-full rounded bg-bg border border-border px-3 py-2 text-body text-text-primary outline-none focus:border-border-focus"
|
|
50
|
+
autoFocus
|
|
51
|
+
/>
|
|
52
|
+
</div>
|
|
53
|
+
)}
|
|
54
|
+
|
|
55
|
+
<div className="flex justify-end gap-2">
|
|
56
|
+
<button
|
|
57
|
+
onClick={onCancel}
|
|
58
|
+
className="rounded px-3 py-1.5 text-body text-text-secondary hover:bg-surface-raised transition-colors"
|
|
59
|
+
>
|
|
60
|
+
Cancel
|
|
61
|
+
</button>
|
|
62
|
+
<button
|
|
63
|
+
onClick={onConfirm}
|
|
64
|
+
disabled={!canConfirm}
|
|
65
|
+
className={`rounded px-3 py-1.5 text-body font-medium transition-colors disabled:opacity-40 ${
|
|
66
|
+
destructive
|
|
67
|
+
? 'bg-error/15 text-error hover:bg-error/25'
|
|
68
|
+
: 'bg-accent text-white hover:bg-accent-hover'
|
|
69
|
+
}`}
|
|
70
|
+
>
|
|
71
|
+
{confirmLabel}
|
|
72
|
+
</button>
|
|
73
|
+
</div>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
);
|
|
77
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { LucideIcon } from 'lucide-react';
|
|
2
|
+
|
|
3
|
+
export function EmptyState({
|
|
4
|
+
icon: Icon,
|
|
5
|
+
title,
|
|
6
|
+
description,
|
|
7
|
+
action,
|
|
8
|
+
}: {
|
|
9
|
+
icon: LucideIcon;
|
|
10
|
+
title: string;
|
|
11
|
+
description: string;
|
|
12
|
+
action?: React.ReactNode;
|
|
13
|
+
}) {
|
|
14
|
+
return (
|
|
15
|
+
<div className="flex flex-col items-center justify-center py-16 text-center">
|
|
16
|
+
<div className="rounded-lg bg-surface p-3 mb-4">
|
|
17
|
+
<Icon className="h-6 w-6 text-text-tertiary" />
|
|
18
|
+
</div>
|
|
19
|
+
<h3 className="text-heading font-medium text-text-primary mb-1">{title}</h3>
|
|
20
|
+
<p className="text-body text-text-secondary max-w-sm mb-4">{description}</p>
|
|
21
|
+
{action}
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type InputHTMLAttributes } from 'react';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
export function Input({ className, ...props }: InputHTMLAttributes<HTMLInputElement>) {
|
|
5
|
+
return (
|
|
6
|
+
<input
|
|
7
|
+
className={twMerge(
|
|
8
|
+
'min-h-10 w-full rounded border border-border bg-surface px-3 text-body text-text-primary outline-none transition focus:border-border-focus',
|
|
9
|
+
className,
|
|
10
|
+
)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { useState, useCallback } from 'react';
|
|
4
|
+
import { Copy, Eye, EyeOff } from 'lucide-react';
|
|
5
|
+
|
|
6
|
+
export function KeyDisplay({ apiKey, masked = true }: { apiKey: string; masked?: boolean }) {
|
|
7
|
+
const [revealed, setRevealed] = useState(!masked);
|
|
8
|
+
const [copied, setCopied] = useState(false);
|
|
9
|
+
|
|
10
|
+
const maskedKey = apiKey.length > 8
|
|
11
|
+
? `${apiKey.slice(0, 4)}${'•'.repeat(8)}${apiKey.slice(-4)}`
|
|
12
|
+
: '•'.repeat(apiKey.length);
|
|
13
|
+
|
|
14
|
+
const handleCopy = useCallback(() => {
|
|
15
|
+
navigator.clipboard.writeText(apiKey);
|
|
16
|
+
setCopied(true);
|
|
17
|
+
setTimeout(() => setCopied(false), 2000);
|
|
18
|
+
}, [apiKey]);
|
|
19
|
+
|
|
20
|
+
const handleReveal = useCallback(() => {
|
|
21
|
+
setRevealed(true);
|
|
22
|
+
setTimeout(() => setRevealed(false), 5000);
|
|
23
|
+
}, []);
|
|
24
|
+
|
|
25
|
+
return (
|
|
26
|
+
<div className="flex items-center gap-2 rounded bg-surface border border-border px-3 py-1.5 font-mono text-body">
|
|
27
|
+
<span className="flex-1 truncate text-text-secondary select-all">
|
|
28
|
+
{revealed ? apiKey : maskedKey}
|
|
29
|
+
</span>
|
|
30
|
+
{masked && (
|
|
31
|
+
<button
|
|
32
|
+
onClick={revealed ? () => setRevealed(false) : handleReveal}
|
|
33
|
+
className="text-text-tertiary hover:text-text-secondary transition-colors"
|
|
34
|
+
title={revealed ? 'Hide' : 'Reveal for 5 seconds'}
|
|
35
|
+
>
|
|
36
|
+
{revealed ? <EyeOff className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
|
|
37
|
+
</button>
|
|
38
|
+
)}
|
|
39
|
+
<button
|
|
40
|
+
onClick={handleCopy}
|
|
41
|
+
className="text-text-tertiary hover:text-text-secondary transition-colors"
|
|
42
|
+
title="Copy"
|
|
43
|
+
>
|
|
44
|
+
<Copy className="h-3.5 w-3.5" />
|
|
45
|
+
</button>
|
|
46
|
+
{copied && <span className="text-[11px] text-success">Copied</span>}
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type SelectHTMLAttributes } from 'react';
|
|
2
|
+
import { twMerge } from 'tailwind-merge';
|
|
3
|
+
|
|
4
|
+
export function Select({ className, ...props }: SelectHTMLAttributes<HTMLSelectElement>) {
|
|
5
|
+
return (
|
|
6
|
+
<select
|
|
7
|
+
className={twMerge(
|
|
8
|
+
'min-h-10 w-full rounded border border-border bg-surface px-3 text-body text-text-primary outline-none transition focus:border-border-focus',
|
|
9
|
+
className,
|
|
10
|
+
)}
|
|
11
|
+
{...props}
|
|
12
|
+
/>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function Skeleton({ className = '' }: { className?: string }) {
|
|
2
|
+
return <div className={`skeleton ${className}`} />;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
export function SkeletonRow() {
|
|
6
|
+
return (
|
|
7
|
+
<div className="flex items-center gap-4 px-4 h-9">
|
|
8
|
+
<Skeleton className="h-3 w-24" />
|
|
9
|
+
<Skeleton className="h-3 w-32" />
|
|
10
|
+
<Skeleton className="h-3 w-16" />
|
|
11
|
+
<Skeleton className="h-3 w-20" />
|
|
12
|
+
</div>
|
|
13
|
+
);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function SkeletonMetric() {
|
|
17
|
+
return (
|
|
18
|
+
<div className="rounded border border-border bg-surface p-4">
|
|
19
|
+
<Skeleton className="h-3 w-20 mb-3" />
|
|
20
|
+
<Skeleton className="h-6 w-12 mb-1" />
|
|
21
|
+
<Skeleton className="h-3 w-16" />
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
}
|