Skip to content

Commit 3493329

Browse files
add server component with server-side function call
1 parent 9238f68 commit 3493329

File tree

4 files changed

+76
-114
lines changed

4 files changed

+76
-114
lines changed

src/app/[orgId]/settings/resources/[resourceId]/ResourceInfoBox.tsx

Lines changed: 42 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
SelectTrigger,
1818
SelectValue
1919
} from "@/components/ui/select";
20+
import { internal } from "@/lib/api";
2021
import { useEnvContext } from "@app/hooks/useEnvContext";
2122
import { useDockerSocket } from "@app/hooks/useDockerSocket";
2223
import { useTranslations } from "next-intl";
@@ -28,7 +29,9 @@ import { createApiClient } from "@app/lib/api";
2829
import { build } from "@server/build";
2930

3031

31-
type ResourceInfoBoxType = {};
32+
type ResourceInfoBoxType = {
33+
orgs: ResponseOrg[];
34+
};
3235

3336
type ResponseOrg = {
3437
orgId: string;
@@ -37,7 +40,7 @@ type ResponseOrg = {
3740

3841

3942

40-
export default function ResourceInfoBox({ }: ResourceInfoBoxType) {
43+
export default function ResourceInfoBox({ orgs }: ResourceInfoBoxType) {
4144
const { resource, authInfo, site } = useResourceContext();
4245
const api = createApiClient(useEnvContext());
4346

@@ -46,33 +49,9 @@ export default function ResourceInfoBox({ }: ResourceInfoBoxType) {
4649

4750
let fullUrl = `${resource.ssl ? "https" : "http"}://${resource.fullDomain}`;
4851

49-
const [availableOrgs, setAvailableOrgs] = useState<{ id: string; name: string }[]>([]);
50-
const [selectedOrg, setSelectedOrg] = useState("");
52+
const [selectedOrg, setSelectedOrg] = useState<string | undefined>(undefined);
5153
const [isLoading, setIsLoading] = useState(false);
5254

53-
useEffect(() => {
54-
const fetchOrgs = async () => {
55-
try {
56-
const res = await fetch("/api/orgs");
57-
if (!res.ok) throw new Error("Failed to load orgs");
58-
const allOrgs: ResponseOrg[] = await res.json();
59-
60-
const orgs = allOrgs
61-
.filter((org) => org.orgId !== resource.orgId)
62-
.map((org) => ({
63-
id: org.orgId,
64-
name: org.name
65-
}));
66-
67-
setAvailableOrgs(orgs);
68-
} catch (err) {
69-
console.error("Error fetching orgs:", err);
70-
}
71-
};
72-
73-
fetchOrgs();
74-
}, [resource.orgId]);
75-
7655
const handleMove = async () => {
7756
if (!selectedOrg) return;
7857

@@ -220,43 +199,43 @@ export default function ResourceInfoBox({ }: ResourceInfoBoxType) {
220199
</InfoSection>
221200

222201
<InfoSection>
223-
{/* <InfoSectionTitle>{t("visibility")}</InfoSectionTitle> */}
224202
<InfoSectionContent>
225-
{availableOrgs.length > 0 && (
226-
<div className="flex flex-col gap-2">
227-
<Select
228-
value={selectedOrg}
229-
onValueChange={setSelectedOrg}
230-
>
231-
<SelectTrigger className="w-full">
232-
<SelectValue placeholder="Select target organization" />
233-
</SelectTrigger>
234-
<SelectContent>
235-
{availableOrgs.map((org) => (
236-
<SelectItem key={org.id} value={org.id}>
237-
{org.name}
238-
</SelectItem>
239-
))}
240-
</SelectContent>
241-
</Select>
242-
243-
<Button
244-
size="sm"
245-
onClick={handleMove}
246-
disabled={!selectedOrg || isLoading}
247-
variant="default"
248-
>
249-
{isLoading ? (
250-
<>
251-
<RotateCw className="w-4 h-4 animate-spin mr-2" />
252-
Moving...
253-
</>
254-
) : (
255-
"Move Resource"
256-
)}
257-
</Button>
258-
</div>
259-
)}
203+
<div className="flex flex-col gap-2">
204+
<Select onValueChange={setSelectedOrg}>
205+
<SelectTrigger className="w-full">
206+
<SelectValue
207+
placeholder={
208+
orgs.length === 0
209+
? "No sites available"
210+
: "Select target site"
211+
}
212+
/>
213+
</SelectTrigger>
214+
<SelectContent>
215+
{orgs.map((org) => (
216+
<SelectItem key={org.orgId} value={org.orgId}>
217+
{org.name}
218+
</SelectItem>
219+
))}
220+
</SelectContent>
221+
</Select>
222+
223+
<Button
224+
size="sm"
225+
onClick={handleMove}
226+
disabled={!selectedOrg || isLoading}
227+
variant="default"
228+
>
229+
{isLoading ? (
230+
<>
231+
<RotateCw className="w-4 h-4 animate-spin mr-2" />
232+
Moving...
233+
</>
234+
) : (
235+
"Move Resource"
236+
)}
237+
</Button>
238+
</div>
260239
</InfoSectionContent>
261240
</InfoSection>
262241
</InfoSections>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
import { verifySession } from "@/lib/auth/verifySession";
3+
import { authCookieHeader } from "@/lib/api/cookies";
4+
import { internal } from "@/lib/api";
5+
import { ListUserOrgsResponse } from "@server/routers/org";
6+
import ResourceInfoBox from "./ResourceInfoBox";
7+
8+
9+
interface ResourceInfoWrapperType {
10+
resource: any;
11+
}
12+
13+
export default async function ResourceInfoWrapper({ resource }: ResourceInfoWrapperType) {
14+
const user = await verifySession();
15+
if (!user) return <div className="text-red-500">Unauthorized</div>;
16+
17+
let orgs: ListUserOrgsResponse["orgs"] = [];
18+
19+
try {
20+
const res = await internal.get(`/user/${user.userId}/orgs`, await authCookieHeader());
21+
if (res?.data?.data?.orgs) {
22+
const fetchedOrgs: ListUserOrgsResponse["orgs"] = res.data.data.orgs;
23+
orgs = fetchedOrgs.filter(
24+
(org: { orgId: string; name: string }) => org.orgId !== resource.orgId
25+
);
26+
}
27+
} catch (err) {
28+
console.error("Failed to fetch user orgs:", err);
29+
}
30+
31+
return <ResourceInfoBox orgs={orgs} />;
32+
}

src/app/[orgId]/settings/resources/[resourceId]/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@ import SettingsSectionTitle from "@app/components/SettingsSectionTitle";
1212
import { GetOrgResponse } from "@server/routers/org";
1313
import OrgProvider from "@app/providers/OrgProvider";
1414
import { cache } from "react";
15-
import ResourceInfoBox from "./ResourceInfoBox";
1615
import { GetSiteResponse } from "@server/routers/site";
1716
import { getTranslations } from 'next-intl/server';
17+
import ResourceInfoWrapper from "./ResourceInfoWrapper";
1818

1919
interface ResourceLayoutProps {
2020
children: React.ReactNode;
@@ -124,7 +124,7 @@ export default async function ResourceLayout(props: ResourceLayoutProps) {
124124
authInfo={authInfo}
125125
>
126126
<div className="space-y-6">
127-
<ResourceInfoBox />
127+
<ResourceInfoWrapper resource={resource} />
128128
<HorizontalTabs items={navItems}>
129129
{children}
130130
</HorizontalTabs>

src/app/api/orgs/route.ts

Lines changed: 0 additions & 49 deletions
This file was deleted.

0 commit comments

Comments
 (0)