183 lines
4.4 KiB
JavaScript
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 } |