feat: Initial commit of KROW Workforce Web client (Base44 export)
This commit is contained in:
183
src/components/ui/use-toast.jsx
Normal file
183
src/components/ui/use-toast.jsx
Normal file
@@ -0,0 +1,183 @@
|
||||
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 }
|
||||
Reference in New Issue
Block a user