Skip to content

Commit

Permalink
chore: Add integration with backend
Browse files Browse the repository at this point in the history
  • Loading branch information
daavidrgz committed Oct 12, 2024
1 parent 19f7ff8 commit 8d6e6fd
Show file tree
Hide file tree
Showing 11 changed files with 200 additions and 61 deletions.
11 changes: 11 additions & 0 deletions crates/web/frontend/next.config.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
const host = process.env.API_HOST || "localhost";
const port = process.env.API_PORT || 3001;

const nextConfig = {
async rewrites() {
return [
{
source: "/api/:path*",
destination: `http://${host}:${port}/:path*`,
},
];
},
webpack: (config) => {
config.experiments = {
asyncWebAssembly: true,
Expand Down
33 changes: 32 additions & 1 deletion crates/web/frontend/package-lock.json

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

5 changes: 4 additions & 1 deletion crates/web/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@radix-ui/react-toast": "^1.2.2",
"@radix-ui/react-tooltip": "^1.1.3",
"@types/js-beautify": "^1.14.3",
"@types/uuid": "^10.0.0",
"@uiw/codemirror-themes": "^4.23.5",
"@uiw/react-codemirror": "^4.23.5",
"@wasm-tool/wasm-pack-plugin": "^1.7.0",
Expand All @@ -52,9 +53,11 @@
"sonner": "^1.5.0",
"tailwind-merge": "^2.5.3",
"tailwindcss-animate": "^1.0.7",
"uuid": "^10.0.0",
"vaul": "^1.0.0",
"vscode-languageserver-protocol": "^3.17.5",
"webworker-promise": "^0.5.1"
"webworker-promise": "^0.5.1",
"zod": "^3.23.8"
},
"devDependencies": {
"@biomejs/biome": "1.9.3",
Expand Down
20 changes: 18 additions & 2 deletions crates/web/frontend/src/app/page-utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Completion } from "@/model/completion";
import type { Data } from "@/model/data";
import type FileType from "@/model/file-type";
import { Data } from "@/model/data";
import FileType from "@/model/file-type";
import { getShare } from "@/service/share-service";
import type { CompletionContext, CompletionSource } from "@codemirror/autocomplete";
import { toast } from "sonner";
import type PromiseWorker from "webworker-promise";
Expand Down Expand Up @@ -51,3 +52,18 @@ export const getQueryCompletionSource = (
};
};
};

export const importShare = async (shareId: string): Promise<{ input: Data; query: Data }> => {
const toastId = toast.loading("Importing share...");
try {
const share = await getShare(shareId);
toast.success("Share succesfully imported", { id: toastId });
return Promise.resolve({
input: new Data(share.json, FileType.JSON),
query: new Data(share.query, FileType.GQ),
});
} catch (error) {
toast.error(`Error importing share: ${error.message}`, { id: toastId });
return Promise.reject(error);
}
};
15 changes: 13 additions & 2 deletions crates/web/frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ import { useSettings } from "@/providers/settings-provider";
import { useWorker } from "@/providers/worker-provider";
import type { CompletionSource } from "@codemirror/autocomplete";
import { Link2, Link2Off } from "lucide-react";
import { useCallback, useRef, useState } from "react";
import { useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { applyGq, getQueryCompletionSource } from "./page-utils";
import { applyGq, getQueryCompletionSource, importShare } from "./page-utils";
import styles from "./page.module.css";
import { useParams, usePathname, useSearchParams } from "next/navigation";

const Home = () => {
const [errorMessage, setErrorMessage] = useState<string | undefined>(undefined);
Expand All @@ -45,6 +46,7 @@ const Home = () => {
} = useSettings();
const debounce = useDebounce(debounceTime);
const { gqWorker, lspWorker } = useWorker();
const shareId = useSearchParams().get("id");

const updateOutputData = useCallback(
async (inputContent: string, inputType: FileType, queryContent: string, silent = true) => {
Expand Down Expand Up @@ -125,6 +127,15 @@ const Home = () => {
[autoApply, debounce, updateOutputData, debounceTime],
);

useEffect(() => {
if (!shareId) return;
importShare(shareId).then((data) => {
updateInputEditorCallback.current(data.input);
updateQueryEditorCallback.current(data.query);
// updateOutputData(data.input.content, data.input.type, data.output.content, true);
});
}, [shareId]);

return (
<main className="flex flex-col items-center pt-4 px-12 h-screen">
<Header className="w-full mb-8" onClickExample={handleClickExample} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,7 @@ const ImportPopup = ({
>
Cancel
</Button>
<Button className="py-1 px-8" variant="success" type="submit">
<Button className="py-1 px-8" variant="success" type="submit" disabled={!(file || url)}>
Import
</Button>
</div>
Expand Down
120 changes: 71 additions & 49 deletions crates/web/frontend/src/components/share-popup/share-popup.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
import { Clipboard, ClipboardCopy, ClipboardIcon, InfoIcon, Share, X } from "lucide-react";
import { Clipboard, Clock, Share } from "lucide-react";
import { useState } from "react";
import ActionButton from "../action-button/action-button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "../ui/dialog";
import { Button } from "../ui/button";
import { Label } from "../ui/label";
import { Slider } from "../ui/slider";
import { SliderWithMarks } from "../ui/slider-with-marks";
import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
import { Tooltip, TooltipProvider } from "@radix-ui/react-tooltip";
import { TooltipContent, TooltipTrigger } from "../ui/tooltip";
import { Input } from "../ui/input";
import { copyToClipboard } from "@/lib/utils";
import { cn, copyToClipboard } from "@/lib/utils";
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
import { Separator } from "../ui/separator";
import { Loader } from "../ui/sonner";

const SharePopup = () => {
const [expirationTime, setExpirationTime] = useState(3600);
const [shareLink, setShareLink] = useState(
"https://gq.hermo.dev/3c8ec511-754f-4e19-ade1-62974d745106",
);
const [expirationTime, setExpirationTime] = useState<"1 hour" | "1 day" | "1 week">("1 day");
const [shareLink, setShareLink] = useState<string>();
const [isLoading, setIsLoading] = useState(false);
const [selectedExpirationTime, setSelectedExpirationTime] = useState<
"1 hour" | "1 day" | "1 week"
>();

const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
setIsLoading(true);
setTimeout(() => {
setIsLoading(false);
setShareLink("https://gq.hermo.dev/test");
setSelectedExpirationTime(expirationTime);
}, 2000);
};

const handleExpirationTimeChange = (value: number[]) => {
setExpirationTime(value[0]);
const handleChangeExpirationTime = (value: string) => {
setShareLink(undefined);
setExpirationTime(value as "1 hour" | "1 day" | "1 week");
};

return (
Expand All @@ -41,15 +40,13 @@ const SharePopup = () => {
<Share className="w-4 h-4" />
</ActionButton>
</PopoverTrigger>
<PopoverContent

className="w-[26rem] max-w-[80vw] max-h-[80vh] gap-0 relative right-2"
>
<PopoverContent className="w-[24rem] max-w-[80vw] max-h-[80vh] gap-0 relative right-2">
<div className="flex items-center mb-1.5">
<TooltipProvider>
<h4 className="text-lg font-semibold leading-none tracking-tight">
Share your playground
</h4>
<h4 className="text-lg font-semibold leading-none tracking-tight">
Share your playground
</h4>
{/* TODO: Fix this */}
{/* <TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<InfoIcon className="w-3 h-3 ml-2 mt-1" />
Expand All @@ -64,55 +61,80 @@ const SharePopup = () => {
</span>
</TooltipContent>
</Tooltip>
</TooltipProvider>
</TooltipProvider> */}
</div>
<span className="text-sm">Create a shareable link to your current playground state</span>
<form onSubmit={handleSubmit} autoComplete="off" className="overflow-x-auto mt-8">
{/* <span className="text-sm">Create a shareable link to your current playground state</span> */}
<form onSubmit={handleSubmit} autoComplete="off" className="overflow-x-auto mt-4">
<div>
<Label htmlFor="expiration-time" variant="default">
Expiration time
</Label>
<RadioGroup
className="mt-4 text-xs flex gap-4"
defaultValue="1-day"
value={expirationTime}
onValueChange={handleChangeExpirationTime}
disabled={isLoading}
className="mt-4 text-xs flex gap-4 peer"
id="expiration-time"
>
<div className="flex items-center">
<RadioGroupItem value="1-hour" id="1-hour" />
<RadioGroupItem value="1 hour" id="1-hour" />
<Label className="pl-2" htmlFor="1-hour">
1 hour
</Label>
</div>
<div className="flex items-center">
<RadioGroupItem value="1-day" id="1-day" />
<RadioGroupItem value="1 day" id="1-day" />
<Label className="pl-2" htmlFor="1-day">
1 day
</Label>
</div>
<div className="flex items-center">
<RadioGroupItem value="1-week" id="1-week" />
<RadioGroupItem value="1 week" id="1-week" />
<Label className="pl-2" htmlFor="1-week">
1 week
</Label>
</div>
</RadioGroup>
</div>

<div className="mt-8 w-full flex">
<Input readOnly className="mb-0 rounded-r-none border-r-0" value={shareLink} />
<ActionButton
className="px-4 py-2 h-10 rounded-l-none"
description="Copy to clipboard"
variant="outline"
onClick={() => copyToClipboard(shareLink)}
>
<Clipboard className="w-3.5 h-3.5" />
</ActionButton>
</div>
<Button className="mt-8 w-full py-1 px-8" variant="outline" type="submit">
Generate link
<Button
className={cn("mt-8 w-full py-1 px-8", isLoading && "!opacity-100")}
variant="outline"
type="submit"
disabled={
isLoading || (shareLink !== undefined && expirationTime === selectedExpirationTime)
}
>
{isLoading ? (
<div className="flex items-center gap-2">
<Loader />
<span>Generating</span>
</div>
) : (
<span>Generate link</span>
)}
</Button>
</form>
{shareLink && (
<div className="animate-in fade-in">
<Separator />
<div className="w-full flex">
<Input readOnly className="mb-0 rounded-r-none border-r-0" value={shareLink} />
<ActionButton
className="px-4 py-2 h-10 rounded-l-none"
description="Copy to clipboard"
variant="outline"
onClick={() => copyToClipboard(shareLink)}
>
<Clipboard className="w-3.5 h-3.5" />
</ActionButton>
</div>
<div className="flex items-center gap-2 mt-4">
<Clock className="w-2.5 h-2.5 mt-[2px]" />
<span className="text-xs">Your link will expire in {selectedExpirationTime}</span>
</div>
</div>
)}
</PopoverContent>
</Popover>
);
Expand Down
8 changes: 3 additions & 5 deletions crates/web/frontend/src/components/ui/button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { type MouseEvent, forwardRef, useEffect, useRef, useState } from "react"
import styles from "./button.module.css";

const buttonVariants = cva(
"relative overflow-hidden inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50",
"relative overflow-hidden inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50 transition-opacity",
{
variants: {
variant: {
Expand Down Expand Up @@ -90,16 +90,14 @@ const Button = forwardRef<HTMLButtonElement, ButtonProps>(
return (
<div ref={containerRef}>
<Comp
className={cn(
buttonVariants({ variant, size, className }),
disabled && "cursor-default opacity-50",
)}
className={cn(buttonVariants({ variant, size, className }))}
ref={ref}
onClick={handleClick}
onMouseEnter={() => setIsHover(true)}
onMouseLeave={() => setIsHover(false)}
onMouseMove={handleMouseMove}
{...props}
disabled={disabled}
>
{!disabled && (
<motion.div
Expand Down
Loading

0 comments on commit 8d6e6fd

Please sign in to comment.