How to structure nestjs project [closed]

How to structure an event organization web application?

I’m new to programming projects from scratch, and I’ve started creating an event organization web application. I’m confused about how to divide the functionality.

Application Requirements:

  1. User:

    • Can see upcoming events
    • Can choose an existing group to enroll in
  2. Admin:

    • Can create and manage groups for an event
    • Each group represents an activity for the event (presentation, song, dance, etc.)

My Questions:

  1. What is the right way to define modules for this nestjs project

  2. How to define whick entities shoould i create

I would appreciate any guidance on the architecture and role division for this type of application.

I haven’t started creating modules yet, was a bit scared to mess things up from the start

btFixedConstraint freeze objects

I am trying to ‘freeze objects together’ using Bullet (via JavaScript + Three.JS)

Here is my scene
https://codepen.io/PartyPants2/pen/emYLRPX?editors=0010

Here we see a Merry-go-round simulation, in which 8 horses are generated above a turntable/disc.

a 3d simulation of horses on a Merry-go-round

This GIF illustrates the system working as expected – the 8 horses (instances of bodyA) are frozen-in-place to the turntable/disc (bodyB)

However a problem becomes apparent when the disc (bodyB) has different rotation applied: the horses are being rotated by a factor of bodyB‘s rotation, knocking them off of their target axis.

a 3d simulation of horses on a Merry-go-round has tilted turntable and the horses are being tilted a disproportionally when constraints are activated2

When we turn on the physics, the FixedConstraints activate. Because the constraints are being misconfigured (in some way I am trying to determine) the horses are rotating disproportionately to the turntable.

I have tried every combination of absolute and relative rotations that I can think of (to the point of making an interface to trial different combinations), but the horses never adhere correctly to the turntable.

Here’s a simplified version of my btFixedConstraint implementation

// bodyA = the rigidBody being attached
// bodyB = what bodyA is being attached to
const applyFixedConstraint = (bodyA, bodyB) => {
    const relRotationAB = getRelativeRotation(bodyA, bodyB);
    const relPosBA = getRelativePosition(bodyB, bodyA);
    // FRAME IN A
    const frameInA = new Ammo.btTransform();
    frameInA.setIdentity();
    frameInA.getOrigin().setValue(0, 0, 0);
    frameInB.setRotation(new Ammo.btQuaternion(0,0,0,1)); // i.e. 'none'
    // FRAME IN B
    const frameInB = new Ammo.btTransform();
    frameInB.setIdentity();
    frameInB.getOrigin().setValue(relPosBA.x, relPosBA.y, relPosBA.z); 
    frameInB.setRotation(new Ammo.btQuaternion(relRotationAB.x, relRotationAB.y, relRotationAB.z, relRotationAB.w));
    // RESULT
    const fixedConstraint = new Ammo.btFixedConstraint(bodyA,bodyB,frameInA,frameInB); // this line doesn't "freeze items in the air" like it should
    physicsWorld.addConstraint(fixedConstraint, true);
    return fixedConstraint;
}

btFixedConstraint only has one constructor: new Ammo.btFixedConstraint(bodyA,bodyB,frameInA,frameInB); and since bodyA and bodyB are certain to be correct, only frameInA or frameInB could have the problem…

How can I calculate the correct frameInA and frameInB for freezing objects together using btFixedConstraint ?

Resolving Javascript Modules with importmap not working on android chrome

I have a symfony project with the assetmapper package active. There is an app.js which imports:

import './styles/app.css';
import Wood from "./wood.js";

The gernerated importmap looks like this:

<script type="importmap">
{
    "imports": {
        "app": "/assets/app-g2dctYT.js",
        "/assets/styles/app.css": "data:application/javascript,",
        "/assets/wood.js": "/assets/wood-PRFWpuV.js"
    }
}
</script>

On my Desktop Chrome. Everything works as expected. But on the mobile chrome on my android device (134.0.6998.135) it will try to load the file from /assets/wood.js instead of /assets/wood-PRFWpuV.js. If a manually edit the importmap making it “foo”: “/assets/wood-PRFWpuV.js” and making it import Wood from “foo” accordingly it works. Is there a known issue on chrome Android with this or am I doing something wrong?

Video element shows blank while the media stream is set through srcObject

I know this is a little long code, however, I gave complete code because I really couldn’t find exact cause.
The local view works perfectly, but other’s users shows blank div in chrome.
Please help with this, I’m stuck with this since a week.

And, as I tested, the MediaStream (event.stream) wasn’t null, and is valid.

Full code: https://drive.google.com/file/d/1f2YV5tyXgIiRQV378zIhsDJ03j3EYFnK/view?usp=sharing

import SendIcon from '@mui/icons-material/Send';
import GridLayout from "react-grid-layout";


import "./Video.css"

import ReactPlayer from 'react-player';

const server_url = 'http://localhost:3002/';
const beforeUnloadListener = (event) => {
    //Send something to back end
    // event.preventDefault(); // This is necessary for the confirmation dialog to show in some browsers
    // event.returnValue = 'Are you sure you want to leave?'; // This will show a confirmation dialog
    this.handleDeleteCurrUserFromDB();
    this.handleEndCall();

}



const viewTypes = [
    {
        value: 'Default',
        label: <LabelWithIcon icon={InterpreterModeIcon} text="Default View" />,
    },
    {
        value: 'GridView',
        label: <LabelWithIcon icon={GridViewIcon} text="Grid View" />,
    },

];


class Video extends Component {




    constructor(props) {
        super(props)

        this.myVidRef = React.createRef();
        this.remoteStreamsRef = React.createRef();

        this.videoContainerRef = React.createRef();


        this.localVideoref = React.createRef()

        this.videoAvailable = false
        this.audioAvailable = false

        this.state = {
            video: false,
            audio: false,
            screen: false,
            showModal: false,
            screenAvailable: false,
            messages: [],
            localStream: [],
            streams: [],
            message: "",
            newmessages: 0,
            askForUsername: true,
            username: name,
            gridRows: 1,
            meetLinkPSM: meetLinkPSMt,
            videoType: "Default", // Add this line
            remoteStreams: [],
            forceRenderKey: 0, // Force re-render when needed
            gridLayoutData: [],
            renderReloader: 0,

        }
        connections = {}

        this.getPermissions()




    }

    handleVideoTypeChange = (event) => {
        const selectedType = event.target.value;
        this.setState({ videoType: selectedType }, () => {
            console.log("Selected video type:", this.state.videoType); // Debug log
        });
        this.getUserMedia(); // Call getUserMedia after updating the video type
        console.log("Local video stream:", this.localVideoref.current?.srcObject);
        

    };
    getPermissions = async () => {
        try {
            await navigator.mediaDevices.getUserMedia({ video: true })
                .then(() => this.videoAvailable = true)
                .catch(() => this.videoAvailable = false)

            await navigator.mediaDevices.getUserMedia({ audio: true })
                .then(() => this.audioAvailable = true)
                .catch(() => this.audioAvailable = false)

            if (navigator.mediaDevices.getDisplayMedia) {
                this.setState({ screenAvailable: true })
            } else {
                this.setState({ screenAvailable: false })
            }

            if (this.videoAvailable || this.audioAvailable) {
                navigator.mediaDevices.getUserMedia({ video: this.videoAvailable, audio: this.audioAvailable })
                    .then((stream) => {
                        window.localStream = stream
                        this.localVideoref.current.srcObject = stream
                    })
                    .then((stream) => { })
                    .catch((e) => console.log(e))
            }
        } catch (e) { console.log(e) }
    }
    putfullScreen = (event) => {
        let elem = event.target
        if (elem.requestFullscreen) {
            elem.requestFullscreen()
        } else if (elem.mozRequestFullScreen) { /* Firefox */
            elem.mozRequestFullScreen()
        } else if (elem.webkitRequestFullscreen) { /* Chrome, Safari and Opera */
            elem.webkitRequestFullscreen()
        } else if (elem.msRequestFullscreen) { /* IE/Edge */
            elem.msRequestFullscreen()
        }

    }
    getMedia = () => {
        this.setState({
            video: this.videoAvailable,
            audio: this.audioAvailable
        }, () => {
            this.getUserMedia()
            this.connectToSocketServer()
        })
    }

    getUserMedia = () => {
        if ((this.state.video && this.videoAvailable) || (this.state.audio && this.audioAvailable)) {
            navigator.mediaDevices.getUserMedia({ video: this.state.video, audio: this.state.audio })
                .then(this.getUserMediaSuccess)
                .then((stream) => { })
                .catch((e) => console.log(e))
        } else {
            try {
                let tracks = this.localVideoref.current.srcObject.getTracks()
                tracks.forEach(track => track.stop())
            } catch (e) { }
        }
    }

    getUserMediaSuccess = (stream) => {
        try {
            window.localStream.getTracks().forEach(track => track.stop())
        } catch (e) { console.log(e) }

        setTimeout(() => {
            const videoElem = document.getElementById('my-video');
            if (videoElem) {
                videoElem.srcObject = stream;
                console.log("Video element found, setting srcObject");
            } else {
                console.error("Video element not found in the DOM");
            }
        }, 1000);




        this.setState({ localStream: stream });

        for (let id in connections) {
            if (id === socketId) continue

            connections[id].addStream(window.localStream)

            connections[id].createOffer().then((description) => {
                connections[id].setLocalDescription(description)
                    .then(() => {
                        socket.emit('signal', id, JSON.stringify({ 'sdp': connections[id].localDescription }))
                    })
                    .catch(e => console.log(e))
            })
        }

        stream.getTracks().forEach(track => track.onended = () => {
            this.setState({
                video: false,
                audio: false,
            }, () => {
                try {
                    let tracks = this.localVideoref.current.srcObject.getTracks()
                    tracks.forEach(track => track.stop())
                } catch (e) { console.log(e) }

                let blackSilence = (...args) => new MediaStream([this.black(...args), this.silence()])
                window.localStream = blackSilence()
                this.localVideoref.current.srcObject = window.localStream

                for (let id in connections) {
                    connections[id].addStream(window.localStream)

                    connections[id].createOffer().then((description) => {
                        connections[id].setLocalDescription(description)
                            .then(() => {
                                socket.emit('signal', id, JSON.stringify({ 'sdp': connections[id].localDescription }))
                            })
                            .catch(e => console.log(e))
                    })
                }
            })
        })
    }

    getDislayMedia = () => {
        if (this.state.screen) {
            if (navigator.mediaDevices.getDisplayMedia) {
                navigator.mediaDevices.getDisplayMedia({ video: true, audio: true })
                    .then(this.getDislayMediaSuccess)
                    .then((stream) => { })
                    .catch((e) => console.log(e))
            }
        }
    }

    getDislayMediaSuccess = (stream) => {
        try {
            window.localStream.getTracks().forEach(track => track.stop())
        } catch (e) { console.log(e) }

        window.localStream = stream
        this.localVideoref.current.srcObject = stream

        for (let id in connections) {
            if (id === socketId) continue

            connections[id].addStream(window.localStream)

            connections[id].createOffer().then((description) => {
                connections[id].setLocalDescription(description)
                    .then(() => {
                        socket.emit('signal', id, JSON.stringify({ 'sdp': connections[id].localDescription }))
                    })
                    .catch(e => console.log(e))
            })
        }

        stream.getTracks().forEach(track => track.onended = () => {
            this.setState({
                screen: false,
            }, () => {
                try {
                    let tracks = this.localVideoref.current.srcObject.getTracks()
                    tracks.forEach(track => track.stop())
                } catch (e) { console.log(e) }

                let blackSilence = (...args) => new MediaStream([this.black(...args), this.silence()])
                window.localStream = blackSilence()
                this.localVideoref.current.srcObject = window.localStream

                this.getUserMedia()
            })
        })
    }




    gotMessageFromServer = (fromId, message) => {
        var signal = JSON.parse(message)

        if (fromId !== socketId) {
            if (signal.sdp) {
                connections[fromId].setRemoteDescription(new RTCSessionDescription(signal.sdp)).then(() => {
                    if (signal.sdp.type === 'offer') {
                        connections[fromId].createAnswer().then((description) => {
                            connections[fromId].setLocalDescription(description).then(() => {
                                socket.emit('signal', fromId, JSON.stringify({ 'sdp': connections[fromId].localDescription }))
                            }).catch(e => console.log(e))
                        }).catch(e => console.log(e))
                    }
                }).catch(e => console.log(e))
            }

            if (signal.ice) {
                connections[fromId].addIceCandidate(new RTCIceCandidate(signal.ice)).catch(e => console.log(e))
            }
        }
    }



    connectToSocketServer = () => {
        socket = io.connect(server_url, { secure: false })

        socket.on('signal', this.gotMessageFromServer)

        socket.on('connect', () => {
            socket.emit('join-call', { path: window.location.href, username: this.state.username })
            socketId = socket.id



            // socket.on('chat-message', this.addMessage)
            socket.on('chat-message', (data, sender, socketIdSender) => {
                console.log("Received chat message:", data, "from:", sender, "socketId:", socketIdSender); // Debug log
                this.addMessage(data, sender, socketIdSender);
            });

            socket.on('user-left', (id) => {

                this.state.gridLayoutData = this.state.gridLayoutData.filter(item => item.i !== id); // Remove the user from the grid layout data



                // Force a re-render
                this.forceUpdate();
                let video = document.querySelector(`[data-socket="${id}"]`)
                if (video !== null) {
                    elms--
                    video.parentNode.removeChild(video)

                    // let main = document.getElementById('main')
                    // this.changeCssVideos(main)
                }
            })

            socket.on('user-joined', (id, clients) => {
                clients.forEach((client) => {

                    const socketListId = client.id;
                    socketdmd = socketListId;
                    const username = client.username; // Add this line to get the username


                    this.triggerEventMessage(username + " Joined"); // Call the function with the socketListId and username

                    connections[socketListId] = new RTCPeerConnection(peerConnectionConfig)
                    // Wait for their ice candidate       
                    connections[socketListId].onicecandidate = function (event) {
                        if (event.candidate != null) {
                            socket.emit('signal', socketListId, JSON.stringify({ 'ice': event.candidate }))
                        }
                    }


                    const userExists = this.state.gridLayoutData.some(item => item.i == socketListId);
                    if (!userExists && socketListId !== socketId) {

                        var gridData = {
                            i: socketListId,
                            x: this.state.gridRows,
                            y: 0,
                            w: 2,
                            h: 6,
                            static: true,
                            username: username, // Add the username to the grid data
                        };
                        


                        this.setState((prevState) => {
                            // Check if the user already exists in gridLayoutData

                            const updatedGridLayoutData = prevState.gridLayoutData.map((item) => {
                                if (item.i === socketListId) {
                                    return { ...item, stream }; // Update the stream property
                                }
                                return item;

                            });

                            return { gridLayoutData: updatedGridLayoutData };
                        });
                        console.log("Stream added:", stream); // Debug log






                    };




                    // Add the local video stream
                    if (window.localStream !== undefined && window.localStream !== null) {
                        // alert("Local Stream is not null");
                        connections[socketListId].addStream(window.localStream)
                    } else {
                        // alert("Local Stream is null");
                        let blackSilence = (...args) => new MediaStream([this.black(...args), this.silence()])
                        window.localStream = blackSilence()
                        connections[socketListId].addStream(window.localStream)
                    }
                })

                if (id === socketId) {
                    for (let id2 in connections) {
                        if (id2 === socketId) continue

                        try {
                            connections[id2].addStream(window.localStream)
                        } catch (e) { }

                        connections[id2].createOffer().then((description) => {
                            connections[id2].setLocalDescription(description)
                                .then(() => {
                                    socket.emit('signal', id2, JSON.stringify({ 'sdp': connections[id2].localDescription }))
                                })
                                .catch(e => console.log(e))
                        })
                    }
                }
            })
        })
    };

    silence = () => {
        let ctx = new AudioContext()
        let oscillator = ctx.createOscillator()
        let dst = oscillator.connect(ctx.createMediaStreamDestination())
        oscillator.start()
        ctx.resume()
        return Object.assign(dst.stream.getAudioTracks()[0], { enabled: false })
    }
    black = ({ width = 640, height = 480 } = {}) => {
        let canvas = Object.assign(document.createElement("canvas"), { width, height })
        canvas.getContext('2d').fillRect(0, 0, width, height)
        let stream = canvas.captureStream()
        return Object.assign(stream.getVideoTracks()[0], { enabled: false })
    }

    handleVideo = () => this.setState({ video: !this.state.video }, () => this.getUserMedia())
    handleAudio = () => this.setState({ audio: !this.state.audio }, () => this.getUserMedia())
    handleScreen = () => this.setState({ screen: !this.state.screen }, () => this.getDislayMedia())





    openChat = () => this.setState({ showModal: true, newmessages: 0 })
    closeChat = () => this.setState({ showModal: false })
    handleMessage = (e) => this.setState({ message: e.target.value })

    // addMessage = (data, sender, socketIdSender) => {
    //  this.setState(prevState => ({
    //      messages: [...prevState.messages, { "sender": sender, "data": data }],
    //  }))
    //  if (socketIdSender !== socketId) {
    //      this.setState({ newmessages: this.state.newmessages + 1 })
    //  }
    // }

    addMessage = (data, sender, socketIdSender) => {
        console.log("Adding message to state:", data, sender, socketIdSender); // Debug log
        this.setState(prevState => ({
            messages: [...prevState.messages, { sender, data }],
        }), () => {
            console.log("Updated messages state:", this.state.messages); // Debug log after state update
        });
        if (socketIdSender !== socketId) {
            this.setState({ newmessages: this.state.newmessages + 1 });
        }
    };


    handleUsername = (e) => this.setState({ username: e.target.value })

    sendMessage = () => {
        socket.emit('chat-message', this.state.message, this.state.username)
        console.log("Message sent:", this.state.message, this.state.username)
        this.setState({ message: "", sender: this.state.username })
    }


    connect = () => {
        this.setState({ askForUsername: false }, () => this.getMedia());
        this.updateDataBaseMain();
    }
    handleShowDiagForEnd = () => {
        this.setState({ openDialog: true });
    }



    render() {

        const isMobile = this.isMobileDevice(); // Check if the device is mobile



        return (
            <div>
                {this.state.askForUsername === true ?
                    <div>
                        <div style={{
                            background: "white", width: "30%", height: "auto", padding: "20px", minWidth: "400px",
                            textAlign: "center", margin: "auto", marginTop: "50px", justifyContent: "center"
                        }}>
                            <p style={{ margin: 0, fontWeight: "bold", paddingRight: "50px" }}>Please Type You Name Here!</p>
                            <Input placeholder="Your Name" value={this.state.username} onChange={e => this.handleUsername(e)} />
                            <Button variant="contained" color="primary" onClick={this.connect} style={{ margin: "20px" }}>Connect</Button>
                        </div>

                        <div style={{ justifyContent: "center", textAlign: "center", paddingTop: "40px" }}>
                            <video id="my-video" ref={this.localVideoref} autoPlay muted style={{
                                borderStyle: "solid", borderColor: "#bdbdbd", objectFit: "fill", width: "60%", height: "30%"
                            }}></video>
                        </div>
                    </div>
                    :
                    <div>

                        <LatestEvent eventMessage={this.state.eventMessage} />
                        <div className="btn-down" style={{ position: "fixed", backgroundColor: "gray", color: "whitesmoke", textAlign: "center" }}>
                            <IconButton style={{ color: "#424242" }} onClick={this.handleVideo}>
                                {(this.state.video === true) ? <VideocamIcon /> : <VideocamOffIcon />}
                            </IconButton>

                            <IconButton style={{ color: "#f44336" }} id="btnEC" onClick={this.handleShowDiagForEnd}>
                                <CallEndIcon />
                            </IconButton>

                            <IconButton style={{ color: "#424242" }} onClick={this.handleAudio}>
                                {this.state.audio === true ? <MicIcon /> : <MicOffIcon />}
                            </IconButton>

                            {this.state.screenAvailable === true ?
                                <IconButton style={{ color: "#424242" }} onClick={this.handleScreen}>
                                    {this.state.screen === true ? <ScreenShareIcon /> : <StopScreenShareIcon />}
                                </IconButton>
                                : null}

                            <Badge badgeContent={this.state.newmessages} max={999} color="secondary" onClick={this.openChat}>
                                <IconButton style={{ color: "#424242" }} onClick={this.openChat}>
                                    <ChatIcon />
                                </IconButton>
                            </Badge>
                        </div>

                        <Modal show={this.state.showModal} onHide={this.closeChat} style={{ zIndex: "999999" }}>
                            <Modal.Header closeButton={false}>
                                <Modal.Title>Chat Room</Modal.Title>
                                <CloseIcon style={{ color: "#f44336", cursor: "pointer" }} id="btnEC" onClick={this.closeChat}>
                                </CloseIcon>
                            </Modal.Header>
                            <Modal.Body style={{ overflow: "auto", overflowY: "auto", height: "400px", textAlign: "left" }} >
                                {this.state.messages.length > 0 ? this.state.messages.map((item, index) => (
                                    <div key={index} style={{ textAlign: "left" }}>
                                        <p style={{ wordBreak: "break-all" }}><b>{item.sender}</b>: {item.data}</p>
                                    </div>
                                )) : <p>No message yet</p>}
                            </Modal.Body>
                            <Modal.Footer className="div-send-msg">
                                <TextField id="filled-full-width" variant='filled' fullWidth multiline placeholder="Message" value={this.state.message} onChange={e => this.handleMessage(e)} />
                                <br />
                                <br />
                                <Button onClick={this.sendMessage} variant="contained" endIcon={<SendIcon />}>
                                    Send
                                </Button>
                                {/* <Button variant="contained" color="primary" onClick={this.sendMessage}>Send</Button> */}
                            </Modal.Footer>
                        </Modal>

                        <div className="container">
                            <div className='header'>

                                <div className='left'>


                                    <div style={{ paddingTop: "20px" }}>

                                        <InfoIcon />
                                        <Input value={this.state.meetLinkPSM} disable="true"></Input>
                                        <Button style={{
                                            backgroundColor: "#3f51b5", color: "whitesmoke", marginLeft: "20px",
                                            marginTop: "10px", width: "120px", fontSize: "10px"
                                        }} onClick={this.copyUrl}>Copy invite link</Button>

                                    </div>
                                    <div className='right'>

                                        {!isMobile && (

                                            <TextField
                                                id="outlined-select-currency"
                                                select
                                                className='selectView'
                                                style={{ right: 0 }}
                                                value={this.state.videoType}
                                                onChange={this.handleVideoTypeChange}
                                                variant="outlined"
                                            >
                                                {viewTypes.map((option) => (
                                                    <MenuItem key={option.value} value={option.value}>
                                                        {option.label}
                                                    </MenuItem>
                                                ))}
                                            </TextField>

                                        )}
                                    </div>

                                </div>

                            </div>

                            {/* <Row id="main" className="flex-container" style={{ margin: 0, padding: 0 }}>

                                <br />

                            </Row> */}

                            {this.state.videoType === "GridView" ?

                                <div>



                                    <div style={{ paddingBottom: "80px" }}>
                                        <GridLayout
                                            id="main"
                                            className="layout"
                                            layout={this.state.gridLayoutData}
                                            cols={6}
                                            rowHeight={30}
                                            width={1200}
                                            isResizable={false}
                                            isDraggable={true}
                                        >


                                            <div
                                                key="local"
                                                data-grid={{ i: "local", x: 0, y: 0, w: 2, h: 6 }}
                                                className="video-tile main-video"
                                            >

                                                <video
                                                    id="my-video"
                                                    autoPlay
                                                    ref={this.localVideoref}
                                                    muted
                                                    style={{ width: '100%', height: '100%', objectFit: 'cover' }}
                                                />
                                                <div className="video-label">
                                                    {this.state.username} (You)
                                                </div>
                                            </div>

                                            {this.state.gridLayoutData.map((item) => (
                                                <div
                                                    id={item.i}
                                                    data-grid={{ i: item.i, x: item.x, y: item.y, w: item.w, h: item.h }}
                                                    key={item.i} className="video-container"
                                                >

                                                    <>
                                                        <video
                                                            id={item.i}
                                                            autoPlay
                                                            playsInline
                                                            muted
                                                            style={{ borderColor: "#000", borderStyle: "solid", borderWidth: "1", width: "100%", height: "100%", objectFit: "cover", display: "block" }}
                                                            ref={(videoElement) => {
                                                                if (videoElement && item.stream) {
                                                                    console.log(" Video element found:", videoElement);
                                                                    console.log(" Stream for item:", item.stream);
                                                                    
                                                                    // Set attributes
                                                                    videoElement.setAttribute("data-socket", item.i);
                                                                    videoElement.setAttribute("title", item.username);
                                                                    videoElement.muted = true;
                                                                    videoElement.autoplay = true;
                                                            
                                                                    // If a different stream is set, remove the old one
                                                                    if (videoElement.srcObject !== item.stream) {
                                                                        console.log("Updating srcObject...");
                                                                        videoElement.srcObject = item.stream;
                                                                    }
                                                            
                                                                    // Debugging: Check if the stream actually has video tracks
                                                                    const videoTracks = item.stream.getVideoTracks();
                                                                    if (videoTracks.length === 0) {
                                                                        console.error(" No video tracks found in the stream!");
                                                                    } else {
                                                                        console.log(" Video track found:", videoTracks[0]);
                                                                    }
                                                            
                                                                    // Ensure the video plays when the metadata is loaded
                                                                    videoElement.onloadedmetadata = () => {
                                                                        console.log("Video metadata loaded, attempting to play...");
                                                                        videoElement.play()
                                                                            .then(() => console.log("✅ Video is playing!"))
                                                                            .catch((error) => console.error("⚠️ Video play error:", error));
                                                                    };
                                                            
                                                                    // Extra debugging: Check when a track is added or removed
                                                                    item.stream.onaddtrack = (event) => {
                                                                        console.log(" New track added:", event.track);
                                                                    };
                                                            
                                                                    item.stream.onremovetrack = (event) => {
                                                                        console.log("Track removed:", event.track);
                                                                    };
                                                                }
                                                            }}
                                                            
                                                        ></video>

                                                    </>

                                                </div>
                                            ))}




                                        </GridLayout>
                                    </div>


                                </div>


How to execute code after a call to a function that uses fetch is done? [duplicate]

I have a function that I call that uses fetch:

function fetchData() {
fetch(`${url}`)
    .then(response => response.json())
    .then(json => {
         // use the json to update some UI
        });

    })
    .catch(function (err) {

    })
    .finally(function () {
        
    });
}

Now whenever I fetch this data, I always want to update a certain part of the UI the same way, that’s why I have the json part inside the function:

    .then(response => response.json())
    .then(json => {
         // use the json to update some UI
        });

    })

But I also want to call this function to do other different UI updates depending on where it was called from, for example opening different modals:

function someFunction() {
    fetchData();
    openModal();
}

function someOtherFunction() {
    fetchData();
    openOtherModal();
}

How can I call the second function only after fetchData() is done? Is there a way to “chain” the then() outside?

For example something like:

fetchData().then(openModal());

Or, it’s not possible in the way it’s currently written?

Is there any to select child elements by the relative position of the same class?

This example provides the desired outcome of selecting the first, second, and third child elements that are of class “subhead”. However, my question is, Is there any selection method that will select the first, second, and third occurrences of class “subhead” irregardless of its exact child position in the parent, such that this would work when it is not known in advance what those positions will be; and we could use postions 1,2,3 instead of 1,3,5 since it won’t known how many sibling elements will be between each subhead?

Thank you.

div.scrl_can * {
  height:25px;
  border: 1px solid black;
}
.subhead:nth-of-type(1) {
  background-color: blue;
}
.subhead:nth-of-type(3) {
  background-color: green;
}
.subhead:nth-of-type(5) {
  background-color: yellow;
}
<div id="main">
  <div>
    <div>
      <div class="scrl_can">
        <div class="subhead"></div>
        <div></div>
        <div class="subhead"></div>
        <div></div>
        <div class="subhead"></div>
        <div></div>
      </div>
    </div>
  </div>
</div>

Issue related to skywise – Slate dashboard

I am working on modifying an existing dashboard in Airbus Skywise. My task involves:

Fetching Data:

When the user clicks the “Fetch” button, the system should fetch data from the columns specified by the user and store it for later use.

Manual Description Input:

In the “Manual Description” cell, the user will manually paste description texts from the Airbus database, corresponding to specific FUID IDs.

Generating a TDD Assessment:

When the user clicks “Generate Assessment”, the system should:

  1. Use the previously fetched data and the manual descriptions as
    references.
  2. Leverage ML/AI models to auto-generate a TDD Assessment based on
    predefined reference scripts for different error types.
  3. Since I am new to Skywise, I am looking for guidance on how to
    implement this functionality. Specifically, I need help with:
  4. Fetching and storing user-specified column data.
  5. Handling manual descriptions and linking them to FUID IDs.
  6. Implementing ML/AI-based auto-generation of the TDD Assessment using
    reference scripts.

Any insights or best practices on Skywise development would be greatly appreciated!

Can I get any google user’s profile picture?

I have a big software with thousands of clients. I just thought it would be a nice touch if I could add their google profile picture, just to identify them easier.

I mean, I’m not attempting to hack or intrude anything, I’m just trying to access a low resolution image of their PUBLIC profiles from some URL or API, only using their emails, either to store the pictures or just to request them to display realtime. This has nothing to do with logins or with asking permissions.

What I want is either:

a) an URL I can access via javascript or PHP’s file_get_contents or similar

b) an API I can call via PHP
…so I can loop the entire DB and do this with those who have gmail.

Thank you.

Some Nuxt 3 API endpoints work and some not, same code logic for client and server

I’m making a fully AI made app, for the sake of experimenting and because I needed something fast. One feature is importing a CSV file into a sqlite database (I’m using Bun) and another is adding notes to some row, but I’m facing a problem, one endpoint works and the other doesn’t (among others but I’m using this one as an example), if I import the csv file, it works great, but adding the notes the request doesn’t even reach the server (which is localhost of course) and I’m at the point I don’t even know what the crap is happening, not even Gemini or Grok could solve it.
The api structure is as follows:

  • server/api
    • migrations
      • clear.delete.ts (this one works)
      • notes.put.ts (this one doesn’t work)
      • status.post.ts (works)
    • migrations.get.ts (works)
    • migrations.post.ts (works)
    • pbrimport.post.ts (doesn’t work)
  • server/middleware
    • logRequests.global.ts (logs requests only on endpoints that say it works)

I’ll post just the parts that make the fetch and receive the data, it’s all the same.

ImportModal.vue:

let fetchOptions: RequestInit = {
        method: "POST",
        headers: { "Content-Type": "application/json" }, // Always JSON now
    };

    try {
        if (currentUploadType === "main") {
            apiUrl = "/api/migrations";
            payload = { data: dataToUpload };
        } else {
            // PBR upload
            apiUrl = "/api/pbr_import";
            payload = { data: dataToUpload };
        }

        fetchOptions.body = JSON.stringify(payload);
        const payloadSize = fetchOptions.body.length;
        console.debug(`[UploadModal] Sending JSON payload (${payloadSize} bytes) to ${apiUrl}`);

        const response = await $fetch(apiUrl, fetchOptions);

NotesModal.vue

// THIS DOESN'T WORK
try {
            const response = await $fetch(apiUrl, {
                // <-- Use full URL
                method: "PUT",
                body: {
                    virtual_server: props.virtualServerName,
                    notes: notesToSave,
                },
                // Content-Type: application/json is usually added automatically by $fetch for object bodies
            });

            if (response.success) {

migrations.post.ts — This endpoint is for the ImportModal.vue, the one that works

import { db, dbReady } from "@/server/db/index";
// Import Kysely specific types if needed for stricter validation, or use Partial
import type { WafMigracionTable } from "@/server/db/types";
import logger from "@/server/utils/logger";

// Define type for incoming records more strictly based on Kysely Insertable if desired
// This helps catch issues earlier if CSV parsing yields unexpected types
type IncomingRecord = Partial<Omit<WafMigracionTable, "id">>;

export default defineEventHandler(async (event) => {
    const requestInfo = { url: event.node.req.url, method: event.node.req.method };
    logger.info("[POST /api/migrations] Received request.", requestInfo);

    try {
        // Ensure DB setup is complete
        await dbReady;

pbrimport.post.ts — This is the api endpoint for the ImportModal.vue, the else which posts to /api/pbr_import

// File: server/api/pbr_import.post.ts

import { db, dbReady } from "@/server/db/index";
import type { NewFirewallPbr, FirewallPbrUpdate } from "@/server/db/types";
import logger from "@/server/utils/logger";
// Remove readRawBody import if present
// import { readRawBody } from 'h3';
// Remove papaparse import
// import Papa from 'papaparse';

// Type for expected data row within body.data
interface PbrDataRow {
    node_ip?: string | null;
    priority?: number | string | null;
    waf?: string | null;
    [key: string]: any; // Allow other columns from client parsing
}

export default defineEventHandler(async (event) => {
    const requestInfo = { url: event.node.req.url, method: event.node.req.method };
    // Log expecting JSON now
    logger.info("[POST /api/pbr_import] Received request (expecting JSON body).", requestInfo);

    try {
        await dbReady;

notes.put.ts — This endpoint is for the NotesModal.vue, this one doesn’t work, not even the logger.info or the middleware logs.

import { db, dbReady } from "@/server/db/index";
import type { NewVsNotes, VsNotesUpdate } from "@/server/db/types";
import logger from "@/server/utils/logger";

interface RequestBody {
    virtual_server: string;
    notes: string | null; // Allow null to clear notes
}

export default defineEventHandler(async (event) => {
    const requestInfo = { url: event.node.req.url, method: event.node.req.method };
    logger.info("[PUT /api/migrations/notes] Received request.", requestInfo);

    try {
        await dbReady;

At first I tought there was something wrong with the csv file, but I made a separate script to put the data in the database and it works ok, I just don’t know how or why one works and the rest doesn’t, maybe is something wrong with the file hierarchy or naming? For every case, the request is made on the client but it’s forever pending, and they doesn’t even reach the middleware let alone the endpoint, but the migrations.post.ts works ok. I tried axios for fetching, I also even tried downgrading nuxt and nothing.

Counter variable inside for/while loop [duplicate]

For loop with counter:

for(let i = page; i < numPages + 1; i++){
  const fn = async() => {
    const res = await xxx(i);
    console.log("page", i);
    return res;
  }

  promises.push(fn);
}

While loop with same type of counter:

while(page < numPages + 1){
  page++;
  const fn = async() => {
    const res = await xxx(page);
    console.log("page", page);
    return res;
  }

  promises.push(fn);
}

They are producing different results.
For is display the counter normally.

But while is displaying the last value every time.

why?

Setting axis label width in Billboard JS

I have a set of billboard JS charts on a page, in a bootstrap row and column grid layout. So all the ‘cells’ of this layout have the same width. But billboard is deciding how much width to give the axis labels. Ideally what I’d like is to be able to force-set the width of the vertical axis label width so the charts line up nicely when stacked on top of each other.

So far, I haven’t been able to find a way to set the width of axis labels in billboard JS. Would love some help if someone knows how.

example chart - data blurred out

Cannot remove outline in input

import React, { useState } from 'react';
import "./styles/input.css";
import { CiSearch } from 'react-icons/ci';

interface SearchProps {
  isMobile: boolean;
  onSearch?: (query: string) => void;
}

const Search: React.FC<SearchProps> = ({ isMobile, onSearch = () => {} }) => {
  const [searchQuery, setSearchQuery] = useState('');
  const [isFocused, setIsFocused] = useState(false);

  const handleSearchChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setSearchQuery(e.target.value);
  };

  const handleSearchSubmit = (e: React.FormEvent) => {
    e.preventDefault();
    onSearch(searchQuery);
  };

  const handleFocus = (e) => {
    setIsFocused(true);
    console.log('Focused');
  };

  const handleBlur = () => {
    setIsFocused(false);
    console.log('Blurred');
  };

  const borderClass = isFocused ? 'border-b-2 border-main_theme' : 'border-b border-gray-300';
//   console.log('Applied class:', borderClass);

  return (
    <form onSubmit={handleSearchSubmit} className="relative w-[350px] lg:w-[500px]">
      <div className={`flex items-center`}>
        
        <input
          type="text"
          placeholder="Поиск"
          className="w-full p-2 border-none"
          value={searchQuery}
          onChange={handleSearchChange}
          onFocus={handleFocus}
          onBlur={handleBlur}
        />
        <button
          type="submit"
          className="p-2 text-gray-400 focus:outline-hidden"
        >
          <CiSearch className="h-5 w-5" />
        </button>
      </div>
      <hr className={`${borderClass}`} />
    </form>
  );
};

export default Search;

This is my code, the problem occurs with an input element, tried to style it both with Tailwind CSS, inline styles and additional css as in example, but none of variants helped(additional styling for it below) –

input.css

input {
    outline: none; 
    border: none;  
    box-shadow: none; 
}

input:focus {
    outline: none; 
    border-bottom: none;
}

For some reason after all corrections and additions I get this result when focused(screen). Meanwhile I need to completely remove an outline while focused

Problem screen

How can i add sprites to my raycaster, and various walls textures?

Here’s my RayCast algorythm, not so complicated:

var currentAngle = playerAngle + HALF_FOV;
        var rayStartX = Math.floor(playerX / MAP_SCALE ) * MAP_SCALE;
        var rayStartY = Math.floor(playerY / MAP_SCALE) * MAP_SCALE;
        for(var ray = 0; ray < WIDTH; ray++){
            var currentSin = Math.sin(currentAngle); currentSin = currentSin ? currentSin : 0.000001;
            var currentCos = Math.cos(currentAngle); currentCos = currentCos ? currentCos : 0.000001;      
        
            //vertical collisions
            var rayEndX, rayEndY, rayDirectionX, verticalDepth, textureEndY, textureX;
            if(currentSin > 0) { rayEndX = rayStartX + MAP_SCALE; rayDirectionX = 1}
            else { rayEndX = rayStartX; rayDirectionX = -1}
            for (var offset = 0; offset < MAP_RANGE; offset += MAP_SCALE) {
                verticalDepth = (rayEndX - playerX) / currentSin;
                rayEndY = playerY + verticalDepth * currentCos;
                var mapTargetX = Math.floor(rayEndX / MAP_SCALE);
                var mapTargetY = Math.floor(rayEndY / MAP_SCALE);
                if(currentSin <= 0) mapTargetX += rayDirectionX;
                var targetSquare = mapTargetY * MAP_SIZE + mapTargetX;
                if(targetSquare < 0 || targetSquare > map.length - 1) break;
                if(map[targetSquare] == 1 || map[targetSquare] == 2) { textureY = map[targetSquare]; break;}
                rayEndX += rayDirectionX * MAP_SCALE;
            }
            textureEndY = rayEndY;

            var tempY = rayEndY;
            var tempX = rayEndX;

            
            //horizontal collisions
            var rayEndY, rayEndX, rayDirectionY, horizontalDepth, textureEndX, textureY;
            if(currentCos > 0) { rayEndY = rayStartY + MAP_SCALE; rayDirectionY = 1}
            else { rayEndY = rayStartY; rayDirectionY = -1}
            for (var offset = 0; offset < MAP_RANGE; offset += MAP_SCALE) {
                horizontalDepth = (rayEndY - playerY) / currentCos;
                rayEndX = playerX + horizontalDepth * currentSin;
                var mapTargetX = Math.floor(rayEndX / MAP_SCALE);
                var mapTargetY = Math.floor(rayEndY / MAP_SCALE);
                if(currentCos <= 0) mapTargetY += rayDirectionY;
                var targetSquare = mapTargetY * MAP_SIZE + mapTargetX;
                if(targetSquare < 0 || targetSquare > map.length - 1) break;
                if(map[targetSquare] == 1 || map[targetSquare] == 2) {texturex = map[targetSquare]; break;}
                rayEndY += rayDirectionY * MAP_SCALE;
            }
            textureEndX = rayEndX;
            
            var endX = verticalDepth < horizontalDepth ? tempX : rayEndX;
            var endY = verticalDepth < horizontalDepth ? tempY : rayEndY;


            //3D projection
            var textureImg = verticalDepth < horizontalDepth ? textureY : textureX;
            var depth = verticalDepth < horizontalDepth ? verticalDepth : horizontalDepth;
            var textureOffset = verticalDepth < horizontalDepth ? textureEndY : textureEndX;
            textureOffset = textureOffset - Math.floor(textureOffset / MAP_SCALE) * MAP_SCALE;
            depth *= Math.cos(playerAngle - currentAngle)
            var WallHeight = Math.min(Math.floor(MAP_SCALE * 300 / (depth + 0.001)), 50000);
            context.globalAlpha = 1;
            context.fillStyle = verticalDepth < horizontalDepth ? "#aaa" : '#555';
            context.fillRect( 148 + ray, 46 + ( HEIGHT / 2 - WallHeight / 2), 1, 
            WallHeight); 
            var textureImg = verticalDepth < horizontalDepth ? textureY : textureX;
            //textures
            context.drawImage(
                WALLS[0],
                textureOffset,
                0,
                1,
                64,
                ray + 148,
                46 + (HALF_HEIGHT - WallHeight / 2),
                1,
                WallHeight
            );

Well, I want to add some sprites at game. How can I do it, using html canvas and based on it raycaster? Is it even possible? I tried to draw a circle on 2D map, as a result I get another wall, it’s kinda strange. Also I tried to make a different textures on the walls, by replacing WALLS[0] to WALLS[textureImg] thats not worked(I get an error).

How to write an HTTP/2 SETTINGS frame – from server to client – in runtime agnostic JavaScript?

I’m trying to create an HTTP/2 SETTINGS frame per https://datatracker.ietf.org/doc/html/rfc7540#section-6.5 and https://datatracker.ietf.org/doc/html/rfc7540#section-6.5.1.

If I’m reading this correctly a SETTINGS frame can have zero parameters

The payload of a SETTINGS frame consists of zero or more parameters,
each consisting of an unsigned 16-bit setting identifier and an
unsigned 32-bit value.

Given an ArrayBuffer and a DataView instance in JavaScript, for example, in the console of the browser, how to write the most basic HTTP/2 SETTINGS frame – from server to client?