@nextsparkjs/core 0.1.0-beta.67 → 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.
- package/dist/components/dashboard/block-editor/block-picker.d.ts +7 -2
- package/dist/components/dashboard/block-editor/block-picker.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/block-picker.js +27 -20
- package/dist/components/dashboard/block-editor/block-preview-canvas.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/block-preview-canvas.js +37 -37
- package/dist/components/dashboard/block-editor/block-settings-panel.js +3 -3
- package/dist/components/dashboard/block-editor/builder-editor-view.d.ts.map +1 -1
- package/dist/components/dashboard/block-editor/builder-editor-view.js +124 -82
- package/dist/components/dashboard/block-editor/config-panel.d.ts +18 -0
- package/dist/components/dashboard/block-editor/config-panel.d.ts.map +1 -0
- package/dist/components/dashboard/block-editor/config-panel.js +413 -0
- package/dist/components/dashboard/block-editor/floating-block-toolbar.js +1 -1
- package/dist/components/dashboard/block-editor/pattern-card.js +1 -1
- package/dist/components/dashboard/block-editor/pattern-reference-preview.js +1 -1
- package/dist/components/dashboard/block-editor/sortable-block.js +1 -1
- package/dist/components/dashboard/block-editor/tree-view-node.d.ts +11 -0
- package/dist/components/dashboard/block-editor/tree-view-node.d.ts.map +1 -0
- package/dist/components/dashboard/block-editor/tree-view-node.js +91 -0
- package/dist/components/dashboard/block-editor/tree-view.d.ts +17 -0
- package/dist/components/dashboard/block-editor/tree-view.d.ts.map +1 -0
- package/dist/components/dashboard/block-editor/tree-view.js +125 -0
- package/dist/components/dashboard/block-editor/viewport-toggle.d.ts +10 -0
- package/dist/components/dashboard/block-editor/viewport-toggle.d.ts.map +1 -0
- package/dist/components/dashboard/block-editor/viewport-toggle.js +55 -0
- package/dist/components/public/pageBuilder/PageRenderer.d.ts.map +1 -1
- package/dist/components/public/pageBuilder/PageRenderer.js +10 -1
- package/dist/components/settings/layouts/SettingsSidebar.d.ts.map +1 -1
- package/dist/components/settings/layouts/SettingsSidebar.js +14 -0
- package/dist/components/ui/dynamic-icon.d.ts +12 -0
- package/dist/components/ui/dynamic-icon.d.ts.map +1 -0
- package/dist/components/ui/dynamic-icon.js +11 -0
- package/dist/components/ui/index.d.ts +7 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +7 -0
- package/dist/components/ui/skeleton-dashboard.d.ts +32 -0
- package/dist/components/ui/skeleton-dashboard.d.ts.map +1 -0
- package/dist/components/ui/skeleton-dashboard.js +69 -0
- package/dist/components/ui/skeleton-detail.d.ts.map +1 -1
- package/dist/components/ui/skeleton-detail.js +0 -1
- package/dist/components/ui/skeleton-features.d.ts +27 -0
- package/dist/components/ui/skeleton-features.d.ts.map +1 -0
- package/dist/components/ui/skeleton-features.js +90 -0
- package/dist/components/ui/skeleton-form.d.ts.map +1 -1
- package/dist/components/ui/skeleton-form.js +0 -1
- package/dist/components/ui/skeleton-list.d.ts.map +1 -1
- package/dist/components/ui/skeleton-list.js +0 -1
- package/dist/components/ui/skeleton-public.d.ts +26 -0
- package/dist/components/ui/skeleton-public.d.ts.map +1 -0
- package/dist/components/ui/skeleton-public.js +61 -0
- package/dist/components/ui/skeleton-settings.d.ts +54 -0
- package/dist/components/ui/skeleton-settings.d.ts.map +1 -0
- package/dist/components/ui/skeleton-settings.js +332 -0
- package/dist/components/ui/skeleton.d.ts +23 -1
- package/dist/components/ui/skeleton.d.ts.map +1 -1
- package/dist/components/ui/skeleton.js +46 -2
- package/dist/contexts/TeamContext.d.ts +2 -0
- package/dist/contexts/TeamContext.d.ts.map +1 -1
- package/dist/contexts/TeamContext.js +78 -68
- package/dist/hooks/usePrefetch.d.ts +43 -0
- package/dist/hooks/usePrefetch.d.ts.map +1 -0
- package/dist/hooks/usePrefetch.js +56 -0
- package/dist/lib/actions/index.d.ts +27 -14
- package/dist/lib/actions/index.d.ts.map +1 -1
- package/dist/lib/actions/index.js +19 -1
- package/dist/lib/actions/team.actions.d.ts +107 -0
- package/dist/lib/actions/team.actions.d.ts.map +1 -0
- package/dist/lib/actions/team.actions.js +220 -0
- package/dist/lib/actions/user.actions.d.ts +99 -0
- package/dist/lib/actions/user.actions.d.ts.map +1 -0
- package/dist/lib/actions/user.actions.js +149 -0
- package/dist/lib/selectors/core-selectors.d.ts +98 -44
- package/dist/lib/selectors/core-selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/block-editor.selectors.d.ts +136 -71
- package/dist/lib/selectors/domains/block-editor.selectors.d.ts.map +1 -1
- package/dist/lib/selectors/domains/block-editor.selectors.js +130 -60
- package/dist/lib/selectors/selectors.d.ts +196 -88
- package/dist/lib/selectors/selectors.d.ts.map +1 -1
- package/dist/messages/de/devtools.json +4 -0
- package/dist/messages/de/index.d.ts +4 -0
- package/dist/messages/de/index.d.ts.map +1 -1
- package/dist/messages/en/admin.json +15 -1
- package/dist/messages/en/devtools.json +16 -0
- package/dist/messages/en/index.d.ts +30 -0
- package/dist/messages/en/index.d.ts.map +1 -1
- package/dist/messages/es/admin.json +16 -1
- package/dist/messages/es/devtools.json +4 -0
- package/dist/messages/es/index.d.ts +19 -0
- package/dist/messages/es/index.d.ts.map +1 -1
- package/dist/messages/fr/devtools.json +4 -0
- package/dist/messages/fr/index.d.ts +4 -0
- package/dist/messages/fr/index.d.ts.map +1 -1
- package/dist/messages/it/devtools.json +4 -0
- package/dist/messages/it/index.d.ts +4 -0
- package/dist/messages/it/index.d.ts.map +1 -1
- package/dist/messages/pt/devtools.json +4 -0
- package/dist/messages/pt/index.d.ts +4 -0
- package/dist/messages/pt/index.d.ts.map +1 -1
- package/dist/nextspark-entities.d.ts +59 -0
- package/dist/presets/blocks/cta-section/component.tsx +4 -4
- package/dist/presets/blocks/features-grid/component.tsx +5 -5
- package/dist/presets/blocks/hero/component.tsx +2 -2
- package/dist/presets/blocks/testimonials/component.tsx +4 -4
- package/dist/presets/blocks/text-content/component.tsx +2 -2
- package/dist/presets/theme/blocks/hero/component.tsx +2 -2
- package/dist/presets/theme/tests/cypress/src/core/BlockEditorBasePOM.ts +123 -24
- package/dist/styles/classes.json +22 -2
- package/dist/styles/ui.css +1 -1
- package/dist/templates/app/(public)/[...slug]/page.tsx +2 -1
- package/dist/templates/app/(public)/docs/[section]/[page]/page.tsx +1 -1
- package/dist/templates/app/api/devtools/config/entities/route.ts +2 -1
- package/dist/templates/app/api/user/plan-flags/route.ts +1 -1
- package/dist/templates/app/api/v1/[entity]/[id]/child/[childType]/[childId]/route.ts +4 -2
- package/dist/templates/app/dashboard/(main)/layout.tsx +2 -1
- package/dist/templates/app/dashboard/(main)/loading.tsx +5 -0
- package/dist/templates/app/dashboard/features/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/api-keys/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/billing/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/invoices/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/notifications/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/password/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/plans/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/profile/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/security/loading.tsx +5 -0
- package/dist/templates/app/dashboard/settings/teams/loading.tsx +5 -0
- package/dist/templates/app/devtools/config/page.tsx +1 -1
- package/dist/templates/app/devtools/page.tsx +1 -1
- package/dist/templates/app/devtools/tests/[[...path]]/page.tsx +1 -1
- package/dist/templates/contents/themes/starter/messages/de/common.json +4 -1
- package/dist/templates/contents/themes/starter/messages/de/index.ts +15 -0
- package/dist/templates/contents/themes/starter/messages/en/common.json +4 -1
- package/dist/templates/contents/themes/starter/messages/en/index.ts +15 -0
- package/dist/templates/contents/themes/starter/messages/es/common.json +4 -1
- package/dist/templates/contents/themes/starter/messages/es/index.ts +15 -0
- package/dist/templates/contents/themes/starter/messages/fr/common.json +4 -1
- package/dist/templates/contents/themes/starter/messages/fr/index.ts +15 -0
- package/dist/templates/contents/themes/starter/messages/it/common.json +4 -1
- package/dist/templates/contents/themes/starter/messages/it/index.ts +13 -0
- package/dist/templates/contents/themes/starter/messages/pt/common.json +4 -1
- package/dist/templates/contents/themes/starter/messages/pt/index.ts +13 -0
- package/dist/templates/contents/themes/starter/styles/globals.css +3 -1
- package/dist/templates/contents/themes/starter/templates/(dashboard)/analytics/loading.tsx +5 -0
- package/dist/templates/contents/themes/starter/templates/(public)/loading.tsx +5 -0
- package/dist/templates/features/blog/blocks/post-content/component.tsx +2 -2
- package/dist/templates/features/pages/blocks/hero/component.tsx +2 -2
- package/dist/templates/next.config.mjs +10 -3
- package/dist/templates/{middleware.ts → proxy.ts} +5 -6
- package/globals.css +54 -0
- package/nextspark-entities.d.ts +59 -0
- package/package.json +18 -16
- package/scripts/build/registry/discovery/api-presets.mjs +20 -12
- package/scripts/build/registry/generators/api-presets-registry.mjs +18 -5
- package/scripts/build/registry/generators/block-registry.mjs +14 -3
- package/scripts/build/registry/generators/docs-registry.mjs +21 -3
- package/scripts/build/registry/generators/translation-registry.mjs +16 -7
- package/scripts/build/theme.mjs +2 -1
- package/templates/app/(public)/[...slug]/page.tsx +2 -1
- package/templates/app/(public)/docs/[section]/[page]/page.tsx +1 -1
- package/templates/app/api/auth/[...all]/route.ts +13 -5
- package/templates/app/api/devtools/config/entities/route.ts +2 -1
- package/templates/app/api/user/plan-flags/route.ts +1 -1
- package/templates/app/api/v1/[entity]/[id]/child/[childType]/[childId]/route.ts +4 -2
- package/templates/app/dashboard/(main)/layout.tsx +2 -1
- package/templates/app/dashboard/(main)/loading.tsx +5 -0
- package/templates/app/dashboard/features/loading.tsx +5 -0
- package/templates/app/dashboard/settings/api-keys/loading.tsx +5 -0
- package/templates/app/dashboard/settings/billing/loading.tsx +5 -0
- package/templates/app/dashboard/settings/invoices/loading.tsx +5 -0
- package/templates/app/dashboard/settings/loading.tsx +5 -0
- package/templates/app/dashboard/settings/notifications/loading.tsx +5 -0
- package/templates/app/dashboard/settings/password/loading.tsx +5 -0
- package/templates/app/dashboard/settings/plans/loading.tsx +5 -0
- package/templates/app/dashboard/settings/profile/loading.tsx +5 -0
- package/templates/app/dashboard/settings/security/loading.tsx +5 -0
- package/templates/app/dashboard/settings/teams/loading.tsx +5 -0
- package/templates/app/devtools/config/page.tsx +1 -1
- package/templates/app/devtools/page.tsx +1 -1
- package/templates/app/devtools/tests/[[...path]]/page.tsx +1 -1
- package/templates/contents/themes/starter/config/app.config.ts +8 -7
- package/templates/contents/themes/starter/messages/de/common.json +4 -1
- package/templates/contents/themes/starter/messages/de/index.ts +15 -0
- package/templates/contents/themes/starter/messages/en/common.json +4 -1
- package/templates/contents/themes/starter/messages/en/index.ts +15 -0
- package/templates/contents/themes/starter/messages/es/common.json +4 -1
- package/templates/contents/themes/starter/messages/es/index.ts +15 -0
- package/templates/contents/themes/starter/messages/fr/common.json +4 -1
- package/templates/contents/themes/starter/messages/fr/index.ts +15 -0
- package/templates/contents/themes/starter/messages/it/common.json +4 -1
- package/templates/contents/themes/starter/messages/it/index.ts +13 -0
- package/templates/contents/themes/starter/messages/pt/common.json +4 -1
- package/templates/contents/themes/starter/messages/pt/index.ts +13 -0
- package/templates/contents/themes/starter/styles/globals.css +3 -1
- package/templates/contents/themes/starter/templates/(dashboard)/analytics/loading.tsx +5 -0
- package/templates/contents/themes/starter/templates/(public)/loading.tsx +5 -0
- package/templates/features/blog/blocks/post-content/component.tsx +2 -2
- package/templates/features/pages/blocks/hero/component.tsx +2 -2
- package/templates/next.config.mjs +10 -3
- package/templates/pnpm-workspace.yaml +5 -0
- package/templates/{middleware.ts → proxy.ts} +5 -6
- package/tests/jest/setup.ts +5 -0
- package/dist/presets/plugin/.env.example.template +0 -19
|
@@ -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 [
|
|
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
|
|
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
|
-
|
|
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
|
|
113
|
-
|
|
114
|
-
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usePrefetch.d.ts","sourceRoot":"","sources":["../../src/hooks/usePrefetch.ts"],"names":[],"mappings":"AAyBA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,mBAAmB;;;EAuBlC;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,cAgBnD"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { useQueryClient } from "@tanstack/react-query";
|
|
3
|
+
import { useCallback } from "react";
|
|
4
|
+
import { TEAMS_QUERY_KEY, fetchUserTeams } from "../contexts/TeamContext.js";
|
|
5
|
+
const USER_PROFILE_QUERY_KEY = ["user-profile"];
|
|
6
|
+
async function fetchUserProfile() {
|
|
7
|
+
const response = await fetch("/api/user/profile");
|
|
8
|
+
if (!response.ok) {
|
|
9
|
+
throw new Error("Failed to fetch profile");
|
|
10
|
+
}
|
|
11
|
+
return response.json();
|
|
12
|
+
}
|
|
13
|
+
function usePrefetchSettings() {
|
|
14
|
+
const queryClient = useQueryClient();
|
|
15
|
+
const prefetchProfile = useCallback(() => {
|
|
16
|
+
queryClient.prefetchQuery({
|
|
17
|
+
queryKey: USER_PROFILE_QUERY_KEY,
|
|
18
|
+
queryFn: fetchUserProfile,
|
|
19
|
+
staleTime: 1e3 * 60 * 5
|
|
20
|
+
// 5 minutes
|
|
21
|
+
});
|
|
22
|
+
}, [queryClient]);
|
|
23
|
+
const prefetchTeams = useCallback(() => {
|
|
24
|
+
queryClient.prefetchQuery({
|
|
25
|
+
queryKey: TEAMS_QUERY_KEY,
|
|
26
|
+
queryFn: fetchUserTeams,
|
|
27
|
+
staleTime: 1e3 * 60 * 5
|
|
28
|
+
// 5 minutes
|
|
29
|
+
});
|
|
30
|
+
}, [queryClient]);
|
|
31
|
+
return {
|
|
32
|
+
prefetchProfile,
|
|
33
|
+
prefetchTeams
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function usePrefetchEntity(entitySlug) {
|
|
37
|
+
const queryClient = useQueryClient();
|
|
38
|
+
return useCallback(() => {
|
|
39
|
+
queryClient.prefetchQuery({
|
|
40
|
+
queryKey: ["entity", entitySlug, "list"],
|
|
41
|
+
queryFn: async () => {
|
|
42
|
+
const response = await fetch(`/api/v1/${entitySlug}?limit=20`);
|
|
43
|
+
if (!response.ok) {
|
|
44
|
+
throw new Error(`Failed to fetch ${entitySlug}`);
|
|
45
|
+
}
|
|
46
|
+
return response.json();
|
|
47
|
+
},
|
|
48
|
+
staleTime: 1e3 * 60 * 2
|
|
49
|
+
// 2 minutes for entity lists
|
|
50
|
+
});
|
|
51
|
+
}, [queryClient, entitySlug]);
|
|
52
|
+
}
|
|
53
|
+
export {
|
|
54
|
+
usePrefetchEntity,
|
|
55
|
+
usePrefetchSettings
|
|
56
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* NextSpark Server Actions
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Server Actions for CRUD operations, user management, and team management.
|
|
5
5
|
* Auth (userId/teamId) is obtained automatically from session and cookies.
|
|
6
6
|
*
|
|
7
7
|
* Import from '@nextsparkjs/core/actions' or '@nextsparkjs/core/lib/actions'.
|
|
@@ -9,31 +9,44 @@
|
|
|
9
9
|
* @example
|
|
10
10
|
* ```typescript
|
|
11
11
|
* import {
|
|
12
|
+
* // Entity actions
|
|
12
13
|
* createEntity,
|
|
13
14
|
* updateEntity,
|
|
14
15
|
* deleteEntity,
|
|
15
16
|
* getEntity,
|
|
16
17
|
* listEntities,
|
|
18
|
+
* // User actions
|
|
19
|
+
* updateProfile,
|
|
20
|
+
* updateAvatar,
|
|
21
|
+
* deleteAccount,
|
|
22
|
+
* // Team actions
|
|
23
|
+
* updateTeam,
|
|
24
|
+
* inviteMember,
|
|
25
|
+
* removeMember,
|
|
26
|
+
* updateMemberRole,
|
|
17
27
|
* } from '@nextsparkjs/core/actions'
|
|
18
28
|
*
|
|
19
|
-
* //
|
|
29
|
+
* // Entity operations - auth obtained from server session
|
|
20
30
|
* const result = await createEntity('schools', { name: 'MIT' })
|
|
21
|
-
*
|
|
22
|
-
* // Update with revalidation
|
|
23
|
-
* await updateEntity('campaigns', id, { status: 'paused' }, {
|
|
24
|
-
* revalidatePaths: ['/dashboard']
|
|
25
|
-
* })
|
|
26
|
-
*
|
|
27
|
-
* // Delete with redirect
|
|
31
|
+
* await updateEntity('campaigns', id, { status: 'paused' })
|
|
28
32
|
* await deleteEntity('leads', id, { redirectTo: '/leads' })
|
|
29
33
|
*
|
|
30
|
-
* //
|
|
31
|
-
*
|
|
34
|
+
* // User profile operations
|
|
35
|
+
* await updateProfile({ firstName: 'John', lastName: 'Doe' })
|
|
36
|
+
* await updateAvatar(formData)
|
|
37
|
+
* await deleteAccount()
|
|
32
38
|
*
|
|
33
|
-
* //
|
|
34
|
-
*
|
|
39
|
+
* // Team operations
|
|
40
|
+
* await updateTeam('team-id', { name: 'New Name' })
|
|
41
|
+
* await inviteMember('team-id', 'user@example.com', 'member')
|
|
42
|
+
* await removeMember('team-id', 'member-id')
|
|
43
|
+
* await updateMemberRole('team-id', 'member-id', 'admin')
|
|
35
44
|
* ```
|
|
36
45
|
*/
|
|
37
46
|
export { createEntity, updateEntity, deleteEntity, getEntity, listEntities, deleteEntities, entityExists, countEntities, } from './entity.actions';
|
|
47
|
+
export { updateProfile, updateAvatar, deleteAccount, } from './user.actions';
|
|
48
|
+
export type { UpdateProfileData, ProfileUpdateResult, } from './user.actions';
|
|
49
|
+
export { updateTeam, inviteMember, removeMember, updateMemberRole, } from './team.actions';
|
|
50
|
+
export type { UpdateTeamData, InviteMemberResult, } from './team.actions';
|
|
38
51
|
export type { EntityActionResult, EntityActionVoidResult, CreateEntityInput, UpdateEntityInput, ListEntityOptions, ListEntityResult, ActionConfig, ActionAuthContext, BatchDeleteResult, } from './types';
|
|
39
52
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/actions/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/lib/actions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AAMH,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,SAAS,EACT,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,aAAa,GACd,MAAM,kBAAkB,CAAA;AAMzB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,aAAa,GACd,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,gBAAgB,CAAA;AAMvB,OAAO,EACL,UAAU,EACV,YAAY,EACZ,YAAY,EACZ,gBAAgB,GACjB,MAAM,gBAAgB,CAAA;AAEvB,YAAY,EACV,cAAc,EACd,kBAAkB,GACnB,MAAM,gBAAgB,CAAA;AAMvB,YAAY,EACV,kBAAkB,EAClB,sBAAsB,EACtB,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,iBAAiB,GAClB,MAAM,SAAS,CAAA"}
|
|
@@ -8,13 +8,31 @@ import {
|
|
|
8
8
|
entityExists,
|
|
9
9
|
countEntities
|
|
10
10
|
} from "./entity.actions.js";
|
|
11
|
+
import {
|
|
12
|
+
updateProfile,
|
|
13
|
+
updateAvatar,
|
|
14
|
+
deleteAccount
|
|
15
|
+
} from "./user.actions.js";
|
|
16
|
+
import {
|
|
17
|
+
updateTeam,
|
|
18
|
+
inviteMember,
|
|
19
|
+
removeMember,
|
|
20
|
+
updateMemberRole
|
|
21
|
+
} from "./team.actions.js";
|
|
11
22
|
export {
|
|
12
23
|
countEntities,
|
|
13
24
|
createEntity,
|
|
25
|
+
deleteAccount,
|
|
14
26
|
deleteEntities,
|
|
15
27
|
deleteEntity,
|
|
16
28
|
entityExists,
|
|
17
29
|
getEntity,
|
|
30
|
+
inviteMember,
|
|
18
31
|
listEntities,
|
|
19
|
-
|
|
32
|
+
removeMember,
|
|
33
|
+
updateAvatar,
|
|
34
|
+
updateEntity,
|
|
35
|
+
updateMemberRole,
|
|
36
|
+
updateProfile,
|
|
37
|
+
updateTeam
|
|
20
38
|
};
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { Team, TeamRole, TeamMember } from '../teams/types';
|
|
2
|
+
import type { EntityActionResult, EntityActionVoidResult } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Team update data that can be passed to updateTeam
|
|
5
|
+
*/
|
|
6
|
+
export interface UpdateTeamData {
|
|
7
|
+
name?: string;
|
|
8
|
+
slug?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
avatarUrl?: string;
|
|
11
|
+
settings?: Record<string, unknown>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Result of invite member action
|
|
15
|
+
*/
|
|
16
|
+
export interface InviteMemberResult {
|
|
17
|
+
memberId: string;
|
|
18
|
+
userId: string;
|
|
19
|
+
teamId: string;
|
|
20
|
+
role: TeamRole;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Update a team's information
|
|
24
|
+
*
|
|
25
|
+
* Requires owner or admin role in the team.
|
|
26
|
+
*
|
|
27
|
+
* @param teamId - The team ID to update
|
|
28
|
+
* @param data - Team fields to update
|
|
29
|
+
* @returns Updated team data wrapped in EntityActionResult
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const result = await updateTeam('team-123', {
|
|
34
|
+
* name: 'New Team Name',
|
|
35
|
+
* description: 'Updated description'
|
|
36
|
+
* })
|
|
37
|
+
*
|
|
38
|
+
* if (result.success) {
|
|
39
|
+
* console.log('Team updated:', result.data.name)
|
|
40
|
+
* }
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function updateTeam(teamId: string, data: UpdateTeamData): Promise<EntityActionResult<Team>>;
|
|
44
|
+
/**
|
|
45
|
+
* Invite a user to join the team
|
|
46
|
+
*
|
|
47
|
+
* Requires owner or admin role in the team.
|
|
48
|
+
* The user must already exist in the system.
|
|
49
|
+
*
|
|
50
|
+
* @param teamId - The team ID
|
|
51
|
+
* @param email - Email of the user to invite
|
|
52
|
+
* @param role - Role to assign (member, admin, viewer)
|
|
53
|
+
* @returns Created membership data wrapped in EntityActionResult
|
|
54
|
+
*
|
|
55
|
+
* @example
|
|
56
|
+
* ```typescript
|
|
57
|
+
* const result = await inviteMember('team-123', 'user@example.com', 'member')
|
|
58
|
+
*
|
|
59
|
+
* if (result.success) {
|
|
60
|
+
* console.log('Member invited:', result.data.memberId)
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function inviteMember(teamId: string, email: string, role?: TeamRole): Promise<EntityActionResult<InviteMemberResult>>;
|
|
65
|
+
/**
|
|
66
|
+
* Remove a member from the team
|
|
67
|
+
*
|
|
68
|
+
* Requires owner or admin role in the team.
|
|
69
|
+
* Cannot remove the team owner (must transfer ownership first).
|
|
70
|
+
*
|
|
71
|
+
* @param teamId - The team ID
|
|
72
|
+
* @param memberId - The member ID to remove (from team_members table)
|
|
73
|
+
* @returns Success status
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* const result = await removeMember('team-123', 'member-id-456')
|
|
78
|
+
*
|
|
79
|
+
* if (result.success) {
|
|
80
|
+
* console.log('Member removed')
|
|
81
|
+
* }
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function removeMember(teamId: string, memberId: string): Promise<EntityActionVoidResult>;
|
|
85
|
+
/**
|
|
86
|
+
* Update a team member's role
|
|
87
|
+
*
|
|
88
|
+
* Requires owner role to change to/from admin.
|
|
89
|
+
* Admins can change member/viewer roles.
|
|
90
|
+
* Cannot change owner role (must transfer ownership).
|
|
91
|
+
*
|
|
92
|
+
* @param teamId - The team ID
|
|
93
|
+
* @param memberId - The member's user ID
|
|
94
|
+
* @param role - New role to assign
|
|
95
|
+
* @returns Updated membership data wrapped in EntityActionResult
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const result = await updateMemberRole('team-123', 'user-456', 'admin')
|
|
100
|
+
*
|
|
101
|
+
* if (result.success) {
|
|
102
|
+
* console.log('Role updated:', result.data.role)
|
|
103
|
+
* }
|
|
104
|
+
* ```
|
|
105
|
+
*/
|
|
106
|
+
export declare function updateMemberRole(teamId: string, memberId: string, role: TeamRole): Promise<EntityActionResult<TeamMember>>;
|
|
107
|
+
//# sourceMappingURL=team.actions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"team.actions.d.ts","sourceRoot":"","sources":["../../../src/lib/actions/team.actions.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAChE,OAAO,KAAK,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAA;AAMzE;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,QAAQ,CAAA;CACf;AAgDD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,UAAU,CAC9B,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,cAAc,GACnB,OAAO,CAAC,kBAAkB,CAAC,IAAI,CAAC,CAAC,CA4DnC;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,IAAI,GAAE,QAAmB,GACxB,OAAO,CAAC,kBAAkB,CAAC,kBAAkB,CAAC,CAAC,CAqEjD;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,YAAY,CAChC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,sBAAsB,CAAC,CAgEjC;AAMD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,gBAAgB,CACpC,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,QAAQ,GACb,OAAO,CAAC,kBAAkB,CAAC,UAAU,CAAC,CAAC,CAsEzC"}
|