@stackframe/stack 2.8.63 → 2.8.65

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 (45) hide show
  1. package/dist/components/team-switcher.js +1 -1
  2. package/dist/components/team-switcher.js.map +1 -1
  3. package/dist/components-page/account-settings/payments/payments-page.js +20 -5
  4. package/dist/components-page/account-settings/payments/payments-page.js.map +1 -1
  5. package/dist/components-page/account-settings.js +65 -3
  6. package/dist/components-page/account-settings.js.map +1 -1
  7. package/dist/components-page/cli-auth-confirm.js +1 -7
  8. package/dist/components-page/cli-auth-confirm.js.map +1 -1
  9. package/dist/components-page/onboarding.js +1 -1
  10. package/dist/components-page/onboarding.js.map +1 -1
  11. package/dist/esm/components/team-switcher.js +1 -1
  12. package/dist/esm/components/team-switcher.js.map +1 -1
  13. package/dist/esm/components-page/account-settings/payments/payments-page.js +21 -6
  14. package/dist/esm/components-page/account-settings/payments/payments-page.js.map +1 -1
  15. package/dist/esm/components-page/account-settings.js +66 -4
  16. package/dist/esm/components-page/account-settings.js.map +1 -1
  17. package/dist/esm/components-page/cli-auth-confirm.js +1 -7
  18. package/dist/esm/components-page/cli-auth-confirm.js.map +1 -1
  19. package/dist/esm/components-page/onboarding.js +1 -1
  20. package/dist/esm/components-page/onboarding.js.map +1 -1
  21. package/dist/esm/generated/quetzal-translations.js +1558 -1558
  22. package/dist/esm/generated/quetzal-translations.js.map +1 -1
  23. package/dist/esm/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  24. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js +4 -3
  25. package/dist/esm/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  26. package/dist/esm/lib/stack-app/apps/implementations/common.js +1 -1
  27. package/dist/esm/lib/stack-app/apps/implementations/common.js.map +1 -1
  28. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js +4 -0
  29. package/dist/esm/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  30. package/dist/esm/lib/stack-app/users/index.js +7 -1
  31. package/dist/esm/lib/stack-app/users/index.js.map +1 -1
  32. package/dist/generated/quetzal-translations.js +1558 -1558
  33. package/dist/generated/quetzal-translations.js.map +1 -1
  34. package/dist/index.d.mts +13 -3
  35. package/dist/index.d.ts +13 -3
  36. package/dist/lib/stack-app/apps/implementations/admin-app-impl.js.map +1 -1
  37. package/dist/lib/stack-app/apps/implementations/client-app-impl.js +4 -3
  38. package/dist/lib/stack-app/apps/implementations/client-app-impl.js.map +1 -1
  39. package/dist/lib/stack-app/apps/implementations/common.js +1 -1
  40. package/dist/lib/stack-app/apps/implementations/common.js.map +1 -1
  41. package/dist/lib/stack-app/apps/implementations/server-app-impl.js +4 -0
  42. package/dist/lib/stack-app/apps/implementations/server-app-impl.js.map +1 -1
  43. package/dist/lib/stack-app/users/index.js +7 -1
  44. package/dist/lib/stack-app/users/index.js.map +1 -1
  45. package/package.json +4 -4
@@ -60,7 +60,7 @@ function Inner(props) {
60
60
  } : userFromHook;
61
61
  const navigate = app.useNavigate();
62
62
  const project = app.useProject();
63
- const rawTeams = user?.useTeams();
63
+ const rawTeams = props.teams ?? user?.useTeams();
64
64
  const selectedTeam = props.team || rawTeams?.find((team) => team.id === props.teamId);
65
65
  const teams = (0, import_react.useMemo)(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);
66
66
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/team-switcher.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { StackAssertionError } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport {\n Button,\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Typography,\n cn,\n} from \"@stackframe/stack-ui\";\nimport { PlusCircle, Settings } from \"lucide-react\";\nimport { Suspense, useMemo } from \"react\";\nimport { Team, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { TeamIcon } from \"./team-icon\";\n\ntype MockTeam = {\n id: string,\n displayName: string,\n profileImageUrl?: string | null,\n};\n\ntype TeamSwitcherProps<AllowNull extends boolean = false> = {\n team?: Team,\n teamId?: string,\n allowNull?: AllowNull,\n nullLabel?: string,\n triggerClassName?: string,\n onChange?: (team: AllowNull extends true ? Team | null : Team) => Promise<void>,\n // Mock data props\n mockUser?: {\n team?: MockTeam,\n },\n mockTeams?: MockTeam[],\n mockProject?: {\n config: {\n clientTeamCreationEnabled: boolean,\n },\n },\n};\n\nexport function TeamSwitcher<AllowNull extends boolean = false>(props: TeamSwitcherProps<AllowNull>) {\n return <Suspense fallback={<Fallback />}>\n <Inner {...props} />\n </Suspense>;\n}\n\nfunction Fallback() {\n return <Skeleton className=\"h-9 w-full max-w-64 stack-scope\" />;\n}\n\nfunction Inner<AllowNull extends boolean>(props: TeamSwitcherProps<AllowNull>) {\n const { t } = useTranslation();\n const appFromHook = useStackApp();\n const userFromHook = useUser();\n\n // Use mock data if provided, otherwise use real data\n const app = props.mockUser ? {\n useProject: () => props.mockProject || { config: { clientTeamCreationEnabled: false } },\n useNavigate: () => () => {}, // Mock navigate function\n urls: { accountSettings: '/account-settings' },\n } : appFromHook;\n\n const user = props.mockUser ? {\n selectedTeam: props.mockUser.team,\n useTeams: () => props.mockTeams || [],\n setSelectedTeam: async () => {}, // Mock function\n } : userFromHook;\n\n const navigate = app.useNavigate();\n const project = app.useProject();\n const rawTeams = user?.useTeams();\n const selectedTeam = props.team || rawTeams?.find(team => team.id === props.teamId);\n const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);\n\n\n return (\n <Select\n value={selectedTeam?.id || (props.allowNull ? 'null-sentinel' : undefined)}\n onValueChange={(value) => {\n runAsynchronouslyWithAlert(async () => {\n let team: MockTeam | null = null;\n if (value !== 'null-sentinel') {\n team = teams?.find(team => team.id === value) || null;\n if (!team) {\n throw new StackAssertionError('Team not found, this should not happen');\n }\n } else {\n team = null;\n }\n\n // Call onChange callback if provided\n if (props.onChange) {\n await props.onChange(team as Team);\n }\n });\n }}\n >\n <SelectTrigger className={cn(\"stack-scope max-w-64\", props.triggerClassName)}>\n <SelectValue placeholder=\"Select team\"/>\n </SelectTrigger>\n <SelectContent className=\"stack-scope\">\n {selectedTeam ? <SelectGroup>\n <SelectLabel>\n <div className=\"flex items-center justify-between\">\n <span>\n {t('Current team')}\n </span>\n <Button\n variant='ghost'\n size='icon'\n className=\"h-6 w-6\"\n onClick={() => {\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-${selectedTeam.id}`);\n }\n }}\n >\n <Settings className=\"h-4 w-4\"/>\n </Button>\n </div>\n </SelectLabel>\n <SelectItem value={selectedTeam.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={selectedTeam as Team} />\n <Typography className=\"max-w-40 truncate\">{selectedTeam.displayName}</Typography>\n </div>\n </SelectItem>\n </SelectGroup> : undefined}\n\n {props.allowNull && <SelectGroup>\n <SelectItem value=\"null-sentinel\">\n <div className=\"flex items-center gap-2\">\n <TeamIcon team='personal' />\n <Typography className=\"max-w-40 truncate\">{props.nullLabel || t('No team')}</Typography>\n </div>\n </SelectItem>\n </SelectGroup>}\n\n {teams?.length ?\n <SelectGroup>\n <SelectLabel>{t('Other teams')}</SelectLabel>\n {teams.filter(team => team.id !== selectedTeam?.id)\n .map(team => (\n <SelectItem value={team.id} key={team.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={team as Team} />\n <Typography className=\"max-w-64 truncate\">{team.displayName}</Typography>\n </div>\n </SelectItem>\n ))}\n </SelectGroup> : null}\n\n {!teams?.length && !props.allowNull ?\n <SelectGroup>\n <SelectLabel>{t('No teams yet')}</SelectLabel>\n </SelectGroup> : null}\n\n {project.config.clientTeamCreationEnabled && <>\n <SelectSeparator/>\n <div>\n <Button\n onClick={() => {\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-creation`);\n }\n }}\n className=\"w-full\"\n variant='ghost'\n >\n <PlusCircle className=\"mr-2 h-4 w-4\"/> {t('Create a team')}\n </Button>\n </div>\n </>}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":"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","names":["team"]}
1
+ {"version":3,"sources":["../../src/components/team-switcher.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { StackAssertionError } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport {\n Button,\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Typography,\n cn,\n} from \"@stackframe/stack-ui\";\nimport { PlusCircle, Settings } from \"lucide-react\";\nimport { Suspense, useMemo } from \"react\";\nimport { Team, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { TeamIcon } from \"./team-icon\";\n\ntype MockTeam = {\n id: string,\n displayName: string,\n profileImageUrl?: string | null,\n};\n\ntype TeamSwitcherProps<AllowNull extends boolean = false> = {\n team?: Team,\n teamId?: string,\n teams?: Team[],\n allowNull?: AllowNull,\n nullLabel?: string,\n triggerClassName?: string,\n onChange?: (team: AllowNull extends true ? Team | null : Team) => Promise<void>,\n // Mock data props\n mockUser?: {\n team?: MockTeam,\n },\n mockTeams?: MockTeam[],\n mockProject?: {\n config: {\n clientTeamCreationEnabled: boolean,\n },\n },\n};\n\nexport function TeamSwitcher<AllowNull extends boolean = false>(props: TeamSwitcherProps<AllowNull>) {\n return <Suspense fallback={<Fallback />}>\n <Inner {...props} />\n </Suspense>;\n}\n\nfunction Fallback() {\n return <Skeleton className=\"h-9 w-full max-w-64 stack-scope\" />;\n}\n\nfunction Inner<AllowNull extends boolean>(props: TeamSwitcherProps<AllowNull>) {\n const { t } = useTranslation();\n const appFromHook = useStackApp();\n const userFromHook = useUser();\n\n // Use mock data if provided, otherwise use real data\n const app = props.mockUser ? {\n useProject: () => props.mockProject || { config: { clientTeamCreationEnabled: false } },\n useNavigate: () => () => {}, // Mock navigate function\n urls: { accountSettings: '/account-settings' },\n } : appFromHook;\n\n const user = props.mockUser ? {\n selectedTeam: props.mockUser.team,\n useTeams: () => props.mockTeams || [],\n setSelectedTeam: async () => {}, // Mock function\n } : userFromHook;\n\n const navigate = app.useNavigate();\n const project = app.useProject();\n const rawTeams = props.teams ?? user?.useTeams();\n const selectedTeam = props.team || rawTeams?.find(team => team.id === props.teamId);\n const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);\n\n\n return (\n <Select\n value={selectedTeam?.id || (props.allowNull ? 'null-sentinel' : undefined)}\n onValueChange={(value) => {\n runAsynchronouslyWithAlert(async () => {\n let team: MockTeam | null = null;\n if (value !== 'null-sentinel') {\n team = teams?.find(team => team.id === value) || null;\n if (!team) {\n throw new StackAssertionError('Team not found, this should not happen');\n }\n } else {\n team = null;\n }\n\n // Call onChange callback if provided\n if (props.onChange) {\n await props.onChange(team as Team);\n }\n });\n }}\n >\n <SelectTrigger className={cn(\"stack-scope max-w-64\", props.triggerClassName)}>\n <SelectValue placeholder=\"Select team\"/>\n </SelectTrigger>\n <SelectContent className=\"stack-scope\">\n {selectedTeam ? <SelectGroup>\n <SelectLabel>\n <div className=\"flex items-center justify-between\">\n <span>\n {t('Current team')}\n </span>\n <Button\n variant='ghost'\n size='icon'\n className=\"h-6 w-6\"\n onClick={() => {\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-${selectedTeam.id}`);\n }\n }}\n >\n <Settings className=\"h-4 w-4\"/>\n </Button>\n </div>\n </SelectLabel>\n <SelectItem value={selectedTeam.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={selectedTeam as Team} />\n <Typography className=\"max-w-40 truncate\">{selectedTeam.displayName}</Typography>\n </div>\n </SelectItem>\n </SelectGroup> : undefined}\n\n {props.allowNull && <SelectGroup>\n <SelectItem value=\"null-sentinel\">\n <div className=\"flex items-center gap-2\">\n <TeamIcon team='personal' />\n <Typography className=\"max-w-40 truncate\">{props.nullLabel || t('No team')}</Typography>\n </div>\n </SelectItem>\n </SelectGroup>}\n\n {teams?.length ?\n <SelectGroup>\n <SelectLabel>{t('Other teams')}</SelectLabel>\n {teams.filter(team => team.id !== selectedTeam?.id)\n .map(team => (\n <SelectItem value={team.id} key={team.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={team as Team} />\n <Typography className=\"max-w-64 truncate\">{team.displayName}</Typography>\n </div>\n </SelectItem>\n ))}\n </SelectGroup> : null}\n\n {!teams?.length && !props.allowNull ?\n <SelectGroup>\n <SelectLabel>{t('No teams yet')}</SelectLabel>\n </SelectGroup> : null}\n\n {project.config.clientTeamCreationEnabled && <>\n <SelectSeparator/>\n <div>\n <Button\n onClick={() => {\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-creation`);\n }\n }}\n className=\"w-full\"\n variant='ghost'\n >\n <PlusCircle className=\"mr-2 h-4 w-4\"/> {t('Create a team')}\n </Button>\n </div>\n </>}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":"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","names":["team"]}
@@ -35,11 +35,25 @@ var import_jsx_runtime = require("react/jsx-runtime");
35
35
  function PaymentsPage(props) {
36
36
  const { t } = (0, import_translations.useTranslation)();
37
37
  const user = (0, import_hooks.useUser)({ or: props.mockMode ? "return-null" : "redirect" });
38
- const teams = user?.useTeams() ?? [];
38
+ const teams = props.availableTeams ?? user?.useTeams() ?? [];
39
+ const allowPersonal = props.allowPersonal ?? true;
39
40
  const hasTeams = teams.length > 0;
40
41
  const [selectedTeam, setSelectedTeam] = (0, import_react.useState)(null);
41
- const customer = selectedTeam ?? user;
42
- const customerType = selectedTeam ? "team" : "user";
42
+ const effectiveSelectedTeam = selectedTeam ?? (!allowPersonal ? teams[0] ?? null : null);
43
+ const customer = effectiveSelectedTeam ?? (allowPersonal ? user : null);
44
+ const customerType = effectiveSelectedTeam ? "team" : "user";
45
+ (0, import_react.useEffect)(() => {
46
+ if (props.mockMode) {
47
+ return;
48
+ }
49
+ if (!allowPersonal && !selectedTeam && teams.length > 0) {
50
+ setSelectedTeam(teams[0]);
51
+ return;
52
+ }
53
+ if (selectedTeam && !teams.some((team) => team.id === selectedTeam.id)) {
54
+ setSelectedTeam(allowPersonal ? null : teams[0] ?? null);
55
+ }
56
+ }, [allowPersonal, props.mockMode, selectedTeam, teams]);
43
57
  if (props.mockMode) {
44
58
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_page_layout.PageLayout, { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
45
59
  import_payments_panel.PaymentsPanel,
@@ -55,8 +69,9 @@ function PaymentsPage(props) {
55
69
  hasTeams ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
56
70
  import__.TeamSwitcher,
57
71
  {
58
- team: selectedTeam ?? void 0,
59
- allowNull: true,
72
+ team: effectiveSelectedTeam ?? void 0,
73
+ teams,
74
+ allowNull: allowPersonal,
60
75
  nullLabel: t("Personal"),
61
76
  onChange: async (team) => {
62
77
  setSelectedTeam(team);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components-page/account-settings/payments/payments-page.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { useState } from \"react\";\nimport { Team, TeamSwitcher } from \"../../..\";\nimport { useUser } from \"../../../lib/hooks\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { PageLayout } from \"../page-layout\";\nimport { PaymentsPanel } from \"./payments-panel\";\n\nexport function PaymentsPage(props: { mockMode?: boolean }) {\n const { t } = useTranslation();\n const user = useUser({ or: props.mockMode ? \"return-null\" : \"redirect\" });\n const teams = user?.useTeams() ?? [];\n const hasTeams = teams.length > 0;\n const [selectedTeam, setSelectedTeam] = useState<Team | null>(null);\n const customer = selectedTeam ?? user;\n const customerType = selectedTeam ? \"team\" : \"user\";\n\n if (props.mockMode) {\n return (\n <PageLayout>\n <PaymentsPanel\n mockMode\n />\n </PageLayout>\n );\n }\n\n if (!customer) {\n return null;\n }\n\n\n return (\n <PageLayout>\n {hasTeams ? (\n <TeamSwitcher\n team={selectedTeam ?? undefined}\n allowNull\n nullLabel={t(\"Personal\")}\n onChange={async (team) => {\n setSelectedTeam(team);\n }}\n />\n ) : null}\n <PaymentsPanel\n customer={customer}\n customerType={customerType}\n />\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,mBAAyB;AACzB,eAAmC;AACnC,mBAAwB;AACxB,0BAA+B;AAC/B,yBAA2B;AAC3B,4BAA8B;AActB;AAZD,SAAS,aAAa,OAA+B;AAC1D,QAAM,EAAE,EAAE,QAAI,oCAAe;AAC7B,QAAM,WAAO,sBAAQ,EAAE,IAAI,MAAM,WAAW,gBAAgB,WAAW,CAAC;AACxE,QAAM,QAAQ,MAAM,SAAS,KAAK,CAAC;AACnC,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAsB,IAAI;AAClE,QAAM,WAAW,gBAAgB;AACjC,QAAM,eAAe,eAAe,SAAS;AAE7C,MAAI,MAAM,UAAU;AAClB,WACE,4CAAC,iCACC;AAAA,MAAC;AAAA;AAAA,QACC,UAAQ;AAAA;AAAA,IACV,GACF;AAAA,EAEJ;AAEA,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAGA,SACE,6CAAC,iCACE;AAAA,eACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAgB;AAAA,QACtB,WAAS;AAAA,QACT,WAAW,EAAE,UAAU;AAAA,QACvB,UAAU,OAAO,SAAS;AACxB,0BAAgB,IAAI;AAAA,QACtB;AAAA;AAAA,IACF,IACE;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../src/components-page/account-settings/payments/payments-page.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { useEffect, useState } from \"react\";\nimport { Team, TeamSwitcher } from \"../../..\";\nimport { useUser } from \"../../../lib/hooks\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { PageLayout } from \"../page-layout\";\nimport { PaymentsPanel } from \"./payments-panel\";\n\nexport function PaymentsPage(props: { mockMode?: boolean, availableTeams?: Team[], allowPersonal?: boolean }) {\n const { t } = useTranslation();\n const user = useUser({ or: props.mockMode ? \"return-null\" : \"redirect\" });\n const teams = props.availableTeams ?? user?.useTeams() ?? [];\n const allowPersonal = props.allowPersonal ?? true;\n const hasTeams = teams.length > 0;\n const [selectedTeam, setSelectedTeam] = useState<Team | null>(null);\n const effectiveSelectedTeam = selectedTeam ?? (!allowPersonal ? (teams[0] ?? null) : null);\n const customer = effectiveSelectedTeam ?? (allowPersonal ? user : null);\n const customerType = effectiveSelectedTeam ? \"team\" : \"user\";\n\n useEffect(() => {\n if (props.mockMode) {\n return;\n }\n if (!allowPersonal && !selectedTeam && teams.length > 0) {\n setSelectedTeam(teams[0]);\n return;\n }\n if (selectedTeam && !teams.some(team => team.id === selectedTeam.id)) {\n setSelectedTeam(allowPersonal ? null : (teams[0] ?? null));\n }\n }, [allowPersonal, props.mockMode, selectedTeam, teams]);\n\n if (props.mockMode) {\n return (\n <PageLayout>\n <PaymentsPanel\n mockMode\n />\n </PageLayout>\n );\n }\n\n if (!customer) {\n return null;\n }\n\n\n return (\n <PageLayout>\n {hasTeams ? (\n <TeamSwitcher\n team={effectiveSelectedTeam ?? undefined}\n teams={teams}\n allowNull={allowPersonal}\n nullLabel={t(\"Personal\")}\n onChange={async (team) => {\n setSelectedTeam(team);\n }}\n />\n ) : null}\n <PaymentsPanel\n customer={customer}\n customerType={customerType}\n />\n </PageLayout>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,mBAAoC;AACpC,eAAmC;AACnC,mBAAwB;AACxB,0BAA+B;AAC/B,yBAA2B;AAC3B,4BAA8B;AA6BtB;AA3BD,SAAS,aAAa,OAAiF;AAC5G,QAAM,EAAE,EAAE,QAAI,oCAAe;AAC7B,QAAM,WAAO,sBAAQ,EAAE,IAAI,MAAM,WAAW,gBAAgB,WAAW,CAAC;AACxE,QAAM,QAAQ,MAAM,kBAAkB,MAAM,SAAS,KAAK,CAAC;AAC3D,QAAM,gBAAgB,MAAM,iBAAiB;AAC7C,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAsB,IAAI;AAClE,QAAM,wBAAwB,iBAAiB,CAAC,gBAAiB,MAAM,CAAC,KAAK,OAAQ;AACrF,QAAM,WAAW,0BAA0B,gBAAgB,OAAO;AAClE,QAAM,eAAe,wBAAwB,SAAS;AAEtD,8BAAU,MAAM;AACd,QAAI,MAAM,UAAU;AAClB;AAAA,IACF;AACA,QAAI,CAAC,iBAAiB,CAAC,gBAAgB,MAAM,SAAS,GAAG;AACvD,sBAAgB,MAAM,CAAC,CAAC;AACxB;AAAA,IACF;AACA,QAAI,gBAAgB,CAAC,MAAM,KAAK,UAAQ,KAAK,OAAO,aAAa,EAAE,GAAG;AACpE,sBAAgB,gBAAgB,OAAQ,MAAM,CAAC,KAAK,IAAK;AAAA,IAC3D;AAAA,EACF,GAAG,CAAC,eAAe,MAAM,UAAU,cAAc,KAAK,CAAC;AAEvD,MAAI,MAAM,UAAU;AAClB,WACE,4CAAC,iCACC;AAAA,MAAC;AAAA;AAAA,QACC,UAAQ;AAAA;AAAA,IACV,GACF;AAAA,EAEJ;AAEA,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAGA,SACE,6CAAC,iCACE;AAAA,eACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,yBAAyB;AAAA,QAC/B;AAAA,QACA,WAAW;AAAA,QACX,WAAW,EAAE,UAAU;AAAA,QACvB,UAAU,OAAO,SAAS;AACxB,0BAAgB,IAAI;AAAA,QACtB;AAAA;AAAA,IACF,IACE;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
@@ -25,6 +25,7 @@ __export(account_settings_exports, {
25
25
  AccountSettings: () => AccountSettings
26
26
  });
27
27
  module.exports = __toCommonJS(account_settings_exports);
28
+ var import_promises = require("@stackframe/stack-shared/dist/utils/promises");
28
29
  var import_stack_ui = require("@stackframe/stack-ui");
29
30
  var import_lucide_react = require("lucide-react");
30
31
  var import_react = require("react");
@@ -71,6 +72,60 @@ function AccountSettings(props) {
71
72
  const project = props.mockProject || projectFromHook;
72
73
  const teams = user?.useTeams() || [];
73
74
  const billing = user?.useBilling() || null;
75
+ const teamsKey = (0, import_react.useMemo)(() => teams.map((team) => team.id).join("|"), [teams]);
76
+ const teamsById = (0, import_react.useMemo)(() => teams, [teamsKey]);
77
+ const userRef = (0, import_react.useRef)(userFromHook ?? null);
78
+ const userId = userFromHook?.id ?? null;
79
+ const [paymentsAvailability, setPaymentsAvailability] = (0, import_react.useState)(() => ({
80
+ userHasProducts: false,
81
+ teamIdsWithProducts: /* @__PURE__ */ new Set(),
82
+ isReady: !!props.mockUser
83
+ }));
84
+ (0, import_react.useEffect)(() => {
85
+ userRef.current = userFromHook ?? null;
86
+ }, [userFromHook]);
87
+ (0, import_react.useEffect)(() => {
88
+ if (props.mockUser || !userId) {
89
+ return;
90
+ }
91
+ let cancelled = false;
92
+ (0, import_promises.runAsynchronouslyWithAlert)(async () => {
93
+ const currentUser = userRef.current;
94
+ if (!currentUser || currentUser.id !== userId) {
95
+ return;
96
+ }
97
+ const [userProducts, teamsWithProducts2] = await Promise.all([
98
+ currentUser.listProducts({ limit: 1 }),
99
+ Promise.all(teamsById.map(async (team) => {
100
+ const isTeamAdmin = await currentUser.hasPermission(team, "team_admin");
101
+ if (!isTeamAdmin) {
102
+ return null;
103
+ }
104
+ const teamProducts = await team.listProducts({ limit: 1 });
105
+ const hasTeamProducts = teamProducts.some((product) => product.customerType === "team");
106
+ return hasTeamProducts ? team.id : null;
107
+ }))
108
+ ]);
109
+ if (cancelled) {
110
+ return;
111
+ }
112
+ const userHasProducts = userProducts.some((product) => product.customerType === "user");
113
+ const teamIdsWithProducts = new Set(teamsWithProducts2.filter((id) => id !== null));
114
+ setPaymentsAvailability({
115
+ userHasProducts,
116
+ teamIdsWithProducts,
117
+ isReady: true
118
+ });
119
+ });
120
+ return () => {
121
+ cancelled = true;
122
+ };
123
+ }, [props.mockUser, teamsById, userId]);
124
+ const teamsWithProducts = (0, import_react.useMemo)(
125
+ () => teamsById.filter((team) => paymentsAvailability.teamIdsWithProducts.has(team.id)),
126
+ [paymentsAvailability.teamIdsWithProducts, teamsById]
127
+ );
128
+ const shouldShowPaymentsTab = props.mockUser || paymentsAvailability.isReady && (paymentsAvailability.userHasProducts || teamsWithProducts.length > 0);
74
129
  if (!props.mockUser && !userFromHook) {
75
130
  return null;
76
131
  }
@@ -113,13 +168,20 @@ function AccountSettings(props) {
113
168
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "Key" }),
114
169
  content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ApiKeysPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_api_keys_page.ApiKeysPage, { mockApiKeys: props.mockApiKeys, mockMode: !!props.mockUser }) })
115
170
  }] : [],
116
- {
171
+ ...shouldShowPaymentsTab ? [{
117
172
  title: t("Payments"),
118
173
  type: "item",
119
174
  id: "payments",
120
175
  icon: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { name: "CreditCard" }),
121
- content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PaymentsPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_payments_page.PaymentsPage, { mockMode: !!props.mockUser }) })
122
- },
176
+ content: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_react.Suspense, { fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PaymentsPageSkeleton, {}), children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
177
+ import_payments_page.PaymentsPage,
178
+ {
179
+ mockMode: !!props.mockUser,
180
+ allowPersonal: paymentsAvailability.userHasProducts,
181
+ availableTeams: teamsWithProducts
182
+ }
183
+ ) })
184
+ }] : [],
123
185
  {
124
186
  title: t("Settings"),
125
187
  type: "item",
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { Skeleton, Typography } from '@stackframe/stack-ui';\nimport { Contact, ShieldCheck, Bell, Monitor, Key, Settings, CirclePlus, CreditCard } from 'lucide-react';\nimport React, { Suspense } from \"react\";\nimport { useStackApp, useUser } from '..';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { TeamIcon } from '../components/team-icon';\nimport { useTranslation } from \"../lib/translations\";\nimport { ActiveSessionsPage } from \"./account-settings/active-sessions/active-sessions-page\";\nimport { ApiKeysPage } from \"./account-settings/api-keys/api-keys-page\";\nimport { EmailsAndAuthPage } from './account-settings/email-and-auth/email-and-auth-page';\nimport { NotificationsPage } from './account-settings/notifications/notifications-page';\nimport { ProfilePage } from \"./account-settings/profile-page/profile-page\";\nimport { PaymentsPage } from \"./account-settings/payments/payments-page\";\nimport { SettingsPage } from './account-settings/settings/settings-page';\nimport { TeamCreationPage } from './account-settings/teams/team-creation-page';\nimport { TeamPage } from './account-settings/teams/team-page';\n\nconst iconMap = {\n Contact,\n ShieldCheck,\n Bell,\n Monitor,\n Key,\n Settings,\n CirclePlus,\n CreditCard,\n} as const;\n\nconst Icon = ({ name }: { name: keyof typeof iconMap }) => {\n const LucideIcon = iconMap[name];\n return <LucideIcon className=\"mr-2 h-4 w-4\"/>;\n};\n\nexport function AccountSettings(props: {\n fullPage?: boolean,\n extraItems?: ({\n title: string,\n content: React.ReactNode,\n id: string,\n } & ({\n icon?: React.ReactNode,\n } | {\n iconName?: keyof typeof iconMap,\n }))[],\n mockUser?: {\n displayName?: string,\n profileImageUrl?: string,\n },\n mockApiKeys?: Array<{\n id: string,\n description: string,\n createdAt: string,\n expiresAt?: string,\n manuallyRevokedAt?: string,\n }>,\n mockProject?: {\n config: {\n allowUserApiKeys: boolean,\n clientTeamCreationEnabled: boolean,\n },\n },\n mockSessions?: Array<{\n id: string,\n isCurrentSession: boolean,\n isImpersonation?: boolean,\n createdAt: string,\n lastUsedAt?: string,\n geoInfo?: {\n ip?: string,\n cityName?: string,\n },\n }>,\n}) {\n const { t } = useTranslation();\n const userFromHook = useUser({ or: props.mockUser ? 'return-null' : 'redirect' });\n const stackApp = useStackApp();\n const projectFromHook = stackApp.useProject();\n\n // Use mock data if provided, otherwise use real data\n const user = props.mockUser ? {\n useTeams: () => [], // Mock empty teams for now\n useBilling: () => ({ hasCustomer: false }), // Mock empty billing for now\n } : userFromHook;\n\n const project = props.mockProject || projectFromHook;\n const teams = user?.useTeams() || [];\n const billing = user?.useBilling() || null;\n\n // If we're not in mock mode and don't have a user, the useUser hook will handle redirect\n if (!props.mockUser && !userFromHook) {\n return null;\n }\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div className=\"self-stretch flex-grow w-full\">\n <SidebarLayout\n items={([\n {\n title: t('My Profile'),\n type: 'item',\n id: 'profile',\n icon: <Icon name=\"Contact\"/>,\n content: <ProfilePage mockUser={props.mockUser}/>,\n },\n {\n title: t('Emails & Auth'),\n type: 'item',\n id: 'auth',\n icon: <Icon name=\"ShieldCheck\"/>,\n content: <Suspense fallback={<EmailsAndAuthPageSkeleton/>}>\n <EmailsAndAuthPage mockMode={!!props.mockUser}/>\n </Suspense>,\n },\n {\n title: t('Notifications'),\n type: 'item',\n id: 'notifications',\n icon: <Icon name=\"Bell\"/>,\n content: <Suspense fallback={<NotificationsPageSkeleton/>}>\n <NotificationsPage/>\n </Suspense>,\n },\n {\n title: t('Active Sessions'),\n type: 'item',\n id: 'sessions',\n icon: <Icon name=\"Monitor\"/>,\n content: <Suspense fallback={<ActiveSessionsPageSkeleton/>}>\n <ActiveSessionsPage mockSessions={props.mockSessions} mockMode={!!props.mockUser}/>\n </Suspense>,\n },\n ...(project.config.allowUserApiKeys ? [{\n title: t('API Keys'),\n type: 'item',\n id: 'api-keys',\n icon: <Icon name=\"Key\" />,\n content: <Suspense fallback={<ApiKeysPageSkeleton/>}>\n <ApiKeysPage mockApiKeys={props.mockApiKeys} mockMode={!!props.mockUser} />\n </Suspense>,\n }] as const : []),\n {\n title: t('Payments'),\n type: 'item',\n id: 'payments',\n icon: <Icon name=\"CreditCard\" />,\n content: <Suspense fallback={<PaymentsPageSkeleton/>}>\n <PaymentsPage mockMode={!!props.mockUser} />\n </Suspense>,\n },\n {\n title: t('Settings'),\n type: 'item',\n id: 'settings',\n icon: <Icon name=\"Settings\"/>,\n content: <SettingsPage mockMode={!!props.mockUser}/>,\n },\n ...(props.extraItems?.map(item => ({\n title: item.title,\n type: 'item',\n id: item.id,\n icon: (() => {\n const iconName = (item as any).iconName as keyof typeof iconMap | undefined;\n if (iconName) {\n return <Icon name={iconName}/>;\n } else if ((item as any).icon) {\n return (item as any).icon;\n }\n return null;\n })(),\n content: item.content,\n } as const)) || []),\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: t('Teams'),\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center w-full'>\n <TeamIcon team={team}/>\n <Typography className=\"max-w-[320px] md:w-[90%] truncate\">{team.displayName}</Typography>\n </div>,\n type: 'item',\n id: `team-${team.id}`,\n content: <Suspense fallback={<TeamPageSkeleton/>}>\n <TeamPage team={team}/>\n </Suspense>,\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: t('Create a team'),\n icon: <Icon name=\"CirclePlus\"/>,\n type: 'item',\n id: 'team-creation',\n content: <Suspense fallback={<TeamCreationSkeleton/>}>\n <TeamCreationPage mockMode={!!props.mockUser} />\n </Suspense>,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title={t(\"Account Settings\")}\n />\n </div>\n </MaybeFullPage>\n );\n}\n\nfunction PageLayout(props: { children: React.ReactNode }) {\n return (\n <div className='flex flex-col gap-6'>\n {props.children}\n </div>\n );\n}\n\nfunction EmailsAndAuthPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n </PageLayout>;\n}\n\nfunction ActiveSessionsPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-6 w-48 mb-2\"/>\n <Skeleton className=\"h-4 w-full mb-4\"/>\n <Skeleton className=\"h-[200px] w-full mt-1 rounded-md\"/>\n </PageLayout>;\n}\n\nfunction ApiKeysPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-[200px] w-full mt-1 rounded-md\"/>\n </PageLayout>;\n}\n\nfunction PaymentsPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-6 w-48 mb-2\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-[200px] w-full mt-1 rounded-md\"/>\n </PageLayout>;\n}\n\nfunction TeamPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-[200px] w-full mt-1 rounded-md\"/>\n </PageLayout>;\n}\n\nfunction TeamCreationSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n </PageLayout>;\n}\n\nfunction NotificationsPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n </PageLayout>;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components-page/account-settings.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Skeleton, Typography } from '@stackframe/stack-ui';\nimport { Contact, ShieldCheck, Bell, Monitor, Key, Settings, CirclePlus, CreditCard } from 'lucide-react';\nimport React, { Suspense, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { useStackApp, useUser } from '..';\nimport { MaybeFullPage } from \"../components/elements/maybe-full-page\";\nimport { SidebarLayout } from '../components/elements/sidebar-layout';\nimport { TeamIcon } from '../components/team-icon';\nimport { useTranslation } from \"../lib/translations\";\nimport { ActiveSessionsPage } from \"./account-settings/active-sessions/active-sessions-page\";\nimport { ApiKeysPage } from \"./account-settings/api-keys/api-keys-page\";\nimport { EmailsAndAuthPage } from './account-settings/email-and-auth/email-and-auth-page';\nimport { NotificationsPage } from './account-settings/notifications/notifications-page';\nimport { ProfilePage } from \"./account-settings/profile-page/profile-page\";\nimport { PaymentsPage } from \"./account-settings/payments/payments-page\";\nimport { SettingsPage } from './account-settings/settings/settings-page';\nimport { TeamCreationPage } from './account-settings/teams/team-creation-page';\nimport { TeamPage } from './account-settings/teams/team-page';\n\nconst iconMap = {\n Contact,\n ShieldCheck,\n Bell,\n Monitor,\n Key,\n Settings,\n CirclePlus,\n CreditCard,\n} as const;\n\nconst Icon = ({ name }: { name: keyof typeof iconMap }) => {\n const LucideIcon = iconMap[name];\n return <LucideIcon className=\"mr-2 h-4 w-4\"/>;\n};\n\nexport function AccountSettings(props: {\n fullPage?: boolean,\n extraItems?: ({\n title: string,\n content: React.ReactNode,\n id: string,\n } & ({\n icon?: React.ReactNode,\n } | {\n iconName?: keyof typeof iconMap,\n }))[],\n mockUser?: {\n displayName?: string,\n profileImageUrl?: string,\n },\n mockApiKeys?: Array<{\n id: string,\n description: string,\n createdAt: string,\n expiresAt?: string,\n manuallyRevokedAt?: string,\n }>,\n mockProject?: {\n config: {\n allowUserApiKeys: boolean,\n clientTeamCreationEnabled: boolean,\n },\n },\n mockSessions?: Array<{\n id: string,\n isCurrentSession: boolean,\n isImpersonation?: boolean,\n createdAt: string,\n lastUsedAt?: string,\n geoInfo?: {\n ip?: string,\n cityName?: string,\n },\n }>,\n}) {\n const { t } = useTranslation();\n const userFromHook = useUser({ or: props.mockUser ? 'return-null' : 'redirect' });\n const stackApp = useStackApp();\n const projectFromHook = stackApp.useProject();\n\n // Use mock data if provided, otherwise use real data\n const user = props.mockUser ? {\n useTeams: () => [], // Mock empty teams for now\n useBilling: () => ({ hasCustomer: false }), // Mock empty billing for now\n } : userFromHook;\n\n const project = props.mockProject || projectFromHook;\n const teams = user?.useTeams() || [];\n const billing = user?.useBilling() || null;\n const teamsKey = useMemo(() => teams.map(team => team.id).join(\"|\"), [teams]);\n const teamsById = useMemo(() => teams, [teamsKey]);\n const userRef = useRef(userFromHook ?? null);\n const userId = userFromHook?.id ?? null;\n const [paymentsAvailability, setPaymentsAvailability] = useState<{\n userHasProducts: boolean,\n teamIdsWithProducts: Set<string>,\n isReady: boolean,\n }>(() => ({\n userHasProducts: false,\n teamIdsWithProducts: new Set<string>(),\n isReady: !!props.mockUser,\n }));\n\n useEffect(() => {\n userRef.current = userFromHook ?? null;\n }, [userFromHook]);\n\n useEffect(() => {\n if (props.mockUser || !userId) {\n return;\n }\n let cancelled = false;\n runAsynchronouslyWithAlert(async () => {\n const currentUser = userRef.current;\n if (!currentUser || currentUser.id !== userId) {\n return;\n }\n const [userProducts, teamsWithProducts] = await Promise.all([\n currentUser.listProducts({ limit: 1 }),\n Promise.all(teamsById.map(async (team) => {\n const isTeamAdmin = await currentUser.hasPermission(team, \"team_admin\");\n if (!isTeamAdmin) {\n return null;\n }\n const teamProducts = await team.listProducts({ limit: 1 });\n const hasTeamProducts = teamProducts.some((product) => product.customerType === \"team\");\n return hasTeamProducts ? team.id : null;\n })),\n ]);\n if (cancelled) {\n return;\n }\n const userHasProducts = userProducts.some((product) => product.customerType === \"user\");\n const teamIdsWithProducts = new Set<string>(teamsWithProducts.filter((id): id is string => id !== null));\n setPaymentsAvailability({\n userHasProducts,\n teamIdsWithProducts,\n isReady: true,\n });\n });\n return () => {\n cancelled = true;\n };\n }, [props.mockUser, teamsById, userId]);\n\n const teamsWithProducts = useMemo(\n () => teamsById.filter(team => paymentsAvailability.teamIdsWithProducts.has(team.id)),\n [paymentsAvailability.teamIdsWithProducts, teamsById],\n );\n const shouldShowPaymentsTab = props.mockUser\n || (paymentsAvailability.isReady\n && (paymentsAvailability.userHasProducts || teamsWithProducts.length > 0));\n\n // If we're not in mock mode and don't have a user, the useUser hook will handle redirect\n if (!props.mockUser && !userFromHook) {\n return null;\n }\n\n return (\n <MaybeFullPage fullPage={!!props.fullPage}>\n <div className=\"self-stretch flex-grow w-full\">\n <SidebarLayout\n items={([\n {\n title: t('My Profile'),\n type: 'item',\n id: 'profile',\n icon: <Icon name=\"Contact\"/>,\n content: <ProfilePage mockUser={props.mockUser}/>,\n },\n {\n title: t('Emails & Auth'),\n type: 'item',\n id: 'auth',\n icon: <Icon name=\"ShieldCheck\"/>,\n content: <Suspense fallback={<EmailsAndAuthPageSkeleton/>}>\n <EmailsAndAuthPage mockMode={!!props.mockUser}/>\n </Suspense>,\n },\n {\n title: t('Notifications'),\n type: 'item',\n id: 'notifications',\n icon: <Icon name=\"Bell\"/>,\n content: <Suspense fallback={<NotificationsPageSkeleton/>}>\n <NotificationsPage/>\n </Suspense>,\n },\n {\n title: t('Active Sessions'),\n type: 'item',\n id: 'sessions',\n icon: <Icon name=\"Monitor\"/>,\n content: <Suspense fallback={<ActiveSessionsPageSkeleton/>}>\n <ActiveSessionsPage mockSessions={props.mockSessions} mockMode={!!props.mockUser}/>\n </Suspense>,\n },\n ...(project.config.allowUserApiKeys ? [{\n title: t('API Keys'),\n type: 'item',\n id: 'api-keys',\n icon: <Icon name=\"Key\" />,\n content: <Suspense fallback={<ApiKeysPageSkeleton/>}>\n <ApiKeysPage mockApiKeys={props.mockApiKeys} mockMode={!!props.mockUser} />\n </Suspense>,\n }] as const : []),\n ...(shouldShowPaymentsTab ? [{\n title: t('Payments'),\n type: 'item',\n id: 'payments',\n icon: <Icon name=\"CreditCard\" />,\n content: <Suspense fallback={<PaymentsPageSkeleton/>}>\n <PaymentsPage\n mockMode={!!props.mockUser}\n allowPersonal={paymentsAvailability.userHasProducts}\n availableTeams={teamsWithProducts}\n />\n </Suspense>,\n }] as const : []),\n {\n title: t('Settings'),\n type: 'item',\n id: 'settings',\n icon: <Icon name=\"Settings\"/>,\n content: <SettingsPage mockMode={!!props.mockUser}/>,\n },\n ...(props.extraItems?.map(item => ({\n title: item.title,\n type: 'item',\n id: item.id,\n icon: (() => {\n const iconName = (item as any).iconName as keyof typeof iconMap | undefined;\n if (iconName) {\n return <Icon name={iconName}/>;\n } else if ((item as any).icon) {\n return (item as any).icon;\n }\n return null;\n })(),\n content: item.content,\n } as const)) || []),\n ...(teams.length > 0 || project.config.clientTeamCreationEnabled) ? [{\n title: t('Teams'),\n type: 'divider',\n }] as const : [],\n ...teams.map(team => ({\n title: <div className='flex gap-2 items-center w-full'>\n <TeamIcon team={team}/>\n <Typography className=\"max-w-[320px] md:w-[90%] truncate\">{team.displayName}</Typography>\n </div>,\n type: 'item',\n id: `team-${team.id}`,\n content: <Suspense fallback={<TeamPageSkeleton/>}>\n <TeamPage team={team}/>\n </Suspense>,\n } as const)),\n ...project.config.clientTeamCreationEnabled ? [{\n title: t('Create a team'),\n icon: <Icon name=\"CirclePlus\"/>,\n type: 'item',\n id: 'team-creation',\n content: <Suspense fallback={<TeamCreationSkeleton/>}>\n <TeamCreationPage mockMode={!!props.mockUser} />\n </Suspense>,\n }] as const : [],\n ] as const).filter((p) => p.type === 'divider' || (p as any).content )}\n title={t(\"Account Settings\")}\n />\n </div>\n </MaybeFullPage>\n );\n}\n\nfunction PageLayout(props: { children: React.ReactNode }) {\n return (\n <div className='flex flex-col gap-6'>\n {props.children}\n </div>\n );\n}\n\nfunction EmailsAndAuthPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n </PageLayout>;\n}\n\nfunction ActiveSessionsPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-6 w-48 mb-2\"/>\n <Skeleton className=\"h-4 w-full mb-4\"/>\n <Skeleton className=\"h-[200px] w-full mt-1 rounded-md\"/>\n </PageLayout>;\n}\n\nfunction ApiKeysPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-[200px] w-full mt-1 rounded-md\"/>\n </PageLayout>;\n}\n\nfunction PaymentsPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-6 w-48 mb-2\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-[200px] w-full mt-1 rounded-md\"/>\n </PageLayout>;\n}\n\nfunction TeamPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-[200px] w-full mt-1 rounded-md\"/>\n </PageLayout>;\n}\n\nfunction TeamCreationSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n </PageLayout>;\n}\n\nfunction NotificationsPageSkeleton() {\n return <PageLayout>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n <Skeleton className=\"h-9 w-full mt-1\"/>\n </PageLayout>;\n}\n"],"mappings":"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","names":["teamsWithProducts"]}
@@ -77,9 +77,7 @@ function CliAuthConfirmation({ fullPage = true }) {
77
77
  {
78
78
  title: t("CLI Authorization Successful"),
79
79
  fullPage,
80
- primaryButtonText: t("Close"),
81
- primaryAction: () => window.close(),
82
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("The CLI application has been authorized successfully. You can now close this window and return to the command line.") })
80
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("The CLI application has been authorized successfully. You can close this window and return to the command line.") })
83
81
  }
84
82
  );
85
83
  }
@@ -91,8 +89,6 @@ function CliAuthConfirmation({ fullPage = true }) {
91
89
  fullPage,
92
90
  primaryButtonText: t("Try Again"),
93
91
  primaryAction: () => setError(null),
94
- secondaryButtonText: t("Cancel"),
95
- secondaryAction: () => window.close(),
96
92
  children: [
97
93
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { className: "text-red-600", children: t("Failed to authorize the CLI application:") }),
98
94
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { className: "text-red-600", children: error.message })
@@ -107,8 +103,6 @@ function CliAuthConfirmation({ fullPage = true }) {
107
103
  fullPage,
108
104
  primaryButtonText: authorizing ? t("Authorizing...") : t("Authorize"),
109
105
  primaryAction: handleAuthorize,
110
- secondaryButtonText: t("Cancel"),
111
- secondaryAction: () => window.close(),
112
106
  children: [
113
107
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { children: t("A command line application is requesting access to your account. Click the button below to authorize it.") }),
114
108
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_stack_ui.Typography, { variant: "destructive", children: t("WARNING: Make sure you trust the command line application, as it will gain access to your account. If you did not initiate this request, you can close this page and ignore it. We will never send you this link via email or any other means.") })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components-page/cli-auth-confirm.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { Typography } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { stackAppInternalsSymbol, useStackApp } from \"..\";\nimport { MessageCard } from \"../components/message-cards/message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport function CliAuthConfirmation({ fullPage = true }: { fullPage?: boolean }) {\n const { t } = useTranslation();\n const app = useStackApp();\n const [authorizing, setAuthorizing] = useState(false);\n const [success, setSuccess] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const user = app.useUser({ or: \"redirect\" });\n\n const handleAuthorize = async () => {\n if (authorizing) return;\n\n setAuthorizing(true);\n try {\n // Get login code from URL query parameters\n const urlParams = new URLSearchParams(window.location.search);\n const loginCode = urlParams.get(\"login_code\");\n\n if (!loginCode) {\n throw new Error(\"Missing login code in URL parameters\");\n }\n const refreshToken = (await user.currentSession.getTokens()).refreshToken;\n if (!refreshToken) {\n throw new Error(\"You must be logged in to authorize CLI access\");\n }\n\n // Use the internal API to send the CLI login request\n const result = await (app as any)[stackAppInternalsSymbol].sendRequest(\"/auth/cli/complete\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify({\n login_code: loginCode,\n refresh_token: (await user.currentSession.getTokens()).refreshToken\n })\n });\n\n if (!result.ok) {\n throw new Error(`Authorization failed: ${result.status} ${await result.text()}`);\n }\n\n setSuccess(true);\n } catch (err) {\n setError(err as Error);\n } finally {\n setAuthorizing(false);\n }\n };\n\n if (success) {\n return (\n <MessageCard\n title={t(\"CLI Authorization Successful\")}\n fullPage={fullPage}\n primaryButtonText={t(\"Close\")}\n primaryAction={() => window.close()}\n >\n <Typography>\n {t(\"The CLI application has been authorized successfully. You can now close this window and return to the command line.\")}\n </Typography>\n </MessageCard>\n );\n }\n\n if (error) {\n return (\n <MessageCard\n title={t(\"Authorization Failed\")}\n fullPage={fullPage}\n primaryButtonText={t(\"Try Again\")}\n primaryAction={() => setError(null)}\n secondaryButtonText={t(\"Cancel\")}\n secondaryAction={() => window.close()}\n >\n <Typography className=\"text-red-600\">\n {t(\"Failed to authorize the CLI application:\")}\n </Typography>\n <Typography className=\"text-red-600\">\n {error.message}\n </Typography>\n </MessageCard>\n );\n }\n\n return (\n <MessageCard\n title={t(\"Authorize CLI Application\")}\n fullPage={fullPage}\n primaryButtonText={authorizing ? t(\"Authorizing...\") : t(\"Authorize\")}\n primaryAction={handleAuthorize}\n secondaryButtonText={t(\"Cancel\")}\n secondaryAction={() => window.close()}\n >\n <Typography>\n {t(\"A command line application is requesting access to your account. Click the button below to authorize it.\")}\n </Typography>\n <Typography variant=\"destructive\">\n {t(\"WARNING: Make sure you trust the command line application, as it will gain access to your account. If you did not initiate this request, you can close this page and ignore it. We will never send you this link via email or any other means.\")}\n </Typography>\n </MessageCard>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,sBAA2B;AAC3B,mBAAyB;AACzB,eAAqD;AACrD,0BAA4B;AAC5B,0BAA+B;AA4DvB;AA1DD,SAAS,oBAAoB,EAAE,WAAW,KAAK,GAA2B;AAC/E,QAAM,EAAE,EAAE,QAAI,oCAAe;AAC7B,QAAM,UAAM,sBAAY;AACxB,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AACpD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAuB,IAAI;AAErD,QAAM,OAAO,IAAI,QAAQ,EAAE,IAAI,WAAW,CAAC;AAE3C,QAAM,kBAAkB,YAAY;AAClC,QAAI,YAAa;AAEjB,mBAAe,IAAI;AACnB,QAAI;AAEF,YAAM,YAAY,IAAI,gBAAgB,OAAO,SAAS,MAAM;AAC5D,YAAM,YAAY,UAAU,IAAI,YAAY;AAE5C,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AACA,YAAM,gBAAgB,MAAM,KAAK,eAAe,UAAU,GAAG;AAC7D,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,MAAM,+CAA+C;AAAA,MACjE;AAGA,YAAM,SAAS,MAAO,IAAY,gCAAuB,EAAE,YAAY,sBAAsB;AAAA,QAC3F,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,YAAY;AAAA,UACZ,gBAAgB,MAAM,KAAK,eAAe,UAAU,GAAG;AAAA,QACzD,CAAC;AAAA,MACH,CAAC;AAED,UAAI,CAAC,OAAO,IAAI;AACd,cAAM,IAAI,MAAM,yBAAyB,OAAO,MAAM,IAAI,MAAM,OAAO,KAAK,CAAC,EAAE;AAAA,MACjF;AAEA,iBAAW,IAAI;AAAA,IACjB,SAAS,KAAK;AACZ,eAAS,GAAY;AAAA,IACvB,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,8BAA8B;AAAA,QACvC;AAAA,QACA,mBAAmB,EAAE,OAAO;AAAA,QAC5B,eAAe,MAAM,OAAO,MAAM;AAAA,QAElC,sDAAC,8BACE,YAAE,qHAAqH,GAC1H;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,MAAI,OAAO;AACT,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,sBAAsB;AAAA,QAC/B;AAAA,QACA,mBAAmB,EAAE,WAAW;AAAA,QAChC,eAAe,MAAM,SAAS,IAAI;AAAA,QAClC,qBAAqB,EAAE,QAAQ;AAAA,QAC/B,iBAAiB,MAAM,OAAO,MAAM;AAAA,QAEpC;AAAA,sDAAC,8BAAW,WAAU,gBACnB,YAAE,0CAA0C,GAC/C;AAAA,UACA,4CAAC,8BAAW,WAAU,gBACnB,gBAAM,SACT;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,2BAA2B;AAAA,MACpC;AAAA,MACA,mBAAmB,cAAc,EAAE,gBAAgB,IAAI,EAAE,WAAW;AAAA,MACpE,eAAe;AAAA,MACf,qBAAqB,EAAE,QAAQ;AAAA,MAC/B,iBAAiB,MAAM,OAAO,MAAM;AAAA,MAEpC;AAAA,oDAAC,8BACE,YAAE,0GAA0G,GAC/G;AAAA,QACA,4CAAC,8BAAW,SAAQ,eACjB,YAAE,gPAAgP,GACrP;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../src/components-page/cli-auth-confirm.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { Typography } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { stackAppInternalsSymbol, useStackApp } from \"..\";\nimport { MessageCard } from \"../components/message-cards/message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport function CliAuthConfirmation({ fullPage = true }: { fullPage?: boolean }) {\n const { t } = useTranslation();\n const app = useStackApp();\n const [authorizing, setAuthorizing] = useState(false);\n const [success, setSuccess] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const user = app.useUser({ or: \"redirect\" });\n\n const handleAuthorize = async () => {\n if (authorizing) return;\n\n setAuthorizing(true);\n try {\n // Get login code from URL query parameters\n const urlParams = new URLSearchParams(window.location.search);\n const loginCode = urlParams.get(\"login_code\");\n\n if (!loginCode) {\n throw new Error(\"Missing login code in URL parameters\");\n }\n const refreshToken = (await user.currentSession.getTokens()).refreshToken;\n if (!refreshToken) {\n throw new Error(\"You must be logged in to authorize CLI access\");\n }\n\n // Use the internal API to send the CLI login request\n const result = await (app as any)[stackAppInternalsSymbol].sendRequest(\"/auth/cli/complete\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify({\n login_code: loginCode,\n refresh_token: (await user.currentSession.getTokens()).refreshToken\n })\n });\n\n if (!result.ok) {\n throw new Error(`Authorization failed: ${result.status} ${await result.text()}`);\n }\n\n setSuccess(true);\n } catch (err) {\n setError(err as Error);\n } finally {\n setAuthorizing(false);\n }\n };\n\n if (success) {\n return (\n <MessageCard\n title={t(\"CLI Authorization Successful\")}\n fullPage={fullPage}\n >\n <Typography>\n {t(\"The CLI application has been authorized successfully. You can close this window and return to the command line.\")}\n </Typography>\n </MessageCard>\n );\n }\n\n if (error) {\n return (\n <MessageCard\n title={t(\"Authorization Failed\")}\n fullPage={fullPage}\n primaryButtonText={t(\"Try Again\")}\n primaryAction={() => setError(null)}\n >\n <Typography className=\"text-red-600\">\n {t(\"Failed to authorize the CLI application:\")}\n </Typography>\n <Typography className=\"text-red-600\">\n {error.message}\n </Typography>\n </MessageCard>\n );\n }\n\n return (\n <MessageCard\n title={t(\"Authorize CLI Application\")}\n fullPage={fullPage}\n primaryButtonText={authorizing ? t(\"Authorizing...\") : t(\"Authorize\")}\n primaryAction={handleAuthorize}\n >\n <Typography>\n {t(\"A command line application is requesting access to your account. Click the button below to authorize it.\")}\n </Typography>\n <Typography variant=\"destructive\">\n {t(\"WARNING: Make sure you trust the command line application, as it will gain access to your account. If you did not initiate this request, you can close this page and ignore it. We will never send you this link via email or any other means.\")}\n </Typography>\n </MessageCard>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA,sBAA2B;AAC3B,mBAAyB;AACzB,eAAqD;AACrD,0BAA4B;AAC5B,0BAA+B;AA0DvB;AAxDD,SAAS,oBAAoB,EAAE,WAAW,KAAK,GAA2B;AAC/E,QAAM,EAAE,EAAE,QAAI,oCAAe;AAC7B,QAAM,UAAM,sBAAY;AACxB,QAAM,CAAC,aAAa,cAAc,QAAI,uBAAS,KAAK;AACpD,QAAM,CAAC,SAAS,UAAU,QAAI,uBAAS,KAAK;AAC5C,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAuB,IAAI;AAErD,QAAM,OAAO,IAAI,QAAQ,EAAE,IAAI,WAAW,CAAC;AAE3C,QAAM,kBAAkB,YAAY;AAClC,QAAI,YAAa;AAEjB,mBAAe,IAAI;AACnB,QAAI;AAEF,YAAM,YAAY,IAAI,gBAAgB,OAAO,SAAS,MAAM;AAC5D,YAAM,YAAY,UAAU,IAAI,YAAY;AAE5C,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,sCAAsC;AAAA,MACxD;AACA,YAAM,gBAAgB,MAAM,KAAK,eAAe,UAAU,GAAG;AAC7D,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,MAAM,+CAA+C;AAAA,MACjE;AAGA,YAAM,SAAS,MAAO,IAAY,gCAAuB,EAAE,YAAY,sBAAsB;AAAA,QAC3F,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,YAAY;AAAA,UACZ,gBAAgB,MAAM,KAAK,eAAe,UAAU,GAAG;AAAA,QACzD,CAAC;AAAA,MACH,CAAC;AAED,UAAI,CAAC,OAAO,IAAI;AACd,cAAM,IAAI,MAAM,yBAAyB,OAAO,MAAM,IAAI,MAAM,OAAO,KAAK,CAAC,EAAE;AAAA,MACjF;AAEA,iBAAW,IAAI;AAAA,IACjB,SAAS,KAAK;AACZ,eAAS,GAAY;AAAA,IACvB,UAAE;AACA,qBAAe,KAAK;AAAA,IACtB;AAAA,EACF;AAEA,MAAI,SAAS;AACX,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,8BAA8B;AAAA,QACvC;AAAA,QAEA,sDAAC,8BACE,YAAE,iHAAiH,GACtH;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,MAAI,OAAO;AACT,WACE;AAAA,MAAC;AAAA;AAAA,QACC,OAAO,EAAE,sBAAsB;AAAA,QAC/B;AAAA,QACA,mBAAmB,EAAE,WAAW;AAAA,QAChC,eAAe,MAAM,SAAS,IAAI;AAAA,QAElC;AAAA,sDAAC,8BAAW,WAAU,gBACnB,YAAE,0CAA0C,GAC/C;AAAA,UACA,4CAAC,8BAAW,WAAU,gBACnB,gBAAM,SACT;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,EAAE,2BAA2B;AAAA,MACpC;AAAA,MACA,mBAAmB,cAAc,EAAE,gBAAgB,IAAI,EAAE,WAAW;AAAA,MACpE,eAAe;AAAA,MAEf;AAAA,oDAAC,8BACE,YAAE,0GAA0G,GAC/G;AAAA,QACA,4CAAC,8BAAW,SAAQ,eACjB,YAAE,gPAAgP,GACrP;AAAA;AAAA;AAAA,EACF;AAEJ;","names":[]}
@@ -65,7 +65,7 @@ function Onboarding(props) {
65
65
  secondaryAction: async () => {
66
66
  await user.signOut();
67
67
  },
68
- children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("Please complete your account setup to continue.") })
68
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: t("You have not yet completed your account setup. Please reach out to support if you believe this is an error.") })
69
69
  }
70
70
  );
71
71
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components-page/onboarding.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronously, runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Typography } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp, useUser } from \"..\";\nimport { FormWarningText } from \"../components/elements/form-warning\";\nimport { MessageCard } from \"../components/message-cards/message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport function Onboarding(props: {\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const user = useUser({ or: \"return-null\", includeRestricted: true });\n\n // If user is not restricted anymore, redirect to the intended destination\n // redirectToAfterSignIn automatically checks for after_auth_return_to in the URL\n if (user && !user.isRestricted) {\n runAsynchronously(stackApp.redirectToAfterSignIn());\n // TODO: This should return a loading indicator, not just null\n return null;\n }\n\n // If user is anonymous or not logged in, redirect to sign-in\n if (!user || user.isAnonymous) {\n runAsynchronously(stackApp.redirectToSignIn());\n // TODO: This should return a loading indicator, not just null\n return null;\n }\n\n // User is restricted - show appropriate onboarding step based on restricted reason\n const restrictedReason = user.restrictedReason;\n\n if (restrictedReason?.type === \"email_not_verified\") {\n // Check if user has a primary email\n const hasPrimaryEmail = !!user.primaryEmail;\n\n if (!hasPrimaryEmail) {\n // User needs to add an email first\n return <AddEmailForm fullPage={props.fullPage} />;\n }\n\n // User has email but it's not verified\n return <VerifyEmailScreen user={user} email={user.primaryEmail} fullPage={props.fullPage} />;\n }\n\n // Unknown restricted reason - show generic message\n return (\n <MessageCard\n title={t(\"Complete your account setup\")}\n fullPage={!!props.fullPage}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <p>{t(\"Please complete your account setup to continue.\")}</p>\n </MessageCard>\n );\n}\n\nfunction AddEmailForm(props: {\n fullPage?: boolean,\n onEmailAdded?: () => void,\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\", includeRestricted: true });\n const stackApp = useStackApp();\n const [loading, setLoading] = useState(false);\n\n const emailSchema = yupObject({\n email: strictEmailSchema(t('Please enter a valid email address'))\n .defined()\n .nonEmpty(t('Email is required')),\n });\n\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(emailSchema)\n });\n\n const onSubmit = async (data: yup.InferType<typeof emailSchema>) => {\n setLoading(true);\n try {\n await user.update({ primaryEmail: data.email });\n props.onEmailAdded?.();\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <MessageCard\n title={t(\"Add your email address\")}\n fullPage={!!props.fullPage}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <Typography className=\"mb-4\">\n {t(\"Please add an email address to complete your account setup. We'll send you a verification email.\")}\n </Typography>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n className='flex flex-col gap-2'\n >\n <Input\n {...register(\"email\")}\n placeholder={t(\"Enter your email\")}\n type=\"email\"\n />\n {errors.email && <FormWarningText text={errors.email.message} />}\n <Button type=\"submit\" loading={loading} className=\"w-full\">\n {t(\"Continue\")}\n </Button>\n </form>\n </MessageCard>\n );\n}\n\nfunction VerifyEmailScreen(props: {\n user: NonNullable<ReturnType<typeof useUser>>,\n email: string,\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n const { user, email } = props;\n const [changingEmail, setChangingEmail] = useState(false);\n\n if (changingEmail) {\n return <AddEmailForm fullPage={props.fullPage} onEmailAdded={() => setChangingEmail(false)} />;\n }\n\n return (\n <MessageCard\n title={t(\"Please check your email inbox\")}\n fullPage={!!props.fullPage}\n primaryButtonText={t(\"Resend verification email\")}\n primaryAction={async () => {\n await user.sendVerificationEmail();\n }}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <Typography>\n {t(\"Please verify your email address \")}\n <span className=\"font-semibold\">{email}</span>\n {\" (\"}\n <button\n type=\"button\"\n className=\"text-primary hover:underline\"\n onClick={() => setChangingEmail(true)}\n >\n {t(\"change\")}\n </button>\n {\"). \"}\n {t(\"Click the button below to resend the verification link.\")}\n </Typography>\n </MessageCard>\n );\n}\n\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/components-page/onboarding.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { yupResolver } from \"@hookform/resolvers/yup\";\nimport { strictEmailSchema, yupObject } from \"@stackframe/stack-shared/dist/schema-fields\";\nimport { runAsynchronously, runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport { Button, Input, Typography } from \"@stackframe/stack-ui\";\nimport { useState } from \"react\";\nimport { useForm } from \"react-hook-form\";\nimport * as yup from \"yup\";\nimport { useStackApp, useUser } from \"..\";\nimport { FormWarningText } from \"../components/elements/form-warning\";\nimport { MessageCard } from \"../components/message-cards/message-card\";\nimport { useTranslation } from \"../lib/translations\";\n\nexport function Onboarding(props: {\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n const stackApp = useStackApp();\n const user = useUser({ or: \"return-null\", includeRestricted: true });\n\n // If user is not restricted anymore, redirect to the intended destination\n // redirectToAfterSignIn automatically checks for after_auth_return_to in the URL\n if (user && !user.isRestricted) {\n runAsynchronously(stackApp.redirectToAfterSignIn());\n // TODO: This should return a loading indicator, not just null\n return null;\n }\n\n // If user is anonymous or not logged in, redirect to sign-in\n if (!user || user.isAnonymous) {\n runAsynchronously(stackApp.redirectToSignIn());\n // TODO: This should return a loading indicator, not just null\n return null;\n }\n\n // User is restricted - show appropriate onboarding step based on restricted reason\n const restrictedReason = user.restrictedReason;\n\n if (restrictedReason?.type === \"email_not_verified\") {\n // Check if user has a primary email\n const hasPrimaryEmail = !!user.primaryEmail;\n\n if (!hasPrimaryEmail) {\n // User needs to add an email first\n return <AddEmailForm fullPage={props.fullPage} />;\n }\n\n // User has email but it's not verified\n return <VerifyEmailScreen user={user} email={user.primaryEmail} fullPage={props.fullPage} />;\n }\n\n // Unknown restricted reason - show generic message\n return (\n <MessageCard\n title={t(\"Complete your account setup\")}\n fullPage={!!props.fullPage}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <p>{t(\"You have not yet completed your account setup. Please reach out to support if you believe this is an error.\")}</p>\n </MessageCard>\n );\n}\n\nfunction AddEmailForm(props: {\n fullPage?: boolean,\n onEmailAdded?: () => void,\n}) {\n const { t } = useTranslation();\n const user = useUser({ or: \"throw\", includeRestricted: true });\n const stackApp = useStackApp();\n const [loading, setLoading] = useState(false);\n\n const emailSchema = yupObject({\n email: strictEmailSchema(t('Please enter a valid email address'))\n .defined()\n .nonEmpty(t('Email is required')),\n });\n\n const { register, handleSubmit, formState: { errors } } = useForm({\n resolver: yupResolver(emailSchema)\n });\n\n const onSubmit = async (data: yup.InferType<typeof emailSchema>) => {\n setLoading(true);\n try {\n await user.update({ primaryEmail: data.email });\n props.onEmailAdded?.();\n } finally {\n setLoading(false);\n }\n };\n\n return (\n <MessageCard\n title={t(\"Add your email address\")}\n fullPage={!!props.fullPage}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <Typography className=\"mb-4\">\n {t(\"Please add an email address to complete your account setup. We'll send you a verification email.\")}\n </Typography>\n <form\n onSubmit={e => runAsynchronouslyWithAlert(handleSubmit(onSubmit)(e))}\n noValidate\n className='flex flex-col gap-2'\n >\n <Input\n {...register(\"email\")}\n placeholder={t(\"Enter your email\")}\n type=\"email\"\n />\n {errors.email && <FormWarningText text={errors.email.message} />}\n <Button type=\"submit\" loading={loading} className=\"w-full\">\n {t(\"Continue\")}\n </Button>\n </form>\n </MessageCard>\n );\n}\n\nfunction VerifyEmailScreen(props: {\n user: NonNullable<ReturnType<typeof useUser>>,\n email: string,\n fullPage?: boolean,\n}) {\n const { t } = useTranslation();\n const { user, email } = props;\n const [changingEmail, setChangingEmail] = useState(false);\n\n if (changingEmail) {\n return <AddEmailForm fullPage={props.fullPage} onEmailAdded={() => setChangingEmail(false)} />;\n }\n\n return (\n <MessageCard\n title={t(\"Please check your email inbox\")}\n fullPage={!!props.fullPage}\n primaryButtonText={t(\"Resend verification email\")}\n primaryAction={async () => {\n await user.sendVerificationEmail();\n }}\n secondaryButtonText={t(\"Sign out\")}\n secondaryAction={async () => {\n await user.signOut();\n }}\n >\n <Typography>\n {t(\"Please verify your email address \")}\n <span className=\"font-semibold\">{email}</span>\n {\" (\"}\n <button\n type=\"button\"\n className=\"text-primary hover:underline\"\n onClick={() => setChangingEmail(true)}\n >\n {t(\"change\")}\n </button>\n {\"). \"}\n {t(\"Click the button below to resend the verification link.\")}\n </Typography>\n </MessageCard>\n );\n}\n\n"],"mappings":"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","names":[]}
@@ -50,7 +50,7 @@ function Inner(props) {
50
50
  } : userFromHook;
51
51
  const navigate = app.useNavigate();
52
52
  const project = app.useProject();
53
- const rawTeams = user?.useTeams();
53
+ const rawTeams = props.teams ?? user?.useTeams();
54
54
  const selectedTeam = props.team || rawTeams?.find((team) => team.id === props.teamId);
55
55
  const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);
56
56
  return /* @__PURE__ */ jsxs(
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/team-switcher.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { StackAssertionError } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport {\n Button,\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Typography,\n cn,\n} from \"@stackframe/stack-ui\";\nimport { PlusCircle, Settings } from \"lucide-react\";\nimport { Suspense, useMemo } from \"react\";\nimport { Team, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { TeamIcon } from \"./team-icon\";\n\ntype MockTeam = {\n id: string,\n displayName: string,\n profileImageUrl?: string | null,\n};\n\ntype TeamSwitcherProps<AllowNull extends boolean = false> = {\n team?: Team,\n teamId?: string,\n allowNull?: AllowNull,\n nullLabel?: string,\n triggerClassName?: string,\n onChange?: (team: AllowNull extends true ? Team | null : Team) => Promise<void>,\n // Mock data props\n mockUser?: {\n team?: MockTeam,\n },\n mockTeams?: MockTeam[],\n mockProject?: {\n config: {\n clientTeamCreationEnabled: boolean,\n },\n },\n};\n\nexport function TeamSwitcher<AllowNull extends boolean = false>(props: TeamSwitcherProps<AllowNull>) {\n return <Suspense fallback={<Fallback />}>\n <Inner {...props} />\n </Suspense>;\n}\n\nfunction Fallback() {\n return <Skeleton className=\"h-9 w-full max-w-64 stack-scope\" />;\n}\n\nfunction Inner<AllowNull extends boolean>(props: TeamSwitcherProps<AllowNull>) {\n const { t } = useTranslation();\n const appFromHook = useStackApp();\n const userFromHook = useUser();\n\n // Use mock data if provided, otherwise use real data\n const app = props.mockUser ? {\n useProject: () => props.mockProject || { config: { clientTeamCreationEnabled: false } },\n useNavigate: () => () => {}, // Mock navigate function\n urls: { accountSettings: '/account-settings' },\n } : appFromHook;\n\n const user = props.mockUser ? {\n selectedTeam: props.mockUser.team,\n useTeams: () => props.mockTeams || [],\n setSelectedTeam: async () => {}, // Mock function\n } : userFromHook;\n\n const navigate = app.useNavigate();\n const project = app.useProject();\n const rawTeams = user?.useTeams();\n const selectedTeam = props.team || rawTeams?.find(team => team.id === props.teamId);\n const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);\n\n\n return (\n <Select\n value={selectedTeam?.id || (props.allowNull ? 'null-sentinel' : undefined)}\n onValueChange={(value) => {\n runAsynchronouslyWithAlert(async () => {\n let team: MockTeam | null = null;\n if (value !== 'null-sentinel') {\n team = teams?.find(team => team.id === value) || null;\n if (!team) {\n throw new StackAssertionError('Team not found, this should not happen');\n }\n } else {\n team = null;\n }\n\n // Call onChange callback if provided\n if (props.onChange) {\n await props.onChange(team as Team);\n }\n });\n }}\n >\n <SelectTrigger className={cn(\"stack-scope max-w-64\", props.triggerClassName)}>\n <SelectValue placeholder=\"Select team\"/>\n </SelectTrigger>\n <SelectContent className=\"stack-scope\">\n {selectedTeam ? <SelectGroup>\n <SelectLabel>\n <div className=\"flex items-center justify-between\">\n <span>\n {t('Current team')}\n </span>\n <Button\n variant='ghost'\n size='icon'\n className=\"h-6 w-6\"\n onClick={() => {\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-${selectedTeam.id}`);\n }\n }}\n >\n <Settings className=\"h-4 w-4\"/>\n </Button>\n </div>\n </SelectLabel>\n <SelectItem value={selectedTeam.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={selectedTeam as Team} />\n <Typography className=\"max-w-40 truncate\">{selectedTeam.displayName}</Typography>\n </div>\n </SelectItem>\n </SelectGroup> : undefined}\n\n {props.allowNull && <SelectGroup>\n <SelectItem value=\"null-sentinel\">\n <div className=\"flex items-center gap-2\">\n <TeamIcon team='personal' />\n <Typography className=\"max-w-40 truncate\">{props.nullLabel || t('No team')}</Typography>\n </div>\n </SelectItem>\n </SelectGroup>}\n\n {teams?.length ?\n <SelectGroup>\n <SelectLabel>{t('Other teams')}</SelectLabel>\n {teams.filter(team => team.id !== selectedTeam?.id)\n .map(team => (\n <SelectItem value={team.id} key={team.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={team as Team} />\n <Typography className=\"max-w-64 truncate\">{team.displayName}</Typography>\n </div>\n </SelectItem>\n ))}\n </SelectGroup> : null}\n\n {!teams?.length && !props.allowNull ?\n <SelectGroup>\n <SelectLabel>{t('No teams yet')}</SelectLabel>\n </SelectGroup> : null}\n\n {project.config.clientTeamCreationEnabled && <>\n <SelectSeparator/>\n <div>\n <Button\n onClick={() => {\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-creation`);\n }\n }}\n className=\"w-full\"\n variant='ghost'\n >\n <PlusCircle className=\"mr-2 h-4 w-4\"/> {t('Create a team')}\n </Button>\n </div>\n </>}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":";;;AAMA,SAAS,2BAA2B;AACpC,SAAS,kCAAkC;AAC3C;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AACP,SAAS,YAAY,gBAAgB;AACrC,SAAS,UAAU,eAAe;AAClC,SAAe,aAAa,eAAe;AAC3C,SAAS,sBAAsB;AAC/B,SAAS,gBAAgB;AA4BI,SAoHwB,UApHxB,KA8DjB,YA9DiB;AADtB,SAAS,aAAgD,OAAqC;AACnG,SAAO,oBAAC,YAAS,UAAU,oBAAC,YAAS,GACnC,8BAAC,SAAO,GAAG,OAAO,GACpB;AACF;AAEA,SAAS,WAAW;AAClB,SAAO,oBAAC,YAAS,WAAU,mCAAkC;AAC/D;AAEA,SAAS,MAAiC,OAAqC;AAC7E,QAAM,EAAE,EAAE,IAAI,eAAe;AAC7B,QAAM,cAAc,YAAY;AAChC,QAAM,eAAe,QAAQ;AAG7B,QAAM,MAAM,MAAM,WAAW;AAAA,IAC3B,YAAY,MAAM,MAAM,eAAe,EAAE,QAAQ,EAAE,2BAA2B,MAAM,EAAE;AAAA,IACtF,aAAa,MAAM,MAAM;AAAA,IAAC;AAAA;AAAA,IAC1B,MAAM,EAAE,iBAAiB,oBAAoB;AAAA,EAC/C,IAAI;AAEJ,QAAM,OAAO,MAAM,WAAW;AAAA,IAC5B,cAAc,MAAM,SAAS;AAAA,IAC7B,UAAU,MAAM,MAAM,aAAa,CAAC;AAAA,IACpC,iBAAiB,YAAY;AAAA,IAAC;AAAA;AAAA,EAChC,IAAI;AAEJ,QAAM,WAAW,IAAI,YAAY;AACjC,QAAM,UAAU,IAAI,WAAW;AAC/B,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,eAAe,MAAM,QAAQ,UAAU,KAAK,UAAQ,KAAK,OAAO,MAAM,MAAM;AAClF,QAAM,QAAQ,QAAQ,MAAM,UAAU,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,cAAc,KAAK,IAAI,EAAE,GAAG,CAAC,UAAU,YAAY,CAAC;AAGlH,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAO,cAAc,OAAO,MAAM,YAAY,kBAAkB;AAAA,MAChE,eAAe,CAAC,UAAU;AACxB,mCAA2B,YAAY;AACrC,cAAI,OAAwB;AAC5B,cAAI,UAAU,iBAAiB;AAC7B,mBAAO,OAAO,KAAK,CAAAA,UAAQA,MAAK,OAAO,KAAK,KAAK;AACjD,gBAAI,CAAC,MAAM;AACT,oBAAM,IAAI,oBAAoB,wCAAwC;AAAA,YACxE;AAAA,UACF,OAAO;AACL,mBAAO;AAAA,UACT;AAGA,cAAI,MAAM,UAAU;AAClB,kBAAM,MAAM,SAAS,IAAY;AAAA,UACnC;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA;AAAA,4BAAC,iBAAc,WAAW,GAAG,wBAAwB,MAAM,gBAAgB,GACzE,8BAAC,eAAY,aAAY,eAAa,GACxC;AAAA,QACA,qBAAC,iBAAc,WAAU,eACtB;AAAA,yBAAe,qBAAC,eACf;AAAA,gCAAC,eACC,+BAAC,SAAI,WAAU,qCACb;AAAA,kCAAC,UACE,YAAE,cAAc,GACnB;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,SAAQ;AAAA,kBACR,MAAK;AAAA,kBACL,WAAU;AAAA,kBACV,SAAS,MAAM;AACb,wBAAI,CAAC,MAAM,UAAU;AACnB,+BAAS,GAAG,IAAI,KAAK,eAAe,SAAS,aAAa,EAAE,EAAE;AAAA,oBAChE;AAAA,kBACF;AAAA,kBAEA,8BAAC,YAAS,WAAU,WAAS;AAAA;AAAA,cAC/B;AAAA,eACF,GACF;AAAA,YACA,oBAAC,cAAW,OAAO,aAAa,IAC9B,+BAAC,SAAI,WAAU,2BACb;AAAA,kCAAC,YAAS,MAAM,cAAsB;AAAA,cACtC,oBAAC,cAAW,WAAU,qBAAqB,uBAAa,aAAY;AAAA,eACtE,GACF;AAAA,aACF,IAAiB;AAAA,UAEhB,MAAM,aAAa,oBAAC,eACnB,8BAAC,cAAW,OAAM,iBAChB,+BAAC,SAAI,WAAU,2BACb;AAAA,gCAAC,YAAS,MAAK,YAAW;AAAA,YAC1B,oBAAC,cAAW,WAAU,qBAAqB,gBAAM,aAAa,EAAE,SAAS,GAAE;AAAA,aAC7E,GACF,GACF;AAAA,UAEC,OAAO,SACN,qBAAC,eACC;AAAA,gCAAC,eAAa,YAAE,aAAa,GAAE;AAAA,YAC9B,MAAM,OAAO,UAAQ,KAAK,OAAO,cAAc,EAAE,EAC/C,IAAI,UACH,oBAAC,cAAW,OAAO,KAAK,IACtB,+BAAC,SAAI,WAAU,2BACb;AAAA,kCAAC,YAAS,MAAoB;AAAA,cAC9B,oBAAC,cAAW,WAAU,qBAAqB,eAAK,aAAY;AAAA,eAC9D,KAJ+B,KAAK,EAKtC,CACD;AAAA,aACL,IAAiB;AAAA,UAElB,CAAC,OAAO,UAAU,CAAC,MAAM,YACxB,oBAAC,eACC,8BAAC,eAAa,YAAE,cAAc,GAAE,GAClC,IAAiB;AAAA,UAElB,QAAQ,OAAO,6BAA6B,iCAC3C;AAAA,gCAAC,mBAAe;AAAA,YAChB,oBAAC,SACC;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS,MAAM;AACb,sBAAI,CAAC,MAAM,UAAU;AACnB,6BAAS,GAAG,IAAI,KAAK,eAAe,gBAAgB;AAAA,kBACtD;AAAA,gBACF;AAAA,gBACA,WAAU;AAAA,gBACV,SAAQ;AAAA,gBAER;AAAA,sCAAC,cAAW,WAAU,gBAAc;AAAA,kBAAE;AAAA,kBAAE,EAAE,eAAe;AAAA;AAAA;AAAA,YAC3D,GACF;AAAA,aACF;AAAA,WACF;AAAA;AAAA;AAAA,EACF;AAEJ;","names":["team"]}
1
+ {"version":3,"sources":["../../../src/components/team-switcher.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\nimport { StackAssertionError } from \"@stackframe/stack-shared/dist/utils/errors\";\nimport { runAsynchronouslyWithAlert } from \"@stackframe/stack-shared/dist/utils/promises\";\nimport {\n Button,\n Select,\n SelectContent,\n SelectGroup,\n SelectItem,\n SelectLabel,\n SelectSeparator,\n SelectTrigger,\n SelectValue,\n Skeleton,\n Typography,\n cn,\n} from \"@stackframe/stack-ui\";\nimport { PlusCircle, Settings } from \"lucide-react\";\nimport { Suspense, useMemo } from \"react\";\nimport { Team, useStackApp, useUser } from \"..\";\nimport { useTranslation } from \"../lib/translations\";\nimport { TeamIcon } from \"./team-icon\";\n\ntype MockTeam = {\n id: string,\n displayName: string,\n profileImageUrl?: string | null,\n};\n\ntype TeamSwitcherProps<AllowNull extends boolean = false> = {\n team?: Team,\n teamId?: string,\n teams?: Team[],\n allowNull?: AllowNull,\n nullLabel?: string,\n triggerClassName?: string,\n onChange?: (team: AllowNull extends true ? Team | null : Team) => Promise<void>,\n // Mock data props\n mockUser?: {\n team?: MockTeam,\n },\n mockTeams?: MockTeam[],\n mockProject?: {\n config: {\n clientTeamCreationEnabled: boolean,\n },\n },\n};\n\nexport function TeamSwitcher<AllowNull extends boolean = false>(props: TeamSwitcherProps<AllowNull>) {\n return <Suspense fallback={<Fallback />}>\n <Inner {...props} />\n </Suspense>;\n}\n\nfunction Fallback() {\n return <Skeleton className=\"h-9 w-full max-w-64 stack-scope\" />;\n}\n\nfunction Inner<AllowNull extends boolean>(props: TeamSwitcherProps<AllowNull>) {\n const { t } = useTranslation();\n const appFromHook = useStackApp();\n const userFromHook = useUser();\n\n // Use mock data if provided, otherwise use real data\n const app = props.mockUser ? {\n useProject: () => props.mockProject || { config: { clientTeamCreationEnabled: false } },\n useNavigate: () => () => {}, // Mock navigate function\n urls: { accountSettings: '/account-settings' },\n } : appFromHook;\n\n const user = props.mockUser ? {\n selectedTeam: props.mockUser.team,\n useTeams: () => props.mockTeams || [],\n setSelectedTeam: async () => {}, // Mock function\n } : userFromHook;\n\n const navigate = app.useNavigate();\n const project = app.useProject();\n const rawTeams = props.teams ?? user?.useTeams();\n const selectedTeam = props.team || rawTeams?.find(team => team.id === props.teamId);\n const teams = useMemo(() => rawTeams?.sort((a, b) => b.id === selectedTeam?.id ? 1 : -1), [rawTeams, selectedTeam]);\n\n\n return (\n <Select\n value={selectedTeam?.id || (props.allowNull ? 'null-sentinel' : undefined)}\n onValueChange={(value) => {\n runAsynchronouslyWithAlert(async () => {\n let team: MockTeam | null = null;\n if (value !== 'null-sentinel') {\n team = teams?.find(team => team.id === value) || null;\n if (!team) {\n throw new StackAssertionError('Team not found, this should not happen');\n }\n } else {\n team = null;\n }\n\n // Call onChange callback if provided\n if (props.onChange) {\n await props.onChange(team as Team);\n }\n });\n }}\n >\n <SelectTrigger className={cn(\"stack-scope max-w-64\", props.triggerClassName)}>\n <SelectValue placeholder=\"Select team\"/>\n </SelectTrigger>\n <SelectContent className=\"stack-scope\">\n {selectedTeam ? <SelectGroup>\n <SelectLabel>\n <div className=\"flex items-center justify-between\">\n <span>\n {t('Current team')}\n </span>\n <Button\n variant='ghost'\n size='icon'\n className=\"h-6 w-6\"\n onClick={() => {\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-${selectedTeam.id}`);\n }\n }}\n >\n <Settings className=\"h-4 w-4\"/>\n </Button>\n </div>\n </SelectLabel>\n <SelectItem value={selectedTeam.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={selectedTeam as Team} />\n <Typography className=\"max-w-40 truncate\">{selectedTeam.displayName}</Typography>\n </div>\n </SelectItem>\n </SelectGroup> : undefined}\n\n {props.allowNull && <SelectGroup>\n <SelectItem value=\"null-sentinel\">\n <div className=\"flex items-center gap-2\">\n <TeamIcon team='personal' />\n <Typography className=\"max-w-40 truncate\">{props.nullLabel || t('No team')}</Typography>\n </div>\n </SelectItem>\n </SelectGroup>}\n\n {teams?.length ?\n <SelectGroup>\n <SelectLabel>{t('Other teams')}</SelectLabel>\n {teams.filter(team => team.id !== selectedTeam?.id)\n .map(team => (\n <SelectItem value={team.id} key={team.id}>\n <div className=\"flex items-center gap-2\">\n <TeamIcon team={team as Team} />\n <Typography className=\"max-w-64 truncate\">{team.displayName}</Typography>\n </div>\n </SelectItem>\n ))}\n </SelectGroup> : null}\n\n {!teams?.length && !props.allowNull ?\n <SelectGroup>\n <SelectLabel>{t('No teams yet')}</SelectLabel>\n </SelectGroup> : null}\n\n {project.config.clientTeamCreationEnabled && <>\n <SelectSeparator/>\n <div>\n <Button\n onClick={() => {\n if (!props.mockUser) {\n navigate(`${app.urls.accountSettings}#team-creation`);\n }\n }}\n className=\"w-full\"\n variant='ghost'\n >\n <PlusCircle className=\"mr-2 h-4 w-4\"/> {t('Create a team')}\n </Button>\n </div>\n </>}\n </SelectContent>\n </Select>\n );\n}\n"],"mappings":"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","names":["team"]}
@@ -2,7 +2,7 @@
2
2
  "use client";
3
3
 
4
4
  // src/components-page/account-settings/payments/payments-page.tsx
5
- import { useState } from "react";
5
+ import { useEffect, useState } from "react";
6
6
  import { TeamSwitcher } from "../../../index.js";
7
7
  import { useUser } from "../../../lib/hooks.js";
8
8
  import { useTranslation } from "../../../lib/translations.js";
@@ -12,11 +12,25 @@ import { jsx, jsxs } from "react/jsx-runtime";
12
12
  function PaymentsPage(props) {
13
13
  const { t } = useTranslation();
14
14
  const user = useUser({ or: props.mockMode ? "return-null" : "redirect" });
15
- const teams = user?.useTeams() ?? [];
15
+ const teams = props.availableTeams ?? user?.useTeams() ?? [];
16
+ const allowPersonal = props.allowPersonal ?? true;
16
17
  const hasTeams = teams.length > 0;
17
18
  const [selectedTeam, setSelectedTeam] = useState(null);
18
- const customer = selectedTeam ?? user;
19
- const customerType = selectedTeam ? "team" : "user";
19
+ const effectiveSelectedTeam = selectedTeam ?? (!allowPersonal ? teams[0] ?? null : null);
20
+ const customer = effectiveSelectedTeam ?? (allowPersonal ? user : null);
21
+ const customerType = effectiveSelectedTeam ? "team" : "user";
22
+ useEffect(() => {
23
+ if (props.mockMode) {
24
+ return;
25
+ }
26
+ if (!allowPersonal && !selectedTeam && teams.length > 0) {
27
+ setSelectedTeam(teams[0]);
28
+ return;
29
+ }
30
+ if (selectedTeam && !teams.some((team) => team.id === selectedTeam.id)) {
31
+ setSelectedTeam(allowPersonal ? null : teams[0] ?? null);
32
+ }
33
+ }, [allowPersonal, props.mockMode, selectedTeam, teams]);
20
34
  if (props.mockMode) {
21
35
  return /* @__PURE__ */ jsx(PageLayout, { children: /* @__PURE__ */ jsx(
22
36
  PaymentsPanel,
@@ -32,8 +46,9 @@ function PaymentsPage(props) {
32
46
  hasTeams ? /* @__PURE__ */ jsx(
33
47
  TeamSwitcher,
34
48
  {
35
- team: selectedTeam ?? void 0,
36
- allowNull: true,
49
+ team: effectiveSelectedTeam ?? void 0,
50
+ teams,
51
+ allowNull: allowPersonal,
37
52
  nullLabel: t("Personal"),
38
53
  onChange: async (team) => {
39
54
  setSelectedTeam(team);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/components-page/account-settings/payments/payments-page.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { useState } from \"react\";\nimport { Team, TeamSwitcher } from \"../../..\";\nimport { useUser } from \"../../../lib/hooks\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { PageLayout } from \"../page-layout\";\nimport { PaymentsPanel } from \"./payments-panel\";\n\nexport function PaymentsPage(props: { mockMode?: boolean }) {\n const { t } = useTranslation();\n const user = useUser({ or: props.mockMode ? \"return-null\" : \"redirect\" });\n const teams = user?.useTeams() ?? [];\n const hasTeams = teams.length > 0;\n const [selectedTeam, setSelectedTeam] = useState<Team | null>(null);\n const customer = selectedTeam ?? user;\n const customerType = selectedTeam ? \"team\" : \"user\";\n\n if (props.mockMode) {\n return (\n <PageLayout>\n <PaymentsPanel\n mockMode\n />\n </PageLayout>\n );\n }\n\n if (!customer) {\n return null;\n }\n\n\n return (\n <PageLayout>\n {hasTeams ? (\n <TeamSwitcher\n team={selectedTeam ?? undefined}\n allowNull\n nullLabel={t(\"Personal\")}\n onChange={async (team) => {\n setSelectedTeam(team);\n }}\n />\n ) : null}\n <PaymentsPanel\n customer={customer}\n customerType={customerType}\n />\n </PageLayout>\n );\n}\n"],"mappings":";;;AAOA,SAAS,gBAAgB;AACzB,SAAe,oBAAoB;AACnC,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AActB,cAaJ,YAbI;AAZD,SAAS,aAAa,OAA+B;AAC1D,QAAM,EAAE,EAAE,IAAI,eAAe;AAC7B,QAAM,OAAO,QAAQ,EAAE,IAAI,MAAM,WAAW,gBAAgB,WAAW,CAAC;AACxE,QAAM,QAAQ,MAAM,SAAS,KAAK,CAAC;AACnC,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,CAAC,cAAc,eAAe,IAAI,SAAsB,IAAI;AAClE,QAAM,WAAW,gBAAgB;AACjC,QAAM,eAAe,eAAe,SAAS;AAE7C,MAAI,MAAM,UAAU;AAClB,WACE,oBAAC,cACC;AAAA,MAAC;AAAA;AAAA,QACC,UAAQ;AAAA;AAAA,IACV,GACF;AAAA,EAEJ;AAEA,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAGA,SACE,qBAAC,cACE;AAAA,eACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,gBAAgB;AAAA,QACtB,WAAS;AAAA,QACT,WAAW,EAAE,UAAU;AAAA,QACvB,UAAU,OAAO,SAAS;AACxB,0BAAgB,IAAI;AAAA,QACtB;AAAA;AAAA,IACF,IACE;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../../src/components-page/account-settings/payments/payments-page.tsx"],"sourcesContent":["'use client';\n\n\n//===========================================\n// THIS FILE IS AUTO-GENERATED FROM TEMPLATE. DO NOT EDIT IT DIRECTLY, INSTEAD EDIT THE CORRESPONDING FILE IN packages/template\n//===========================================\n\nimport { useEffect, useState } from \"react\";\nimport { Team, TeamSwitcher } from \"../../..\";\nimport { useUser } from \"../../../lib/hooks\";\nimport { useTranslation } from \"../../../lib/translations\";\nimport { PageLayout } from \"../page-layout\";\nimport { PaymentsPanel } from \"./payments-panel\";\n\nexport function PaymentsPage(props: { mockMode?: boolean, availableTeams?: Team[], allowPersonal?: boolean }) {\n const { t } = useTranslation();\n const user = useUser({ or: props.mockMode ? \"return-null\" : \"redirect\" });\n const teams = props.availableTeams ?? user?.useTeams() ?? [];\n const allowPersonal = props.allowPersonal ?? true;\n const hasTeams = teams.length > 0;\n const [selectedTeam, setSelectedTeam] = useState<Team | null>(null);\n const effectiveSelectedTeam = selectedTeam ?? (!allowPersonal ? (teams[0] ?? null) : null);\n const customer = effectiveSelectedTeam ?? (allowPersonal ? user : null);\n const customerType = effectiveSelectedTeam ? \"team\" : \"user\";\n\n useEffect(() => {\n if (props.mockMode) {\n return;\n }\n if (!allowPersonal && !selectedTeam && teams.length > 0) {\n setSelectedTeam(teams[0]);\n return;\n }\n if (selectedTeam && !teams.some(team => team.id === selectedTeam.id)) {\n setSelectedTeam(allowPersonal ? null : (teams[0] ?? null));\n }\n }, [allowPersonal, props.mockMode, selectedTeam, teams]);\n\n if (props.mockMode) {\n return (\n <PageLayout>\n <PaymentsPanel\n mockMode\n />\n </PageLayout>\n );\n }\n\n if (!customer) {\n return null;\n }\n\n\n return (\n <PageLayout>\n {hasTeams ? (\n <TeamSwitcher\n team={effectiveSelectedTeam ?? undefined}\n teams={teams}\n allowNull={allowPersonal}\n nullLabel={t(\"Personal\")}\n onChange={async (team) => {\n setSelectedTeam(team);\n }}\n />\n ) : null}\n <PaymentsPanel\n customer={customer}\n customerType={customerType}\n />\n </PageLayout>\n );\n}\n"],"mappings":";;;AAOA,SAAS,WAAW,gBAAgB;AACpC,SAAe,oBAAoB;AACnC,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AA6BtB,cAaJ,YAbI;AA3BD,SAAS,aAAa,OAAiF;AAC5G,QAAM,EAAE,EAAE,IAAI,eAAe;AAC7B,QAAM,OAAO,QAAQ,EAAE,IAAI,MAAM,WAAW,gBAAgB,WAAW,CAAC;AACxE,QAAM,QAAQ,MAAM,kBAAkB,MAAM,SAAS,KAAK,CAAC;AAC3D,QAAM,gBAAgB,MAAM,iBAAiB;AAC7C,QAAM,WAAW,MAAM,SAAS;AAChC,QAAM,CAAC,cAAc,eAAe,IAAI,SAAsB,IAAI;AAClE,QAAM,wBAAwB,iBAAiB,CAAC,gBAAiB,MAAM,CAAC,KAAK,OAAQ;AACrF,QAAM,WAAW,0BAA0B,gBAAgB,OAAO;AAClE,QAAM,eAAe,wBAAwB,SAAS;AAEtD,YAAU,MAAM;AACd,QAAI,MAAM,UAAU;AAClB;AAAA,IACF;AACA,QAAI,CAAC,iBAAiB,CAAC,gBAAgB,MAAM,SAAS,GAAG;AACvD,sBAAgB,MAAM,CAAC,CAAC;AACxB;AAAA,IACF;AACA,QAAI,gBAAgB,CAAC,MAAM,KAAK,UAAQ,KAAK,OAAO,aAAa,EAAE,GAAG;AACpE,sBAAgB,gBAAgB,OAAQ,MAAM,CAAC,KAAK,IAAK;AAAA,IAC3D;AAAA,EACF,GAAG,CAAC,eAAe,MAAM,UAAU,cAAc,KAAK,CAAC;AAEvD,MAAI,MAAM,UAAU;AAClB,WACE,oBAAC,cACC;AAAA,MAAC;AAAA;AAAA,QACC,UAAQ;AAAA;AAAA,IACV,GACF;AAAA,EAEJ;AAEA,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAGA,SACE,qBAAC,cACE;AAAA,eACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAM,yBAAyB;AAAA,QAC/B;AAAA,QACA,WAAW;AAAA,QACX,WAAW,EAAE,UAAU;AAAA,QACvB,UAAU,OAAO,SAAS;AACxB,0BAAgB,IAAI;AAAA,QACtB;AAAA;AAAA,IACF,IACE;AAAA,IACJ;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA;AAAA;AAAA,IACF;AAAA,KACF;AAEJ;","names":[]}