@nextsparkjs/core 0.1.0-beta.68 → 0.1.0-beta.69

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 (152) hide show
  1. package/dist/components/settings/layouts/SettingsSidebar.d.ts.map +1 -1
  2. package/dist/components/settings/layouts/SettingsSidebar.js +14 -0
  3. package/dist/components/ui/index.d.ts +7 -0
  4. package/dist/components/ui/index.d.ts.map +1 -1
  5. package/dist/components/ui/index.js +7 -0
  6. package/dist/components/ui/skeleton-dashboard.d.ts +32 -0
  7. package/dist/components/ui/skeleton-dashboard.d.ts.map +1 -0
  8. package/dist/components/ui/skeleton-dashboard.js +69 -0
  9. package/dist/components/ui/skeleton-detail.d.ts.map +1 -1
  10. package/dist/components/ui/skeleton-detail.js +0 -1
  11. package/dist/components/ui/skeleton-features.d.ts +27 -0
  12. package/dist/components/ui/skeleton-features.d.ts.map +1 -0
  13. package/dist/components/ui/skeleton-features.js +90 -0
  14. package/dist/components/ui/skeleton-form.d.ts.map +1 -1
  15. package/dist/components/ui/skeleton-form.js +0 -1
  16. package/dist/components/ui/skeleton-list.d.ts.map +1 -1
  17. package/dist/components/ui/skeleton-list.js +0 -1
  18. package/dist/components/ui/skeleton-public.d.ts +26 -0
  19. package/dist/components/ui/skeleton-public.d.ts.map +1 -0
  20. package/dist/components/ui/skeleton-public.js +61 -0
  21. package/dist/components/ui/skeleton-settings.d.ts +54 -0
  22. package/dist/components/ui/skeleton-settings.d.ts.map +1 -0
  23. package/dist/components/ui/skeleton-settings.js +332 -0
  24. package/dist/components/ui/skeleton.d.ts +23 -1
  25. package/dist/components/ui/skeleton.d.ts.map +1 -1
  26. package/dist/components/ui/skeleton.js +46 -2
  27. package/dist/contexts/TeamContext.d.ts +2 -0
  28. package/dist/contexts/TeamContext.d.ts.map +1 -1
  29. package/dist/contexts/TeamContext.js +78 -68
  30. package/dist/hooks/usePrefetch.d.ts +43 -0
  31. package/dist/hooks/usePrefetch.d.ts.map +1 -0
  32. package/dist/hooks/usePrefetch.js +56 -0
  33. package/dist/lib/actions/index.d.ts +27 -14
  34. package/dist/lib/actions/index.d.ts.map +1 -1
  35. package/dist/lib/actions/index.js +19 -1
  36. package/dist/lib/actions/team.actions.d.ts +107 -0
  37. package/dist/lib/actions/team.actions.d.ts.map +1 -0
  38. package/dist/lib/actions/team.actions.js +220 -0
  39. package/dist/lib/actions/user.actions.d.ts +99 -0
  40. package/dist/lib/actions/user.actions.d.ts.map +1 -0
  41. package/dist/lib/actions/user.actions.js +149 -0
  42. package/dist/messages/de/devtools.json +4 -0
  43. package/dist/messages/de/index.d.ts +4 -0
  44. package/dist/messages/de/index.d.ts.map +1 -1
  45. package/dist/messages/en/devtools.json +16 -0
  46. package/dist/messages/en/index.d.ts +16 -0
  47. package/dist/messages/en/index.d.ts.map +1 -1
  48. package/dist/messages/es/devtools.json +4 -0
  49. package/dist/messages/es/index.d.ts +4 -0
  50. package/dist/messages/es/index.d.ts.map +1 -1
  51. package/dist/messages/fr/devtools.json +4 -0
  52. package/dist/messages/fr/index.d.ts +4 -0
  53. package/dist/messages/fr/index.d.ts.map +1 -1
  54. package/dist/messages/it/devtools.json +4 -0
  55. package/dist/messages/it/index.d.ts +4 -0
  56. package/dist/messages/it/index.d.ts.map +1 -1
  57. package/dist/messages/pt/devtools.json +4 -0
  58. package/dist/messages/pt/index.d.ts +4 -0
  59. package/dist/messages/pt/index.d.ts.map +1 -1
  60. package/dist/nextspark-entities.d.ts +59 -0
  61. package/dist/styles/classes.json +15 -2
  62. package/dist/styles/ui.css +1 -1
  63. package/dist/templates/app/(public)/[...slug]/page.tsx +2 -1
  64. package/dist/templates/app/(public)/docs/[section]/[page]/page.tsx +1 -1
  65. package/dist/templates/app/api/devtools/config/entities/route.ts +2 -1
  66. package/dist/templates/app/api/user/plan-flags/route.ts +1 -1
  67. package/dist/templates/app/api/v1/[entity]/[id]/child/[childType]/[childId]/route.ts +4 -2
  68. package/dist/templates/app/dashboard/(main)/layout.tsx +2 -1
  69. package/dist/templates/app/dashboard/(main)/loading.tsx +5 -0
  70. package/dist/templates/app/dashboard/features/loading.tsx +5 -0
  71. package/dist/templates/app/dashboard/settings/api-keys/loading.tsx +5 -0
  72. package/dist/templates/app/dashboard/settings/billing/loading.tsx +5 -0
  73. package/dist/templates/app/dashboard/settings/invoices/loading.tsx +5 -0
  74. package/dist/templates/app/dashboard/settings/loading.tsx +5 -0
  75. package/dist/templates/app/dashboard/settings/notifications/loading.tsx +5 -0
  76. package/dist/templates/app/dashboard/settings/password/loading.tsx +5 -0
  77. package/dist/templates/app/dashboard/settings/plans/loading.tsx +5 -0
  78. package/dist/templates/app/dashboard/settings/profile/loading.tsx +5 -0
  79. package/dist/templates/app/dashboard/settings/security/loading.tsx +5 -0
  80. package/dist/templates/app/dashboard/settings/teams/loading.tsx +5 -0
  81. package/dist/templates/app/devtools/config/page.tsx +1 -1
  82. package/dist/templates/app/devtools/page.tsx +1 -1
  83. package/dist/templates/app/devtools/tests/[[...path]]/page.tsx +1 -1
  84. package/dist/templates/contents/themes/starter/messages/de/common.json +4 -1
  85. package/dist/templates/contents/themes/starter/messages/de/index.ts +15 -0
  86. package/dist/templates/contents/themes/starter/messages/en/common.json +4 -1
  87. package/dist/templates/contents/themes/starter/messages/en/index.ts +15 -0
  88. package/dist/templates/contents/themes/starter/messages/es/common.json +4 -1
  89. package/dist/templates/contents/themes/starter/messages/es/index.ts +15 -0
  90. package/dist/templates/contents/themes/starter/messages/fr/common.json +4 -1
  91. package/dist/templates/contents/themes/starter/messages/fr/index.ts +15 -0
  92. package/dist/templates/contents/themes/starter/messages/it/common.json +4 -1
  93. package/dist/templates/contents/themes/starter/messages/it/index.ts +13 -0
  94. package/dist/templates/contents/themes/starter/messages/pt/common.json +4 -1
  95. package/dist/templates/contents/themes/starter/messages/pt/index.ts +13 -0
  96. package/dist/templates/contents/themes/starter/styles/globals.css +3 -1
  97. package/dist/templates/contents/themes/starter/templates/(dashboard)/analytics/loading.tsx +5 -0
  98. package/dist/templates/contents/themes/starter/templates/(public)/loading.tsx +5 -0
  99. package/dist/templates/next.config.mjs +5 -0
  100. package/dist/templates/{middleware.ts → proxy.ts} +5 -6
  101. package/globals.css +54 -0
  102. package/nextspark-entities.d.ts +59 -0
  103. package/package.json +14 -13
  104. package/scripts/build/registry/discovery/api-presets.mjs +20 -12
  105. package/scripts/build/registry/generators/api-presets-registry.mjs +18 -5
  106. package/scripts/build/registry/generators/block-registry.mjs +14 -3
  107. package/scripts/build/registry/generators/docs-registry.mjs +21 -3
  108. package/scripts/build/registry/generators/translation-registry.mjs +16 -7
  109. package/scripts/build/theme.mjs +2 -1
  110. package/templates/app/(public)/[...slug]/page.tsx +2 -1
  111. package/templates/app/(public)/docs/[section]/[page]/page.tsx +1 -1
  112. package/templates/app/api/auth/[...all]/route.ts +13 -5
  113. package/templates/app/api/devtools/config/entities/route.ts +2 -1
  114. package/templates/app/api/user/plan-flags/route.ts +1 -1
  115. package/templates/app/api/v1/[entity]/[id]/child/[childType]/[childId]/route.ts +4 -2
  116. package/templates/app/dashboard/(main)/layout.tsx +2 -1
  117. package/templates/app/dashboard/(main)/loading.tsx +5 -0
  118. package/templates/app/dashboard/features/loading.tsx +5 -0
  119. package/templates/app/dashboard/settings/api-keys/loading.tsx +5 -0
  120. package/templates/app/dashboard/settings/billing/loading.tsx +5 -0
  121. package/templates/app/dashboard/settings/invoices/loading.tsx +5 -0
  122. package/templates/app/dashboard/settings/loading.tsx +5 -0
  123. package/templates/app/dashboard/settings/notifications/loading.tsx +5 -0
  124. package/templates/app/dashboard/settings/password/loading.tsx +5 -0
  125. package/templates/app/dashboard/settings/plans/loading.tsx +5 -0
  126. package/templates/app/dashboard/settings/profile/loading.tsx +5 -0
  127. package/templates/app/dashboard/settings/security/loading.tsx +5 -0
  128. package/templates/app/dashboard/settings/teams/loading.tsx +5 -0
  129. package/templates/app/devtools/config/page.tsx +1 -1
  130. package/templates/app/devtools/page.tsx +1 -1
  131. package/templates/app/devtools/tests/[[...path]]/page.tsx +1 -1
  132. package/templates/contents/themes/starter/config/app.config.ts +8 -7
  133. package/templates/contents/themes/starter/messages/de/common.json +4 -1
  134. package/templates/contents/themes/starter/messages/de/index.ts +15 -0
  135. package/templates/contents/themes/starter/messages/en/common.json +4 -1
  136. package/templates/contents/themes/starter/messages/en/index.ts +15 -0
  137. package/templates/contents/themes/starter/messages/es/common.json +4 -1
  138. package/templates/contents/themes/starter/messages/es/index.ts +15 -0
  139. package/templates/contents/themes/starter/messages/fr/common.json +4 -1
  140. package/templates/contents/themes/starter/messages/fr/index.ts +15 -0
  141. package/templates/contents/themes/starter/messages/it/common.json +4 -1
  142. package/templates/contents/themes/starter/messages/it/index.ts +13 -0
  143. package/templates/contents/themes/starter/messages/pt/common.json +4 -1
  144. package/templates/contents/themes/starter/messages/pt/index.ts +13 -0
  145. package/templates/contents/themes/starter/styles/globals.css +3 -1
  146. package/templates/contents/themes/starter/templates/(dashboard)/analytics/loading.tsx +5 -0
  147. package/templates/contents/themes/starter/templates/(public)/loading.tsx +5 -0
  148. package/templates/next.config.mjs +5 -0
  149. package/templates/pnpm-workspace.yaml +5 -0
  150. package/templates/{middleware.ts → proxy.ts} +5 -6
  151. package/tests/jest/setup.ts +5 -0
  152. package/dist/presets/plugin/.env.example.template +0 -19
@@ -0,0 +1,332 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Card, CardContent, CardHeader } from "./card.js";
3
+ import { Skeleton, SkeletonContainer } from "./skeleton.js";
4
+ function SkeletonSettingsNavCard() {
5
+ return /* @__PURE__ */ jsx("div", { className: "block p-6 rounded-lg border border-border bg-card", children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-4", children: [
6
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-5 flex-shrink-0" }),
7
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0 space-y-2", children: [
8
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-32" }),
9
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
10
+ ] })
11
+ ] }) });
12
+ }
13
+ function SkeletonSettingsOverview() {
14
+ return /* @__PURE__ */ jsx("div", { "data-cy": "skeleton-settings-overview", className: "max-w-2xl", children: /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
15
+ /* @__PURE__ */ jsxs("header", { children: [
16
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-48 mb-2" }),
17
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-72" })
18
+ ] }),
19
+ /* @__PURE__ */ jsxs(SkeletonContainer, { className: "space-y-4", children: [
20
+ /* @__PURE__ */ jsx(SkeletonSettingsNavCard, {}),
21
+ /* @__PURE__ */ jsx(SkeletonSettingsNavCard, {}),
22
+ /* @__PURE__ */ jsx(SkeletonSettingsNavCard, {}),
23
+ /* @__PURE__ */ jsx(SkeletonSettingsNavCard, {}),
24
+ /* @__PURE__ */ jsx(SkeletonSettingsNavCard, {}),
25
+ /* @__PURE__ */ jsx(SkeletonSettingsNavCard, {})
26
+ ] })
27
+ ] }) });
28
+ }
29
+ function SkeletonProfileForm() {
30
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-profile-form", className: "max-w-4xl space-y-6", children: [
31
+ /* @__PURE__ */ jsxs("header", { children: [
32
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-32 mb-2" }),
33
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-64" })
34
+ ] }),
35
+ /* @__PURE__ */ jsxs(Card, { children: [
36
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
37
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
38
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-5" }),
39
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-40" })
40
+ ] }),
41
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-56" })
42
+ ] }),
43
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-6", children: [
44
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 sm:grid-cols-2", children: [
45
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
46
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
47
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
48
+ ] }),
49
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
50
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
51
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
52
+ ] })
53
+ ] }),
54
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 grid-cols-1 md:grid-cols-4", children: [
55
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 md:col-span-2", children: [
56
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }),
57
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" }),
58
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-3 w-48" })
59
+ ] }),
60
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
61
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
62
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 py-2", children: [
63
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4" }),
64
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" })
65
+ ] })
66
+ ] }),
67
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
68
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-28" }),
69
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 py-2", children: [
70
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4" }),
71
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" })
72
+ ] })
73
+ ] })
74
+ ] }),
75
+ /* @__PURE__ */ jsxs("div", { className: "grid gap-4 grid-cols-1 md:grid-cols-10", children: [
76
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 md:col-span-2", children: [
77
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }),
78
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
79
+ ] }),
80
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 md:col-span-3", children: [
81
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-12" }),
82
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
83
+ ] }),
84
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 md:col-span-5", children: [
85
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
86
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
87
+ ] })
88
+ ] }),
89
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col md:flex-row md:justify-between md:items-center gap-4 pt-2", children: [
90
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
91
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4" }),
92
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" })
93
+ ] }),
94
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-32" })
95
+ ] })
96
+ ] })
97
+ ] })
98
+ ] });
99
+ }
100
+ function SkeletonBillingPage() {
101
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-billing-page", className: "max-w-4xl space-y-6", children: [
102
+ /* @__PURE__ */ jsxs("header", { children: [
103
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-48 mb-2" }),
104
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-64" })
105
+ ] }),
106
+ /* @__PURE__ */ jsxs(Card, { children: [
107
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
108
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-32" }),
109
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
110
+ ] }),
111
+ /* @__PURE__ */ jsx(CardContent, { className: "space-y-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
112
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
113
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-24" }),
114
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" })
115
+ ] }),
116
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-32" })
117
+ ] }) })
118
+ ] }),
119
+ /* @__PURE__ */ jsx(SkeletonContainer, { className: "grid gap-4 md:grid-cols-3", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs(Card, { children: [
120
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
121
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-20" }),
122
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1", children: [
123
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-16" }),
124
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-12" })
125
+ ] })
126
+ ] }),
127
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
128
+ /* @__PURE__ */ jsx("div", { className: "space-y-2", children: Array.from({ length: 4 }).map((_2, j) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
129
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4" }),
130
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" })
131
+ ] }, j)) }),
132
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
133
+ ] })
134
+ ] }, i)) })
135
+ ] });
136
+ }
137
+ function SkeletonPasswordPage() {
138
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-password-page", className: "max-w-xl space-y-6", children: [
139
+ /* @__PURE__ */ jsxs("header", { children: [
140
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-40 mb-2" }),
141
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-56" })
142
+ ] }),
143
+ /* @__PURE__ */ jsxs(Card, { children: [
144
+ /* @__PURE__ */ jsx(CardHeader, { children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
145
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-5" }),
146
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-36" })
147
+ ] }) }),
148
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
149
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
150
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-32" }),
151
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
152
+ ] }),
153
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
154
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-28" }),
155
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
156
+ ] }),
157
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
158
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-36" }),
159
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
160
+ ] }),
161
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
162
+ ] })
163
+ ] })
164
+ ] });
165
+ }
166
+ function SkeletonSecurityPage() {
167
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-security-page", className: "max-w-4xl space-y-6", children: [
168
+ /* @__PURE__ */ jsxs("header", { children: [
169
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-32 mb-2" }),
170
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-64" })
171
+ ] }),
172
+ /* @__PURE__ */ jsxs(Card, { children: [
173
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
174
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-36" }),
175
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-56" })
176
+ ] }),
177
+ /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(SkeletonContainer, { className: "space-y-4", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 border rounded-lg", children: [
178
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
179
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-10 rounded-lg" }),
180
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
181
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-32" }),
182
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
183
+ ] })
184
+ ] }),
185
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" })
186
+ ] }, i)) }) })
187
+ ] })
188
+ ] });
189
+ }
190
+ function SkeletonApiKeysPage() {
191
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-api-keys-page", className: "max-w-4xl space-y-6", children: [
192
+ /* @__PURE__ */ jsxs("header", { className: "flex items-center justify-between", children: [
193
+ /* @__PURE__ */ jsxs("div", { children: [
194
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-32 mb-2" }),
195
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-64" })
196
+ ] }),
197
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-32" })
198
+ ] }),
199
+ /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: "p-0", children: /* @__PURE__ */ jsx(SkeletonContainer, { className: "divide-y", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4", children: [
200
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-4", children: [
201
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-5" }),
202
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
203
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-32" }),
204
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
205
+ ] })
206
+ ] }),
207
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
208
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-16" }),
209
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-8" })
210
+ ] })
211
+ ] }, i)) }) }) })
212
+ ] });
213
+ }
214
+ function SkeletonNotificationsPage() {
215
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-notifications-page", className: "max-w-2xl space-y-6", children: [
216
+ /* @__PURE__ */ jsxs("header", { children: [
217
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-36 mb-2" }),
218
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-64" })
219
+ ] }),
220
+ /* @__PURE__ */ jsx(SkeletonContainer, { className: "space-y-4", children: Array.from({ length: 4 }).map((_, i) => /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsx(CardContent, { className: "p-4", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
221
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
222
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-40" }),
223
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-56" })
224
+ ] }),
225
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-12 rounded-full" })
226
+ ] }) }) }, i)) })
227
+ ] });
228
+ }
229
+ function SkeletonTeamsPage() {
230
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-teams-page", className: "max-w-4xl space-y-6", children: [
231
+ /* @__PURE__ */ jsxs("header", { children: [
232
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-32 mb-2" }),
233
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-64" })
234
+ ] }),
235
+ /* @__PURE__ */ jsxs(Card, { children: [
236
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
237
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
238
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
239
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-5" }),
240
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-32" })
241
+ ] }),
242
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-9 w-32" })
243
+ ] }),
244
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-48" })
245
+ ] }),
246
+ /* @__PURE__ */ jsx(CardContent, { children: /* @__PURE__ */ jsx(SkeletonContainer, { className: "space-y-2", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-4 rounded-lg border", children: [
247
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
248
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-10 rounded-full" }),
249
+ /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
250
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-32" }),
251
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" })
252
+ ] })
253
+ ] }),
254
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
255
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-16 rounded-full" }),
256
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4" })
257
+ ] })
258
+ ] }, i)) }) })
259
+ ] })
260
+ ] });
261
+ }
262
+ function SkeletonInvoicesPage() {
263
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-invoices-page", className: "max-w-4xl space-y-6", children: [
264
+ /* @__PURE__ */ jsxs("header", { children: [
265
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-40 mb-2" }),
266
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-64" })
267
+ ] }),
268
+ /* @__PURE__ */ jsxs(Card, { children: [
269
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
270
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
271
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-5" }),
272
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-36" })
273
+ ] }),
274
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-56" })
275
+ ] }),
276
+ /* @__PURE__ */ jsxs(CardContent, { children: [
277
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3 border-b bg-muted/50", children: [
278
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
279
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
280
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }),
281
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-20" }),
282
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" })
283
+ ] }),
284
+ /* @__PURE__ */ jsx(SkeletonContainer, { className: "divide-y", children: Array.from({ length: 5 }).map((_, i) => /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between p-3", children: [
285
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-28" }),
286
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-24" }),
287
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-16" }),
288
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-16 rounded-full" }),
289
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-8 w-20" })
290
+ ] }, i)) })
291
+ ] })
292
+ ] })
293
+ ] });
294
+ }
295
+ function SkeletonPlansPage() {
296
+ return /* @__PURE__ */ jsxs("div", { "data-cy": "skeleton-plans-page", className: "max-w-6xl space-y-6", children: [
297
+ /* @__PURE__ */ jsxs("header", { className: "text-center", children: [
298
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-64 mx-auto mb-2" }),
299
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-5 w-96 mx-auto" })
300
+ ] }),
301
+ /* @__PURE__ */ jsx(SkeletonContainer, { className: "grid gap-6 md:grid-cols-3", children: Array.from({ length: 3 }).map((_, i) => /* @__PURE__ */ jsxs(Card, { className: i === 1 ? "border-primary" : "", children: [
302
+ /* @__PURE__ */ jsxs(CardHeader, { children: [
303
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-6 w-20" }),
304
+ /* @__PURE__ */ jsxs("div", { className: "flex items-baseline gap-1 mt-2", children: [
305
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-16" }),
306
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-12" })
307
+ ] }),
308
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-full mt-2" })
309
+ ] }),
310
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-4", children: [
311
+ /* @__PURE__ */ jsx("div", { className: "space-y-3", children: Array.from({ length: 5 }).map((_2, j) => /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
312
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-4" }),
313
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-4 w-40" })
314
+ ] }, j)) }),
315
+ /* @__PURE__ */ jsx(Skeleton, { className: "h-10 w-full" })
316
+ ] })
317
+ ] }, i)) })
318
+ ] });
319
+ }
320
+ export {
321
+ SkeletonApiKeysPage,
322
+ SkeletonBillingPage,
323
+ SkeletonInvoicesPage,
324
+ SkeletonNotificationsPage,
325
+ SkeletonPasswordPage,
326
+ SkeletonPlansPage,
327
+ SkeletonProfileForm,
328
+ SkeletonSecurityPage,
329
+ SkeletonSettingsNavCard,
330
+ SkeletonSettingsOverview,
331
+ SkeletonTeamsPage
332
+ };
@@ -1,3 +1,25 @@
1
+ /**
2
+ * Optimized Skeleton component for improved INP (Interaction to Next Paint)
3
+ *
4
+ * Performance optimizations:
5
+ * - CSS containment isolates layout/paint calculations
6
+ * - content-visibility:auto skips rendering for off-screen elements
7
+ * - GPU-accelerated opacity animation with will-change hint
8
+ * - will-change hint pre-optimizes composition layer
9
+ * - Respects prefers-reduced-motion for accessibility
10
+ */
1
11
  declare function Skeleton({ className, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
2
- export { Skeleton };
12
+ /**
13
+ * SkeletonContainer - Wraps multiple skeletons with content-visibility optimization
14
+ * Use this for lists or grids of skeleton items to improve rendering performance
15
+ */
16
+ declare function SkeletonContainer({ className, children, ...props }: React.HTMLAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
17
+ /**
18
+ * SkeletonText - Optimized skeleton for text content
19
+ * Pre-sized for common text patterns to reduce layout shift
20
+ */
21
+ declare function SkeletonText({ className, lines, ...props }: React.HTMLAttributes<HTMLDivElement> & {
22
+ lines?: number;
23
+ }): import("react/jsx-runtime").JSX.Element;
24
+ export { Skeleton, SkeletonContainer, SkeletonText };
3
25
  //# sourceMappingURL=skeleton.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/ui/skeleton.tsx"],"names":[],"mappings":"AAEA,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,2CAOtC;AAED,OAAO,EAAE,QAAQ,EAAE,CAAA"}
1
+ {"version":3,"file":"skeleton.d.ts","sourceRoot":"","sources":["../../../src/components/ui/skeleton.tsx"],"names":[],"mappings":"AAEA;;;;;;;;;GASG;AACH,iBAAS,QAAQ,CAAC,EAChB,SAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,2CAetC;AAED;;;GAGG;AACH,iBAAS,iBAAiB,CAAC,EACzB,SAAS,EACT,QAAQ,EACR,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,2CAYtC;AAED;;;GAGG;AACH,iBAAS,YAAY,CAAC,EACpB,SAAS,EACT,KAAS,EACT,GAAG,KAAK,EACT,EAAE,KAAK,CAAC,cAAc,CAAC,cAAc,CAAC,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,2CAe3D;AAED,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,YAAY,EAAE,CAAA"}
@@ -7,11 +7,55 @@ function Skeleton({
7
7
  return /* @__PURE__ */ jsx(
8
8
  "div",
9
9
  {
10
- className: cn("animate-pulse rounded-md bg-muted", className),
10
+ className: cn(
11
+ // Base styles
12
+ "rounded-md bg-muted",
13
+ // Optimized animation - GPU accelerated
14
+ "animate-skeleton-pulse",
15
+ // CSS containment for better INP
16
+ "skeleton-contained",
17
+ className
18
+ ),
11
19
  ...props
12
20
  }
13
21
  );
14
22
  }
23
+ function SkeletonContainer({
24
+ className,
25
+ children,
26
+ ...props
27
+ }) {
28
+ return /* @__PURE__ */ jsx(
29
+ "div",
30
+ {
31
+ className: cn(
32
+ "skeleton-container",
33
+ className
34
+ ),
35
+ ...props,
36
+ children
37
+ }
38
+ );
39
+ }
40
+ function SkeletonText({
41
+ className,
42
+ lines = 1,
43
+ ...props
44
+ }) {
45
+ return /* @__PURE__ */ jsx("div", { className: cn("space-y-2", className), ...props, children: Array.from({ length: lines }).map((_, i) => /* @__PURE__ */ jsx(
46
+ Skeleton,
47
+ {
48
+ className: cn(
49
+ "h-4",
50
+ // Last line is typically shorter
51
+ i === lines - 1 && lines > 1 ? "w-3/4" : "w-full"
52
+ )
53
+ },
54
+ i
55
+ )) });
56
+ }
15
57
  export {
16
- Skeleton
58
+ Skeleton,
59
+ SkeletonContainer,
60
+ SkeletonText
17
61
  };
@@ -9,6 +9,8 @@ interface TeamContextValue {
9
9
  switchTeam: (teamId: string) => Promise<void>;
10
10
  refreshTeams: () => Promise<void>;
11
11
  }
12
+ export declare const TEAMS_QUERY_KEY: readonly ["user-teams"];
13
+ export declare function fetchUserTeams(): Promise<UserTeamMembership[]>;
12
14
  export declare function TeamProvider({ children }: {
13
15
  children: ReactNode;
14
16
  }): import("react/jsx-runtime").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"TeamContext.d.ts","sourceRoot":"","sources":["../../src/contexts/TeamContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAA+D,SAAS,EAAE,MAAM,OAAO,CAAA;AAG9F,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAM7D,UAAU,gBAAgB;IACxB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB,EAAE,OAAO,CAAA;IACjC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAClC;AAID,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAsLjE;AAED,wBAAgB,cAAc,qBAM7B"}
1
+ {"version":3,"file":"TeamContext.d.ts","sourceRoot":"","sources":["../../src/contexts/TeamContext.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAwE,SAAS,EAAE,MAAM,OAAO,CAAA;AAGvG,OAAO,EAAE,IAAI,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAM7D,UAAU,gBAAgB;IACxB,WAAW,EAAE,IAAI,GAAG,IAAI,CAAA;IACxB,SAAS,EAAE,kBAAkB,EAAE,CAAA;IAC/B,SAAS,EAAE,OAAO,CAAA;IAClB,WAAW,EAAE,OAAO,CAAA;IACpB,wBAAwB,EAAE,OAAO,CAAA;IACjC,UAAU,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAClC;AAKD,eAAO,MAAM,eAAe,yBAA0B,CAAA;AAGtD,wBAAsB,cAAc,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAwBpE;AAED,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,2CAkKjE;AAED,wBAAgB,cAAc,qBAM7B"}
@@ -1,74 +1,94 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { createContext, useContext, useState, useEffect, useCallback } from "react";
3
+ import { createContext, useContext, useState, useEffect, useCallback, useMemo } from "react";
4
4
  import { useRouter } from "next/navigation";
5
- import { useQueryClient } from "@tanstack/react-query";
5
+ import { useQuery, useQueryClient } from "@tanstack/react-query";
6
6
  import { useAuth } from "../hooks/useAuth.js";
7
7
  import { TeamSwitchModal } from "../components/teams/TeamSwitchModal.js";
8
8
  import { APP_CONFIG_MERGED } from "../lib/config/config-sync.js";
9
9
  import { canUserCreateTeam } from "../lib/teams/helpers.js";
10
10
  const TeamContext = createContext(void 0);
11
+ const TEAMS_QUERY_KEY = ["user-teams"];
12
+ async function fetchUserTeams() {
13
+ const response = await fetch("/api/v1/teams");
14
+ const data = await response.json();
15
+ if (!response.ok || !data.data) {
16
+ throw new Error("Failed to fetch teams");
17
+ }
18
+ return data.data.map((t) => ({
19
+ team: {
20
+ id: t.id,
21
+ name: t.name,
22
+ slug: t.slug,
23
+ description: t.description,
24
+ ownerId: t.owner_id || t.ownerId,
25
+ avatarUrl: t.avatar_url || t.avatarUrl,
26
+ settings: t.settings || {},
27
+ createdAt: t.created_at || t.createdAt,
28
+ updatedAt: t.updated_at || t.updatedAt
29
+ },
30
+ role: t.userRole || t.user_role || t.role,
31
+ joinedAt: t.joinedAt || t.joined_at
32
+ }));
33
+ }
11
34
  function TeamProvider({ children }) {
12
- const { user } = useAuth();
35
+ const { user, isLoading: authLoading } = useAuth();
13
36
  const router = useRouter();
14
37
  const queryClient = useQueryClient();
15
38
  const [currentTeam, setCurrentTeam] = useState(null);
16
- const [userTeams, setUserTeams] = useState([]);
17
- const [isLoading, setIsLoading] = useState(true);
18
39
  const [isSwitching, setIsSwitching] = useState(false);
19
- const [canCurrentUserCreateTeam, setCanCurrentUserCreateTeam] = useState(true);
40
+ const [initialSyncDone, setInitialSyncDone] = useState(false);
20
41
  const [switchModalOpen, setSwitchModalOpen] = useState(false);
21
42
  const [previousTeam, setPreviousTeam] = useState(null);
22
43
  const [targetTeam, setTargetTeam] = useState(null);
23
- const loadUserTeams = useCallback(async () => {
44
+ const {
45
+ data: userTeams = [],
46
+ isLoading: teamsLoading,
47
+ refetch: refetchTeams
48
+ } = useQuery({
49
+ queryKey: TEAMS_QUERY_KEY,
50
+ queryFn: fetchUserTeams,
51
+ enabled: !!user && !authLoading,
52
+ staleTime: 1e3 * 60 * 5,
53
+ // Cache for 5 minutes - prevents refetch on navigation
54
+ gcTime: 1e3 * 60 * 60,
55
+ // Keep in cache for 1 hour
56
+ refetchOnWindowFocus: false,
57
+ // Don't refetch when window regains focus
58
+ refetchOnMount: false
59
+ // Don't refetch if data exists and is not stale
60
+ });
61
+ const isLoading = authLoading || teamsLoading;
62
+ const canCurrentUserCreateTeam = useMemo(() => {
63
+ if (!user || !userTeams.length) return false;
64
+ const { mode, options } = APP_CONFIG_MERGED.teams;
65
+ const ownedTeamsCount = userTeams.filter((m) => m.role === "owner").length;
66
+ return canUserCreateTeam(mode, options || {}, ownedTeamsCount);
67
+ }, [userTeams, user]);
68
+ useEffect(() => {
69
+ if (!userTeams.length || initialSyncDone) return;
70
+ const storedTeamId = typeof window !== "undefined" ? localStorage.getItem("activeTeamId") : null;
71
+ const storedTeam = userTeams.find((t) => t.team.id === storedTeamId);
72
+ const activeTeam = storedTeam || userTeams[0];
73
+ if (activeTeam) {
74
+ setCurrentTeam(activeTeam.team);
75
+ if (typeof window !== "undefined" && storedTeamId !== activeTeam.team.id) {
76
+ localStorage.setItem("activeTeamId", activeTeam.team.id);
77
+ }
78
+ if (typeof window !== "undefined") {
79
+ fetch("/api/v1/teams/switch", {
80
+ method: "POST",
81
+ headers: { "Content-Type": "application/json" },
82
+ body: JSON.stringify({ teamId: activeTeam.team.id })
83
+ }).catch((err) => console.error("Failed to sync team cookie:", err));
84
+ }
85
+ setInitialSyncDone(true);
86
+ }
87
+ }, [userTeams, initialSyncDone]);
88
+ useEffect(() => {
24
89
  if (!user) {
25
- setUserTeams([]);
26
90
  setCurrentTeam(null);
27
- setIsLoading(false);
28
- return;
29
- }
30
- try {
31
- setIsLoading(true);
32
- const response = await fetch("/api/v1/teams");
33
- const data = await response.json();
34
- if (response.ok && data.data) {
35
- const teams = data.data.map((t) => ({
36
- team: {
37
- id: t.id,
38
- name: t.name,
39
- slug: t.slug,
40
- description: t.description,
41
- ownerId: t.owner_id || t.ownerId,
42
- avatarUrl: t.avatar_url || t.avatarUrl,
43
- settings: t.settings || {},
44
- createdAt: t.created_at || t.createdAt,
45
- updatedAt: t.updated_at || t.updatedAt
46
- },
47
- role: t.userRole || t.user_role || t.role,
48
- joinedAt: t.joinedAt || t.joined_at
49
- }));
50
- setUserTeams(teams);
51
- const storedTeamId = typeof window !== "undefined" ? localStorage.getItem("activeTeamId") : null;
52
- const storedTeam = teams.find((t) => t.team.id === storedTeamId);
53
- const activeTeam = storedTeam || teams[0];
54
- if (activeTeam) {
55
- setCurrentTeam(activeTeam.team);
56
- if (typeof window !== "undefined" && storedTeamId !== activeTeam.team.id) {
57
- localStorage.setItem("activeTeamId", activeTeam.team.id);
58
- }
59
- if (typeof window !== "undefined") {
60
- fetch("/api/v1/teams/switch", {
61
- method: "POST",
62
- headers: { "Content-Type": "application/json" },
63
- body: JSON.stringify({ teamId: activeTeam.team.id })
64
- }).catch((err) => console.error("Failed to sync team cookie:", err));
65
- }
66
- }
67
- }
68
- } catch (error) {
69
- console.error("Failed to load teams:", error);
70
- } finally {
71
- setIsLoading(false);
91
+ setInitialSyncDone(false);
72
92
  }
73
93
  }, [user]);
74
94
  const handleSwitchComplete = useCallback(() => {
@@ -109,21 +129,9 @@ function TeamProvider({ children }) {
109
129
  }
110
130
  }, [userTeams, currentTeam]);
111
131
  const refreshTeams = useCallback(async () => {
112
- await loadUserTeams();
113
- }, [loadUserTeams]);
114
- useEffect(() => {
115
- loadUserTeams();
116
- }, [loadUserTeams]);
117
- useEffect(() => {
118
- if (!user || !userTeams) {
119
- setCanCurrentUserCreateTeam(false);
120
- return;
121
- }
122
- const { mode, options } = APP_CONFIG_MERGED.teams;
123
- const ownedTeamsCount = userTeams.filter((m) => m.role === "owner").length;
124
- const canCreate = canUserCreateTeam(mode, options || {}, ownedTeamsCount);
125
- setCanCurrentUserCreateTeam(canCreate);
126
- }, [userTeams, user]);
132
+ await queryClient.invalidateQueries({ queryKey: TEAMS_QUERY_KEY });
133
+ await refetchTeams();
134
+ }, [queryClient, refetchTeams]);
127
135
  return /* @__PURE__ */ jsxs(
128
136
  TeamContext.Provider,
129
137
  {
@@ -159,6 +167,8 @@ function useTeamContext() {
159
167
  return context;
160
168
  }
161
169
  export {
170
+ TEAMS_QUERY_KEY,
162
171
  TeamProvider,
172
+ fetchUserTeams,
163
173
  useTeamContext
164
174
  };
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Hook to prefetch settings page data on hover
3
+ *
4
+ * @example
5
+ * ```tsx
6
+ * function SettingsSidebar() {
7
+ * const { prefetchProfile, prefetchTeams } = usePrefetchSettings()
8
+ *
9
+ * return (
10
+ * <nav>
11
+ * <Link href="/dashboard/settings/profile" onMouseEnter={prefetchProfile}>
12
+ * Profile
13
+ * </Link>
14
+ * <Link href="/dashboard/settings/teams" onMouseEnter={prefetchTeams}>
15
+ * Teams
16
+ * </Link>
17
+ * </nav>
18
+ * )
19
+ * }
20
+ * ```
21
+ */
22
+ export declare function usePrefetchSettings(): {
23
+ prefetchProfile: () => void;
24
+ prefetchTeams: () => void;
25
+ };
26
+ /**
27
+ * Generic prefetch hook for any entity list
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * function EntityNav() {
32
+ * const prefetchProducts = usePrefetchEntity('products')
33
+ *
34
+ * return (
35
+ * <Link href="/dashboard/products" onMouseEnter={prefetchProducts}>
36
+ * Products
37
+ * </Link>
38
+ * )
39
+ * }
40
+ * ```
41
+ */
42
+ export declare function usePrefetchEntity(entitySlug: string): () => void;
43
+ //# sourceMappingURL=usePrefetch.d.ts.map