diff --git a/apps/console/src/components/ui/toast.tsx b/apps/console/src/components/ui/toast.tsx index 2ddb7c5a8..8b108bc50 100644 --- a/apps/console/src/components/ui/toast.tsx +++ b/apps/console/src/components/ui/toast.tsx @@ -1,11 +1,11 @@ -import * as React from "react" -import * as ToastPrimitives from "@radix-ui/react-toast" -import { cva, type VariantProps } from "class-variance-authority" -import { X } from "lucide-react" +import * as React from "react"; +import * as ToastPrimitives from "@radix-ui/react-toast"; +import { cva, type VariantProps } from "class-variance-authority"; +import { X } from "lucide-react"; -import { cn } from "@/lib/utils" +import { cn } from "@/lib/utils"; -const ToastProvider = ToastPrimitives.Provider +const ToastProvider = ToastPrimitives.Provider; const ToastViewport = React.forwardRef< React.ElementRef, @@ -15,12 +15,12 @@ const ToastViewport = React.forwardRef< ref={ref} className={cn( "fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px]", - className + className, )} {...props} /> -)) -ToastViewport.displayName = ToastPrimitives.Viewport.displayName +)); +ToastViewport.displayName = ToastPrimitives.Viewport.displayName; const toastVariants = cva( "group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md border p-4 pr-6 shadow-lg transition-all data-[swipe=cancel]:translate-x-0 data-[swipe=end]:translate-x-[var(--radix-toast-swipe-end-x)] data-[swipe=move]:translate-x-[var(--radix-toast-swipe-move-x)] data-[swipe=move]:transition-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full", @@ -35,8 +35,8 @@ const toastVariants = cva( defaultVariants: { variant: "default", }, - } -) + }, +); const Toast = React.forwardRef< React.ElementRef, @@ -49,9 +49,9 @@ const Toast = React.forwardRef< className={cn(toastVariants({ variant }), className)} {...props} /> - ) -}) -Toast.displayName = ToastPrimitives.Root.displayName + ); +}); +Toast.displayName = ToastPrimitives.Root.displayName; const ToastAction = React.forwardRef< React.ElementRef, @@ -61,12 +61,12 @@ const ToastAction = React.forwardRef< ref={ref} className={cn( "inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium transition-colors hover:bg-secondary focus:outline-none focus:ring-1 focus:ring-ring disabled:pointer-events-none disabled:opacity-50 group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive", - className + className, )} {...props} /> -)) -ToastAction.displayName = ToastPrimitives.Action.displayName +)); +ToastAction.displayName = ToastPrimitives.Action.displayName; const ToastClose = React.forwardRef< React.ElementRef, @@ -76,15 +76,15 @@ const ToastClose = React.forwardRef< ref={ref} className={cn( "absolute right-1 top-1 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-1 group-hover:opacity-100 group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600", - className + className, )} toast-close="" {...props} > -)) -ToastClose.displayName = ToastPrimitives.Close.displayName +)); +ToastClose.displayName = ToastPrimitives.Close.displayName; const ToastTitle = React.forwardRef< React.ElementRef, @@ -95,8 +95,8 @@ const ToastTitle = React.forwardRef< className={cn("text-sm font-semibold [&+div]:text-xs", className)} {...props} /> -)) -ToastTitle.displayName = ToastPrimitives.Title.displayName +)); +ToastTitle.displayName = ToastPrimitives.Title.displayName; const ToastDescription = React.forwardRef< React.ElementRef, @@ -107,12 +107,12 @@ const ToastDescription = React.forwardRef< className={cn("text-sm opacity-90", className)} {...props} /> -)) -ToastDescription.displayName = ToastPrimitives.Description.displayName +)); +ToastDescription.displayName = ToastPrimitives.Description.displayName; -type ToastProps = React.ComponentPropsWithoutRef +type ToastProps = React.ComponentPropsWithoutRef; -type ToastActionElement = React.ReactElement +type ToastActionElement = React.ReactElement; export { type ToastProps, @@ -124,4 +124,4 @@ export { ToastDescription, ToastClose, ToastAction, -} +}; diff --git a/apps/console/src/components/ui/toaster.tsx b/apps/console/src/components/ui/toaster.tsx index 6c67edff6..5887f0804 100644 --- a/apps/console/src/components/ui/toaster.tsx +++ b/apps/console/src/components/ui/toaster.tsx @@ -1,4 +1,4 @@ -import { useToast } from "@/hooks/use-toast" +import { useToast } from "@/hooks/use-toast"; import { Toast, ToastClose, @@ -6,10 +6,10 @@ import { ToastProvider, ToastTitle, ToastViewport, -} from "@/components/ui/toast" +} from "@/components/ui/toast"; export function Toaster() { - const { toasts } = useToast() + const { toasts } = useToast(); return ( @@ -25,9 +25,9 @@ export function Toaster() { {action} - ) + ); })} - ) + ); } diff --git a/apps/console/src/hooks/use-toast.ts b/apps/console/src/hooks/use-toast.ts index 02e111d81..6555e795c 100644 --- a/apps/console/src/hooks/use-toast.ts +++ b/apps/console/src/hooks/use-toast.ts @@ -1,78 +1,75 @@ -"use client" +"use client"; // Inspired by react-hot-toast library -import * as React from "react" +import * as React from "react"; -import type { - ToastActionElement, - ToastProps, -} from "@/components/ui/toast" +import type { ToastActionElement, ToastProps } from "@/components/ui/toast"; -const TOAST_LIMIT = 1 -const TOAST_REMOVE_DELAY = 1000000 +const TOAST_LIMIT = 1; +const TOAST_REMOVE_DELAY = 1000000; 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) { @@ -80,27 +77,27 @@ export const reducer = (state: State, action: Action): State => { return { ...state, toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT), - } + }; case "UPDATE_TOAST": return { ...state, toasts: state.toasts.map((t) => - t.id === action.toast.id ? { ...t, ...action.toast } : 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,46 +108,46 @@ export const reducer = (state: State, action: Action): State => { ...t, open: false, } - : t + : 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 = Omit; 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", @@ -159,36 +156,36 @@ function toast({ ...props }: Toast) { 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 }; diff --git a/apps/console/src/pages/CreatePeoplePage.tsx b/apps/console/src/pages/CreatePeoplePage.tsx index 8e45de9a5..284ced04d 100644 --- a/apps/console/src/pages/CreatePeoplePage.tsx +++ b/apps/console/src/pages/CreatePeoplePage.tsx @@ -32,7 +32,10 @@ const createPeoplePageQuery = graphql` `; const createPeopleMutation = graphql` - mutation CreatePeoplePageCreatePeopleMutation($input: CreatePeopleInput!, $connections: [ID!]!) { + mutation CreatePeoplePageCreatePeopleMutation( + $input: CreatePeopleInput! + $connections: [ID!]! + ) { createPeople(input: $input) { peopleEdge @prependEdge(connections: $connections) { node { @@ -89,17 +92,18 @@ function CreatePeoplePageContent({ const navigate = useNavigate(); const environment = useRelayEnvironment(); const data = usePreloadedQuery(createPeoplePageQuery, queryRef); - const [createPeople] = useMutation(createPeopleMutation); + const [createPeople] = + useMutation(createPeopleMutation); const { toast } = useToast(); const [formData, setFormData] = useState({ - fullName: '', - primaryEmailAddress: '', + fullName: "", + primaryEmailAddress: "", additionalEmailAddresses: [] as string[], - kind: 'EMPLOYEE' as 'EMPLOYEE' | 'CONTRACTOR', + kind: "EMPLOYEE" as "EMPLOYEE" | "CONTRACTOR", }); const handleFieldChange = (field: keyof typeof formData, value: any) => { - setFormData(prev => ({ + setFormData((prev) => ({ ...prev, [field]: value, })); @@ -107,7 +111,10 @@ function CreatePeoplePageContent({ const handleSubmit = (e: React.FormEvent) => { e.preventDefault(); - const peopleConnectionId = ConnectionHandler.getConnectionID(data.currentOrganization.id, "PeopleListPage_peoples"); + const peopleConnectionId = ConnectionHandler.getConnectionID( + data.currentOrganization.id, + "PeopleListPage_peoples", + ); createPeople({ variables: { @@ -150,7 +157,7 @@ function CreatePeoplePageContent({ handleFieldChange('fullName', value)} + onChange={(value) => handleFieldChange("fullName", value)} required /> @@ -158,7 +165,9 @@ function CreatePeoplePageContent({ label="Primary Email" value={formData.primaryEmailAddress} type="email" - onChange={(value) => handleFieldChange('primaryEmailAddress', value)} + onChange={(value) => + handleFieldChange("primaryEmailAddress", value) + } required /> @@ -174,17 +183,28 @@ function CreatePeoplePageContent({ type="email" value={email} onChange={(e) => { - const newEmails = [...formData.additionalEmailAddresses]; + const newEmails = [ + ...formData.additionalEmailAddresses, + ]; newEmails[index] = e.target.value; - handleFieldChange('additionalEmailAddresses', newEmails); + handleFieldChange( + "additionalEmailAddresses", + newEmails, + ); }} /> - - - -

- {formData.serviceCriticality === 'HIGH' && + {formData.serviceCriticality === "HIGH" && "Critical service - downtime severely impacts end-users"} - {formData.serviceCriticality === 'MEDIUM' && + {formData.serviceCriticality === "MEDIUM" && "Important service - downtime moderately affects end-users"} - {formData.serviceCriticality === 'LOW' && + {formData.serviceCriticality === "LOW" && "Non-critical service - minimal end-user impact if down"}

@@ -305,46 +319,48 @@ function VendorOverviewPageContent({
- - -

- {formData.riskTier === 'CRITICAL' && + {formData.riskTier === "CRITICAL" && "Handles sensitive data, critical for platform operation"} - {formData.riskTier === 'SIGNIFICANT' && + {formData.riskTier === "SIGNIFICANT" && "No user data access, but important for platform management"} - {formData.riskTier === 'GENERAL' && + {formData.riskTier === "GENERAL" && "General vendor with minimal risk"}

@@ -352,19 +368,25 @@ function VendorOverviewPageContent({ handleFieldChange('statusPageUrl', value)} + onChange={(value) => + handleFieldChange("statusPageUrl", value) + } /> handleFieldChange('termsOfServiceUrl', value)} + onChange={(value) => + handleFieldChange("termsOfServiceUrl", value) + } /> handleFieldChange('privacyPolicyUrl', value)} + onChange={(value) => + handleFieldChange("privacyPolicyUrl", value) + } /> @@ -374,13 +396,10 @@ function VendorOverviewPageContent({ {hasChanges && (
- -