From f54224650f6f6f35434bcfb1292663d2c11dae57 Mon Sep 17 00:00:00 2001 From: mbecker20 Date: Wed, 22 May 2024 04:20:48 -0700 Subject: [PATCH] fix update --- frontend/src/lib/socket.tsx | 18 +++-- frontend/src/ui/use-toast.ts | 131 ++++++++++++++++++----------------- 2 files changed, 81 insertions(+), 68 deletions(-) diff --git a/frontend/src/lib/socket.tsx b/frontend/src/lib/socket.tsx index b8546f26d..c8045416a 100644 --- a/frontend/src/lib/socket.tsx +++ b/frontend/src/lib/socket.tsx @@ -9,6 +9,7 @@ import { cn } from "@lib/utils"; import { AUTH_TOKEN_STORAGE_KEY } from "@main"; import { ResourceComponents } from "@components/resources"; import { UsableResource } from "@types"; +import { ResourceName } from "@components/resources/common"; const rws_atom = atom(null); const useWebsocket = () => useAtom(rws_atom); @@ -41,13 +42,22 @@ const on_message = ( const update = JSON.parse(data) as Types.UpdateListItem; const Components = ResourceComponents[update.target.type as UsableResource]; - const title = Components - ? `${update.operation} - ${Components.list_item(update.target.id)?.name}` - : update.operation; + const title = Components ? ( +
+
{update.operation}
- +
+ +
+
+ ) : ( + update.operation + ); toast({ title, - description: update.username, variant: update.success ? "default" : "destructive", }); diff --git a/frontend/src/ui/use-toast.ts b/frontend/src/ui/use-toast.ts index d47d42e1e..58c3071ed 100644 --- a/frontend/src/ui/use-toast.ts +++ b/frontend/src/ui/use-toast.ts @@ -1,76 +1,73 @@ // Inspired by react-hot-toast library -import * as React from "react" +import * as React from "react"; -import type { - ToastActionElement, - ToastProps, -} from "@//ui/toast" +import type { ToastActionElement, ToastProps } from "@//ui/toast"; -const TOAST_LIMIT = 3 -const TOAST_REMOVE_DELAY = 5_000 +const TOAST_LIMIT = 3; +const TOAST_REMOVE_DELAY = 5_000; type ToasterToast = ToastProps & { - id: string - title?: React.ReactNode - description?: React.ReactNode - action?: ToastActionElement -} + id: string; + title?: React.ReactNode; + description?: React.ReactNode; + action?: ToastActionElement; +}; const actionTypes = { ADD_TOAST: "ADD_TOAST", UPDATE_TOAST: "UPDATE_TOAST", DISMISS_TOAST: "DISMISS_TOAST", REMOVE_TOAST: "REMOVE_TOAST", -} as const +} as const; -let count = 0 +let count = 0; function genId() { - count = (count + 1) % Number.MAX_SAFE_INTEGER - return count.toString() + count = (count + 1) % Number.MAX_SAFE_INTEGER; + return count.toString(); } -type ActionType = typeof actionTypes +type ActionType = typeof actionTypes; type Action = | { - type: ActionType["ADD_TOAST"] - toast: ToasterToast + type: ActionType["ADD_TOAST"]; + toast: ToasterToast; } | { - type: ActionType["UPDATE_TOAST"] - toast: Partial + type: ActionType["UPDATE_TOAST"]; + toast: Partial; } | { - type: ActionType["DISMISS_TOAST"] - toastId?: ToasterToast["id"] + type: ActionType["DISMISS_TOAST"]; + toastId?: ToasterToast["id"]; } | { - type: ActionType["REMOVE_TOAST"] - toastId?: ToasterToast["id"] - } + type: ActionType["REMOVE_TOAST"]; + toastId?: ToasterToast["id"]; + }; interface State { - toasts: ToasterToast[] + toasts: ToasterToast[]; } -const toastTimeouts = new Map>() +const toastTimeouts = new Map>(); const addToRemoveQueue = (toastId: string) => { if (toastTimeouts.has(toastId)) { - return + return; } const timeout = setTimeout(() => { - toastTimeouts.delete(toastId) + toastTimeouts.delete(toastId); dispatch({ type: "REMOVE_TOAST", toastId: toastId, - }) - }, TOAST_REMOVE_DELAY) + }); + }, TOAST_REMOVE_DELAY); - toastTimeouts.set(toastId, timeout) -} + toastTimeouts.set(toastId, timeout); +}; export const reducer = (state: State, action: Action): State => { switch (action.type) { @@ -78,7 +75,7 @@ export const reducer = (state: State, action: Action): State => { return { ...state, toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - } + }; case "UPDATE_TOAST": return { @@ -86,19 +83,19 @@ export const reducer = (state: State, action: Action): State => { toasts: state.toasts.map((t) => t.id === action.toast.id ? { ...t, ...action.toast } : t ), - } + }; case "DISMISS_TOAST": { - const { toastId } = action + const { toastId } = action; // ! Side effects ! - This could be extracted into a dismissToast() action, // but I'll keep it here for simplicity if (toastId) { - addToRemoveQueue(toastId) + addToRemoveQueue(toastId); } else { state.toasts.forEach((toast) => { - addToRemoveQueue(toast.id) - }) + addToRemoveQueue(toast.id); + }); } return { @@ -111,82 +108,88 @@ export const reducer = (state: State, action: Action): State => { } : t ), - } + }; } case "REMOVE_TOAST": if (action.toastId === undefined) { return { ...state, toasts: [], - } + }; } return { ...state, toasts: state.toasts.filter((t) => t.id !== action.toastId), - } + }; } -} +}; -const listeners: Array<(state: State) => void> = [] +const listeners: Array<(state: State) => void> = []; -let memoryState: State = { toasts: [] } +let memoryState: State = { toasts: [] }; function dispatch(action: Action) { - memoryState = reducer(memoryState, action) + memoryState = reducer(memoryState, action); listeners.forEach((listener) => { - listener(memoryState) - }) + listener(memoryState); + }); } -type Toast = Omit +type Toast = { + title?: React.ReactNode; + description?: React.ReactNode; + action?: ToastActionElement; + variant?: ToastProps["variant"]; +}; function toast({ ...props }: Toast) { - const id = genId() + const id = genId(); const update = (props: ToasterToast) => dispatch({ type: "UPDATE_TOAST", toast: { ...props, id }, - }) - const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }) + }); + const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id }); dispatch({ type: "ADD_TOAST", toast: { ...props, + title: props.title as any, id, open: true, onOpenChange: (open) => { - if (!open) dismiss() + if (!open) dismiss(); }, }, - }) + }); return { id: id, dismiss, update, - } + }; } function useToast() { - const [state, setState] = React.useState(memoryState) + const [state, setState] = React.useState(memoryState); React.useEffect(() => { - listeners.push(setState) + listeners.push(setState); return () => { - const index = listeners.indexOf(setState) + const index = listeners.indexOf(setState); if (index > -1) { - listeners.splice(index, 1) + listeners.splice(index, 1); } - } - }, [state]) + }; + }, [state]); return { ...state, toast, dismiss: (toastId?: string) => dispatch({ type: "DISMISS_TOAST", toastId }), - } + }; } -export { useToast, toast } +export { useToast, toast };