Skip to content

Commit

Permalink
chore: Unify notification duration
Browse files Browse the repository at this point in the history
  • Loading branch information
daavidrgz committed Oct 19, 2024
1 parent 1a18644 commit 6c8711d
Show file tree
Hide file tree
Showing 12 changed files with 83 additions and 45 deletions.
20 changes: 11 additions & 9 deletions crates/web/frontend/src/app/page-utils.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { notify } from "@/lib/notify";
import type { Completion } from "@/model/completion";
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";

export const applyGq = async (
Expand All @@ -20,7 +20,7 @@ export const applyGq = async (
outputType: outputType,
indent: indent,
});
!silent && toast.success(`Query applied to ${inputData.type.toUpperCase()}`);
!silent && notify.success(`Query applied to ${inputData.type.toUpperCase()}`);
return result;
};

Expand Down Expand Up @@ -53,17 +53,19 @@ export const getQueryCompletionSource = (
};
};

export const importShare = async (shareId: string): Promise<{ input: Data; query: Data }> => {
const toastId = toast.loading("Importing share...");
export const importShare = async (
shareId: string,
): Promise<{ input: Data; query: Data } | undefined> => {
const toastId = notify.loading("Importing share...");
try {
const share = await getShare(shareId);
toast.success("Share successfully imported", { id: toastId });
return Promise.resolve({
notify.success("Share successfully imported", { id: toastId });
return {
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, duration: 5000 });
return Promise.reject(error);
notify.error(`Error importing share: ${error.message}`, { id: toastId });
return undefined;
}
};
20 changes: 9 additions & 11 deletions crates/web/frontend/src/app/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import Editor from "@/components/editor/editor";
import Footer from "@/components/footer/footer";
import Header from "@/components/header/header";
import useDebounce from "@/hooks/useDebounce";
import { notify } from "@/lib/notify";
import { cn, i } from "@/lib/utils";
import { Data } from "@/model/data";
import FileType from "@/model/file-type";
Expand All @@ -17,7 +18,6 @@ import type { CompletionSource } from "@codemirror/autocomplete";
import { Link2, Link2Off } from "lucide-react";
import { useSearchParams } from "next/navigation";
import { type MutableRefObject, Suspense, useCallback, useEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { applyGq, getQueryCompletionSource, importShare } from "./page-utils";
import styles from "./page.module.css";

Expand All @@ -32,12 +32,11 @@ const ShareLoader = ({

useEffect(() => {
if (!shareId) return;
importShare(shareId)
.then((data) => {
updateInputEditorCallback?.current(data.input);
updateQueryEditorCallback?.current(data.query);
})
.catch(() => {});
importShare(shareId).then((data) => {
if (!data) return;
updateInputEditorCallback?.current(data.input);
updateQueryEditorCallback?.current(data.query);
});
}, [shareId, updateInputEditorCallback, updateQueryEditorCallback]);

return null;
Expand Down Expand Up @@ -105,7 +104,7 @@ const Home = () => {
updateInputEditorCallback.current(json);
updateQueryEditorCallback.current(query);
updateOutputData(json.content, json.type, query.content, true);
toast.success("Example loaded!");
notify.success("Example loaded!");
},
[updateOutputData],
);
Expand All @@ -122,9 +121,8 @@ const Home = () => {

const handleChangeLinked = useCallback(() => {
setSettings((prev) => setLinkEditors(prev, !linkEditors));
toast.info(`${linkEditors ? "Unlinked" : "Linked"} editors!`);
if (linkEditors) return;
convertOutputEditorCallback.current(inputType.current);
notify.info(`${linkEditors ? "Unlinked" : "Linked"} editors!`);
if (!linkEditors) convertOutputEditorCallback.current(inputType.current);
}, [linkEditors, setSettings]);

const handleChangeInputContent = useCallback(
Expand Down
16 changes: 8 additions & 8 deletions crates/web/frontend/src/components/editor/editor-utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { notify } from "@/lib/notify";
import { isMac } from "@/lib/utils";
import type { Data } from "@/model/data";
import FileType from "@/model/file-type";
Expand All @@ -19,7 +20,6 @@ import {
} from "@codemirror/language";
import { parser } from "@lezer/json";
import { EditorView, type Extension, Prec, keymap } from "@uiw/react-codemirror";
import { toast } from "sonner";
import type PromiseWorker from "webworker-promise";
import { validateFile } from "../import-popup/import-utils";
import urlPlugin from "./url-plugin";
Expand All @@ -32,7 +32,7 @@ export const exportFile = (data: Data, filename: string) => {
a.download = `${filename}.${data.type}`;
a.click();
URL.revokeObjectURL(url);
toast.success("File exported successfully!");
notify.success("File exported successfully!");
};

export const formatCode = async (
Expand All @@ -41,13 +41,13 @@ export const formatCode = async (
formatWorker: PromiseWorker,
silent = true,
): Promise<Data> => {
const toastId = silent ? undefined : toast.loading("Formatting code...");
const toastId = silent ? undefined : notify.loading("Formatting code...");
try {
const response: Data = await formatWorker.postMessage({ data, indent });
!silent && toast.success("Code formatted!", { id: toastId });
!silent && notify.success("Code formatted!", { id: toastId });
return response;
} catch (err) {
!silent && toast.error(err.message, { id: toastId, duration: 5000 });
!silent && notify.error(err.message, { id: toastId });
throw err;
}
};
Expand All @@ -59,13 +59,13 @@ export const convertCode = async (
convertWorker: PromiseWorker,
silent = true,
): Promise<Data> => {
const toastId = silent ? undefined : toast.loading("Converting code...");
const toastId = silent ? undefined : notify.loading("Converting code...");
try {
const result: Data = await convertWorker.postMessage({ data, outputType, indent });
!silent && toast.success("Code converted!", { id: toastId });
!silent && notify.success("Code converted!", { id: toastId });
return result;
} catch (err) {
!silent && toast.error(err.message, { id: toastId, duration: 5000 });
!silent && notify.error(err.message, { id: toastId });
throw err;
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { notify } from "@/lib/notify";
import { statusTextMap } from "@/lib/utils";
import { Data } from "@/model/data";
import type FileType from "@/model/file-type";
Expand Down Expand Up @@ -25,14 +26,14 @@ export const validateFile = (
const error = new Error(
`Files of type ${importedFileType} cannot be imported into this editor`,
);
toast.error(error.message);
notify.error(error.message);
onError?.(error);
return;
}
onSuccess?.({ f: file, type: importedFileType });
} catch {
const error = new Error(`Unable to import files of type ${file.type}`);
toast.error(error.message);
notify.error(error.message);
onError?.(error);
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ExpirationTime, toSeconds } from "@/model/expiration-time";
import { notify } from "@/lib/notify";
import { ShareTooLargeError } from "@/model/errors/share-input-too-large-error";
import { type ExpirationTime, toSeconds } from "@/model/expiration-time";
import { createShare } from "@/service/share-service";
import { toast } from "sonner";

export const createShareLink = async (
inputContent: string,
Expand All @@ -9,11 +10,15 @@ export const createShareLink = async (
): Promise<string> => {
try {
const shareId = await createShare(inputContent, queryContent, toSeconds(expirationTime));
toast.success("Share link created!");
notify.success("Share link created!");
const shareLink = `${window.location.origin}?id=${shareId}`;
return Promise.resolve(shareLink);
} catch (err) {
toast.error(`An error occurred while creating the share link: ${err.message}`);
if (err instanceof ShareTooLargeError) {
notify.error(err.message);
} else {
notify.error(`Unexpected error while creating the share link: ${err.message}`);
}
return Promise.reject(err);
}
};
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { cn, copyToClipboard } from "@/lib/utils";
import { Clipboard, Clock, InfoIcon, Link, Share } from "lucide-react";
import type { ExpirationTime } from "@/model/expiration-time";
import { Clipboard, Clock, Share } from "lucide-react";
import { useCallback, useState } from "react";
import ActionButton from "../action-button/action-button";
import { Button } from "../ui/button";
Expand All @@ -16,10 +17,7 @@ import {
import { RadioGroup, RadioGroupItem } from "../ui/radio-group";
import { Separator } from "../ui/separator";
import { Loader } from "../ui/sonner";
import { ExpirationTime } from "@/model/expiration-time";
import { createShareLink } from "./share-popover-utils";
import { Data } from "@/model/data";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../ui/tooltip";

interface SharePopoverProps {
inputContent: string;
Expand Down
1 change: 1 addition & 0 deletions crates/web/frontend/src/lib/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const MAX_SHARE_SIZE = 2000000; // 2MB
24 changes: 24 additions & 0 deletions crates/web/frontend/src/lib/notify.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { type ExternalToast, toast } from "sonner";

const loading = (message: string | React.ReactNode, data?: ExternalToast): string | number => {
return toast.loading(message, data);
};

const success = (message: string | React.ReactNode, data?: ExternalToast): string | number => {
return toast.success(message, { ...data, duration: 2000 });
};

const info = (message: string | React.ReactNode, data?: ExternalToast): string | number => {
return toast.info(message, { ...data, duration: 2000 });
};

const error = (message: string | React.ReactNode, data?: ExternalToast): string | number => {
return toast.error(message, { ...data, duration: 5000 });
};

export const notify = {
loading,
success,
info,
error,
};
4 changes: 2 additions & 2 deletions crates/web/frontend/src/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ClassValue, clsx } from "clsx";
import { toast } from "sonner";
import { twMerge } from "tailwind-merge";
import { notify } from "./notify";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
Expand Down Expand Up @@ -31,7 +31,7 @@ export const isMac = navigator.platform.includes("Mac"); // Deprecated navigator

export const copyToClipboard = (content: string) => {
navigator.clipboard.writeText(content);
toast.success("Copied to your clipboard!");
notify.success("Copied to your clipboard!");
};

export const statusTextMap = new Map([
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export class ShareTooLargeError extends Error {
constructor() {
super("The playground content is larger than the maximum allowed size (2MB)");
}
}
8 changes: 4 additions & 4 deletions crates/web/frontend/src/providers/worker-provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,10 @@ interface Props {
}

export const WorkerProvider = ({ children }: Props) => {
const [formatWorker, setFormatWorker] = useState<PromiseWorker | undefined>(undefined);
const [gqWorker, setGqWorker] = useState<PromiseWorker | undefined>(undefined);
const [lspWorker, setLspWorker] = useState<PromiseWorker | undefined>(undefined);
const [convertWorker, setConvertWorker] = useState<PromiseWorker | undefined>(undefined);
const [formatWorker, setFormatWorker] = useState<PromiseWorker>();
const [gqWorker, setGqWorker] = useState<PromiseWorker>();
const [lspWorker, setLspWorker] = useState<PromiseWorker>();
const [convertWorker, setConvertWorker] = useState<PromiseWorker>();

useEffect(() => {
setFormatWorker(new PromiseWorker(new Worker(new URL("../worker/format.ts", import.meta.url))));
Expand Down
6 changes: 5 additions & 1 deletion crates/web/frontend/src/service/share-service.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { MAX_SHARE_SIZE } from "@/lib/constants";
import { ShareTooLargeError } from "@/model/errors/share-input-too-large-error";
import { type Share, ShareSchema } from "@/model/share";
import type { ZodSchema } from "zod";

Expand All @@ -13,7 +15,9 @@ export const createShare = async (
queryContent: string,
expirationTimeSecs: number,
): Promise<string> => {
console.log("createShare", inputContent, queryContent, expirationTimeSecs);
if (inputContent.length + queryContent.length > MAX_SHARE_SIZE) {
throw new ShareTooLargeError();
}
const res = await fetch(sharesEndpoint, {
method: "POST",
body: JSON.stringify({ json: inputContent, query: queryContent, expirationTimeSecs }),
Expand Down

0 comments on commit 6c8711d

Please sign in to comment.