finished conenct modal
This commit is contained in:
@@ -5,6 +5,7 @@ import { Server } from "socket.io";
|
|||||||
import { createAdapter } from "@socket.io/redis-adapter";
|
import { createAdapter } from "@socket.io/redis-adapter";
|
||||||
import { jwtMiddleware } from "modules/socketJWTmiddleware";
|
import { jwtMiddleware } from "modules/socketJWTmiddleware";
|
||||||
import { pubClient, subClient } from "modules/redis";
|
import { pubClient, subClient } from "modules/redis";
|
||||||
|
import { handle } from "socket-events/connect-dispatch";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
const server = createServer(app);
|
const server = createServer(app);
|
||||||
@@ -17,7 +18,7 @@ const io = new Server(server, {
|
|||||||
io.use(jwtMiddleware);
|
io.use(jwtMiddleware);
|
||||||
|
|
||||||
io.on("connection", (socket) => {
|
io.on("connection", (socket) => {
|
||||||
socket.on("connect-dispatch", () => {});
|
socket.on("connect-dispatch", handle(socket, io));
|
||||||
});
|
});
|
||||||
server.listen(process.env.PORT, () => {
|
server.listen(process.env.PORT, () => {
|
||||||
console.log(`Server running on port ${process.env.PORT}`);
|
console.log(`Server running on port ${process.env.PORT}`);
|
||||||
|
|||||||
@@ -13,12 +13,12 @@
|
|||||||
"@types/express": "^5.0.0",
|
"@types/express": "^5.0.0",
|
||||||
"@types/node": "^22.13.5",
|
"@types/node": "^22.13.5",
|
||||||
"@types/nodemailer": "^6.4.17",
|
"@types/nodemailer": "^6.4.17",
|
||||||
"@types/socket.io-redis": "^3.0.0",
|
|
||||||
"concurrently": "^9.1.2",
|
"concurrently": "^9.1.2",
|
||||||
"typescript": "latest"
|
"typescript": "latest"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-email/components": "^0.0.33",
|
"@react-email/components": "^0.0.33",
|
||||||
|
"@redis/json": "^1.0.7",
|
||||||
"@socket.io/redis-adapter": "^8.3.0",
|
"@socket.io/redis-adapter": "^8.3.0",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"cron": "^4.1.0",
|
"cron": "^4.1.0",
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
"nodemailer": "^6.10.0",
|
"nodemailer": "^6.10.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"redis": "^4.7.0",
|
"redis": "^4.7.0",
|
||||||
"socket.io": "^4.8.1",
|
"socket.io": "^4.8.1"
|
||||||
"socket.io-redis": "^6.1.1"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,34 @@
|
|||||||
import { pubClient } from "modules/redis";
|
import { pubClient } from "modules/redis";
|
||||||
import { Server, Socket } from "socket.io";
|
import { Server, Socket } from "socket.io";
|
||||||
|
|
||||||
export const handle = (socket: Socket, io: Server) => async (jwt: string) => {
|
export const handle =
|
||||||
const userId = socket.data.user.id; // User ID aus dem JWT-Token
|
(socket: Socket, io: Server) =>
|
||||||
await pubClient.set(`dispatchers:${socket.id}`, userId);
|
async ({
|
||||||
|
logoffTime,
|
||||||
|
selectedZone,
|
||||||
|
}: {
|
||||||
|
logoffTime: string;
|
||||||
|
selectedZone: string;
|
||||||
|
}) => {
|
||||||
|
const userId = socket.data.user.id; // User ID aus dem JWT-Token
|
||||||
|
await pubClient.json.set(`dispatchers:${socket.id}`, "$", {
|
||||||
|
logoffTime,
|
||||||
|
selectedZone,
|
||||||
|
userId,
|
||||||
|
});
|
||||||
|
|
||||||
socket.join("dispatchers"); // Dem Dispatcher-Raum beitreten
|
socket.join("dispatchers"); // Dem Dispatcher-Raum beitreten
|
||||||
|
|
||||||
socket.on("disconnect", async () => {
|
const keys = await pubClient.keys("dispatchers:*");
|
||||||
console.log("Disconnected from dispatch server");
|
const dispatchers = await Promise.all(
|
||||||
await pubClient.del(`dispatchers:${socket.id}`);
|
keys.map(async (key) => {
|
||||||
});
|
return await pubClient.json.get(key);
|
||||||
};
|
}),
|
||||||
|
);
|
||||||
|
console.log(dispatchers);
|
||||||
|
|
||||||
|
socket.on("disconnect", async () => {
|
||||||
|
console.log("Disconnected from dispatch server");
|
||||||
|
await pubClient.json.del(`dispatchers:${socket.id}`);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,79 +1,96 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useSession } from "next-auth/react";
|
import { useSession } from "next-auth/react";
|
||||||
import { connectionStore } from "../../_store/connectionStore";
|
import { connectionStore } from "../../_store/connectionStore";
|
||||||
import { useEffect } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { CheckCircledIcon } from "@radix-ui/react-icons";
|
import { useForm } from "react-hook-form";
|
||||||
|
|
||||||
export const ConnectBtn = () => {
|
export const ConnectionBtn = () => {
|
||||||
|
const modalRef = useRef<HTMLDialogElement>(null);
|
||||||
|
const connection = connectionStore((state) => state);
|
||||||
|
const [form, setForm] = useState({
|
||||||
|
logoffTime: "",
|
||||||
|
selectedZone: "LST_01",
|
||||||
|
});
|
||||||
|
const session = useSession();
|
||||||
|
const uid = session.data?.user?.id;
|
||||||
|
if (!uid) return null;
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<button
|
{!connection.isConnected ? (
|
||||||
className="btn btn-soft btn-info"
|
<button
|
||||||
onClick={() =>
|
className="btn btn-soft btn-info"
|
||||||
(
|
onClick={() => modalRef.current?.showModal()}
|
||||||
document.getElementById("my_modal_1") as HTMLDialogElement
|
>
|
||||||
)?.showModal()
|
Verbinden
|
||||||
}
|
</button>
|
||||||
>
|
) : (
|
||||||
Verbinden
|
<button
|
||||||
</button>
|
className="btn btn-soft btn-success"
|
||||||
<dialog id="my_modal_1" className="modal">
|
onClick={() => modalRef.current?.showModal()}
|
||||||
|
>
|
||||||
|
Verbunden
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
|
<dialog ref={modalRef} className="modal">
|
||||||
<div className="modal-box flex flex-col items-center justify-center">
|
<div className="modal-box flex flex-col items-center justify-center">
|
||||||
<h3 className="text-lg font-bold mb-5">Als Disponent anmelden</h3>
|
{connection.isConnected ? (
|
||||||
|
<h3 className="text-lg font-bold mb-5">
|
||||||
|
Verbunden als{" "}
|
||||||
|
<span className="text-info">
|
||||||
|
<{connection.selectedZone}>
|
||||||
|
</span>
|
||||||
|
</h3>
|
||||||
|
) : (
|
||||||
|
<h3 className="text-lg font-bold mb-5">Als Disponent anmelden</h3>
|
||||||
|
)}
|
||||||
<fieldset className="fieldset w-full">
|
<fieldset className="fieldset w-full">
|
||||||
<label className="floating-label w-full text-base">
|
<label className="floating-label w-full text-base">
|
||||||
<span>Logoff Zeit (UTC+1)</span>
|
<span>Logoff Zeit (UTC+1)</span>
|
||||||
<input type="time" className="input w-full" />
|
<input
|
||||||
|
onChange={(e) =>
|
||||||
|
setForm({
|
||||||
|
...form,
|
||||||
|
logoffTime: e.target.value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
value={form.logoffTime}
|
||||||
|
type="time"
|
||||||
|
className="input w-full"
|
||||||
|
/>
|
||||||
</label>
|
</label>
|
||||||
<p className="fieldset-label">
|
{!connection.isConnected && (
|
||||||
Du kannst diese Zeit später noch anpassen.
|
<p className="fieldset-label">
|
||||||
</p>
|
Du kannst diese Zeit später noch anpassen.
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<div className="modal-action flex justify-between w-full">
|
<div className="modal-action flex justify-between w-full">
|
||||||
<form method="dialog" className="w-full flex justify-between">
|
<form method="dialog" className="w-full flex justify-between">
|
||||||
<button className="btn btn-soft">Abbrechen</button>
|
<button className="btn btn-soft">Abbrechen</button>
|
||||||
<button className="btn btn-soft btn-info">Verbinden</button>
|
{connection.isConnected ? (
|
||||||
</form>
|
<button
|
||||||
</div>
|
className="btn btn-soft btn-error"
|
||||||
</div>
|
type="submit"
|
||||||
</dialog>
|
onSubmit={() => false}
|
||||||
</>
|
onClick={() => {
|
||||||
);
|
connection.disconnect();
|
||||||
};
|
}}
|
||||||
|
>
|
||||||
export const ConnectedBtn = () => {
|
Verbindung Trennen
|
||||||
return (
|
</button>
|
||||||
<>
|
) : (
|
||||||
<button
|
<button
|
||||||
className="btn btn-soft btn-success"
|
type="submit"
|
||||||
onClick={() =>
|
onSubmit={() => false}
|
||||||
(
|
onClick={() => {
|
||||||
document.getElementById("my_modal_1") as HTMLDialogElement
|
connection.connect(uid, form.selectedZone, form.logoffTime);
|
||||||
)?.showModal()
|
}}
|
||||||
}
|
className="btn btn-soft btn-info"
|
||||||
>
|
>
|
||||||
Verbunden
|
Verbinden
|
||||||
</button>
|
</button>
|
||||||
<dialog id="my_modal_1" className="modal">
|
)}
|
||||||
<div className="modal-box flex flex-col items-center justify-center">
|
|
||||||
<h3 className="text-lg font-bold mb-5">
|
|
||||||
Verbunden als <span className="text-info"><LST_01></span>
|
|
||||||
</h3>
|
|
||||||
<fieldset className="fieldset w-full">
|
|
||||||
<label className="floating-label w-full text-base join">
|
|
||||||
<span>Logoff Zeit (UTC+1)</span>
|
|
||||||
<input type="time" className="input w-full" />
|
|
||||||
<button className="btn btn-soft btn-info join-item">
|
|
||||||
<CheckCircledIcon className="w-4 h-4" /> Save
|
|
||||||
</button>
|
|
||||||
</label>
|
|
||||||
</fieldset>
|
|
||||||
<div className="modal-action flex justify-between w-full">
|
|
||||||
<form method="dialog" className="w-full flex justify-between">
|
|
||||||
<button className="btn btn-soft">Abbrechen</button>
|
|
||||||
<button className="btn btn-soft btn-error">
|
|
||||||
Verbindung Trennen
|
|
||||||
</button>
|
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -83,15 +100,9 @@ export const ConnectedBtn = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const Connection = () => {
|
export const Connection = () => {
|
||||||
const session = useSession();
|
return (
|
||||||
const cStore = connectionStore((state) => state);
|
<div>
|
||||||
const uid = session.data?.user?.id;
|
<ConnectionBtn />
|
||||||
|
</div>
|
||||||
useEffect(() => {
|
);
|
||||||
if (uid) {
|
|
||||||
cStore.connect(uid);
|
|
||||||
}
|
|
||||||
}, [uid]);
|
|
||||||
|
|
||||||
return <div>{cStore.isConnected ? <ConnectedBtn /> : <ConnectBtn />}</div>;
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,17 +3,39 @@ import { socket } from "../(dispatch)/socket";
|
|||||||
|
|
||||||
interface ConnectionStore {
|
interface ConnectionStore {
|
||||||
isConnected: boolean;
|
isConnected: boolean;
|
||||||
connect: (uid: string) => Promise<void>;
|
selectedZone: string;
|
||||||
|
connect: (
|
||||||
|
uid: string,
|
||||||
|
selectedZone: string,
|
||||||
|
logoffTime: string,
|
||||||
|
) => Promise<void>;
|
||||||
|
disconnect: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const connectionStore = create<ConnectionStore>((set) => ({
|
export const connectionStore = create<ConnectionStore>((set) => ({
|
||||||
isConnected: false,
|
isConnected: false,
|
||||||
connect: async (uid: string) => {
|
selectedZone: "LST_01",
|
||||||
socket.auth = { uid };
|
connect: async (uid, selectedZone, logoffTime) =>
|
||||||
socket.connect();
|
new Promise((resolve) => {
|
||||||
|
socket.auth = { uid };
|
||||||
|
set({ selectedZone });
|
||||||
|
socket.connect();
|
||||||
|
socket.once("connect", () => {
|
||||||
|
socket.emit("connect-dispatch", {
|
||||||
|
logoffTime,
|
||||||
|
selectedZone,
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
disconnect: () => {
|
||||||
|
socket.disconnect();
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
|
|
||||||
socket.on("connect", () => {
|
socket.on("connect", () => {
|
||||||
connectionStore.setState({ isConnected: true });
|
connectionStore.setState({ isConnected: true });
|
||||||
});
|
});
|
||||||
|
socket.on("disconnect", () => {
|
||||||
|
connectionStore.setState({ isConnected: false });
|
||||||
|
});
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
"postcss": "^8.5.1",
|
"postcss": "^8.5.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
"react-hook-form": "^7.54.2",
|
||||||
"socket.io-client": "^4.8.1",
|
"socket.io-client": "^4.8.1",
|
||||||
"tailwindcss": "^4.0.14",
|
"tailwindcss": "^4.0.14",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.3"
|
||||||
|
|||||||
@@ -23,15 +23,11 @@ services:
|
|||||||
- postgres
|
- postgres
|
||||||
redis:
|
redis:
|
||||||
container_name: redis
|
container_name: redis
|
||||||
image: docker.io/bitnami/redis:7.4
|
image: redis/redis-stack:latest
|
||||||
environment:
|
|
||||||
# ALLOW_EMPTY_PASSWORD is recommended only for development.
|
|
||||||
- ALLOW_EMPTY_PASSWORD=yes
|
|
||||||
- REDIS_DISABLE_COMMANDS=FLUSHDB,FLUSHALL
|
|
||||||
ports:
|
ports:
|
||||||
- "6379:6379"
|
- "6379:6379"
|
||||||
volumes:
|
volumes:
|
||||||
- "redis_data:/bitnami/redis/data"
|
- "redis_data:/data"
|
||||||
|
|
||||||
moodle_database:
|
moodle_database:
|
||||||
container_name: moodle_database
|
container_name: moodle_database
|
||||||
|
|||||||
2
package-lock.json
generated
2
package-lock.json
generated
@@ -30,6 +30,7 @@
|
|||||||
"postcss": "^8.5.1",
|
"postcss": "^8.5.1",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
|
"react-hook-form": "^7.54.2",
|
||||||
"socket.io-client": "^4.8.1",
|
"socket.io-client": "^4.8.1",
|
||||||
"tailwindcss": "^4.0.14",
|
"tailwindcss": "^4.0.14",
|
||||||
"zustand": "^5.0.3"
|
"zustand": "^5.0.3"
|
||||||
@@ -48,6 +49,7 @@
|
|||||||
"apps/dispatch-server": {
|
"apps/dispatch-server": {
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-email/components": "^0.0.33",
|
"@react-email/components": "^0.0.33",
|
||||||
|
"@redis/json": "^1.0.7",
|
||||||
"@socket.io/redis-adapter": "^8.3.0",
|
"@socket.io/redis-adapter": "^8.3.0",
|
||||||
"axios": "^1.7.9",
|
"axios": "^1.7.9",
|
||||||
"cron": "^4.1.0",
|
"cron": "^4.1.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user