@burdenoff/microfe-devportal 2026.1031.1 → 2026.1102.1

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.
Files changed (43) hide show
  1. package/dist/devportal/DevportalRoutes.d.ts.map +1 -1
  2. package/dist/devportal/DevportalRoutes.js +13 -9
  3. package/dist/devportal/DevportalRoutes.js.map +1 -1
  4. package/dist/devportal/components/OnboardingChecklist.d.ts +16 -0
  5. package/dist/devportal/components/OnboardingChecklist.d.ts.map +1 -0
  6. package/dist/devportal/components/OnboardingChecklist.js +151 -0
  7. package/dist/devportal/components/OnboardingChecklist.js.map +1 -0
  8. package/dist/devportal/constants/developerLinks.d.ts +47 -0
  9. package/dist/devportal/constants/developerLinks.d.ts.map +1 -0
  10. package/dist/devportal/constants/developerLinks.js +27 -0
  11. package/dist/devportal/constants/developerLinks.js.map +1 -0
  12. package/dist/devportal/hooks/useGraphQL.d.ts.map +1 -1
  13. package/dist/devportal/hooks/useGraphQL.js +2 -1
  14. package/dist/devportal/hooks/useGraphQL.js.map +1 -1
  15. package/dist/devportal/hooks/useProducts.js +1 -1
  16. package/dist/devportal/hooks/useProducts.js.map +1 -1
  17. package/dist/devportal/pages/DashboardPage.d.ts.map +1 -1
  18. package/dist/devportal/pages/DashboardPage.js +107 -105
  19. package/dist/devportal/pages/DashboardPage.js.map +1 -1
  20. package/dist/devportal/pages/DocumentationPage.d.ts.map +1 -1
  21. package/dist/devportal/pages/DocumentationPage.js +114 -148
  22. package/dist/devportal/pages/DocumentationPage.js.map +1 -1
  23. package/dist/devportal/pages/PublisherProfilePage.d.ts.map +1 -1
  24. package/dist/devportal/pages/PublisherProfilePage.js +170 -160
  25. package/dist/devportal/pages/PublisherProfilePage.js.map +1 -1
  26. package/dist/devportal/pages/ResourcesPage.js +2 -2
  27. package/dist/devportal/pages/ResourcesPage.js.map +1 -1
  28. package/dist/devportal/pages/SetupPage.d.ts.map +1 -1
  29. package/dist/devportal/pages/SetupPage.js +363 -218
  30. package/dist/devportal/pages/SetupPage.js.map +1 -1
  31. package/dist/devportal/utils/developerOnboarding.d.ts +85 -0
  32. package/dist/devportal/utils/developerOnboarding.d.ts.map +1 -0
  33. package/dist/devportal/utils/developerOnboarding.js +104 -0
  34. package/dist/devportal/utils/developerOnboarding.js.map +1 -0
  35. package/dist/generated/global-operations.d.ts +92 -39
  36. package/dist/generated/global-operations.d.ts.map +1 -1
  37. package/dist/generated/global-operations.js +177 -141
  38. package/dist/generated/global-operations.js.map +1 -1
  39. package/dist/translations/en.d.ts +50 -0
  40. package/dist/translations/en.d.ts.map +1 -1
  41. package/dist/translations/en.js +51 -1
  42. package/dist/translations/en.js.map +1 -1
  43. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"SetupPage.js","names":[],"sources":["../../../src/devportal/pages/SetupPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport {\n ArrowRight,\n Building2,\n AppWindow,\n Rocket,\n Check,\n Key,\n BookOpen,\n ChevronRight,\n Box,\n Puzzle,\n GitFork,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { Illustration, PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport {\n InputField,\n TextareaField,\n SelectField,\n} from \"../components/FormField\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { useDevportalEventBus } from \"../events\";\nimport { cn } from \"../utils/cn\";\nimport {\n useCreateOrganizationMutation,\n useCreateApplicationMutation,\n} from \"../../generated/global-operations\";\nimport { useCreateBillingAccountMutation } from \"../hooks\";\n\ntype SetupStep = \"org\" | \"app\" | \"done\";\ntype BuilderType = \"app\" | \"node\" | \"workflow\";\n\nconst CATEGORY_OPTIONS = [\n { value: \"productivity\", label: \"Productivity\" },\n { value: \"communication\", label: \"Communication\" },\n { value: \"analytics\", label: \"Analytics\" },\n { value: \"automation\", label: \"Automation\" },\n { value: \"developer-tools\", label: \"Developer Tools\" },\n { value: \"finance\", label: \"Finance\" },\n { value: \"hr\", label: \"HR & People\" },\n { value: \"marketing\", label: \"Marketing\" },\n { value: \"project-management\", label: \"Project Management\" },\n { value: \"security\", label: \"Security\" },\n { value: \"support\", label: \"Support\" },\n { value: \"other\", label: \"Other\" },\n];\n\nfunction generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\n/** Mark that the user has interacted with setup so the dashboard gate won't redirect again. */\nfunction markSetupSeen() {\n try {\n localStorage.setItem(\"devportal_setup_dismissed\", \"1\");\n } catch {\n // localStorage unavailable — not critical\n }\n}\n\n// ─── Step indicator ────────────────────────────────────────────────────────\n\nconst STEPS: { key: SetupStep; label: string }[] = [\n { key: \"org\", label: \"Organization\" },\n { key: \"app\", label: \"First app\" },\n { key: \"done\", label: \"Done\" },\n];\n\nconst StepIndicator: FC<{ current: SetupStep }> = ({ current }) => {\n const currentIdx = STEPS.findIndex((s) => s.key === current);\n return (\n <div className=\"flex items-center gap-0\">\n {STEPS.map((step, idx) => {\n const isCompleted = idx < currentIdx;\n const isActive = idx === currentIdx;\n return (\n <div key={step.key} className=\"flex items-center\">\n <div className=\"flex flex-col items-center gap-1.5\">\n <div\n className={[\n \"flex h-8 w-8 items-center justify-center rounded-full text-sm font-semibold transition-colors\",\n isCompleted\n ? \"bg-action-primary-bg text-action-primary-text\"\n : isActive\n ? \"bg-action-primary-bg text-action-primary-text ring-4 ring-primary/20\"\n : \"bg-bg-sunken text-text-secondary\",\n ].join(\" \")}\n >\n {isCompleted ? <Check size={14} /> : idx + 1}\n </div>\n <span\n className={[\n \"text-xs font-medium whitespace-nowrap\",\n isActive ? \"text-text-primary\" : \"text-text-secondary\",\n ].join(\" \")}\n >\n {step.label}\n </span>\n </div>\n {idx < STEPS.length - 1 && (\n <div\n className={[\n \"mx-3 mb-5 h-px w-16 flex-shrink-0 transition-colors\",\n idx < currentIdx ? \"bg-action-primary-bg\" : \"bg-border\",\n ].join(\" \")}\n />\n )}\n </div>\n );\n })}\n </div>\n );\n};\n\n// ─── Main component ────────────────────────────────────────────────────────\n\nexport const SetupPage: FC = () => {\n const { navigate, basePath, currentUser } = useDevportal();\n const { t } = useI18n();\n const bus = useDevportalEventBus();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const handleNavigate = (path: string) => navigate?.(`${basePath}${path}`);\n\n const [step, setStep] = useState<SetupStep>(\"org\");\n\n // IDs created during wizard — carried forward for success CTAs\n const [createdOrgId, setCreatedOrgId] = useState<string | null>(null);\n const [createdAppId, setCreatedAppId] = useState<string | null>(null);\n\n // ── Step 1: org ──────────────────────────────────────────────\n const [orgName, setOrgName] = useState(\"\");\n const [orgSlug, setOrgSlug] = useState(\"\");\n const [orgDescription, setOrgDescription] = useState(\"\");\n const [orgErrors, setOrgErrors] = useState<{ name?: string; slug?: string }>(\n {},\n );\n\n const [createOrg, { loading: creatingOrg }] = useCreateOrganizationMutation();\n const [createBillingAccountMutation] = useCreateBillingAccountMutation();\n\n const validateOrg = () => {\n const errs: { name?: string; slug?: string } = {};\n if (!orgName.trim())\n errs.name = tr(\n \"devportal.orgNameRequired\",\n \"Organization name is required\",\n );\n else if (orgName.length < 2)\n errs.name = tr(\n \"devportal.orgNameTooShort\",\n \"Name must be at least 2 characters\",\n );\n if (!orgSlug.trim())\n errs.slug = tr(\"devportal.slugRequired\", \"Slug is required\");\n else if (!/^[a-z0-9-]+$/.test(orgSlug))\n errs.slug = tr(\n \"devportal.slugInvalid\",\n \"Lowercase letters, numbers, and hyphens only\",\n );\n setOrgErrors(errs);\n return Object.keys(errs).length === 0;\n };\n\n const handleOrgSubmit = async () => {\n if (!validateOrg()) return;\n try {\n const result = await createOrg({\n variables: {\n input: {\n name: orgName,\n slug: orgSlug || undefined,\n description: orgDescription || undefined,\n },\n },\n });\n const id = result.data?.createDeveloperOrganization?.id;\n if (id) {\n bus.emit(\"devportal.org.created\", {\n organizationId: id,\n name: orgName,\n });\n setCreatedOrgId(id);\n // Fire-and-forget: create a billing account for the new org\n try {\n createBillingAccountMutation({\n variables: {\n input: {\n name: orgName,\n email: currentUser?.email ?? \"\",\n },\n },\n }).catch(() => {});\n } catch {\n // silent failure — billing account creation is non-blocking\n }\n setStep(\"app\");\n }\n } catch {\n // error surfaced via Apollo cache; leave the form open\n }\n };\n\n // ── Step 2: app ──────────────────────────────────────────────\n const [appName, setAppName] = useState(\"\");\n const [appSlug, setAppSlug] = useState(\"\");\n const [builderType, setBuilderType] = useState<BuilderType | null>(null);\n const [appCategory, setAppCategory] = useState(\"\");\n const [appShortDesc, setAppShortDesc] = useState(\"\");\n const [appErrors, setAppErrors] = useState<{\n name?: string;\n builderType?: string;\n category?: string;\n shortDescription?: string;\n }>({});\n\n const [createApp, { loading: creatingApp }] = useCreateApplicationMutation();\n\n const appTypeForBuilder = () => {\n if (builderType === \"node\") return \"NODE\" as const;\n if (builderType === \"workflow\") return \"WORKFLOW\" as const;\n return \"API_INTEGRATION\" as const;\n };\n\n const validateApp = () => {\n const errs: typeof appErrors = {};\n if (!appName.trim())\n errs.name = tr(\n \"devportal.appNameRequired\",\n \"Application name is required\",\n );\n else if (appName.length < 3)\n errs.name = tr(\n \"devportal.nameTooShort\",\n \"Name must be at least 3 characters\",\n );\n if (!builderType)\n errs.builderType = tr(\n \"devportal.appTypeRequired\",\n \"Application type is required\",\n );\n if (!appCategory)\n errs.category = tr(\"devportal.categoryRequired\", \"Category is required\");\n if (!appShortDesc.trim())\n errs.shortDescription = tr(\n \"devportal.shortDescriptionRequired\",\n \"Short description is required\",\n );\n setAppErrors(errs);\n return Object.keys(errs).length === 0;\n };\n\n const handleAppSubmit = async () => {\n if (!validateApp()) return;\n const resolvedType = appTypeForBuilder();\n try {\n const result = await createApp({\n variables: {\n input: {\n name: appName,\n slug: appSlug || undefined,\n appType: resolvedType,\n category: appCategory || undefined,\n shortDescription: appShortDesc || undefined,\n visibility: \"PRIVATE\",\n developerOrganizationId: createdOrgId || undefined,\n },\n },\n });\n const id = result.data?.createApplication?.id;\n if (id) {\n bus.emit(\"devportal.app.created\", {\n appId: id,\n name: appName,\n appType: resolvedType,\n organizationId: createdOrgId,\n });\n setCreatedAppId(id);\n markSetupSeen();\n setStep(\"done\");\n }\n } catch {\n // error surfaced via Apollo cache\n }\n };\n\n const handleSkip = () => {\n markSetupSeen();\n handleNavigate(\"/\");\n };\n\n // ─── Render ─────────────────────────────────────────────────\n\n return (\n <main className=\"min-h-screen bg-surface-default\">\n {/* Header */}\n <div className=\"border-b border-border-default bg-surface-raised\">\n <div className=\"mx-auto max-w-2xl px-6 py-5\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Rocket size={20} />\n </div>\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {tr(\"devportal.developerPortal\", \"Developer Portal\")}\n </p>\n <h1 className=\"text-base font-semibold text-text-primary\">\n {tr(\"devportal.setup.title\", \"Get set up\")}\n </h1>\n </div>\n </div>\n {step !== \"done\" && (\n <button\n type=\"button\"\n onClick={handleSkip}\n className=\"text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.setup.skipForNow\", \"Skip for now\")}\n </button>\n )}\n </div>\n </div>\n </div>\n\n {/* Content */}\n <div className=\"mx-auto max-w-2xl px-6 py-10\">\n {/* Step indicator */}\n <div className=\"mb-10 flex justify-center\">\n <StepIndicator current={step} />\n </div>\n\n {/* Welcome / purpose — what this wizard sets up and why */}\n {step === \"org\" && (\n <div className=\"mb-8 flex flex-col items-center gap-3 text-center\">\n <Illustration\n name=\"onboarding\"\n alt={tr(\n \"devportal.setup.illustrationAlt\",\n \"Getting started with the developer portal\",\n )}\n size=\"md\"\n />\n <PagePurpose className=\"justify-center\">\n {tr(\n \"devportal.setup.purpose\",\n \"Two quick steps to start building: create the organization that owns your apps, then register your first app. You can change everything later — this just gets you to a working starting point.\",\n )}\n </PagePurpose>\n </div>\n )}\n\n {/* ── Step 1: Organization ─────────────────────── */}\n {step === \"org\" && (\n <div className=\"rounded-xl border border-border-default bg-surface-raised p-8 shadow-sm\">\n <div className=\"mb-6 flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={20} />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"devportal.setup.orgTitle\", \"Set up your organization\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.setup.orgSubtitle\",\n \"This groups your apps and teams under one publisher identity.\",\n )}\n </p>\n </div>\n </div>\n\n <div className=\"space-y-5\">\n <InputField\n label={tr(\"devportal.organizationName\", \"Organization Name\")}\n value={orgName}\n onChange={(e) => {\n setOrgName(e.target.value);\n if (!orgSlug || orgSlug === generateSlug(orgName)) {\n setOrgSlug(generateSlug(e.target.value));\n }\n setOrgErrors((p) => ({ ...p, name: undefined }));\n }}\n placeholder={tr(\n \"devportal.organizationNamePlaceholder\",\n \"Acme Development\",\n )}\n required\n error={orgErrors.name}\n />\n\n <InputField\n label={tr(\"devportal.slug\", \"Slug\")}\n value={orgSlug}\n onChange={(e) => {\n setOrgSlug(e.target.value.toLowerCase());\n setOrgErrors((p) => ({ ...p, slug: undefined }));\n }}\n placeholder=\"acme-dev\"\n required\n error={orgErrors.slug}\n hint={tr(\n \"devportal.slugHint\",\n \"URL-friendly identifier — auto-generated from name\",\n )}\n />\n\n <TextareaField\n label={tr(\"devportal.description\", \"Description\")}\n value={orgDescription}\n onChange={(e) => setOrgDescription(e.target.value)}\n placeholder={tr(\n \"devportal.orgDescriptionPlaceholder\",\n \"Tell us about your organization…\",\n )}\n rows={2}\n />\n </div>\n\n <div className=\"mt-8 flex items-center justify-between border-t border-border-default pt-6\">\n <button\n type=\"button\"\n onClick={handleSkip}\n className=\"text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.setup.skipForNow\", \"Skip for now\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleOrgSubmit()}\n disabled={creatingOrg}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-60 transition-colors\"\n >\n {creatingOrg ? (\n <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n ) : null}\n {tr(\"devportal.setup.createAndContinue\", \"Create & Continue\")}\n {!creatingOrg && <ChevronRight size={16} />}\n </button>\n </div>\n </div>\n )}\n\n {/* ── Step 2: First app ─────────────────────── */}\n {step === \"app\" && (\n <div className=\"rounded-xl border border-border-default bg-surface-raised p-8 shadow-sm\">\n <div className=\"mb-6 flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <AppWindow size={20} />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"devportal.setup.appTitle\", \"Create your first app\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.setup.appSubtitle\",\n \"Register the app you want to publish or integrate.\",\n )}\n </p>\n </div>\n </div>\n\n <div className=\"space-y-5\">\n <InputField\n label={tr(\"devportal.applicationName\", \"Application Name\")}\n value={appName}\n onChange={(e) => {\n setAppName(e.target.value);\n if (!appSlug || appSlug === generateSlug(appName)) {\n setAppSlug(generateSlug(e.target.value));\n }\n setAppErrors((p) => ({ ...p, name: undefined }));\n }}\n placeholder={tr(\n \"devportal.applicationNamePlaceholder\",\n \"My Awesome App\",\n )}\n required\n error={appErrors.name}\n />\n\n {/* Builder type picker */}\n <div>\n <p className=\"mb-2 text-sm font-medium text-text-primary\">\n {tr(\"devportal.applicationType\", \"Application Type\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </p>\n <div className=\"grid grid-cols-3 gap-3\">\n <SetupTypeCard\n icon={Box}\n title=\"App\"\n description=\"OAuth integration for the platform\"\n selected={builderType === \"app\"}\n onClick={() => {\n setBuilderType(\"app\");\n setAppErrors((p) => ({ ...p, builderType: undefined }));\n }}\n />\n <SetupTypeCard\n icon={Puzzle}\n title=\"Node\"\n description=\"Custom FluidGrids workflow node\"\n selected={builderType === \"node\"}\n onClick={() => {\n setBuilderType(\"node\");\n setAppErrors((p) => ({ ...p, builderType: undefined }));\n }}\n />\n <SetupTypeCard\n icon={GitFork}\n title=\"Workflow\"\n description=\"Reusable automation template\"\n selected={builderType === \"workflow\"}\n onClick={() => {\n setBuilderType(\"workflow\");\n setAppErrors((p) => ({ ...p, builderType: undefined }));\n }}\n />\n </div>\n {appErrors.builderType && (\n <p className=\"mt-1.5 text-xs text-status-error-text\">\n {appErrors.builderType}\n </p>\n )}\n </div>\n\n <SelectField\n label={tr(\"devportal.category\", \"Category\")}\n value={appCategory}\n onChange={(e) => {\n setAppCategory(e.target.value);\n setAppErrors((p) => ({ ...p, category: undefined }));\n }}\n options={CATEGORY_OPTIONS}\n placeholder={tr(\"devportal.selectCategory\", \"Select category…\")}\n required\n error={appErrors.category}\n />\n\n <TextareaField\n label={tr(\"devportal.shortDescription\", \"Short Description\")}\n value={appShortDesc}\n onChange={(e) => {\n setAppShortDesc(e.target.value);\n setAppErrors((p) => ({ ...p, shortDescription: undefined }));\n }}\n placeholder={tr(\n \"devportal.shortDescriptionPlaceholder\",\n \"A brief description of what your app does\",\n )}\n required\n error={appErrors.shortDescription}\n rows={2}\n hint={`${appShortDesc.length}/200`}\n />\n </div>\n\n <div className=\"mt-8 flex items-center justify-between border-t border-border-default pt-6\">\n <button\n type=\"button\"\n onClick={handleSkip}\n className=\"text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.setup.skipForNow\", \"Skip for now\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleAppSubmit()}\n disabled={creatingApp}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-60 transition-colors\"\n >\n {creatingApp ? (\n <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n ) : null}\n {tr(\"devportal.setup.createApp\", \"Create App\")}\n {!creatingApp && <ChevronRight size={16} />}\n </button>\n </div>\n </div>\n )}\n\n {/* ── Step 3: Done ─────────────────────────── */}\n {step === \"done\" && (\n <div className=\"text-center\">\n <div className=\"mx-auto mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-action-primary-bg/10 text-primary\">\n <Rocket size={32} />\n </div>\n <h2 className=\"text-2xl font-bold text-text-primary\">\n {tr(\"devportal.setup.doneTitle\", \"You're all set!\")}\n </h2>\n <p className=\"mt-2 text-text-secondary\">\n {tr(\n \"devportal.setup.doneSubtitle\",\n \"Your organization and first app are ready. Here's what to do next.\",\n )}\n </p>\n\n <div className=\"mt-8 grid gap-3 sm:grid-cols-2\">\n {createdAppId && (\n <NextStepCard\n icon={<AppWindow size={20} />}\n title={tr(\"devportal.setup.viewApp\", \"View your app\")}\n description={tr(\n \"devportal.setup.viewAppDesc\",\n \"Configure OAuth, webhooks, and versioning\",\n )}\n onClick={() => handleNavigate(`/apps/${createdAppId}`)}\n primary\n />\n )}\n <NextStepCard\n icon={<Key size={20} />}\n title={tr(\"devportal.setup.generateApiKey\", \"Generate API key\")}\n description={tr(\n \"devportal.setup.generateApiKeyDesc\",\n \"Create credentials to start calling APIs\",\n )}\n onClick={() => handleNavigate(\"/api-keys/new\")}\n />\n <NextStepCard\n icon={<BookOpen size={20} />}\n title={tr(\"devportal.setup.browseDocs\", \"Browse docs\")}\n description={tr(\n \"devportal.setup.browseDocsDesc\",\n \"Learn about publishing, SDKs, and webhooks\",\n )}\n onClick={() => handleNavigate(\"/docs\")}\n />\n {createdOrgId && (\n <NextStepCard\n icon={<Building2 size={20} />}\n title={tr(\"devportal.setup.inviteTeam\", \"Invite your team\")}\n description={tr(\n \"devportal.setup.inviteTeamDesc\",\n \"Add members to collaborate on your apps\",\n )}\n onClick={() =>\n handleNavigate(`/organizations/${createdOrgId}/members`)\n }\n />\n )}\n </div>\n\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"/\")}\n className=\"mt-8 inline-flex items-center gap-2 text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.setup.goToDashboard\", \"Go to dashboard\")}\n <ArrowRight size={14} />\n </button>\n </div>\n )}\n </div>\n </main>\n );\n};\n\n// ─── Setup type card ───────────────────────────────────────────────────────\n\nconst SetupTypeCard: FC<{\n icon: FC<{ size?: number; className?: string }>;\n title: string;\n description: string;\n selected: boolean;\n onClick: () => void;\n}> = ({ icon: Icon, title, description, selected, onClick }) => (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n \"relative flex flex-col gap-2 rounded-xl border-2 p-4 text-left transition-all hover:border-primary/50 hover:shadow-sm\",\n selected\n ? \"border-primary bg-action-primary-bg/5 shadow-sm\"\n : \"border-border-subtle bg-bg-surface\",\n )}\n >\n {selected && (\n <span className=\"absolute top-3 right-3 flex h-4 w-4 items-center justify-center rounded-full bg-action-primary-bg text-action-primary-text\">\n <Check size={10} />\n </span>\n )}\n <div className=\"flex h-8 w-8 items-center justify-center rounded-lg bg-bg-sunken\">\n <Icon size={18} className=\"text-text-primary\" />\n </div>\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">{title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{description}</p>\n </div>\n </button>\n);\n\n// ─── Next-step card ────────────────────────────────────────────────────────\n\nconst NextStepCard: FC<{\n icon: React.ReactNode;\n title: string;\n description: string;\n onClick: () => void;\n primary?: boolean;\n}> = ({ icon, title, description, onClick, primary }) => (\n <button\n type=\"button\"\n onClick={onClick}\n className={[\n \"flex items-start gap-4 rounded-xl border p-5 text-left transition-colors\",\n primary\n ? \"border-primary bg-action-primary-bg/5 hover:bg-action-primary-bg/10\"\n : \"border-border-default bg-surface-raised hover:bg-surface-hover\",\n ].join(\" \")}\n >\n <div\n className={[\n \"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg\",\n primary\n ? \"bg-action-primary-bg/20 text-primary\"\n : \"bg-bg-sunken text-text-secondary\",\n ].join(\" \")}\n >\n {icon}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold text-text-primary\">{title}</p>\n <p className=\"mt-0.5 text-sm text-text-secondary\">{description}</p>\n </div>\n <ChevronRight\n size={16}\n className=\"mt-0.5 flex-shrink-0 text-text-secondary\"\n />\n </button>\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"SetupPage.js","names":[],"sources":["../../../src/devportal/pages/SetupPage.tsx"],"sourcesContent":["import type { FC } from \"react\";\nimport { useState } from \"react\";\nimport {\n ArrowRight,\n Building2,\n AppWindow,\n Rocket,\n Check,\n Key,\n BookOpen,\n ChevronRight,\n Box,\n Puzzle,\n GitFork,\n ListChecks,\n ShieldCheck,\n} from \"lucide-react\";\nimport { useI18n } from \"@burdenoff/fe-libs/shared/providers/shell/I18nProvider\";\nimport { Illustration, PagePurpose } from \"@burdenoff/fe-libs/ui\";\nimport {\n InputField,\n TextareaField,\n SelectField,\n} from \"../components/FormField\";\nimport { useDevportal } from \"../providers/DevportalProvider\";\nimport { useDevportalEventBus } from \"../events\";\nimport { cn } from \"../utils/cn\";\nimport {\n useCreateOrganizationMutation,\n useCreateApplicationMutation,\n useCreateDeveloperProfileMutation,\n} from \"../../generated/global-operations\";\nimport { useCreateBillingAccountMutation } from \"../hooks\";\nimport {\n DEVELOPER_AGREEMENT_VERSION,\n DEVELOPER_LINKS,\n} from \"../constants/developerLinks\";\nimport {\n ELIGIBILITY_RULES,\n reviewRequirementsFor,\n} from \"../utils/developerOnboarding\";\n\ntype SetupStep = \"org\" | \"app\" | \"submit\" | \"done\";\ntype BuilderType = \"app\" | \"node\" | \"workflow\";\n\nconst CATEGORY_OPTIONS = [\n { value: \"productivity\", label: \"Productivity\" },\n { value: \"communication\", label: \"Communication\" },\n { value: \"analytics\", label: \"Analytics\" },\n { value: \"automation\", label: \"Automation\" },\n { value: \"developer-tools\", label: \"Developer Tools\" },\n { value: \"finance\", label: \"Finance\" },\n { value: \"hr\", label: \"HR & People\" },\n { value: \"marketing\", label: \"Marketing\" },\n { value: \"project-management\", label: \"Project Management\" },\n { value: \"security\", label: \"Security\" },\n { value: \"support\", label: \"Support\" },\n { value: \"other\", label: \"Other\" },\n];\n\nfunction generateSlug(name: string): string {\n return name\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, \"-\")\n .replace(/^-|-$/g, \"\");\n}\n\n/** Readable message from a failed mutation, falling back to a generic one. */\nfunction errorMessage(err: unknown, fallback: string): string {\n if (err instanceof Error && err.message) return err.message;\n return fallback;\n}\n\n/** Mark that the user has interacted with setup so the dashboard gate won't redirect again. */\nfunction markSetupSeen() {\n try {\n localStorage.setItem(\"devportal_setup_dismissed\", \"1\");\n } catch {\n // localStorage unavailable — not critical\n }\n}\n\n// ─── Step indicator ────────────────────────────────────────────────────────\n\nconst STEPS: { key: SetupStep; label: string }[] = [\n { key: \"org\", label: \"Organization\" },\n { key: \"app\", label: \"First app\" },\n { key: \"submit\", label: \"Submit\" },\n { key: \"done\", label: \"Done\" },\n];\n\nconst StepIndicator: FC<{ current: SetupStep }> = ({ current }) => {\n const currentIdx = STEPS.findIndex((s) => s.key === current);\n return (\n <div className=\"flex items-center gap-0\">\n {STEPS.map((step, idx) => {\n const isCompleted = idx < currentIdx;\n const isActive = idx === currentIdx;\n return (\n <div key={step.key} className=\"flex items-center\">\n <div className=\"flex flex-col items-center gap-1.5\">\n <div\n className={[\n \"flex h-8 w-8 items-center justify-center rounded-full text-sm font-semibold transition-colors\",\n isCompleted\n ? \"bg-action-primary-bg text-action-primary-text\"\n : isActive\n ? \"bg-action-primary-bg text-action-primary-text ring-4 ring-primary/20\"\n : \"bg-bg-sunken text-text-secondary\",\n ].join(\" \")}\n >\n {isCompleted ? <Check size={14} /> : idx + 1}\n </div>\n <span\n className={[\n \"text-xs font-medium whitespace-nowrap\",\n isActive ? \"text-text-primary\" : \"text-text-secondary\",\n ].join(\" \")}\n >\n {step.label}\n </span>\n </div>\n {idx < STEPS.length - 1 && (\n <div\n className={[\n \"mx-3 mb-5 h-px w-16 flex-shrink-0 transition-colors\",\n idx < currentIdx ? \"bg-action-primary-bg\" : \"bg-border\",\n ].join(\" \")}\n />\n )}\n </div>\n );\n })}\n </div>\n );\n};\n\n// ─── Main component ────────────────────────────────────────────────────────\n\nexport const SetupPage: FC = () => {\n const { navigate, basePath, currentUser } = useDevportal();\n const { t } = useI18n();\n const bus = useDevportalEventBus();\n const tr = (key: string, fallback: string): string => {\n const v = t(key);\n return v === key ? fallback : v;\n };\n\n const handleNavigate = (path: string) => navigate?.(`${basePath}${path}`);\n\n const [step, setStep] = useState<SetupStep>(\"org\");\n\n // IDs created during wizard — carried forward for success CTAs\n const [createdOrgId, setCreatedOrgId] = useState<string | null>(null);\n const [createdAppId, setCreatedAppId] = useState<string | null>(null);\n const [createdAppType, setCreatedAppType] = useState<string | null>(null);\n\n // ── Step 1: org ──────────────────────────────────────────────\n const [orgName, setOrgName] = useState(\"\");\n const [orgSlug, setOrgSlug] = useState(\"\");\n const [orgDescription, setOrgDescription] = useState(\"\");\n const [orgErrors, setOrgErrors] = useState<{\n name?: string;\n slug?: string;\n agreement?: string;\n }>({});\n const [agreementAccepted, setAgreementAccepted] = useState(false);\n const [orgSubmitError, setOrgSubmitError] = useState<string | null>(null);\n\n const [createOrg, { loading: creatingOrgOnly }] =\n useCreateOrganizationMutation();\n const [createProfile, { loading: creatingProfile }] =\n useCreateDeveloperProfileMutation();\n const creatingOrg = creatingOrgOnly || creatingProfile;\n const [createBillingAccountMutation] = useCreateBillingAccountMutation();\n\n const validateOrg = () => {\n const errs: { name?: string; slug?: string; agreement?: string } = {};\n if (!orgName.trim())\n errs.name = tr(\n \"devportal.orgNameRequired\",\n \"Organization name is required\",\n );\n else if (orgName.length < 2)\n errs.name = tr(\n \"devportal.orgNameTooShort\",\n \"Name must be at least 2 characters\",\n );\n if (!orgSlug.trim())\n errs.slug = tr(\"devportal.slugRequired\", \"Slug is required\");\n else if (!/^[a-z0-9-]+$/.test(orgSlug))\n errs.slug = tr(\n \"devportal.slugInvalid\",\n \"Lowercase letters, numbers, and hyphens only\",\n );\n if (!agreementAccepted)\n errs.agreement = tr(\n \"devportal.onboarding.agreementRequired\",\n \"Accept the Developer Agreement to continue\",\n );\n setOrgErrors(errs);\n return Object.keys(errs).length === 0;\n };\n\n const handleOrgSubmit = async () => {\n if (!validateOrg()) return;\n setOrgSubmitError(null);\n try {\n // The developer profile is the personal half of the registration: the\n // backend returns the existing one when it is already there, so this is\n // safe to repeat on a retry.\n await createProfile({\n variables: { input: { companyName: orgName } },\n });\n const result = await createOrg({\n variables: {\n input: {\n name: orgName,\n slug: orgSlug || undefined,\n description: orgDescription || undefined,\n contactEmail: currentUser?.email || undefined,\n metadata: {\n developerAgreement: {\n version: DEVELOPER_AGREEMENT_VERSION,\n url: DEVELOPER_LINKS.developerAgreement,\n acceptedAt: new Date().toISOString(),\n acceptedBy: currentUser?.id ?? null,\n },\n registrationSource: \"devportal-setup\",\n },\n },\n },\n });\n const id = result.data?.createDeveloperOrganization?.id;\n if (id) {\n bus.emit(\"devportal.org.created\", {\n organizationId: id,\n name: orgName,\n });\n setCreatedOrgId(id);\n // Fire-and-forget: create a billing account for the new org\n try {\n createBillingAccountMutation({\n variables: {\n input: {\n name: orgName,\n email: currentUser?.email ?? \"\",\n },\n },\n }).catch(() => {});\n } catch {\n // silent failure — billing account creation is non-blocking\n }\n setStep(\"app\");\n }\n } catch (err) {\n setOrgSubmitError(\n errorMessage(\n err,\n tr(\n \"devportal.onboarding.orgCreateFailed\",\n \"We could not create your organization. Please try again.\",\n ),\n ),\n );\n }\n };\n\n // ── Step 2: app ──────────────────────────────────────────────\n const [appName, setAppName] = useState(\"\");\n const [appSlug, setAppSlug] = useState(\"\");\n const [builderType, setBuilderType] = useState<BuilderType | null>(null);\n const [appCategory, setAppCategory] = useState(\"\");\n const [appShortDesc, setAppShortDesc] = useState(\"\");\n const [appErrors, setAppErrors] = useState<{\n name?: string;\n builderType?: string;\n category?: string;\n shortDescription?: string;\n }>({});\n\n const [appSubmitError, setAppSubmitError] = useState<string | null>(null);\n const [createApp, { loading: creatingApp }] = useCreateApplicationMutation();\n\n const appTypeForBuilder = () => {\n if (builderType === \"node\") return \"NODE\" as const;\n if (builderType === \"workflow\") return \"WORKFLOW\" as const;\n return \"API_INTEGRATION\" as const;\n };\n\n const validateApp = () => {\n const errs: typeof appErrors = {};\n if (!appName.trim())\n errs.name = tr(\n \"devportal.appNameRequired\",\n \"Application name is required\",\n );\n else if (appName.length < 3)\n errs.name = tr(\n \"devportal.nameTooShort\",\n \"Name must be at least 3 characters\",\n );\n if (!builderType)\n errs.builderType = tr(\n \"devportal.appTypeRequired\",\n \"Application type is required\",\n );\n if (!appCategory)\n errs.category = tr(\"devportal.categoryRequired\", \"Category is required\");\n if (!appShortDesc.trim())\n errs.shortDescription = tr(\n \"devportal.shortDescriptionRequired\",\n \"Short description is required\",\n );\n setAppErrors(errs);\n return Object.keys(errs).length === 0;\n };\n\n const handleAppSubmit = async () => {\n if (!validateApp()) return;\n const resolvedType = appTypeForBuilder();\n setAppSubmitError(null);\n try {\n const result = await createApp({\n variables: {\n input: {\n name: appName,\n slug: appSlug || undefined,\n appType: resolvedType,\n category: appCategory || undefined,\n shortDescription: appShortDesc || undefined,\n visibility: \"PRIVATE\",\n developerOrganizationId: createdOrgId || undefined,\n },\n },\n });\n const id = result.data?.createApplication?.id;\n if (id) {\n bus.emit(\"devportal.app.created\", {\n appId: id,\n name: appName,\n appType: resolvedType,\n organizationId: createdOrgId,\n });\n setCreatedAppId(id);\n setCreatedAppType(resolvedType);\n markSetupSeen();\n setStep(\"submit\");\n }\n } catch (err) {\n setAppSubmitError(\n errorMessage(\n err,\n tr(\n \"devportal.onboarding.appCreateFailed\",\n \"We could not create your app. Please try again.\",\n ),\n ),\n );\n }\n };\n\n // ── Step 3: get it ready for review ──────────────────────────\n // Submission itself happens on the app page, which checks the listing\n // requirements reviewers need (ApplicationDetailPage's readiness rules);\n // this step tells the developer what that page will ask for.\n const reviewRequirements = reviewRequirementsFor(createdAppType);\n\n const handleSkip = () => {\n markSetupSeen();\n handleNavigate(\"/\");\n };\n\n // ─── Render ─────────────────────────────────────────────────\n\n return (\n <main className=\"min-h-screen bg-surface-default\">\n {/* Header */}\n <div className=\"border-b border-border-default bg-surface-raised\">\n <div className=\"mx-auto max-w-2xl px-6 py-5\">\n <div className=\"flex items-center justify-between\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-9 w-9 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Rocket size={20} />\n </div>\n <div>\n <p className=\"text-xs font-medium text-text-secondary\">\n {tr(\"devportal.developerPortal\", \"Developer Portal\")}\n </p>\n <h1 className=\"text-base font-semibold text-text-primary\">\n {tr(\"devportal.setup.title\", \"Get set up\")}\n </h1>\n </div>\n </div>\n {step !== \"done\" && (\n <button\n type=\"button\"\n onClick={handleSkip}\n className=\"text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.setup.skipForNow\", \"Skip for now\")}\n </button>\n )}\n </div>\n </div>\n </div>\n\n {/* Content */}\n <div className=\"mx-auto max-w-2xl px-6 py-10\">\n {/* Step indicator */}\n <div className=\"mb-10 flex justify-center\">\n <StepIndicator current={step} />\n </div>\n\n {/* Welcome / purpose — what this wizard sets up and why */}\n {step === \"org\" && (\n <div className=\"mb-8 flex flex-col items-center gap-3 text-center\">\n <Illustration\n name=\"onboarding\"\n alt={tr(\n \"devportal.setup.illustrationAlt\",\n \"Getting started with the developer portal\",\n )}\n size=\"md\"\n />\n <PagePurpose className=\"justify-center\">\n {tr(\n \"devportal.setup.purpose\",\n \"Three quick steps to start building: create the organization that owns your apps, register your first app, then submit it for review. Your developer profile is created with your organization. You can change everything later.\",\n )}\n </PagePurpose>\n </div>\n )}\n\n {/* ── Step 1: Organization ─────────────────────── */}\n {step === \"org\" && (\n <div className=\"rounded-xl border border-border-default bg-surface-raised p-8 shadow-sm\">\n <div className=\"mb-6 flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <Building2 size={20} />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"devportal.setup.orgTitle\", \"Set up your organization\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.setup.orgSubtitle\",\n \"This groups your apps and teams under one publisher identity.\",\n )}\n </p>\n </div>\n </div>\n\n <div className=\"space-y-5\">\n <InputField\n label={tr(\"devportal.organizationName\", \"Organization Name\")}\n value={orgName}\n onChange={(e) => {\n setOrgName(e.target.value);\n if (!orgSlug || orgSlug === generateSlug(orgName)) {\n setOrgSlug(generateSlug(e.target.value));\n }\n setOrgErrors((p) => ({ ...p, name: undefined }));\n }}\n placeholder={tr(\n \"devportal.organizationNamePlaceholder\",\n \"Acme Development\",\n )}\n required\n error={orgErrors.name}\n />\n\n <InputField\n label={tr(\"devportal.slug\", \"Slug\")}\n value={orgSlug}\n onChange={(e) => {\n setOrgSlug(e.target.value.toLowerCase());\n setOrgErrors((p) => ({ ...p, slug: undefined }));\n }}\n placeholder=\"acme-dev\"\n required\n error={orgErrors.slug}\n hint={tr(\n \"devportal.slugHint\",\n \"URL-friendly identifier — auto-generated from name\",\n )}\n />\n\n <TextareaField\n label={tr(\"devportal.description\", \"Description\")}\n value={orgDescription}\n onChange={(e) => setOrgDescription(e.target.value)}\n placeholder={tr(\n \"devportal.orgDescriptionPlaceholder\",\n \"Tell us about your organization…\",\n )}\n rows={2}\n />\n\n <EligibilityPanel tr={tr} />\n\n <div>\n <label className=\"flex items-start gap-3 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n data-testid=\"devportal-setup-accept-agreement\"\n checked={agreementAccepted}\n onChange={(e) => {\n setAgreementAccepted(e.target.checked);\n setOrgErrors((p) => ({ ...p, agreement: undefined }));\n }}\n className=\"mt-0.5 h-4 w-4 shrink-0 rounded border-border-default accent-primary\"\n />\n <span>\n {tr(\n \"devportal.onboarding.agreementLabelPrefix\",\n \"I meet these requirements and accept the\",\n )}{\" \"}\n <a\n href={DEVELOPER_LINKS.developerAgreement}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"font-medium text-primary hover:underline\"\n >\n {tr(\n \"devportal.onboarding.developerAgreement\",\n \"Marketplace & Developer Agreement\",\n )}\n </a>{\" \"}\n {tr(\"devportal.onboarding.and\", \"and the\")}{\" \"}\n <a\n href={DEVELOPER_LINKS.acceptableUsePolicy}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n className=\"font-medium text-primary hover:underline\"\n >\n {tr(\n \"devportal.onboarding.acceptableUsePolicy\",\n \"Acceptable Use Policy\",\n )}\n </a>\n .\n </span>\n </label>\n {orgErrors.agreement && (\n <p className=\"mt-1.5 text-xs text-status-error-text\">\n {orgErrors.agreement}\n </p>\n )}\n </div>\n\n {orgSubmitError && (\n <p\n role=\"alert\"\n className=\"rounded-md bg-status-error-bg px-3 py-2 text-sm text-status-error-text\"\n >\n {orgSubmitError}\n </p>\n )}\n </div>\n\n <div className=\"mt-8 flex items-center justify-between border-t border-border-default pt-6\">\n <button\n type=\"button\"\n onClick={handleSkip}\n className=\"text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.setup.skipForNow\", \"Skip for now\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleOrgSubmit()}\n disabled={creatingOrg}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-60 transition-colors\"\n >\n {creatingOrg ? (\n <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n ) : null}\n {tr(\"devportal.setup.createAndContinue\", \"Create & Continue\")}\n {!creatingOrg && <ChevronRight size={16} />}\n </button>\n </div>\n </div>\n )}\n\n {/* ── Step 2: First app ─────────────────────── */}\n {step === \"app\" && (\n <div className=\"rounded-xl border border-border-default bg-surface-raised p-8 shadow-sm\">\n <div className=\"mb-6 flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <AppWindow size={20} />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr(\"devportal.setup.appTitle\", \"Create your first app\")}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.setup.appSubtitle\",\n \"Register the app you want to publish or integrate.\",\n )}\n </p>\n </div>\n </div>\n\n <div className=\"space-y-5\">\n <InputField\n label={tr(\"devportal.applicationName\", \"Application Name\")}\n value={appName}\n onChange={(e) => {\n setAppName(e.target.value);\n if (!appSlug || appSlug === generateSlug(appName)) {\n setAppSlug(generateSlug(e.target.value));\n }\n setAppErrors((p) => ({ ...p, name: undefined }));\n }}\n placeholder={tr(\n \"devportal.applicationNamePlaceholder\",\n \"My Awesome App\",\n )}\n required\n error={appErrors.name}\n />\n\n {/* Builder type picker */}\n <div>\n <p className=\"mb-2 text-sm font-medium text-text-primary\">\n {tr(\"devportal.applicationType\", \"Application Type\")}{\" \"}\n <span className=\"text-status-error-text\">*</span>\n </p>\n <div className=\"grid grid-cols-3 gap-3\">\n <SetupTypeCard\n icon={Box}\n title=\"App\"\n description=\"OAuth integration for the platform\"\n selected={builderType === \"app\"}\n onClick={() => {\n setBuilderType(\"app\");\n setAppErrors((p) => ({ ...p, builderType: undefined }));\n }}\n />\n <SetupTypeCard\n icon={Puzzle}\n title=\"Node\"\n description=\"Custom FluidGrids workflow node\"\n selected={builderType === \"node\"}\n onClick={() => {\n setBuilderType(\"node\");\n setAppErrors((p) => ({ ...p, builderType: undefined }));\n }}\n />\n <SetupTypeCard\n icon={GitFork}\n title=\"Workflow\"\n description=\"Reusable automation template\"\n selected={builderType === \"workflow\"}\n onClick={() => {\n setBuilderType(\"workflow\");\n setAppErrors((p) => ({ ...p, builderType: undefined }));\n }}\n />\n </div>\n {appErrors.builderType && (\n <p className=\"mt-1.5 text-xs text-status-error-text\">\n {appErrors.builderType}\n </p>\n )}\n </div>\n\n <SelectField\n label={tr(\"devportal.category\", \"Category\")}\n value={appCategory}\n onChange={(e) => {\n setAppCategory(e.target.value);\n setAppErrors((p) => ({ ...p, category: undefined }));\n }}\n options={CATEGORY_OPTIONS}\n placeholder={tr(\"devportal.selectCategory\", \"Select category…\")}\n required\n error={appErrors.category}\n />\n\n <TextareaField\n label={tr(\"devportal.shortDescription\", \"Short Description\")}\n value={appShortDesc}\n onChange={(e) => {\n setAppShortDesc(e.target.value);\n setAppErrors((p) => ({ ...p, shortDescription: undefined }));\n }}\n placeholder={tr(\n \"devportal.shortDescriptionPlaceholder\",\n \"A brief description of what your app does\",\n )}\n required\n error={appErrors.shortDescription}\n rows={2}\n hint={`${appShortDesc.length}/200`}\n />\n\n {appSubmitError && (\n <p\n role=\"alert\"\n className=\"rounded-md bg-status-error-bg px-3 py-2 text-sm text-status-error-text\"\n >\n {appSubmitError}\n </p>\n )}\n </div>\n\n <div className=\"mt-8 flex items-center justify-between border-t border-border-default pt-6\">\n <button\n type=\"button\"\n onClick={handleSkip}\n className=\"text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.setup.skipForNow\", \"Skip for now\")}\n </button>\n <button\n type=\"button\"\n onClick={() => void handleAppSubmit()}\n disabled={creatingApp}\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg/90 disabled:opacity-60 transition-colors\"\n >\n {creatingApp ? (\n <span className=\"h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent\" />\n ) : null}\n {tr(\"devportal.setup.createApp\", \"Create App\")}\n {!creatingApp && <ChevronRight size={16} />}\n </button>\n </div>\n </div>\n )}\n\n {/* ── Step 3: Get ready for review ─────────── */}\n {step === \"submit\" && (\n <div className=\"rounded-xl border border-border-default bg-surface-raised p-8 shadow-sm\">\n <div className=\"mb-6 flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-lg bg-action-primary-bg/10 text-primary\">\n <ListChecks size={20} />\n </div>\n <div>\n <h2 className=\"text-lg font-semibold text-text-primary\">\n {tr(\n \"devportal.onboarding.readyTitle\",\n \"Get it ready for review\",\n )}\n </h2>\n <p className=\"text-sm text-text-secondary\">\n {tr(\n \"devportal.onboarding.readySubtitle\",\n \"Reviewers check every app before it is listed. Your app page walks you through what they need, then you submit it from there. It stays private until it is approved and you publish it.\",\n )}\n </p>\n </div>\n </div>\n\n <ul\n data-testid=\"devportal-setup-review-requirements\"\n className=\"space-y-2\"\n >\n {reviewRequirements.map((item) => (\n <li\n key={item.id}\n className=\"flex items-start gap-3 rounded-md bg-bg-sunken px-4 py-3 text-sm text-text-primary\"\n >\n <Check\n size={16}\n className=\"mt-0.5 shrink-0 text-text-secondary\"\n aria-hidden=\"true\"\n />\n {tr(item.key, item.text)}\n </li>\n ))}\n </ul>\n\n <div className=\"mt-8 flex items-center justify-between border-t border-border-default pt-6\">\n <button\n type=\"button\"\n onClick={() => setStep(\"done\")}\n className=\"text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.onboarding.submitLater\", \"Do this later\")}\n </button>\n <button\n type=\"button\"\n data-testid=\"devportal-setup-finish-app\"\n onClick={() =>\n createdAppId && handleNavigate(`/apps/${createdAppId}`)\n }\n className=\"inline-flex items-center gap-2 rounded-lg bg-action-primary-bg px-5 py-2.5 text-sm font-semibold text-action-primary-text hover:bg-action-primary-bg/90 transition-colors\"\n >\n {tr(\"devportal.onboarding.finishApp\", \"Finish and submit\")}\n <ChevronRight size={16} />\n </button>\n </div>\n </div>\n )}\n\n {/* ── Step 4: Done ─────────────────────────── */}\n {step === \"done\" && (\n <div className=\"text-center\">\n <div className=\"mx-auto mb-6 flex h-16 w-16 items-center justify-center rounded-full bg-action-primary-bg/10 text-primary\">\n <Rocket size={32} />\n </div>\n <h2 className=\"text-2xl font-bold text-text-primary\">\n {tr(\"devportal.setup.doneTitle\", \"You're all set!\")}\n </h2>\n <p className=\"mt-2 text-text-secondary\">\n {tr(\n \"devportal.setup.doneSubtitle\",\n \"Your organization and first app are ready. Here's what to do next.\",\n )}\n </p>\n\n <div className=\"mt-8 grid gap-3 sm:grid-cols-2\">\n {createdAppId && (\n <NextStepCard\n icon={<AppWindow size={20} />}\n title={tr(\"devportal.setup.viewApp\", \"View your app\")}\n description={tr(\n \"devportal.setup.viewAppDesc\",\n \"Configure OAuth, webhooks, and versioning\",\n )}\n onClick={() => handleNavigate(`/apps/${createdAppId}`)}\n primary\n />\n )}\n <NextStepCard\n icon={<Key size={20} />}\n title={tr(\"devportal.setup.generateApiKey\", \"Generate API key\")}\n description={tr(\n \"devportal.setup.generateApiKeyDesc\",\n \"Create credentials to start calling APIs\",\n )}\n onClick={() => handleNavigate(\"/api-keys/new\")}\n />\n <NextStepCard\n icon={<BookOpen size={20} />}\n title={tr(\"devportal.setup.browseDocs\", \"Browse docs\")}\n description={tr(\n \"devportal.setup.browseDocsDesc\",\n \"Learn about publishing, SDKs, and webhooks\",\n )}\n onClick={() => handleNavigate(\"/docs\")}\n />\n <NextStepCard\n icon={<Puzzle size={20} />}\n title={tr(\n \"devportal.onboarding.publishConnector\",\n \"Publish a connector\",\n )}\n description={tr(\n \"devportal.onboarding.publishConnectorDesc\",\n \"List an API-key integration in the Workspaces integrations catalog\",\n )}\n onClick={() =>\n window.open(\n DEVELOPER_LINKS.publishConnector,\n \"_blank\",\n \"noopener,noreferrer\",\n )\n }\n />\n {createdOrgId && (\n <NextStepCard\n icon={<Building2 size={20} />}\n title={tr(\"devportal.setup.inviteTeam\", \"Invite your team\")}\n description={tr(\n \"devportal.setup.inviteTeamDesc\",\n \"Add members to collaborate on your apps\",\n )}\n onClick={() =>\n handleNavigate(`/organizations/${createdOrgId}/members`)\n }\n />\n )}\n </div>\n\n <button\n type=\"button\"\n onClick={() => handleNavigate(\"/\")}\n className=\"mt-8 inline-flex items-center gap-2 text-sm text-text-secondary hover:text-text-primary transition-colors\"\n >\n {tr(\"devportal.setup.goToDashboard\", \"Go to dashboard\")}\n <ArrowRight size={14} />\n </button>\n </div>\n )}\n </div>\n </main>\n );\n};\n\n// ─── Eligibility panel ─────────────────────────────────────────────────────\n\nconst EligibilityPanel: FC<{\n tr: (key: string, fallback: string) => string;\n}> = ({ tr }) => (\n <section\n aria-labelledby=\"devportal-setup-eligibility-title\"\n data-testid=\"devportal-setup-eligibility\"\n className=\"rounded-lg border border-border-subtle bg-bg-sunken p-4\"\n >\n <h3\n id=\"devportal-setup-eligibility-title\"\n className=\"flex items-center gap-2 text-sm font-semibold text-text-primary\"\n >\n <ShieldCheck size={16} className=\"text-primary\" aria-hidden=\"true\" />\n {tr(\"devportal.onboarding.eligibilityTitle\", \"Who can register\")}\n </h3>\n <ul className=\"mt-2 list-disc space-y-1 pl-5 text-sm text-text-secondary\">\n {ELIGIBILITY_RULES.map((rule) => (\n <li key={rule.id}>{tr(rule.key, rule.text)}</li>\n ))}\n </ul>\n </section>\n);\n\n// ─── Setup type card ───────────────────────────────────────────────────────\n\nconst SetupTypeCard: FC<{\n icon: FC<{ size?: number; className?: string }>;\n title: string;\n description: string;\n selected: boolean;\n onClick: () => void;\n}> = ({ icon: Icon, title, description, selected, onClick }) => (\n <button\n type=\"button\"\n onClick={onClick}\n className={cn(\n \"relative flex flex-col gap-2 rounded-xl border-2 p-4 text-left transition-all hover:border-primary/50 hover:shadow-sm\",\n selected\n ? \"border-primary bg-action-primary-bg/5 shadow-sm\"\n : \"border-border-subtle bg-bg-surface\",\n )}\n >\n {selected && (\n <span className=\"absolute top-3 right-3 flex h-4 w-4 items-center justify-center rounded-full bg-action-primary-bg text-action-primary-text\">\n <Check size={10} />\n </span>\n )}\n <div className=\"flex h-8 w-8 items-center justify-center rounded-lg bg-bg-sunken\">\n <Icon size={18} className=\"text-text-primary\" />\n </div>\n <div>\n <p className=\"text-sm font-semibold text-text-primary\">{title}</p>\n <p className=\"mt-0.5 text-xs text-text-secondary\">{description}</p>\n </div>\n </button>\n);\n\n// ─── Next-step card ────────────────────────────────────────────────────────\n\nconst NextStepCard: FC<{\n icon: React.ReactNode;\n title: string;\n description: string;\n onClick: () => void;\n primary?: boolean;\n}> = ({ icon, title, description, onClick, primary }) => (\n <button\n type=\"button\"\n onClick={onClick}\n className={[\n \"flex items-start gap-4 rounded-xl border p-5 text-left transition-colors\",\n primary\n ? \"border-primary bg-action-primary-bg/5 hover:bg-action-primary-bg/10\"\n : \"border-border-default bg-surface-raised hover:bg-surface-hover\",\n ].join(\" \")}\n >\n <div\n className={[\n \"flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg\",\n primary\n ? \"bg-action-primary-bg/20 text-primary\"\n : \"bg-bg-sunken text-text-secondary\",\n ].join(\" \")}\n >\n {icon}\n </div>\n <div className=\"min-w-0 flex-1\">\n <p className=\"font-semibold text-text-primary\">{title}</p>\n <p className=\"mt-0.5 text-sm text-text-secondary\">{description}</p>\n </div>\n <ChevronRight\n size={16}\n className=\"mt-0.5 flex-shrink-0 text-text-secondary\"\n />\n </button>\n);\n"],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Developer onboarding model (BOFF-10636).
3
+ *
4
+ * The public "Build on Workspaces" journey ends at a submitted devportal
5
+ * application. This module turns what the backend already knows about the
6
+ * signed-in developer (profile, organizations, applications) into the
7
+ * four-step checklist the dashboard and setup wizard show, and holds the
8
+ * eligibility rules a developer accepts before registering.
9
+ *
10
+ * Pure functions only: the components feed in query results, so the rules
11
+ * are unit-tested without rendering anything.
12
+ */
13
+ /** Application statuses that mean the developer has submitted for review. */
14
+ export declare const SUBMITTED_APP_STATUSES: ReadonlySet<string>;
15
+ /**
16
+ * App types that are reviewed from an uploaded package. Mirrors
17
+ * `PACKAGE_REQUIRED_APP_TYPES` in global-devportal-svc
18
+ * (resolvers/application.ts) and `isPackageApp` in ApplicationDetailPage.
19
+ */
20
+ export declare const PACKAGE_APP_TYPES: ReadonlySet<string>;
21
+ export type OnboardingStepId = "profile" | "organization" | "app" | "submit";
22
+ export interface OnboardingStep {
23
+ id: OnboardingStepId;
24
+ done: boolean;
25
+ /** Devportal-relative path (prefix with basePath) that completes the step. */
26
+ path: string;
27
+ }
28
+ export interface OnboardingInput {
29
+ hasProfile: boolean;
30
+ /** Organization kinds the developer belongs to (DIGITAL / PHYSICAL). */
31
+ organizationKinds: ReadonlyArray<string | null | undefined>;
32
+ applications: ReadonlyArray<{
33
+ id: string;
34
+ status?: string | null;
35
+ }>;
36
+ /**
37
+ * Total number of applications the backend reports. When it is larger than
38
+ * the page that was fetched, the developer is well past onboarding, so the
39
+ * submit step counts as done even if the fetched page holds no submission.
40
+ */
41
+ totalApplications: number;
42
+ }
43
+ export interface OnboardingState {
44
+ steps: OnboardingStep[];
45
+ completedCount: number;
46
+ isComplete: boolean;
47
+ /** First step that is not done yet, or null when everything is done. */
48
+ nextStep: OnboardingStep | null;
49
+ }
50
+ /** Whether an application status counts as submitted for review. */
51
+ export declare function isSubmittedStatus(status: string | null | undefined): boolean;
52
+ export interface ReviewRequirement {
53
+ id: "listing" | "visibility" | "version" | "pricing";
54
+ /** i18n key under `devportal.onboarding.requirements`. */
55
+ key: string;
56
+ text: string;
57
+ }
58
+ /**
59
+ * What the app page asks for before "Submit for Review" is enabled, in the
60
+ * order it asks. Mirrors the readiness rule in ApplicationDetailPage
61
+ * (description, category and icon; Public or Unlisted visibility; a version
62
+ * for package and API-integration apps; pricing chosen). Category is set by
63
+ * the setup wizard already, so it is not repeated here.
64
+ */
65
+ export declare function reviewRequirementsFor(appType: string | null | undefined): ReviewRequirement[];
66
+ /**
67
+ * Build the checklist. Only DIGITAL (or legacy kind-less) organizations
68
+ * count: a PHYSICAL seller organization cannot own an application, so it does
69
+ * not move a developer forward on this journey.
70
+ */
71
+ export declare function computeOnboardingState(input: OnboardingInput): OnboardingState;
72
+ export interface EligibilityRule {
73
+ id: string;
74
+ /** i18n key under `devportal.onboarding.eligibility`. */
75
+ key: string;
76
+ /** Canonical English copy; also the i18n fallback. */
77
+ text: string;
78
+ }
79
+ /**
80
+ * Who can register as a developer. Kept in one place so the setup wizard,
81
+ * the dashboard checklist and the unit tests agree, and mirrored in the
82
+ * public docs page (workspaces-docs: developers/build/register-as-a-developer).
83
+ */
84
+ export declare const ELIGIBILITY_RULES: ReadonlyArray<EligibilityRule>;
85
+ //# sourceMappingURL=developerOnboarding.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"developerOnboarding.d.ts","sourceRoot":"","sources":["../../../src/devportal/utils/developerOnboarding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,6EAA6E;AAC7E,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAQrD,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,MAAM,CAMhD,CAAC;AAEH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,cAAc,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE7E,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,gBAAgB,CAAC;IACrB,IAAI,EAAE,OAAO,CAAC;IACd,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,iBAAiB,EAAE,aAAa,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IAC5D,YAAY,EAAE,aAAa,CAAC;QAC1B,EAAE,EAAE,MAAM,CAAC;QACX,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACxB,CAAC,CAAC;IACH;;;;OAIG;IACH,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,OAAO,CAAC;IACpB,wEAAwE;IACxE,QAAQ,EAAE,cAAc,GAAG,IAAI,CAAC;CACjC;AAED,oEAAoE;AACpE,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAE5E;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,SAAS,GAAG,YAAY,GAAG,SAAS,GAAG,SAAS,CAAC;IACrD,0DAA0D;IAC1D,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACjC,iBAAiB,EAAE,CAqCrB;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,eAAe,GACrB,eAAe,CAsCjB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,GAAG,EAAE,MAAM,CAAC;IACZ,sDAAsD;IACtD,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,aAAa,CAAC,eAAe,CA0B5D,CAAC"}
@@ -0,0 +1,104 @@
1
+ //#region src/devportal/utils/developerOnboarding.ts
2
+ var e = new Set([
3
+ "SUBMITTED",
4
+ "IN_REVIEW",
5
+ "APPROVED",
6
+ "PUBLISHED",
7
+ "ACTIVE",
8
+ "UNLISTED",
9
+ "DEPRECATED"
10
+ ]), t = new Set([
11
+ "NODE",
12
+ "WORKFLOW",
13
+ "PARSER",
14
+ "WIDGET",
15
+ "DASHBOARD"
16
+ ]);
17
+ function n(t) {
18
+ return !!t && e.has(t.toUpperCase());
19
+ }
20
+ function r(e) {
21
+ let n = (e ?? "").toUpperCase(), r = t.has(n), i = r || n === "API_INTEGRATION", a = [{
22
+ id: "listing",
23
+ key: "devportal.onboarding.requirements.listing",
24
+ text: "A full description and an app icon on the Store Listing tab."
25
+ }, {
26
+ id: "visibility",
27
+ key: "devportal.onboarding.requirements.visibility",
28
+ text: "Visibility set to Public (marketplace) or Unlisted (shared by link). Private apps cannot be submitted."
29
+ }];
30
+ return i && a.push(r ? {
31
+ id: "version",
32
+ key: "devportal.onboarding.requirements.package",
33
+ text: "A first version with its uploaded package on the Versions tab."
34
+ } : {
35
+ id: "version",
36
+ key: "devportal.onboarding.requirements.version",
37
+ text: "A first version on the Versions tab."
38
+ }), a.push({
39
+ id: "pricing",
40
+ key: "devportal.onboarding.requirements.pricing",
41
+ text: "Pricing chosen on the Pricing tab: Free, or a credit price (paid apps also link a billing account)."
42
+ }), a;
43
+ }
44
+ function i(e) {
45
+ let t = e.organizationKinds.some((e) => (e ?? "DIGITAL").toUpperCase() !== "PHYSICAL"), r = e.totalApplications > 0 || e.applications.length > 0, i = e.applications.find((e) => !n(e.status)), a = e.applications.some((e) => n(e.status)) || e.totalApplications > e.applications.length, o = [
46
+ {
47
+ id: "profile",
48
+ done: e.hasProfile,
49
+ path: "/profile"
50
+ },
51
+ {
52
+ id: "organization",
53
+ done: t,
54
+ path: t ? "/organizations" : "/setup"
55
+ },
56
+ {
57
+ id: "app",
58
+ done: r,
59
+ path: t ? "/apps/new" : "/setup"
60
+ },
61
+ {
62
+ id: "submit",
63
+ done: a,
64
+ path: i ? `/apps/${i.id}` : "/apps"
65
+ }
66
+ ], s = o.filter((e) => e.done).length;
67
+ return {
68
+ steps: o,
69
+ completedCount: s,
70
+ isComplete: s === o.length,
71
+ nextStep: o.find((e) => !e.done) ?? null
72
+ };
73
+ }
74
+ var a = [
75
+ {
76
+ id: "account",
77
+ key: "devportal.onboarding.eligibility.account",
78
+ text: "A Burdenoff account with a verified email address. Any plan works, including Free; you do not need to be a paying Workspaces customer."
79
+ },
80
+ {
81
+ id: "capacity",
82
+ key: "devportal.onboarding.eligibility.capacity",
83
+ text: "You have reached the age of majority where you live, or you register on behalf of a company and have the authority to bind it."
84
+ },
85
+ {
86
+ id: "agreement",
87
+ key: "devportal.onboarding.eligibility.agreement",
88
+ text: "You accept the Marketplace & Developer Agreement and the Acceptable Use Policy for everything you build and submit."
89
+ },
90
+ {
91
+ id: "sanctions",
92
+ key: "devportal.onboarding.eligibility.sanctions",
93
+ text: "You are not barred from receiving software or services under applicable export-control or sanctions laws."
94
+ },
95
+ {
96
+ id: "review",
97
+ key: "devportal.onboarding.eligibility.review",
98
+ text: "Every submission is reviewed before it is listed. Free and private apps need nothing more; paid listings also need publisher verification (legal details, tax and payouts) before they go live."
99
+ }
100
+ ];
101
+ //#endregion
102
+ export { a as ELIGIBILITY_RULES, i as computeOnboardingState, r as reviewRequirementsFor };
103
+
104
+ //# sourceMappingURL=developerOnboarding.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"developerOnboarding.js","names":[],"sources":["../../../src/devportal/utils/developerOnboarding.ts"],"sourcesContent":["/**\n * Developer onboarding model (BOFF-10636).\n *\n * The public \"Build on Workspaces\" journey ends at a submitted devportal\n * application. This module turns what the backend already knows about the\n * signed-in developer (profile, organizations, applications) into the\n * four-step checklist the dashboard and setup wizard show, and holds the\n * eligibility rules a developer accepts before registering.\n *\n * Pure functions only: the components feed in query results, so the rules\n * are unit-tested without rendering anything.\n */\n\n/** Application statuses that mean the developer has submitted for review. */\nexport const SUBMITTED_APP_STATUSES: ReadonlySet<string> = new Set([\n \"SUBMITTED\",\n \"IN_REVIEW\",\n \"APPROVED\",\n \"PUBLISHED\",\n \"ACTIVE\",\n \"UNLISTED\",\n \"DEPRECATED\",\n]);\n\n/**\n * App types that are reviewed from an uploaded package. Mirrors\n * `PACKAGE_REQUIRED_APP_TYPES` in global-devportal-svc\n * (resolvers/application.ts) and `isPackageApp` in ApplicationDetailPage.\n */\nexport const PACKAGE_APP_TYPES: ReadonlySet<string> = new Set([\n \"NODE\",\n \"WORKFLOW\",\n \"PARSER\",\n \"WIDGET\",\n \"DASHBOARD\",\n]);\n\nexport type OnboardingStepId = \"profile\" | \"organization\" | \"app\" | \"submit\";\n\nexport interface OnboardingStep {\n id: OnboardingStepId;\n done: boolean;\n /** Devportal-relative path (prefix with basePath) that completes the step. */\n path: string;\n}\n\nexport interface OnboardingInput {\n hasProfile: boolean;\n /** Organization kinds the developer belongs to (DIGITAL / PHYSICAL). */\n organizationKinds: ReadonlyArray<string | null | undefined>;\n applications: ReadonlyArray<{\n id: string;\n status?: string | null;\n }>;\n /**\n * Total number of applications the backend reports. When it is larger than\n * the page that was fetched, the developer is well past onboarding, so the\n * submit step counts as done even if the fetched page holds no submission.\n */\n totalApplications: number;\n}\n\nexport interface OnboardingState {\n steps: OnboardingStep[];\n completedCount: number;\n isComplete: boolean;\n /** First step that is not done yet, or null when everything is done. */\n nextStep: OnboardingStep | null;\n}\n\n/** Whether an application status counts as submitted for review. */\nexport function isSubmittedStatus(status: string | null | undefined): boolean {\n return !!status && SUBMITTED_APP_STATUSES.has(status.toUpperCase());\n}\n\nexport interface ReviewRequirement {\n id: \"listing\" | \"visibility\" | \"version\" | \"pricing\";\n /** i18n key under `devportal.onboarding.requirements`. */\n key: string;\n text: string;\n}\n\n/**\n * What the app page asks for before \"Submit for Review\" is enabled, in the\n * order it asks. Mirrors the readiness rule in ApplicationDetailPage\n * (description, category and icon; Public or Unlisted visibility; a version\n * for package and API-integration apps; pricing chosen). Category is set by\n * the setup wizard already, so it is not repeated here.\n */\nexport function reviewRequirementsFor(\n appType: string | null | undefined,\n): ReviewRequirement[] {\n const type = (appType ?? \"\").toUpperCase();\n const needsPackage = PACKAGE_APP_TYPES.has(type);\n const needsVersion = needsPackage || type === \"API_INTEGRATION\";\n const items: ReviewRequirement[] = [\n {\n id: \"listing\",\n key: \"devportal.onboarding.requirements.listing\",\n text: \"A full description and an app icon on the Store Listing tab.\",\n },\n {\n id: \"visibility\",\n key: \"devportal.onboarding.requirements.visibility\",\n text: \"Visibility set to Public (marketplace) or Unlisted (shared by link). Private apps cannot be submitted.\",\n },\n ];\n if (needsVersion) {\n items.push(\n needsPackage\n ? {\n id: \"version\",\n key: \"devportal.onboarding.requirements.package\",\n text: \"A first version with its uploaded package on the Versions tab.\",\n }\n : {\n id: \"version\",\n key: \"devportal.onboarding.requirements.version\",\n text: \"A first version on the Versions tab.\",\n },\n );\n }\n items.push({\n id: \"pricing\",\n key: \"devportal.onboarding.requirements.pricing\",\n text: \"Pricing chosen on the Pricing tab: Free, or a credit price (paid apps also link a billing account).\",\n });\n return items;\n}\n\n/**\n * Build the checklist. Only DIGITAL (or legacy kind-less) organizations\n * count: a PHYSICAL seller organization cannot own an application, so it does\n * not move a developer forward on this journey.\n */\nexport function computeOnboardingState(\n input: OnboardingInput,\n): OnboardingState {\n const hasDigitalOrg = input.organizationKinds.some(\n (kind) => (kind ?? \"DIGITAL\").toUpperCase() !== \"PHYSICAL\",\n );\n const hasApp = input.totalApplications > 0 || input.applications.length > 0;\n const firstUnsubmitted = input.applications.find(\n (app) => !isSubmittedStatus(app.status),\n );\n const hasSubmitted =\n input.applications.some((app) => isSubmittedStatus(app.status)) ||\n input.totalApplications > input.applications.length;\n\n const steps: OnboardingStep[] = [\n { id: \"profile\", done: input.hasProfile, path: \"/profile\" },\n {\n id: \"organization\",\n done: hasDigitalOrg,\n path: hasDigitalOrg ? \"/organizations\" : \"/setup\",\n },\n {\n id: \"app\",\n done: hasApp,\n path: hasDigitalOrg ? \"/apps/new\" : \"/setup\",\n },\n {\n id: \"submit\",\n done: hasSubmitted,\n path: firstUnsubmitted ? `/apps/${firstUnsubmitted.id}` : \"/apps\",\n },\n ];\n\n const completedCount = steps.filter((step) => step.done).length;\n return {\n steps,\n completedCount,\n isComplete: completedCount === steps.length,\n nextStep: steps.find((step) => !step.done) ?? null,\n };\n}\n\nexport interface EligibilityRule {\n id: string;\n /** i18n key under `devportal.onboarding.eligibility`. */\n key: string;\n /** Canonical English copy; also the i18n fallback. */\n text: string;\n}\n\n/**\n * Who can register as a developer. Kept in one place so the setup wizard,\n * the dashboard checklist and the unit tests agree, and mirrored in the\n * public docs page (workspaces-docs: developers/build/register-as-a-developer).\n */\nexport const ELIGIBILITY_RULES: ReadonlyArray<EligibilityRule> = [\n {\n id: \"account\",\n key: \"devportal.onboarding.eligibility.account\",\n text: \"A Burdenoff account with a verified email address. Any plan works, including Free; you do not need to be a paying Workspaces customer.\",\n },\n {\n id: \"capacity\",\n key: \"devportal.onboarding.eligibility.capacity\",\n text: \"You have reached the age of majority where you live, or you register on behalf of a company and have the authority to bind it.\",\n },\n {\n id: \"agreement\",\n key: \"devportal.onboarding.eligibility.agreement\",\n text: \"You accept the Marketplace & Developer Agreement and the Acceptable Use Policy for everything you build and submit.\",\n },\n {\n id: \"sanctions\",\n key: \"devportal.onboarding.eligibility.sanctions\",\n text: \"You are not barred from receiving software or services under applicable export-control or sanctions laws.\",\n },\n {\n id: \"review\",\n key: \"devportal.onboarding.eligibility.review\",\n text: \"Every submission is reviewed before it is listed. Free and private apps need nothing more; paid listings also need publisher verification (legal details, tax and payouts) before they go live.\",\n },\n];\n"],"mappings":";AAcA,IAAa,IAA8C,IAAI,IAAI;CACjE;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,EAOW,IAAyC,IAAI,IAAI;CAC5D;CACA;CACA;CACA;CACA;CACD,CAAC;AAoCF,SAAgB,EAAkB,GAA4C;AAC5E,QAAO,CAAC,CAAC,KAAU,EAAuB,IAAI,EAAO,aAAa,CAAC;;AAiBrE,SAAgB,EACd,GACqB;CACrB,IAAM,KAAQ,KAAW,IAAI,aAAa,EACpC,IAAe,EAAkB,IAAI,EAAK,EAC1C,IAAe,KAAgB,MAAS,mBACxC,IAA6B,CACjC;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP,EACD;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP,CACF;AAqBD,QApBI,KACF,EAAM,KACJ,IACI;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP,GACD;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP,CACN,EAEH,EAAM,KAAK;EACT,IAAI;EACJ,KAAK;EACL,MAAM;EACP,CAAC,EACK;;AAQT,SAAgB,EACd,GACiB;CACjB,IAAM,IAAgB,EAAM,kBAAkB,MAC3C,OAAU,KAAQ,WAAW,aAAa,KAAK,WACjD,EACK,IAAS,EAAM,oBAAoB,KAAK,EAAM,aAAa,SAAS,GACpE,IAAmB,EAAM,aAAa,MACzC,MAAQ,CAAC,EAAkB,EAAI,OAAO,CACxC,EACK,IACJ,EAAM,aAAa,MAAM,MAAQ,EAAkB,EAAI,OAAO,CAAC,IAC/D,EAAM,oBAAoB,EAAM,aAAa,QAEzC,IAA0B;EAC9B;GAAE,IAAI;GAAW,MAAM,EAAM;GAAY,MAAM;GAAY;EAC3D;GACE,IAAI;GACJ,MAAM;GACN,MAAM,IAAgB,mBAAmB;GAC1C;EACD;GACE,IAAI;GACJ,MAAM;GACN,MAAM,IAAgB,cAAc;GACrC;EACD;GACE,IAAI;GACJ,MAAM;GACN,MAAM,IAAmB,SAAS,EAAiB,OAAO;GAC3D;EACF,EAEK,IAAiB,EAAM,QAAQ,MAAS,EAAK,KAAK,CAAC;AACzD,QAAO;EACL;EACA;EACA,YAAY,MAAmB,EAAM;EACrC,UAAU,EAAM,MAAM,MAAS,CAAC,EAAK,KAAK,IAAI;EAC/C;;AAgBH,IAAa,IAAoD;CAC/D;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP;CACD;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP;CACD;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP;CACD;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP;CACD;EACE,IAAI;EACJ,KAAK;EACL,MAAM;EACP;CACF"}
@@ -1949,6 +1949,35 @@ export type RevokeDelegationMutation = {
1949
1949
  __typename?: 'Mutation';
1950
1950
  revokeDelegation: boolean;
1951
1951
  };
1952
+ export type GetDeveloperOnboardingStatusQueryVariables = Types.Exact<{
1953
+ [key: string]: never;
1954
+ }>;
1955
+ export type GetDeveloperOnboardingStatusQuery = {
1956
+ __typename?: 'Query';
1957
+ myDeveloperProfile?: {
1958
+ __typename?: 'DeveloperProfile';
1959
+ id: string;
1960
+ } | null;
1961
+ myDeveloperOrganizations: Array<{
1962
+ __typename?: 'DeveloperOrganization';
1963
+ id: string;
1964
+ kind: Types.DeveloperOrgKind;
1965
+ }>;
1966
+ applications: {
1967
+ __typename?: 'ApplicationConnection';
1968
+ totalCount: number;
1969
+ edges: Array<{
1970
+ __typename?: 'ApplicationEdge';
1971
+ node: {
1972
+ __typename?: 'Application';
1973
+ id: string;
1974
+ name: string;
1975
+ appType: Types.AppType;
1976
+ status: Types.AppStatus;
1977
+ };
1978
+ }>;
1979
+ };
1980
+ };
1952
1981
  export type OrganizationFieldsFragment = {
1953
1982
  __typename?: 'DeveloperOrganization';
1954
1983
  id: string;
@@ -3299,21 +3328,6 @@ export type GetOrgPhysicalItemsQuery = {
3299
3328
  stockQuantity?: number | null;
3300
3329
  }>;
3301
3330
  };
3302
- export type ListProductsForSelectorQueryVariables = Types.Exact<{
3303
- [key: string]: never;
3304
- }>;
3305
- export type ListProductsForSelectorQuery = {
3306
- __typename?: 'Query';
3307
- platformProducts: {
3308
- __typename?: 'PlatformProductList';
3309
- items: Array<{
3310
- __typename?: 'PlatformProduct';
3311
- id: string;
3312
- slug: string;
3313
- name: string;
3314
- }>;
3315
- };
3316
- };
3317
3331
  export type DeveloperProfileFieldsFragment = {
3318
3332
  __typename?: 'DeveloperProfile';
3319
3333
  id: string;
@@ -3504,6 +3518,21 @@ export type UpdateDeveloperProfileMutation = {
3504
3518
  updatedAt: string;
3505
3519
  };
3506
3520
  };
3521
+ export type ListProductsForSelectorQueryVariables = Types.Exact<{
3522
+ [key: string]: never;
3523
+ }>;
3524
+ export type ListProductsForSelectorQuery = {
3525
+ __typename?: 'Query';
3526
+ publicProducts: {
3527
+ __typename?: 'PlatformProductList';
3528
+ items: Array<{
3529
+ __typename?: 'PlatformProduct';
3530
+ id: string;
3531
+ slug: string;
3532
+ name: string;
3533
+ }>;
3534
+ };
3535
+ };
3507
3536
  export type SaleFieldsFragment = {
3508
3537
  __typename?: 'DeveloperOrgSale';
3509
3538
  id: string;
@@ -6307,6 +6336,30 @@ export declare function useRevokeDelegationMutation(baseOptions?: ApolloReactHoo
6307
6336
  export type RevokeDelegationMutationHookResult = ReturnType<typeof useRevokeDelegationMutation>;
6308
6337
  export type RevokeDelegationMutationResult = Apollo.MutationResult<Types.RevokeDelegationMutation>;
6309
6338
  export type RevokeDelegationMutationOptions = Apollo.BaseMutationOptions<Types.RevokeDelegationMutation, Types.RevokeDelegationMutationVariables>;
6339
+ export declare const GetDeveloperOnboardingStatusDocument: Apollo.DocumentNode;
6340
+ /**
6341
+ * __useGetDeveloperOnboardingStatusQuery__
6342
+ *
6343
+ * To run a query within a React component, call `useGetDeveloperOnboardingStatusQuery` and pass it any options that fit your needs.
6344
+ * When your component renders, `useGetDeveloperOnboardingStatusQuery` returns an object from Apollo Client that contains loading, error, and data properties
6345
+ * you can use to render your UI.
6346
+ *
6347
+ * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
6348
+ *
6349
+ * @example
6350
+ * const { data, loading, error } = useGetDeveloperOnboardingStatusQuery({
6351
+ * variables: {
6352
+ * },
6353
+ * });
6354
+ */
6355
+ export declare function useGetDeveloperOnboardingStatusQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<Types.GetDeveloperOnboardingStatusQuery, Types.GetDeveloperOnboardingStatusQueryVariables>): ApolloReactHooks.useQuery.Result<Types.GetDeveloperOnboardingStatusQuery, Types.GetDeveloperOnboardingStatusQueryVariables, "empty" | "complete" | "streaming", Types.GetDeveloperOnboardingStatusQueryVariables>;
6356
+ export declare function useGetDeveloperOnboardingStatusLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.GetDeveloperOnboardingStatusQuery, Types.GetDeveloperOnboardingStatusQueryVariables>): ApolloReactHooks.useLazyQuery.ResultTuple<Types.GetDeveloperOnboardingStatusQuery, Types.GetDeveloperOnboardingStatusQueryVariables, "empty" | "complete" | "streaming">;
6357
+ export declare function useGetDeveloperOnboardingStatusSuspenseQuery(baseOptions?: ApolloReactHooks.SuspenseQueryHookOptions<Types.GetDeveloperOnboardingStatusQuery, Types.GetDeveloperOnboardingStatusQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.GetDeveloperOnboardingStatusQuery, Types.GetDeveloperOnboardingStatusQueryVariables>;
6358
+ export declare function useGetDeveloperOnboardingStatusSuspenseQuery(baseOptions?: ApolloReactHooks.SkipToken | ApolloReactHooks.SuspenseQueryHookOptions<Types.GetDeveloperOnboardingStatusQuery, Types.GetDeveloperOnboardingStatusQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.GetDeveloperOnboardingStatusQuery | undefined, Types.GetDeveloperOnboardingStatusQueryVariables>;
6359
+ export type GetDeveloperOnboardingStatusQueryHookResult = ReturnType<typeof useGetDeveloperOnboardingStatusQuery>;
6360
+ export type GetDeveloperOnboardingStatusLazyQueryHookResult = ReturnType<typeof useGetDeveloperOnboardingStatusLazyQuery>;
6361
+ export type GetDeveloperOnboardingStatusSuspenseQueryHookResult = ReturnType<typeof useGetDeveloperOnboardingStatusSuspenseQuery>;
6362
+ export type GetDeveloperOnboardingStatusQueryResult = Apollo.QueryResult<Types.GetDeveloperOnboardingStatusQuery, Types.GetDeveloperOnboardingStatusQueryVariables>;
6310
6363
  export declare const GetMyOrganizationsDocument: Apollo.DocumentNode;
6311
6364
  /**
6312
6365
  * __useGetMyOrganizationsQuery__
@@ -7168,30 +7221,6 @@ export type GetOrgPhysicalItemsQueryHookResult = ReturnType<typeof useGetOrgPhys
7168
7221
  export type GetOrgPhysicalItemsLazyQueryHookResult = ReturnType<typeof useGetOrgPhysicalItemsLazyQuery>;
7169
7222
  export type GetOrgPhysicalItemsSuspenseQueryHookResult = ReturnType<typeof useGetOrgPhysicalItemsSuspenseQuery>;
7170
7223
  export type GetOrgPhysicalItemsQueryResult = Apollo.QueryResult<Types.GetOrgPhysicalItemsQuery, Types.GetOrgPhysicalItemsQueryVariables>;
7171
- export declare const ListProductsForSelectorDocument: Apollo.DocumentNode;
7172
- /**
7173
- * __useListProductsForSelectorQuery__
7174
- *
7175
- * To run a query within a React component, call `useListProductsForSelectorQuery` and pass it any options that fit your needs.
7176
- * When your component renders, `useListProductsForSelectorQuery` returns an object from Apollo Client that contains loading, error, and data properties
7177
- * you can use to render your UI.
7178
- *
7179
- * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
7180
- *
7181
- * @example
7182
- * const { data, loading, error } = useListProductsForSelectorQuery({
7183
- * variables: {
7184
- * },
7185
- * });
7186
- */
7187
- export declare function useListProductsForSelectorQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>): ApolloReactHooks.useQuery.Result<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables, "empty" | "complete" | "streaming", Types.ListProductsForSelectorQueryVariables>;
7188
- export declare function useListProductsForSelectorLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>): ApolloReactHooks.useLazyQuery.ResultTuple<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables, "empty" | "complete" | "streaming">;
7189
- export declare function useListProductsForSelectorSuspenseQuery(baseOptions?: ApolloReactHooks.SuspenseQueryHookOptions<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>;
7190
- export declare function useListProductsForSelectorSuspenseQuery(baseOptions?: ApolloReactHooks.SkipToken | ApolloReactHooks.SuspenseQueryHookOptions<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.ListProductsForSelectorQuery | undefined, Types.ListProductsForSelectorQueryVariables>;
7191
- export type ListProductsForSelectorQueryHookResult = ReturnType<typeof useListProductsForSelectorQuery>;
7192
- export type ListProductsForSelectorLazyQueryHookResult = ReturnType<typeof useListProductsForSelectorLazyQuery>;
7193
- export type ListProductsForSelectorSuspenseQueryHookResult = ReturnType<typeof useListProductsForSelectorSuspenseQuery>;
7194
- export type ListProductsForSelectorQueryResult = Apollo.QueryResult<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>;
7195
7224
  export declare const GetMyDeveloperProfileDocument: Apollo.DocumentNode;
7196
7225
  /**
7197
7226
  * __useGetMyDeveloperProfileQuery__
@@ -7325,6 +7354,30 @@ export declare function useUpdateDeveloperProfileMutation(baseOptions?: ApolloRe
7325
7354
  export type UpdateDeveloperProfileMutationHookResult = ReturnType<typeof useUpdateDeveloperProfileMutation>;
7326
7355
  export type UpdateDeveloperProfileMutationResult = Apollo.MutationResult<Types.UpdateDeveloperProfileMutation>;
7327
7356
  export type UpdateDeveloperProfileMutationOptions = Apollo.BaseMutationOptions<Types.UpdateDeveloperProfileMutation, Types.UpdateDeveloperProfileMutationVariables>;
7357
+ export declare const ListProductsForSelectorDocument: Apollo.DocumentNode;
7358
+ /**
7359
+ * __useListProductsForSelectorQuery__
7360
+ *
7361
+ * To run a query within a React component, call `useListProductsForSelectorQuery` and pass it any options that fit your needs.
7362
+ * When your component renders, `useListProductsForSelectorQuery` returns an object from Apollo Client that contains loading, error, and data properties
7363
+ * you can use to render your UI.
7364
+ *
7365
+ * @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
7366
+ *
7367
+ * @example
7368
+ * const { data, loading, error } = useListProductsForSelectorQuery({
7369
+ * variables: {
7370
+ * },
7371
+ * });
7372
+ */
7373
+ export declare function useListProductsForSelectorQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>): ApolloReactHooks.useQuery.Result<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables, "empty" | "complete" | "streaming", Types.ListProductsForSelectorQueryVariables>;
7374
+ export declare function useListProductsForSelectorLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>): ApolloReactHooks.useLazyQuery.ResultTuple<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables, "empty" | "complete" | "streaming">;
7375
+ export declare function useListProductsForSelectorSuspenseQuery(baseOptions?: ApolloReactHooks.SuspenseQueryHookOptions<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>;
7376
+ export declare function useListProductsForSelectorSuspenseQuery(baseOptions?: ApolloReactHooks.SkipToken | ApolloReactHooks.SuspenseQueryHookOptions<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>): ApolloReactHooks.UseSuspenseQueryResult<Types.ListProductsForSelectorQuery | undefined, Types.ListProductsForSelectorQueryVariables>;
7377
+ export type ListProductsForSelectorQueryHookResult = ReturnType<typeof useListProductsForSelectorQuery>;
7378
+ export type ListProductsForSelectorLazyQueryHookResult = ReturnType<typeof useListProductsForSelectorLazyQuery>;
7379
+ export type ListProductsForSelectorSuspenseQueryHookResult = ReturnType<typeof useListProductsForSelectorSuspenseQuery>;
7380
+ export type ListProductsForSelectorQueryResult = Apollo.QueryResult<Types.ListProductsForSelectorQuery, Types.ListProductsForSelectorQueryVariables>;
7328
7381
  export declare const GetRevenueSummaryDocument: Apollo.DocumentNode;
7329
7382
  /**
7330
7383
  * __useGetRevenueSummaryQuery__