Skip to content

Commit

Permalink
add share feature
Browse files Browse the repository at this point in the history
  • Loading branch information
yongenaelf committed Sep 10, 2024
1 parent 5651a98 commit 5a8ccda
Show file tree
Hide file tree
Showing 13 changed files with 240 additions and 5 deletions.
23 changes: 23 additions & 0 deletions app/api/get-share/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { getBuildServerBaseUrl } from "@/lib/env";
import { unzipSync } from "fflate";

export async function GET(request: Request) {
const { searchParams } = new URL(request.url);
const id = searchParams.get("id");

if (!id) {
throw new Error("no id");
}

const res = await fetch(
`${getBuildServerBaseUrl()}/playground/share/get/${id}`
);

const data = await res.text();

const zipData = Buffer.from(data, "base64");

const unzipped = unzipSync(zipData);

return Response.json(unzipped);
}
37 changes: 37 additions & 0 deletions app/api/share/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { FileContent } from "@/data/db";
import { getBuildServerBaseUrl } from "@/lib/env";
import { fileContentToZip } from "@/lib/file-content-to-zip";
import { type NextRequest } from "next/server";
import { v4 as uuidv4 } from "uuid";

export async function POST(request: NextRequest) {
const { files } = (await request.json()) as { files: FileContent[] };

const zippedData = fileContentToZip(files);

const formData = new FormData();
const filePath = uuidv4() + ".zip";
formData.append(
"file",
new File([zippedData], filePath, { type: "application/zip" }),
filePath
);

const requestInit: RequestInit = {
method: "POST",
body: formData,
redirect: "follow",
};

const response = await fetch(
`${getBuildServerBaseUrl()}/playground/share/create`,
requestInit
);

if (!response.ok) {
const { message } = await response.json();
return Response.json({ error: message }, { status: response.status });
}

return Response.json(await response.json());
}
3 changes: 1 addition & 2 deletions app/api/test/route.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { FileContent } from "@/data/db";
import { getBuildServerBaseUrl, getSolangBuildServerBaseUrl } from "@/lib/env";
import { getBuildServerBaseUrl } from "@/lib/env";
import { fileContentToZip } from "@/lib/file-content-to-zip";
import { type NextRequest } from "next/server";
import { v4 as uuidv4 } from "uuid";
import { strFromU8, strToU8 } from "fflate";

export async function POST(request: NextRequest) {
const { files } = (await request.json()) as { files: FileContent[] };
Expand Down
2 changes: 2 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import clsx from "clsx";
import { GoogleAnalytics } from "@next/third-parties/google";
import { getGoogleAnalyticsTag } from "@/lib/env";
import Providers from "@/components/providers";
import { Toaster } from "@/components/ui/toaster"

const font = Poppins({
weight: ["100", "200", "300", "400", "500", "600", "700", "800", "900"],
Expand All @@ -30,6 +31,7 @@ export default function RootLayout({ children }: PropsWithChildren) {
<main className="h-[calc(100vh-66px)] overflow-auto">
<Suspense>{children}</Suspense>
</main>
<Toaster />
</Providers>
</body>
{gaId ? <GoogleAnalytics gaId={gaId} /> : null}
Expand Down
12 changes: 12 additions & 0 deletions app/share/[id]/_sharepagecomponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use client";

import { useShare } from "@/data/client";

export function SharePageComponent({ id }: { id: string }) {
const { data, isLoading, error } = useShare(id);

if (isLoading) return <p>Loading...</p>;
else if (error) return <p>Error: {String(error)}</p>;

return <p>{JSON.stringify(data)}</p>;
}
10 changes: 10 additions & 0 deletions app/share/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { SharePageComponent } from "./_sharepagecomponent";



export default function Page({ params: {id} }: { params: { id: string } }) {

return (
<SharePageComponent id={id} />
);
}
12 changes: 11 additions & 1 deletion components/build-deploy-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { useCliCommands } from "./workspace/use-cli-commands";
import useSWR, { mutate } from "swr";
import { db } from "@/data/db";
import { useWorkspaceId } from "./workspace/use-workspace-id";
import { Download, Rocket, ShieldCheck, Wrench, TestTube2 } from "lucide-react";
import { Download, Rocket, ShieldCheck, Wrench, TestTube2, Link2 } from "lucide-react";
import UploadModal from "./workspace/upload-modal";
import { Tooltip } from "./tooltip";

Expand Down Expand Up @@ -100,6 +100,16 @@ export function BuildDeployPanel() {
},
icon: Download,
},
{
disabled: false,
title: "Share",
onClick: async () => {
try {
await commands.share();
} catch (err) {}
},
icon: Link2,
},
];

return (
Expand Down
2 changes: 1 addition & 1 deletion components/ui/toaster.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"use client"

import { useToast } from "@/components/ui/use-toast"
import {
Toast,
ToastClose,
Expand All @@ -8,7 +9,6 @@ import {
ToastTitle,
ToastViewport,
} from "@/components/ui/toast"
import { useToast } from "@/components/ui/use-toast"

export function Toaster() {
const { toasts } = useToast()
Expand Down
45 changes: 45 additions & 0 deletions components/workspace/share-link.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"use client";
import { Copy, CopyCheck } from "lucide-react";
import Link from "next/link";
import { useMemo, useState } from "react";
import { CopyToClipboard } from "react-copy-to-clipboard";
import { useToast } from "@/components/ui/use-toast";

export function ShareLink({ id }: { id: string }) {
const { toast } = useToast();
const origin =
typeof window !== "undefined" && window.location.origin
? window.location.origin
: "";
const [copied, setCopied] = useState(false);

const url = useMemo(() => {
return `${origin}/share/${id}`;
}, [id, origin]);

return (
<div className="flex">
<Link href={url} className="mr-4">
{url}
</Link>
<CopyToClipboard
text={url}
onCopy={() => {
setCopied(true);

toast({
title: "Link Copied",
description: "Share link has been copied to your clipboard.",

});
}}
>
{copied ? (
<CopyCheck className="w-4 h-4 cursor-pointer" />
) : (
<Copy className="w-4 h-4 cursor-pointer" />
)}
</CopyToClipboard>
</div>
);
}
45 changes: 44 additions & 1 deletion components/workspace/use-cli-commands.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { fileContentToZip } from "@/lib/file-content-to-zip";
import { saveAs } from "file-saver";
import { useSetSearchParams } from "@/lib/set-search-params";
import { FormatErrors } from "./format-errors";
import { ShareLink } from "./share-link";

export function useCliCommands() {
const terminalContext = useContext(TerminalContext);
Expand All @@ -35,6 +36,7 @@ export function useCliCommands() {
<li className="ml-8">test - tests the current workspace</li>
<li className="ml-8">deploy - deploys the built smart contract</li>
<li className="ml-8">export - exports the current workspace</li>
<li className="ml-8">share - generates a share link for the current workspace</li>
<li className="ml-8">
check txID - checks the result of transaction
</li>
Expand Down Expand Up @@ -260,6 +262,46 @@ export function useCliCommands() {
);
saveAs(file);
},
share: async () => {
if (typeof id !== "string") throw new Error("id is not string");
const start = `${pathname}/`;
terminalContext.setBufferedContent(
<>
<p>Loading files...</p>
</>
);
const files = (
await db.files.filter((file) => file.path.startsWith(start)).toArray()
).map((file) => ({
path: decodeURIComponent(file.path.replace(start, "")),
contents: file.contents,
}));

terminalContext.setBufferedContent(
<>
<p>Loaded files: {files.map((i) => i.path).join(", ")}</p>
<p>
<Loader2 className="h-4 w-4 animate-spin inline" /> Generating share link...
</p>
</>
);

try {
const res = await fetch(`/api/share`, {
method: "POST",
body: JSON.stringify({ files }),
});
const { id } = await res.json();

terminalContext.setBufferedContent(
<ShareLink id={id} />
);
} catch (err) {
if (err instanceof Error)
terminalContext.setBufferedContent(<>{err.message}</>);
return;
}
},
};

return commands;
Expand Down Expand Up @@ -395,4 +437,5 @@ function AuditReportResult({ codeHash }: { codeHash: string }) {
</table>
</>
);
}
}

12 changes: 12 additions & 0 deletions data/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ export function useTutorialList() {

const data = await res.json();

return data;
});
}

export function useShare(id: string) {
return useSWR<
Record<string, string>
>(`get-share-${id}`, async () => {
const res = await fetch(`/api/get-share?id=${id}`);

const data = await res.json();

return data;
});
}
40 changes: 40 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"parse-github-url": "^1.0.3",
"react": "^18",
"react-accessible-treeview": "^2.9.1",
"react-copy-to-clipboard": "^5.1.0",
"react-dom": "^18",
"react-dropzone": "^14.2.3",
"react-hook-form": "^7.52.1",
Expand All @@ -90,6 +91,7 @@
"@types/node": "^20",
"@types/parse-github-url": "^1.0.3",
"@types/react": "^18",
"@types/react-copy-to-clipboard": "^5.0.7",
"@types/react-dom": "^18",
"@types/uuid": "^10.0.0",
"eslint": "^8",
Expand Down

0 comments on commit 5a8ccda

Please sign in to comment.