creative-connections/Bodylight.js-Components

View on GitHub
src_aurelia-bodylight-plugin/src/elements/fb-config.js

Summary

Maintainability
D
1 day
Test Coverage
/**
 * firebase configuration
 * subscribe to fb-get-message channel to get broadcasted messages from firebase
 * send message to fb-send-message channel to sned the message to firebase
 */
// Import the required functions from the Firebase SDK
import { initializeApp } from 'firebase/app';
//import * as firebase from "firebase/app";
import { getDatabase, ref, set, onValue, off, get, remove } from 'firebase/database';
//import * as firebasedb from 'firebase/database';
import { inject, bindable } from "aurelia-framework";
import { EventAggregator } from 'aurelia-event-aggregator';
import { dPS } from './fb-dps'
import { uuidv7 } from '../utils/uuidv7'

@inject(EventAggregator)
export class FbConfig {
    @bindable apiKey;
    @bindable authDomain;
    @bindable databaseURL;
    @bindable projectId;
    @bindable storageBucket;
    @bindable messagingSenderId;
    @bindable appId;
    @bindable measurementId;
    @bindable apiStr; //encrypted above configuration
    @bindable listen = false;
    @bindable listen2; //realtime database channel to listen for answers, data are processed to aggregate counts etc.
    @bindable listen3; //realtime database channel to listen for other events, e.g. tab id
    @bindable event3; //if specified the listen3 message is sent via event aggregator channel named in this attribute to other subscribers, e.g. `showid` 
    @bindable publish; //realtime database channel to listen for other events, e.g. tab id
    @bindable event4; //if specified it is subscribed and all messages are published  through 'publish' realtime database, e.g. `showid` 
    userid;
    answersent = false;
    showbutton2 = false;  //whether to show button2
    selected2 = true; //whether the listen2 data are processed
    showbutton3 = false; //whether to show button3
    selected3 = false; //whether the listen3 data are processed
    showbutton4 = false; //whether to show publish button
    selected4 = false; //whether the publish button is selected

    constructor(ea) { this.ea = ea }

    async bind() {
        let firebaseConfig;
        console.log('FBconfig.bind()');
        if (!window.userid) {
            let storeduuid = localStorage.getItem('deviceUUID');
            if (storeduuid) window.userid = storeduuid;
            else {
            if (typeof crypto.randomUUID === 'function'){
                window.userid = crypto.randomUUID();}
            else {
                window.userid = uuidv7();
            }
            localStorage.setItem('deviceUUID', window.userid);
            }

        }
        if (this.apiStr && this.apiStr.length > 0)
            firebaseConfig = JSON.parse(await dPS(this.apiStr))
        else
            firebaseConfig = {
                apiKey: this.apiKey,
                authDomain: this.authDomain,
                databaseURL: this.databaseURL,
                projectId: this.projectId,
                storageBucket: this.storageBucket,
                messagingSenderId: this.messagingSenderId,
                appId: this.appId,
                measurementId: this.measurementId
            };
        if (firebaseConfig.databaseURL !== undefined) {
            console.log('firebaseConfig has a defined property databaseURL');
        } else {
            console.warn('firebaseConfig does not have a defined property databaseURL');
            return
        }
        this.app = initializeApp(firebaseConfig);
        this.database = getDatabase(this.app);
        if (typeof this.listen === 'string') {
            this.listen = this.listen === 'true';
        }
        if (this.listen) this.listenForMessages();
        if (this.listen2) this.listenFor2Messages();
        if (this.listen3) this.listenFor3Messages();
        if (this.publish) this.publishForMessages();

        this.subscription = this.ea.subscribe('fb-send-message', payload => {
            this.sendMessage(payload)
        });
        this.subsendanswer = this.ea.subscribe('fb-send-answer', payload => {
            this.sendAnswer(payload)
        });
        /*this.subprocessanswer = this.ea.subscribe('fb-process-answer', payload => {
            this.processAnswers()
        });*/
    }

    attached() {
    }

    detached() {
        //this.ea.
    }
    unbind() {
        this.subscription.dispose();
        this.subsendanswer.dispose();
        this.subprocessanswer.dispose();
        if (this.listen) {
            const messagesRef = ref(this.database, 'messages');

            // Detach the listener if it exists
            if (this.messagesListener) {
                off(messagesRef, 'value', this.messagesListener);
                this.messagesListener = null; // Reset the listener
            }
        }
        if (this.listen2) {
            this.showbutton2 = true;
            const messagesRef = ref(this.database, this.listen2);

            // Detach the listener if it exists
            if (this.messagesListener) {
                off(messagesRef, 'value', this.messagesListener);
                this.messagesListener = null; // Reset the listener
            }

        }
    }

    // Function to listen for new messages
    listenForMessages() {        
        const messagesRef = ref(this.database, 'messages');
        // Define the listener as an arrow function and store it
        this.messagesListener = snapshot => {
            const data = snapshot.val();
            if (data) {
                //TODO send to listening message
                //displayMessage(data.content);         
                this.ea.publish('fb-get-message', data.content);                
            }
        };
        // Attach the listener
        onValue(messagesRef, this.messagesListener);

    }

    // Function to listen for new messages
    listenFor2Messages() {
        this.showbutton2 = true;
        const messagesRef = ref(this.database, this.listen2); //answers
        // Define the listener as an arrow function and store it
        this.messagesListener = snapshot => {
            const data = snapshot.val();
            if (data) {
                //TODO send to listening message
                //displayMessage(data.content);         
                //this.ea.publish('fb-get-message-'+this.listen2, data.content);
                if (this.selected2) this.processAnswers(data);
            }
        };
        // Attach the listener
        onValue(messagesRef, this.messagesListener);
    }

    // Function to listen for new messages
    listenFor3Messages() {
        this.showbutton3 = true;
        const messagesRef = ref(this.database, this.listen3); //answers
        // Define the listener as an arrow function and store it
        this.messagesListener = snapshot => {
            const data = snapshot.val();
            if (data) {
                //TODO send to listening message
                //displayMessage(data.content);         
                if (this.selected3 && this.event3)
                  this.ea.publish(this.event3, data.content);
                //this.processAnswers(data);

            }
        };
        // Attach the listener
        onValue(messagesRef, this.messagesListener);
    }

    // Function to listen for new messages
    publishForMessages() {
        this.showbutton4 = true;
        if (this.event4) {
            this.subscription4 = this.ea.subscribe(this.event4, payload => {
                this.sendMessage4(this.publish,payload)
            });
        }
    }
    

    // Function to send a message
    async sendMessage(message) {
        console.log('sending message');
        //const message = "Hello from Master 2";
        try {
            await set(ref(this.database, 'messages'), { content: message });
            if (message.startsWith('index')) {
                //do reset answers
                this.resetAnswers();
            }
            console.log('Message sent successfully');
        } catch (error) {
            console.error('Error sending message:', error);
        }
    }
    // Function to send a message
    async sendMessage4(channel,message) {
        console.log('sending message');
        //const message = "Hello from Master 2";
        try {
            await set(ref(this.database, channel), { content: message });
            console.log('Message sent successfully');
        } catch (error) {
            console.error('Error sending message:', error);
        }
    }

    // Function to send a message
    async sendAnswer(qas) {
        if (!this.answersent) {
            //this.answersent = true;
            console.log('sending answer');
            //const message = "Hello from Master 2";
            try {
                let screenid = window.location.hash.replace(/[.#]/g, "");
                const userQuestionsRef = ref(this.database, 'answers/' + window.userid + '/questions/'+screenid);
                await set(userQuestionsRef, qas);
                console.log('Answers sent successfully');
            } catch (error) {
                console.error('Error sending answers:', error);
            }
        }

    }

    processAnswers(data) {
        //const dbRef = ref(this.database, 'answers/');
        //dbRef.once('value', snapshot => {
        //const data = snapshot.val();
        let aggregatedResults = {}
        for (let userId in data) {
            const userAnswers = data[userId];
            const screens = userAnswers.questions.screen;
            for (let screenId in screens) {
                const useranswers = screens[screenId];
                for (let answersStruct of useranswers){
                    const qid = answersStruct.id
                    const qname = answersStruct.question.slice(0,4)
                    let ar = {
                        id:qid,
                        q:qname, //first 4 chars of question
                        a: {}
                    }
                    if (aggregatedResults[qid]) {
                        //it exists, increment
                        for (let answer of answersStruct.answers) {
                            const aid = answer.charAt(0);
                            if (aggregatedResults[qid].a[aid])
                                aggregatedResults[qid].a[aid]++;
                            else
                                aggregatedResults[qid].a[aid] = 1;
                        }
                    } else {
                        //do not exist, create
                        aggregatedResults[qid] = ar;
                        for (let answer of answersStruct.answers) {
                            const aid = answer.charAt(0);
                            aggregatedResults[qid].a[aid] = 1;
                        }
                    }
                }
            }
        }
        console.log(aggregatedResults);
        this.ea.publish('fb-process-answer-result', aggregatedResults);
        // Here you can do what you need with the counts (e.g., update the UI)
    }


    // Function to display a message
    //        function displayMessage(message) {
    //            document.getElementById('messages').textContent = message;
    //        }
    click2() {this.selected2 = ! this.selected2}
    click3() {this.selected3 = ! this.selected3}
    click4() {this.selected4 = ! this.selected4}

    renameAnswersObject(oldPath, newPath) {
        const oldRef = ref(this.database,oldPath);
        const newRef = ref(this.database,newPath);
      
        get(oldRef).then((snapshot) => {
            console.log('Data retrieved for renaming.');
            const data = snapshot.val();
            if (data !== null) {
              // Write data to the new location
              set(newRef, data).then(() => {
                console.log('Data successfully copied to new location.');
                // Remove data from the old location after successful copy
                remove(oldRef)
                .then(() => {
                  console.log('Old data successfully removed.');
                })
                .catch((error) => {
                  console.error('Failed to remove old data:', error);
                });
              }).catch((error) => {
                console.log('Data could not be copied to new location:', error);
              });
            } else {
              console.log('No data found at the old location.');
            }
          }).catch((error) => {
            console.log('Failed to get data from old location:', error);
          });
      }

    resetAnswers() {
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); // Creating a timestamp
        this.renameAnswersObject('answers', `answers-archive/${timestamp}`);
    }  
}