Files
Krow-workspace/src/components/ui/use-toast.jsx

183 lines
4.4 KiB
JavaScript

import React from "react"
import { base44 } from "@/api/base44Client";
const TOAST_LIMIT = 5
const TOAST_REMOVE_DELAY = 1000000
let count = 0
function genId() {
count = (count + 1) % Number.MAX_VALUE
return count.toString()
}
const toastTimeouts = new Map()
const addToRemoveQueue = (toastId) => {
if (toastTimeouts.has(toastId)) {
return
}
const timeout = setTimeout(() => {
toastTimeouts.delete(toastId)
dispatch({
type: "REMOVE_TOAST",
toastId: toastId,
})
}, TOAST_REMOVE_DELAY)
toastTimeouts.set(toastId, timeout)
}
const reducer = (state, action) => {
switch (action.type) {
case "ADD_TOAST":
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
),
}
case "DISMISS_TOAST": {
const { toastId } = action
if (toastId) {
addToRemoveQueue(toastId)
} else {
state.toasts.forEach((toast) => {
addToRemoveQueue(toast.id)
})
}
return {
...state,
toasts: state.toasts.map((t) =>
t.id === toastId || toastId === undefined
? {
...t,
open: false,
}
: t
),
}
}
case "REMOVE_TOAST":
if (action.toastId === undefined) {
return {
...state,
toasts: [],
}
}
return {
...state,
toasts: state.toasts.filter((t) => t.id !== action.toastId),
}
}
}
const listeners = []
let memoryState = { toasts: [] }
function dispatch(action) {
memoryState = reducer(memoryState, action)
listeners.forEach((listener) => {
listener(memoryState)
})
}
// Helper function to create notification in ActivityLog instead of toast
async function createNotification(title, description, variant) {
try {
const user = await base44.auth.me();
// Determine icon and color based on variant and title
let icon_type = "check";
let icon_color = "blue";
let activity_type = "message_received";
if (variant === "destructive" || title.includes("Failed") || title.includes("Error")) {
icon_type = "alert";
icon_color = "red";
activity_type = "event_updated";
} else if (title.includes("Success") || title.includes("✅") || title.includes("Saved") || title.includes("Created")) {
icon_type = "check";
icon_color = "green";
activity_type = "event_created";
} else if (title.includes("Invoice") || title.includes("Payment")) {
icon_type = "invoice";
icon_color = "purple";
activity_type = "invoice_created";
} else if (title.includes("Event") || title.includes("Order")) {
icon_type = "calendar";
icon_color = "blue";
activity_type = "event_created";
} else if (title.includes("User") || title.includes("Staff") || title.includes("Member")) {
icon_type = "user";
icon_color = "green";
activity_type = "staff_assigned";
}
await base44.entities.ActivityLog.create({
title: title.replace(/✅|❌|⚠️/g, '').trim(),
description: description || "",
activity_type: activity_type,
user_id: user.id,
is_read: false,
icon_type: icon_type,
icon_color: icon_color,
});
} catch (error) {
console.error("Failed to create notification:", error);
}
}
function toast({ title, description, variant, ...props }) {
const id = genId()
// Instead of showing a toast, create a notification in ActivityLog
createNotification(title, description, variant);
const update = (props) =>
dispatch({
type: "UPDATE_TOAST",
toast: { ...props, id },
})
const dismiss = () => dispatch({ type: "DISMISS_TOAST", toastId: id })
// Don't actually add to visible toasts
// Just return the interface for compatibility
return {
id: id,
dismiss,
update,
}
}
function useToast() {
const [state, setState] = React.useState(memoryState)
React.useEffect(() => {
listeners.push(setState)
return () => {
const index = listeners.indexOf(setState)
if (index > -1) {
listeners.splice(index, 1)
}
}
}, [state])
return {
...state,
toast,
dismiss: (toastId) => dispatch({ type: "DISMISS_TOAST", toastId }),
}
}
export { useToast, toast }