- Added API routes for fetching connected users, keywords, missions, and stations. - Created a new QueryProvider component for managing query states and socket events. - Introduced connection stores for dispatch and pilot, managing socket connections and states. - Updated Prisma schema for connected aircraft model. - Enhanced UI with toast notifications for status updates and chat interactions. - Implemented query functions for fetching connected users and keywords with error handling.
118 lines
2.7 KiB
TypeScript
118 lines
2.7 KiB
TypeScript
import { useState } from "react";
|
|
import { toast } from "react-hot-toast";
|
|
|
|
interface ToastCard {
|
|
id: number;
|
|
title: string;
|
|
content: string;
|
|
}
|
|
|
|
const MapToastCard2 = () => {
|
|
const [cards, setCards] = useState<ToastCard[]>([]);
|
|
const [openCardId, setOpenCardId] = useState<number | null>(null);
|
|
|
|
const addCard = () => {
|
|
const newCard: ToastCard = {
|
|
id: Date.now(),
|
|
title: `Einsatz #${cards.length + 1}`,
|
|
content: `Inhalt von Einsatz #${cards.length + 1}.`,
|
|
};
|
|
setCards([...cards, newCard]);
|
|
// DEBUG
|
|
/* toast("😖 Christoph 31 sendet Status 4", {
|
|
duration: 10000,
|
|
}); */
|
|
// DEBUG
|
|
const toastId = toast.custom(
|
|
<div
|
|
style={{
|
|
display: "flex",
|
|
alignItems: "center",
|
|
lineHeight: 1.3,
|
|
willChange: "transform",
|
|
boxShadow:
|
|
"0 3px 10px rgba(0, 0, 0, 0.1), 0 3px 3px rgba(0, 0, 0, 0.05)",
|
|
maxWidth: "350px",
|
|
pointerEvents: "auto",
|
|
padding: "8px 10px",
|
|
borderRadius: "8px",
|
|
background: "var(--color-base-100)",
|
|
color: "var(--color-base-content)",
|
|
}}
|
|
>
|
|
<div
|
|
className="toastText flex items-center"
|
|
style={{
|
|
display: "flex",
|
|
justifyContent: "center",
|
|
margin: "4px 10px",
|
|
color: "inherit",
|
|
flex: "1 1 auto",
|
|
whiteSpace: "pre-line",
|
|
}}
|
|
>
|
|
😖 Christoph 31 sendet Status 5{" "}
|
|
<button
|
|
className="btn btn-sm btn-soft btn-accent ml-2"
|
|
onClick={() => toast.remove(toastId)}
|
|
>
|
|
U
|
|
</button>
|
|
</div>
|
|
</div>,
|
|
{
|
|
duration: 999999999,
|
|
},
|
|
);
|
|
// DEBUG
|
|
};
|
|
|
|
const removeCard = (id: number) => {
|
|
setCards(cards.filter((card) => card.id !== id));
|
|
};
|
|
|
|
const toggleCard = (id: number) => {
|
|
setOpenCardId(openCardId === id ? null : id);
|
|
};
|
|
|
|
return (
|
|
<div className="absolute top-4 right-4 z-[1000] flex flex-col space-y-4">
|
|
{/* DEBUG */}
|
|
<button
|
|
onClick={addCard}
|
|
className="mb-4 p-2 bg-blue-500 text-white rounded self-end"
|
|
>
|
|
Debug Einsatz
|
|
</button>
|
|
{/* DEBUG */}
|
|
{cards.map((card) => (
|
|
<div
|
|
key={card.id}
|
|
className="collapse collapse-arrow bg-base-100 border-base-300 border w-120 relative"
|
|
>
|
|
<input
|
|
type="checkbox"
|
|
className="absolute top-0 left-0 opacity-0"
|
|
checked={openCardId === card.id}
|
|
onChange={() => toggleCard(card.id)}
|
|
/>
|
|
<div className="collapse-title font-semibold flex justify-between items-center">
|
|
<span>{card.title}</span>
|
|
<button
|
|
className="btn btn-sm btn-circle btn-ghost z-10 absolute top-3.5 right-8"
|
|
onClick={(e) => {
|
|
removeCard(card.id);
|
|
}}
|
|
>
|
|
✕
|
|
</button>
|
|
</div>
|
|
<div className="collapse-content text-sm">{card.content}</div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default MapToastCard2;
|