[TSM.ID].[11031972] PXE : Platform X Ecosystem I [118 Module -LIVE-]

This commit is contained in:
TSM.ID
2026-05-25 03:50:05 +07:00
commit e820143b3c
673 changed files with 101320 additions and 0 deletions
+240
View File
@@ -0,0 +1,240 @@
/* eslint-disable */
// @ts-nocheck
"use client";
import React, { useEffect, useRef, useState } from "react";
import { XCUQuantumCipher } from "../lib/xcu-quantum-cipher";
interface Message {
id: string;
sender: string;
text: string;
timestamp: number;
isSelf: boolean;
isResonanceAudio?: boolean;
}
export const JumlahChat = ({
roomName,
participantName,
participantId,
webTransport,
onClose,
}: {
roomName: string;
participantName: string;
participantId: number;
webTransport: { datagrams: { readable: ReadableStream, writable: WritableStream } } | null;
onClose: () => void;
}) => {
const [messages, setMessages] = useState<Message[]>([]);
const [input, setInput] = useState("");
const [typingHeat, setTypingHeat] = useState(0);
const [isRecording, setIsRecording] = useState(false);
const cipherRef = useRef<XCUQuantumCipher | null>(null);
const chatEndRef = useRef<HTMLDivElement>(null);
const typingTimeout = useRef<NodeJS.Timeout | null>(null);
const mediaRecorderRef = useRef<MediaRecorder | null>(null);
const audioChunksRef = useRef<Blob[]>([]);
useEffect(() => {
const initCipher = async () => {
const cipher = new XCUQuantumCipher(roomName);
await cipher.initialize();
cipherRef.current = cipher;
};
initCipher();
}, [roomName]);
useEffect(() => {
chatEndRef.current?.scrollIntoView({ behavior: "smooth" });
}, [messages, typingHeat]);
useEffect(() => {
if (!webTransport || !webTransport.datagrams) return;
let isActive = true;
const readDatagrams = async () => {
try {
const reader = webTransport.datagrams.readable.getReader();
while (isActive) {
const { value, done } = await reader.read();
if (done) break;
if (value && value.length >= 8) {
const type = value[0];
const senderId = new DataView(value.buffer).getUint16(2, true);
if (senderId === participantId) continue;
const payload = value.slice(8);
if (type === 7 && cipherRef.current) {
try {
const dec = await cipherRef.current.decrypt(payload);
const parsed = JSON.parse(dec);
setMessages((prev) => [...prev, { id: crypto.randomUUID(), sender: parsed.sender, text: parsed.text, timestamp: parsed.timestamp, isSelf: false }]);
} catch (e) {}
} else if (type === 8) {
setTypingHeat((prev) => Math.min(prev + 20, 100));
if (typingTimeout.current) clearTimeout(typingTimeout.current);
typingTimeout.current = setTimeout(() => setTypingHeat(0), 1000);
} else if (type === 9 && cipherRef.current) {
try {
const dec = await cipherRef.current.decrypt(payload);
const parsed = JSON.parse(dec);
setMessages((prev) => [...prev, { id: crypto.randomUUID(), sender: parsed.sender, text: parsed.audioBase64, timestamp: parsed.timestamp, isSelf: false, isResonanceAudio: true }]);
} catch {}
}
}
}
} catch {}
};
readDatagrams();
return () => { isActive = false; };
}, [webTransport, participantId]);
const sendTypingResonance = async () => {
if (!webTransport || !webTransport.datagrams) return;
let writer: WritableStreamDefaultWriter | null = null;
try {
writer = webTransport.datagrams.writable.getWriter();
const buf = new Uint8Array(8);
buf[0] = 8; new DataView(buf.buffer).setUint16(2, participantId, true);
await writer.write(buf);
} catch {} finally { if (writer) writer.releaseLock(); }
};
const sendMessage = async (e: React.FormEvent) => {
e.preventDefault();
if (!input.trim() || !cipherRef.current || !webTransport) return;
const payloadStr = JSON.stringify({ sender: participantName, text: input, timestamp: Date.now() });
const encPayload = await cipherRef.current.encrypt(payloadStr);
const header = new Uint8Array(8);
header[0] = 7; new DataView(header.buffer).setUint16(2, participantId, true);
const fullPacket = new Uint8Array(8 + encPayload.length);
fullPacket.set(header, 0); fullPacket.set(encPayload, 8);
let writer: WritableStreamDefaultWriter | null = null;
try {
writer = webTransport.datagrams.writable.getWriter();
if (writer) await writer.write(fullPacket);
setMessages((prev) => [...prev, { id: crypto.randomUUID(), sender: participantName, text: input, timestamp: Date.now(), isSelf: true }]);
} catch (e) {} finally { if (writer) writer.releaseLock(); }
setInput("");
};
const startRecording = async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
const mediaRecorder = new MediaRecorder(stream, { mimeType: 'audio/webm;codecs=opus' });
mediaRecorderRef.current = mediaRecorder; audioChunksRef.current = [];
mediaRecorder.ondataavailable = (e) => { if (e.data.size > 0) audioChunksRef.current.push(e.data); };
mediaRecorder.onstop = async () => {
const audioBlob = new Blob(audioChunksRef.current, { type: 'audio/webm' });
const reader = new FileReader();
reader.readAsDataURL(audioBlob);
reader.onloadend = async () => {
const base64data = reader.result as string;
if (cipherRef.current && webTransport) {
const payloadStr = JSON.stringify({ sender: participantName, audioBase64: base64data, timestamp: Date.now() });
const encPayload = await cipherRef.current.encrypt(payloadStr);
const header = new Uint8Array(8);
header[0] = 9; new DataView(header.buffer).setUint16(2, participantId, true);
const fullPacket = new Uint8Array(8 + encPayload.length);
fullPacket.set(header, 0); fullPacket.set(encPayload, 8);
let writer: WritableStreamDefaultWriter | null = null;
try {
writer = webTransport.datagrams.writable.getWriter();
if (writer) await writer.write(fullPacket);
} catch (e) {} finally { if (writer) writer.releaseLock(); }
setMessages((prev) => [...prev, { id: crypto.randomUUID(), sender: participantName, text: base64data, timestamp: Date.now(), isSelf: true, isResonanceAudio: true }]);
}
};
stream.getTracks().forEach(t => t.stop());
};
mediaRecorder.start(); setIsRecording(true);
} catch (err) {}
};
const stopRecording = () => { if (mediaRecorderRef.current && isRecording) { mediaRecorderRef.current.stop(); setIsRecording(false); } };
return (
<div className="flex flex-col h-full bg-transparent">
{/* Header */}
<div className="p-6 border-b border-white/5 flex items-center justify-between bg-black/20">
<div className="flex items-center gap-3">
<h2 className="text-sm font-black uppercase tracking-widest text-white/90">In-Meeting Chat</h2>
<span className="px-2 py-0.5 rounded text-[8px] font-black uppercase tracking-widest bg-emerald-500/20 text-emerald-400 border border-emerald-500/30">BYOK XChaCha20</span>
</div>
<button onClick={onClose} className="text-gray-500 hover:text-white transition-colors">
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12" /></svg>
</button>
</div>
{/* Messages Area */}
<div className="flex-1 p-6 overflow-y-auto custom-scroll flex flex-col gap-6">
{messages.length === 0 ? (
<div className="my-auto text-center space-y-4">
<div className="w-12 h-12 bg-emerald-500/10 rounded-2xl flex items-center justify-center mx-auto text-emerald-500">
<svg className="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M8 12h.01M12 12h.01M16 12h.01M21 12c0 4.418-4.03 8-9 8a9.863 9.863 0 01-4.255-.949L3 20l1.395-3.72C3.512 15.042 3 13.574 3 12c0-4.418 4.03-8 9-8s9 3.582 9 8z"></path></svg>
</div>
<p className="text-[10px] text-gray-500 uppercase font-black tracking-widest leading-relaxed">
Kanal Transmisi Kuantum Aktif.<br />BYOK XChaCha20-Poly1305 E2EE.
</p>
</div>
) : (
messages.map((msg) => (
<div key={msg.id} className={`flex flex-col ${msg.isSelf ? "items-end" : "items-start"}`}>
<div className="flex items-center gap-2 mb-1.5 px-1">
<span className="text-[9px] font-black uppercase tracking-widest text-white/40">{msg.sender}</span>
<span className="text-[8px] font-mono text-white/20">{new Date(msg.timestamp).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}</span>
</div>
<div className={`px-4 py-3 rounded-2xl text-[13px] leading-relaxed max-w-[90%] shadow-xl border ${msg.isSelf ? "bg-emerald-600 border-emerald-500 text-black font-medium rounded-tr-none" : "bg-white/5 border-white/5 text-white/90 rounded-tl-none"}`}>
{msg.isResonanceAudio ? (
<audio controls src={msg.text} className="h-8 w-44 filter invert brightness-200" />
) : (
msg.text
)}
</div>
</div>
))
)}
{/* Telepathic Resonance Heatmap */}
{typingHeat > 0 && (
<div className="flex items-center gap-3 px-1">
<span className="text-[9px] font-black text-emerald-500 uppercase tracking-widest animate-pulse">Partisipan Mengetik</span>
<div className="flex items-center gap-1.5">
{[...Array(4)].map((_, i) => (
<div key={i} className="w-1 bg-emerald-500 rounded-full animate-bounce" style={{ height: '8px', animationDelay: `${i * 0.1}s` }} />
))}
</div>
</div>
)}
<div ref={chatEndRef} />
</div>
{/* Input Area */}
<div className="p-6 border-t border-white/5">
<form onSubmit={sendMessage} className="relative group">
<input
type="text" value={input} onChange={(e) => { setInput(e.target.value); sendTypingResonance(); }}
placeholder="Ketik pesan..."
className="w-full bg-white/5 border border-white/5 rounded-2xl pl-4 pr-24 py-4 text-xs text-white placeholder-white/20 focus:outline-none focus:border-emerald-500/50 focus:bg-white/10 transition-all shadow-inner"
/>
<div className="absolute right-2 top-2 bottom-2 flex items-center gap-1">
<button
type="button" onMouseDown={startRecording} onMouseUp={stopRecording} onMouseLeave={stopRecording}
className={`p-2.5 rounded-xl transition-all ${isRecording ? "bg-red-500 animate-pulse scale-110 shadow-lg" : "text-white/40 hover:text-white hover:bg-white/5"}`}
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path></svg>
</button>
<button
type="submit" disabled={!input.trim()}
className="bg-emerald-500 hover:bg-emerald-400 disabled:opacity-20 text-black p-2.5 rounded-xl transition-all shadow-lg"
>
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M14 5l7 7m0 0l-7 7m7-7H3"></path></svg>
</button>
</div>
</form>
<p className="text-[8px] text-center text-white/20 mt-4 uppercase font-black tracking-widest">Quantum Resonance Encryption Active</p>
</div>
</div>
);
};