#StackBounty: #arrays #reactjs #react-hooks #state #prop How to use a useState function in another component with props?

Bounty: 50

I write a React.js note web application where a user can add up to 10 notes.

I use map() to iterate the array of notes, and a useState(1) hook to update its count (the default number of notes is 1), so I would like to do something like this:

  {[...Array(noteCount)].map((_, i) => <Note onUpdateNoteCount={() =>setNoteCount(n => n - 1)} key={i} />)}

The thing is that the Note() component is inside a Main() component which is in the App() component, so I want to get the needed values as props of App(), and than use them in Note(), but can not figure out how and where to put it.

Thanks!

App.js

  import React from 'react';
  import Header from './Header';
  import Main from './Main';
function App () {
  const [noteCount, setNoteCount] = React.useState(1);
  function multiplyNoteComponent () {
    if (noteCount < 20) {
      setNoteCount(n => n + 1)
    }
    else {
      alert('too many notes. remove or combine some of them together!')
    }
  }
  return (
    <div>
      <Header/>
      {[...Array(noteCount)].map((_, i) => <Main onUpdateNoteCount={() =>setNoteCount(n => n - 1)} key={i} />)}

      <button
            style={{left: '5%'}}
          id='addNoteBtn'
          onClick={multiplyNoteComponent}
          title='Add a note'
         >
        +
      </button>
    </div>
  );
}
  export default App;

Main.js

    import React from 'react';
    import Note from './Note';
function Main () {
    return (
        <main>
            your notes are:
            <Note/>
        </main>
    )
}
    export default Main;

Note.js

    import React from 'react';
function Note () {
    return (
        <div> <button title='delete note' onClick={}>X</delete>
            <li>
                <input type='text'/>
            </li>
        </div>
    )
}
    export default Note

Edit: the reason I think I need the setNoteCount() function to be used in the Note() component, is for the count down when a note is being deleted (every note has its own delete button).


Get this bounty!!!

#StackBounty: #html #css #reactjs #iframe Layout Shrinking When The Page Has An Iframe

Bounty: 50

I have a React website (based on Next.js) for which I wrote a React component to embed Tweets. But when a page contains a tweet, the layout shrinks. I have figured out that it happens when there is an iframe on the page as the Twitter API loads an iframe.

I have no clue what is happening and why my viewport settings are not being respected.

Viewport

<meta name="viewport" content="minimum-scale=1, initial-scale=1, width=device-width, shrink-to-fit=no"/>

Ideal Layout

Ideal layout

Shrunken layout (when there is a tweet on the page). Notice the toolbar and text size(s).

Shrunken layout

PS: The same thing happens, if I embed a YouTube video.


Get this bounty!!!

#StackBounty: #javascript #reactjs #firebase #google-cloud-firestore #react-hooks Reading firestore sub-collection data in react – how …

Bounty: 50

I’m trying to figure out how to read firestore sub collection data from react.

I have seen this blog that describes how to do it and am now trying to figure out how to implement the logic of it. I have also seen this gist which sets out a way to assign a parent id to a subcollection where query.

I have a parent collection called glossary and a sub collection within it called relatedTerms.

I have a form that works to correctly submit data to the glossary (parent) and relatedTerms (sub) collections.

I’m struggling to find a way to use react hooks to generate the list of glossary terms (this collection holds data) with associated related terms sub collection data).

My current attempt at doing that is:

function useGlossaryTerms() {
    const [glossaryTerms, setGlossaryTerms] = useState([])
    
    
   // First useEffect - to set the glossaryTerm (the parent document) 
    useEffect(() => {
    

async function fetchGlossaryData() {
          await firebase
            .firestore()
            .collection("glossary")
            .orderBy('term')
            .onSnapshot(snapshot => {
              const glossaryTerms = snapshot.docs.map(doc => ({
                id: doc.id,
                ...doc.data(),
              }))
    

  

    setGlossaryTerms(glossaryTerms)
            });
fetchGlossaryData();
};
            // setRelatedGlossaryTerms(glossaryTerms)
        }, [])
        return glossaryTerms;
      };

    function useRelatedGlossaryTerms() {
    const [relatedGlossaryTerms, setRelatedGlossaryTerms] = useState([])
    const glossaryTerms = useGlossaryTerms()
    // Second useEffect - to set the relatedGlossaryTerm (the sub collection document)
      useEffect(() => {
  

    async function fetchRelatedGlossaryData() {
        await firebase
          .firestore()
          .collection("glossary")
          .doc()
          // {console.log("testing:", glossaryTerms)}
          .collection('relatedTerms')
          
          .where("glossaryId", "==", "glossaryTerms.id") ** This is wrong, but I can't find a way that works. I think I'm trying to ask for the state of glossaryTerms and then the id on the relevant object" **
          .onSnapshot(snapshot => {
            const relatedGlossaryTerms = snapshot.docs.map(doc => ({
              id: doc.id,
              ...doc.data(),
            }))
            setRelatedGlossaryTerms(relatedGlossaryTerms)
          });
fetchRelatedGlossaryData();
}
         
          // setRelatedGlossaryTerms(glossaryTerms)
      }, [glossaryTerms])
      return relatedGlossaryTerms;
    };
    
    
      
    
    const GlossaryTerms = () => {
    
        const glossaryTerms = useGlossaryTerms()
        const relatedGlossaryTerms = useRelatedGlossaryTerms()
          


    const classes = useStyles();

    return ( 
        
            <div className={classes.root}>
            
            {glossaryTerms.map(glossaryTerm => {

{console.log(‘testing log of glossaryTerms’, glossaryTerms)}
return (

                    <Typography className={classes.heading}>{glossaryTerm.term}</Typography>
                    
                    <div>
                    
                    {glossaryTerm.category.map(category => (
                        <Typography className={classes.secondaryHeading}>
                        {category.label}
                        </Typography>
                    )

                    )}
                    
                   
                    <div>    
                        <Typography variant="subtitle2" className={classes.heading2}>Meaning</Typography>
                        <Typography>{glossaryTerm.definition}</Typography>
                    </div>
                       
                    <div>
                    {relatedGlossaryTerms ? (
                      <ul>
                        {relatedGlossaryTerms.map(relatedGlossaryTerm => (
                          <div key={relatedGlossaryTerm.id}>
                            <Typography variant="caption">
                            Placeholder title {relatedGlossaryTerm.title} | 
                            Placeholder description {relatedGlossaryTerm.description} 
                            </Typography>
                          </div>  
                        ))}
                      </ul>
                    ) : null}


                                                {
                            glossaryTerm.templates ? (
                              <div>    
                                <p><Typography variant="caption" >Related Templates</Typography></p>
                                {glossaryTerm.templates.map(template => (
                                    
                                    <Link to="" className="bodylinks"  key={template.id}>
                                      <p><Typography variant="caption" >{template.title}
                                      </Typography></p>
                                    </Link>
                                ))}
                              </div>
                            ) : null
                          }
                    </div>
                    <div>
                        
                 

            )
        })}
            </div>
            
        </div>   
</div>
     );
}
 
export default GlossaryTerms;

When I try this, I don’t get any errors in the console, but, the rendered output is incorrect and confusing.

The glossary currently has 2 documents in that collection. One of the documents has a relatedTerms subcollection which also has 2 documents. The other has no sub collection entries (other than a glossaryId field which I add to the setSubmitting form add so that I could try matching the string ids to filter sub collection documents – this attempt is outlined in the history of this post).

Whilst the glossary data is correctly rendered, the sub collection data for relatedTerms is not rendered at all – BUT the placeholder text is repeated for each instance of the parent collection (2 documents). I currently have 2. If I add another entry to the sub collection to test this, the 2 placeholder sets of text are repeated in each glossary document rendered.

The image below shows the rendered output.
enter image description here

The image below shows the content of the glossary collection.

enter image description here

The image below shows the content of the relatedTerms sub collection.

enter image description here

This is confusing, because the placeholder text is repeated the same number of times as is equal to the number of parent collection document entries. It’s not testing for sub collection values.

It’s also incorrect because I can’t find a way to join the relatedTerm to its relevant glossaryTerm collection entry. Each item in the list should render its sub collection content only.

When I try logging the relatedGlossaryTerms, as follows:

 {console.log("testing log of relatedGlossaryTerms", relatedGlossaryTerms)}
                    {relatedGlossaryTerms ? (
                      
                      <ul>
                        {relatedGlossaryTerms.map(relatedGlossaryTerm => (
                    

I get:

enter image description here

This log is confusing to me because it’s supposed to be the content of the sub collection. Instead it logs the parent collection.

I can’t find a way to log the value of the relatedGlossaryTerms.

When I try adding console log statements to the snapshot, I get errors that I can’t understand. Plenty of other posts show this as a correct method to use to log the values. I tried adding curly braces, but get the same issue.

useEffect(() => {
    firebase
      .firestore()
      .collection("glossary")
      .doc()
      // {console.log("testing:", glossaryTerms)}
      .collection('relatedTerms')
      // .where("glossaryId" === "SQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          
      
          id: doc.id,
          ...doc.data(),
          // console.log('test useEffect setting for relatedGlossaryTerms', doc),
          // console.log(relatedGlossaryTerms)
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
        
      });
  

When I try logging the values of glossaryTerms and relatedGlossaryTerms in the return statement, I get:

enter image description here
enter image description here
Trying Yoruba’s suggestion

I tried Yoruba’s suggestion to use get instead of snapshot. Although it does not make sense to me as to why I can’t use snapshot without mobx, I tried it.

    useEffect(() => {
      firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .get()
        .then(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))

          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  

  useEffect(() => {
    firebase
      .firestore()
      .collection("glossary")
      .doc()
      // {console.log("testing:", glossaryTerms)}
      .collection('relatedTerms')
      // .where("glossaryId" === "SQ3Qf0A65ixNbF07G2")
      .get()
      .then(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          
      
          id: doc.id,
          ...doc.data(),
          
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
        
      });
     
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [glossaryTerms])
  return relatedGlossaryTerms;
};

It doesn’t make any difference. No new console errors. No difference to the rendering problems outlined above.

ALL PREVIOUS ATTEMPTS

 onSubmit={(values, { setSubmitting }) => {
                     setSubmitting(true);
                     
                    //  firestore.collection("glossary").doc().set({
                    //   ...values,
                    //   createdAt: firebase.firestore.FieldValue.serverTimestamp()
                    //   })
                    // .then(() => {
                    //   setSubmitionCompleted(true);
                    // });
                  // }}
                  const newDocRef = firestore.collection("glossary").doc() // auto generated doc id saved here
  let writeBatch = firestore.batch();
  {console.log("logging values:", values)};
  writeBatch.set(newDocRef,{
    term: values.term,
    definition: values.definition,
    category: values.category,
    context: values.context,
    createdAt: firebase.firestore.FieldValue.serverTimestamp()
  });
  writeBatch.set(newDocRef.collection('relatedTerms').doc(),{
    // dataType: values.dataType,
    // title: values.title,
    glossaryId: newDocRef.id,
    ...values.relatedTerms
    // description: values.description,
  })
  writeBatch.commit()
    .then(() => {
      setSubmitionCompleted(true);
    });
}}
  

No error message is shared when I try this, the glossaryId just gets ignored. It remains a mystery to me what the batch concept is- I thought it only ran if all the instructions could be performed.

I’m trying to figure out how to access the data stored in the sub collection. My current attempt at doing that is based on the example in the post linked above.

import React, { useState, useEffect } from 'react';
import {Link } from 'react-router-dom';
import Typography from '@material-ui/core/Typography';
import firebase, { firestore } from "../../../../firebase.js";
import { makeStyles } from '@material-ui/core/styles';
import clsx from 'clsx';

const useStyles = makeStyles((theme) => ({
  root: {
    width: '100%',
    marginTop: '8vh',
    marginBottom: '5vh'
  },
 
}));


function useGlossaryTerms() {
    const [glossaryTerms, setGlossaryTerms] = useState([])
    const [relatedGlossaryTerms, setRelatedGlossaryTerms] = useState([])
    
    
    useEffect(() => {
      firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .onSnapshot(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  }

  const relatedTermsList = (glossaryTerm) => {
    setGlossaryTerms(glossaryTerm);
    firebase.firestore().collection('glossary').doc(glossaryTerm.id).collection('relatedTerms').get()
      .then(response => {
        const relatedGlossaryTerms = [];
        response.forEach(document => {
          const relatedGlossaryTerm = {
            id: document.id,
            ...document.data()
          };
          relatedGlossaryTerms.push(relatedGlossaryTerm);
        });
        setRelatedGlossaryTerms(relatedGlossaryTerms);
      })
      .catch(error => {
        // setError(error);
      });
  }
  

const GlossaryTerms = () => {

    const glossaryTerms = useGlossaryTerms()
    const relatedGlossaryTerms = useGlossaryTerms()
        
    const classes = useStyles();

    return ( 
        <div>
            {glossaryTerms.map(glossaryTerm => {
                return (
                    
               {glossaryTerm.term}
                    {glossaryTerm.category.map(category => (
                        
                        {category.label}
                        
                    )

                    )}
                    
                    </div>
               {glossaryTerm.definition}

                    {glossaryTerm ? (
                      <ul>
                        {relatedGlossaryTerms.map(relatedGlossaryTerm => (
                          <li key={relatedGlossaryTerm.id}>
                            {relatedGlossaryTerm.title} | {relatedGlossaryTerm.description} 
                          </li>
                        ))}
                      </ul>
                    ) : null}

                    
            )
        })}
            </div>
            
         

     );
}
 
export default GlossaryTerms;

When I try this, I get error messages saying that in my relatedTermsList const, the definitions of setGlossaryTerms and setRelatedGlossaryTerms are undefined.

Each of these errors are odd to me because setRelatedGlossaryTerms is defined in the same way as setGlossaryTerms. I don’t understand why it is unrecognisable and setGlossaryTerms is used in the useEffect without any issue.

NEXT ATTEMPT

I tried using a second useEffect function that takes a glossaryTerm.

function useGlossaryTerms() {
    const [glossaryTerms, setGlossaryTerms] = useState([])
    const [relatedGlossaryTerms, setRelatedGlossaryTerms] = useState([])
    
    
    useEffect(() => {
      firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .onSnapshot(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  }

  useEffect((glossaryTerm) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc(glossaryTerm.id)
      .collection('relatedTerms')
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      })
      .catch(error => {
        // setError(error);
      });
  });
  

const GlossaryTerms = () => {

    const glossaryTerms = useGlossaryTerms()
    const relatedGlossaryTerms = useGlossaryTerms()
        
    const classes = useStyles();

    return ( 

I don’t understand why, but the error is that setRelatedGlossaryTerms is not defined – where it’s used in the second useEffect.

NEXT ATTEMPT

This attempt does not produce any errors in the console but the result is incorrect.

I have two useEffect functions as follows:

function useGlossaryTerms() {
    const [glossaryTerms, setGlossaryTerms] = useState([])
    const [relatedGlossaryTerms, setRelatedGlossaryTerms] = useState([])
    
    
    useEffect(() => {
      firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .onSnapshot(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  

  useEffect((glossaryTerms) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc("glossaryTerms.id") //I also tried .doc(glossaryTerms.id)
      .collection('relatedTerms')
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [])
  return relatedGlossaryTerms;
};


  

const GlossaryTerms = () => {

    const glossaryTerms = useGlossaryTerms()
    const relatedGlossaryTerms = useGlossaryTerms()
        
    const classes = useStyles();

    return ( 

The intention behind these two useEffects is that the first one finds the glossaryTerm and then the second one uses the glossaryTerm.id to find if there are any related terms and then sets the state of the relatedGlossaryTerms array with any related terms.

Then in the render, I have:

 {glossaryTerm.category.map(category => (
                        <Typography className={classes.secondaryHeading}>
                        {category.label}
                        </Typography>
                    )

The above works to correctly find the glossaryTerm.

{relatedGlossaryTerms ? (
                      <ul>
                        {relatedGlossaryTerms.map(relatedGlossaryTerm => (
                          <div>
                            <Typography variant="caption">
                            Placeholder title {relatedGlossaryTerm.title} | 
                            Placeholder description {relatedGlossaryTerm.description} 
                            </Typography>
                          </div>  
                        ))}
                      </ul>
                    ) : null}

The intention is for the above to look to see if there are any relatedGlossaryTerms (which should be the result of finding the sub collection inside the glossaryTerm.

This doesn’t produce any console errors, but it does 2 things that need to be corrected.

  1. it renders the same result for each glossaryTerm (regardless of whether it actually has any relatedGlossaryTerms.
  2. It does not render the relatedGlossaryTerm data. The picture below shows the placeholder text printed, repeatedly (as many times as is equal to the total number of related terms in all glossaryTerms documents combined).

enter image description here

I’m trying to find a way to use the glossaryTerm document id to find the sub collection data and render it only inside the relevant glossaryTerm item.

Next Attempt

I also tried:

useEffect((glossaryTermsId) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc(glossaryTermsId)
      .collection('relatedTerms')
      .where(glossaryTermsId === "glossaryId") // I also tried .where(glossaryTerms.id === "glossaryId)
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))

    setRelatedGlossaryTerms(relatedGlossaryTerms)
  });

I have added a field to the sub collection called glossaryId to try to use the where query to filter the sub collection (although even if this worked, which it doesn’t) – I don’t want to search every glossaryTerm document to get the right relatedTerms.

enter image description here
When I try

useEffect((glossaryTerms) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc(glossaryTerms)
      .collection('relatedTerms')
      .where("glossaryId" === "JsSQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
  

I still get the same result as shown in the picture above (just the placeholder text prints – the same way in all of the glossaryTerms – it just ignores the query parameter of the glossaryId attribute in the sub collection document.

NEXT ATTEMPT

I’m scratching for ideas for things to try now. I’ve tried adding glossaryTerms as a dependency to the second useEffect and I tried giving the glossaryTermsId as a prop (instead of the glossaryTerms object), as follows:

useEffect((glossaryTermsId) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc(glossaryTermsId)
      .collection('relatedTerms')
      // .where("glossaryId" === "JsSQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [glossaryTerms])
  return relatedGlossaryTerms;
};

Neither of these things make any difference to the outcomes shown above.

When I try to log the content of glossaryTerm in the render – one strange thing is that the sub collection data is not displayed. I only have 2 test entries in the glossary collection. 1 has a related term and the other doesn’t. Neither is visible in the console log. I think this is because of shallow queries. But, I can’t then find a way to link the collection query to the sub collection data.

enter image description here

Next attempt

Taking Bennett’s advice, I removed the parameters from the useEffect as follows:

useEffect(() => {
    firebase
      .firestore()
      .collection("glossary")
      .doc()
      // {console.log("testing:", glossaryTerms)}
      .collection('relatedTerms')
      
      // .where("glossaryId" === "JSQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
     
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [glossaryTerms])
  return relatedGlossaryTerms;
};

When I try this, it still renders the same output as shown in the image above.

When I uncomment the where query (which is the doc id of a document which has a sub collection for relatedTerms, I’m expecting to be able to get to the subcolleciton data (even if its in all the glossaryTerms, instead of just the one to which the sub collection belongs).

Instead, I get the placeholder text, rendered the number of times as is equal to the total number of related terms recorded in all sub collections in all the glossaryTerms documents (but no data).

Then when I change the string, so it should evaluate to null, I get the same rendered output (still prints the placeholders).


Get this bounty!!!

#StackBounty: #javascript #reactjs #firebase #google-cloud-firestore #react-hooks Reading firestore sub-collection data in react

Bounty: 50

I’m trying to figure out how to read firestore sub collection data from react.

I have seen this blog that describes how to do it and am now trying to figure out how to implement the logic of it.

I have a parent collection called glossary and a sub collection within it called relatedTerms.

I have a form that works to correctly submit data to the glossary (parent) and relatedTerms (sub) collections.

I’m struggling to find a way to use react hooks to generate the list of glossary terms (this collection holds data) with associated related terms sub collection data).

My current attempt at doing that is:

function useGlossaryTerms() {
    const [glossaryTerms, setGlossaryTerms] = useState([])
    
    
   // First useEffect - to set the glossaryTerm (the parent document) 
    useEffect(async() => {
      await firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .onSnapshot(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  };

function useRelatedGlossaryTerms() {
const [relatedGlossaryTerms, setRelatedGlossaryTerms] = useState([])
// Second useEffect - to set the relatedGlossaryTerm (the sub collection document)
  useEffect(async() => {
    await firebase
      .firestore()
      .collection("glossary")
      .doc()
      // {console.log("testing:", glossaryTerms)}
      .collection('relatedTerms')
      
      //.where("glossaryId" === "SQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
     
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [glossaryTerms])
  return relatedGlossaryTerms;
};


  

const GlossaryTerms = () => {

    const glossaryTerms = useGlossaryTerms()
    const relatedGlossaryTerms = useRelatedGlossaryTerms()
        
    const classes = useStyles();

    return ( 
        
            <div className={classes.root}>
            
            {glossaryTerms.map(glossaryTerm => {

{console.log(‘testing log of glossaryTerms’, glossaryTerms)}
return (

                    <Typography className={classes.heading}>{glossaryTerm.term}</Typography>
                    
                    <div>
                    
                    {glossaryTerm.category.map(category => (
                        <Typography className={classes.secondaryHeading}>
                        {category.label}
                        </Typography>
                    )

                    )}
                    
                   
                    <div>    
                        <Typography variant="subtitle2" className={classes.heading2}>Meaning</Typography>
                        <Typography>{glossaryTerm.definition}</Typography>
                    </div>
                       
                    <div>
                    {relatedGlossaryTerms ? (
                      <ul>
                        {relatedGlossaryTerms.map(relatedGlossaryTerm => (
                          <div key={relatedGlossaryTerm.id}>
                            <Typography variant="caption">
                            Placeholder title {relatedGlossaryTerm.title} | 
                            Placeholder description {relatedGlossaryTerm.description} 
                            </Typography>
                          </div>  
                        ))}
                      </ul>
                    ) : null}


                                                {
                            glossaryTerm.templates ? (
                              <div>    
                                <p><Typography variant="caption" >Related Templates</Typography></p>
                                {glossaryTerm.templates.map(template => (
                                    
                                    <Link to="" className="bodylinks"  key={template.id}>
                                      <p><Typography variant="caption" >{template.title}
                                      </Typography></p>
                                    </Link>
                                ))}
                              </div>
                            ) : null
                          }
                    </div>
                    <div>
                        
                 

            )
        })}
            </div>
            
        </div>   
</div>
     );
}
 
export default GlossaryTerms;

When I try this, I don’t get any errors in the console, but, the rendered output is incorrect and confusing.

The glossary currently has 2 documents in that collection. One of the documents has a relatedTerms subcollection which also has 2 documents. The other has no sub collection entries (other than a glossaryId field which I add to the setSubmitting form add so that I could try matching the string ids to filter sub collection documents – this attempt is outlined in the history of this post).

Whilst the glossary data is correctly rendered, the sub collection data for relatedTerms is not rendered at all – BUT the placeholder text is repeated for each instance of the parent collection (2 documents). I currently have 2. If I add another entry to the sub collection to test this, the 2 placeholder sets of text are repeated in each glossary document rendered.

The image below shows the rendered output.
enter image description here

The image below shows the content of the glossary collection.

enter image description here

The image below shows the content of the relatedTerms sub collection.

enter image description here

This is confusing, because the placeholder text is repeated the same number of times as is equal to the number of parent collection document entries. It’s not testing for sub collection values.

It’s also incorrect because I can’t find a way to join the relatedTerm to its relevant glossaryTerm collection entry. Each item in the list should render its sub collection content only.

When I try logging the relatedGlossaryTerms, as follows:

 {console.log("testing log of relatedGlossaryTerms", relatedGlossaryTerms)}
                    {relatedGlossaryTerms ? (
                      
                      <ul>
                        {relatedGlossaryTerms.map(relatedGlossaryTerm => (
                    

I get:

enter image description here

This log is confusing to me because it’s supposed to be the content of the sub collection. Instead it logs the parent collection.

I can’t find a way to log the value of the relatedGlossaryTerms.

When I try adding console log statements to the snapshot, I get errors that I can’t understand. Plenty of other posts show this as a correct method to use to log the values. I tried adding curly braces, but get the same issue.

useEffect(() => {
    firebase
      .firestore()
      .collection("glossary")
      .doc()
      // {console.log("testing:", glossaryTerms)}
      .collection('relatedTerms')
      // .where("glossaryId" === "SQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          
      
          id: doc.id,
          ...doc.data(),
          // console.log('test useEffect setting for relatedGlossaryTerms', doc),
          // console.log(relatedGlossaryTerms)
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
        
      });
  

When I try logging the values of glossaryTerms and relatedGlossaryTerms in the return statement, I get:

enter image description here
enter image description here
Trying Yoruba’s suggestion

I tried Yoruba’s suggestion to use get instead of snapshot. Although it does not make sense to me as to why I can’t use snapshot without mobx, I tried it.

    useEffect(() => {
      firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .get()
        .then(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))

          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  

  useEffect(() => {
    firebase
      .firestore()
      .collection("glossary")
      .doc()
      // {console.log("testing:", glossaryTerms)}
      .collection('relatedTerms')
      // .where("glossaryId" === "SQ3Qf0A65ixNbF07G2")
      .get()
      .then(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          
      
          id: doc.id,
          ...doc.data(),
          
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
        
      });
     
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [glossaryTerms])
  return relatedGlossaryTerms;
};

It doesn’t make any difference. No new console errors. No difference to the rendering problems outlined above.

ALL PREVIOUS ATTEMPTS

 onSubmit={(values, { setSubmitting }) => {
                     setSubmitting(true);
                     
                    //  firestore.collection("glossary").doc().set({
                    //   ...values,
                    //   createdAt: firebase.firestore.FieldValue.serverTimestamp()
                    //   })
                    // .then(() => {
                    //   setSubmitionCompleted(true);
                    // });
                  // }}
                  const newDocRef = firestore.collection("glossary").doc() // auto generated doc id saved here
  let writeBatch = firestore.batch();
  {console.log("logging values:", values)};
  writeBatch.set(newDocRef,{
    term: values.term,
    definition: values.definition,
    category: values.category,
    context: values.context,
    createdAt: firebase.firestore.FieldValue.serverTimestamp()
  });
  writeBatch.set(newDocRef.collection('relatedTerms').doc(),{
    // dataType: values.dataType,
    // title: values.title,
    glossaryId: newDocRef.id,
    ...values.relatedTerms
    // description: values.description,
  })
  writeBatch.commit()
    .then(() => {
      setSubmitionCompleted(true);
    });
}}
  

No error message is shared when I try this, the glossaryId just gets ignored. It remains a mystery to me what the batch concept is- I thought it only ran if all the instructions could be performed.

I’m trying to figure out how to access the data stored in the sub collection. My current attempt at doing that is based on the example in the post linked above.

import React, { useState, useEffect } from 'react';
import {Link } from 'react-router-dom';
import Typography from '@material-ui/core/Typography';
import firebase, { firestore } from "../../../../firebase.js";
import { makeStyles } from '@material-ui/core/styles';
import clsx from 'clsx';

const useStyles = makeStyles((theme) => ({
  root: {
    width: '100%',
    marginTop: '8vh',
    marginBottom: '5vh'
  },
 
}));


function useGlossaryTerms() {
    const [glossaryTerms, setGlossaryTerms] = useState([])
    const [relatedGlossaryTerms, setRelatedGlossaryTerms] = useState([])
    
    
    useEffect(() => {
      firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .onSnapshot(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  }

  const relatedTermsList = (glossaryTerm) => {
    setGlossaryTerms(glossaryTerm);
    firebase.firestore().collection('glossary').doc(glossaryTerm.id).collection('relatedTerms').get()
      .then(response => {
        const relatedGlossaryTerms = [];
        response.forEach(document => {
          const relatedGlossaryTerm = {
            id: document.id,
            ...document.data()
          };
          relatedGlossaryTerms.push(relatedGlossaryTerm);
        });
        setRelatedGlossaryTerms(relatedGlossaryTerms);
      })
      .catch(error => {
        // setError(error);
      });
  }
  

const GlossaryTerms = () => {

    const glossaryTerms = useGlossaryTerms()
    const relatedGlossaryTerms = useGlossaryTerms()
        
    const classes = useStyles();

    return ( 
        <div>
            {glossaryTerms.map(glossaryTerm => {
                return (
                    
               {glossaryTerm.term}
                    {glossaryTerm.category.map(category => (
                        
                        {category.label}
                        
                    )

                    )}
                    
                    </div>
               {glossaryTerm.definition}

                    {glossaryTerm ? (
                      <ul>
                        {relatedGlossaryTerms.map(relatedGlossaryTerm => (
                          <li key={relatedGlossaryTerm.id}>
                            {relatedGlossaryTerm.title} | {relatedGlossaryTerm.description} 
                          </li>
                        ))}
                      </ul>
                    ) : null}

                    
            )
        })}
            </div>
            
         

     );
}
 
export default GlossaryTerms;

When I try this, I get error messages saying that in my relatedTermsList const, the definitions of setGlossaryTerms and setRelatedGlossaryTerms are undefined.

Each of these errors are odd to me because setRelatedGlossaryTerms is defined in the same way as setGlossaryTerms. I don’t understand why it is unrecognisable and setGlossaryTerms is used in the useEffect without any issue.

NEXT ATTEMPT

I tried using a second useEffect function that takes a glossaryTerm.

function useGlossaryTerms() {
    const [glossaryTerms, setGlossaryTerms] = useState([])
    const [relatedGlossaryTerms, setRelatedGlossaryTerms] = useState([])
    
    
    useEffect(() => {
      firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .onSnapshot(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  }

  useEffect((glossaryTerm) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc(glossaryTerm.id)
      .collection('relatedTerms')
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      })
      .catch(error => {
        // setError(error);
      });
  });
  

const GlossaryTerms = () => {

    const glossaryTerms = useGlossaryTerms()
    const relatedGlossaryTerms = useGlossaryTerms()
        
    const classes = useStyles();

    return ( 

I don’t understand why, but the error is that setRelatedGlossaryTerms is not defined – where it’s used in the second useEffect.

NEXT ATTEMPT

This attempt does not produce any errors in the console but the result is incorrect.

I have two useEffect functions as follows:

function useGlossaryTerms() {
    const [glossaryTerms, setGlossaryTerms] = useState([])
    const [relatedGlossaryTerms, setRelatedGlossaryTerms] = useState([])
    
    
    useEffect(() => {
      firebase
        .firestore()
        .collection("glossary")
        .orderBy('term')
        .onSnapshot(snapshot => {
          const glossaryTerms = snapshot.docs.map(doc => ({
            id: doc.id,
            ...doc.data(),
          }))
          setGlossaryTerms(glossaryTerms)
        });
        // setRelatedGlossaryTerms(glossaryTerms)
    }, [])
    return glossaryTerms;
  

  useEffect((glossaryTerms) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc("glossaryTerms.id") //I also tried .doc(glossaryTerms.id)
      .collection('relatedTerms')
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [])
  return relatedGlossaryTerms;
};


  

const GlossaryTerms = () => {

    const glossaryTerms = useGlossaryTerms()
    const relatedGlossaryTerms = useGlossaryTerms()
        
    const classes = useStyles();

    return ( 

The intention behind these two useEffects is that the first one finds the glossaryTerm and then the second one uses the glossaryTerm.id to find if there are any related terms and then sets the state of the relatedGlossaryTerms array with any related terms.

Then in the render, I have:

 {glossaryTerm.category.map(category => (
                        <Typography className={classes.secondaryHeading}>
                        {category.label}
                        </Typography>
                    )

The above works to correctly find the glossaryTerm.

{relatedGlossaryTerms ? (
                      <ul>
                        {relatedGlossaryTerms.map(relatedGlossaryTerm => (
                          <div>
                            <Typography variant="caption">
                            Placeholder title {relatedGlossaryTerm.title} | 
                            Placeholder description {relatedGlossaryTerm.description} 
                            </Typography>
                          </div>  
                        ))}
                      </ul>
                    ) : null}

The intention is for the above to look to see if there are any relatedGlossaryTerms (which should be the result of finding the sub collection inside the glossaryTerm.

This doesn’t produce any console errors, but it does 2 things that need to be corrected.

  1. it renders the same result for each glossaryTerm (regardless of whether it actually has any relatedGlossaryTerms.
  2. It does not render the relatedGlossaryTerm data. The picture below shows the placeholder text printed, repeatedly (as many times as is equal to the total number of related terms in all glossaryTerms documents combined).

enter image description here

I’m trying to find a way to use the glossaryTerm document id to find the sub collection data and render it only inside the relevant glossaryTerm item.

Next Attempt

I also tried:

useEffect((glossaryTermsId) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc(glossaryTermsId)
      .collection('relatedTerms')
      .where(glossaryTermsId === "glossaryId") // I also tried .where(glossaryTerms.id === "glossaryId)
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))

    setRelatedGlossaryTerms(relatedGlossaryTerms)
  });

I have added a field to the sub collection called glossaryId to try to use the where query to filter the sub collection (although even if this worked, which it doesn’t) – I don’t want to search every glossaryTerm document to get the right relatedTerms.

enter image description here
When I try

useEffect((glossaryTerms) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc(glossaryTerms)
      .collection('relatedTerms')
      .where("glossaryId" === "JsSQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
  

I still get the same result as shown in the picture above (just the placeholder text prints – the same way in all of the glossaryTerms – it just ignores the query parameter of the glossaryId attribute in the sub collection document.

NEXT ATTEMPT

I’m scratching for ideas for things to try now. I’ve tried adding glossaryTerms as a dependency to the second useEffect and I tried giving the glossaryTermsId as a prop (instead of the glossaryTerms object), as follows:

useEffect((glossaryTermsId) => {
    firebase
      .firestore()
      .collection("glossary")
      .doc(glossaryTermsId)
      .collection('relatedTerms')
      // .where("glossaryId" === "JsSQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [glossaryTerms])
  return relatedGlossaryTerms;
};

Neither of these things make any difference to the outcomes shown above.

When I try to log the content of glossaryTerm in the render – one strange thing is that the sub collection data is not displayed. I only have 2 test entries in the glossary collection. 1 has a related term and the other doesn’t. Neither is visible in the console log. I think this is because of shallow queries. But, I can’t then find a way to link the collection query to the sub collection data.

enter image description here

Next attempt

Taking Bennett’s advice, I removed the parameters from the useEffect as follows:

useEffect(() => {
    firebase
      .firestore()
      .collection("glossary")
      .doc()
      // {console.log("testing:", glossaryTerms)}
      .collection('relatedTerms')
      
      // .where("glossaryId" === "JSQ3Qf0A65ixNbF07G2")
      .onSnapshot(snapshot => {
        const relatedGlossaryTerms = snapshot.docs.map(doc => ({
          id: doc.id,
          ...doc.data(),
        }))
        setRelatedGlossaryTerms(relatedGlossaryTerms)
      });
     
      // setRelatedGlossaryTerms(glossaryTerms)
  }, [glossaryTerms])
  return relatedGlossaryTerms;
};

When I try this, it still renders the same output as shown in the image above.

When I uncomment the where query (which is the doc id of a document which has a sub collection for relatedTerms, I’m expecting to be able to get to the subcolleciton data (even if its in all the glossaryTerms, instead of just the one to which the sub collection belongs).

Instead, I get the placeholder text, rendered the number of times as is equal to the total number of related terms recorded in all sub collections in all the glossaryTerms documents (but no data).

Then when I change the string, so it should evaluate to null, I get the same rendered output (still prints the placeholders).


Get this bounty!!!

#StackBounty: #javascript #reactjs #azure #react-hooks #azure-ad-b2c How to integrate azure b2c with react

Bounty: 150

I am working with react and I have to give my user login through Azure B2C, So I am trying to do that but I am not able to find out how to do that and what is the.

What I have tried

  1. I got this example from Microsoft site which is done using plain JavaScript (vanilla), I have no idea how I will implement this in my react code.

So I tried to move with some react library, I google around and found This library

I have followed the same code they have written, but when I hit login button it takes me to login page of azure, So in my app.js I am doing console.log(authentication.getAccessToken()); after login it throws null, I don’t know why

My code

authentication.initialize({
        // optional, will default to this
        instance: 'https://login.microsoftonline.com/tfp',
        // My B2C tenant
        tenant: 'mytenant.onmicrosoft.com',
        // the policy to use to sign in, can also be a sign up or sign in policy
        signInPolicy: 'B2c_signupsignin',
        // the the B2C application you want to authenticate with (that's just a random GUID - get yours from the portal)
        clientId: 'fdfsds5-5222-ss522-a659-ada22',
        // where MSAL will store state - localStorage or sessionStorage
        cacheLocation: 'sessionStorage',
        // the scopes you want included in the access token
        scopes: ['https://mytenant.onmicrosoft.com/api/test.read'],
        // optional, the redirect URI - if not specified MSAL will pick up the location from window.href
        redirectUri: 'http://localhost:3000',
    });

And then on click of login I am doing this

const Log_in = () => {
        authentication.run(() => {});
        
    };

in my app.js I am doing like below

import authentication from 'react-azure-b2c';

function App() {
    console.log(authentication.getAccessToken());   
}

So initially it is showing null which is fine, but after login also it is throwing error only.

So I was not able to resolve this, that’s why I move to the other library which is almost similar to this

  1. This one

So here when I click on login button I am getting error as

Error

The example I got from Microsoft with valina Javascript, I think that is the perfect way to do but How can I imliment that through react I don’t know

This the code with vanilla js

I have been stuch here from long time i don’t know what to do now, not able to find good example on google to implement it with react

PS: I am using react hooks functional component to write my code, please guide me through this

I just want to implement this using react in a proper way, I know out tehre so many peoples who are already using this, so I just want to see a good example.


Get this bounty!!!

#StackBounty: #reactjs #typescript #storybook Install and use Storybook in a demo page

Bounty: 50

I am creating a personal project in TypeScript. It should be a library that exports React components and TypeScript functions. The idea is therefore to publish this library on npm in the future.
There is also a demo page within the project and this is where I would like to use Storybook to test React components.

This is the structure of the project:

.
├── demo/              # demo page
│   └── Home.tsx       # where I would like to use Storybook
│   └── index.html
│   └── index.tss
│   └── style.css
├── dist/              # distributable version of app built using Parcel
├── node_modules/      # npm managed libraries
├── src/               # project source code
│   └── lib/           # folder for your library
│      └── myFuncion.ts # function to export
│      └── MyComponent.tsx # react component to export
│   └── index.ts    # app entry point (it simply contains the exports of myFunction and myComponent)
├── .eslintrc.js
├── .gitignore
├── package.json
├── tsconfig.json
├── ...

I have read the Storybook documentation and it recommends to install Storybook by running npx sb init. I tried but the problem is that the stories are put in the project src directory, not in the demo page:

.
├── demo/              # demo page
│   └── Home.tsx       # where I would like to use Storybook
│   └── index.html
│   └── index.tss
│   └── style.css
├── dist/              # distributable version of app built using Parcel
├── node_modules/      # npm managed libraries
├── src/               # project source code
│   └── lib/           # folder for your library
│      └── myFuncion.ts # function to export
│      └── MyComponent.tsx # react component to export
│   └── stories/    # Storybook <<---
│   └── index.ts    # app entry point (it simply contains the exports of myFunction and myComponent)
├── .eslintrc.js
├── .gitignore
├── package.json
├── tsconfig.json
├── ...

And the storybook script that is created is this:

"scripts": {
    "storybook": "start-storybook -p 6006",
    "build-storybook": "build-storybook"
},

but I would like something like:

"scripts": {
    "storybook:demo": "start-storybook -p 6006",
    "build-storybook:demo": "build-storybook"
},

So how can I install and use Storybook only on the demo page?


Get this bounty!!!

#StackBounty: #reactjs #lodash #onchange #debounce Why is my React debounce handler never called?

Bounty: 100

I’m using React 16.13.0 and lodash. I was recommended to use debounce as a way to properly send search requests to my server as a user types in their search term. I implemented this …

...

const handleChange = (event, searchTerm, setSearchTerm, setSearchResults) => {
  console.log("search term:" + searchTerm);
  const query = event.target.value;
  setSearchTerm(query);
  if (!query) {
    setSearchResults( [] );
  } else {
    doSearch(query, searchTerm, setSearchResults);
  }
}

const getDebouncedHandler = (e, handler, delay) => {
  console.log("value:" + e.target.value);
  _.debounce(handler, delay);
}
...

const Search = (props) => {
  const [searchTerm, setSearchTerm] = useState('');
  const [searchResults, setSearchResults] = useState([]);

  const renderSearchResults = ...

  return (
    <div className="searchForm">
      <input
        type="text"
        placeholder="Search"
        value={searchTerm}
        onChange={(e) => {getDebouncedHandler(e, (e) => {handleChange(e, searchTerm, setSearchTerm, setSearchResults); }, 100)}}
      />
      {renderSearchResults()}
    </div>
  );
}

export default Search;

The problem is, although I see my "getDebouncedHandler" method getting called, I don’t think

_.debounce(handler, delay);

is doing anything because I never see the method listed there invoked. What else do I need to do to get debounce handler invoked properly?

Edit: Adding in the logic I’m using for "doSearch"

const doSearch = (query, searchTerm, setSearchResults) => {
  console.log("before fetch, with query:" + query);
  const searchUrl = "/coops/?contains=" + encodeURIComponent(query);
  fetch(searchUrl, {
    method: "GET",
  })
    .then((response) => response.json())
    .then((data) => {
      console.log("returning data for " + searchTerm + " query:" + query);
      console.log(data);
      if (query === searchTerm) {
        console.log("setting search results for search term:" + searchTerm);
        setSearchResults(data);
      }
    });
}


Get this bounty!!!

#StackBounty: #reactjs #continuous-integration #gitlab #licensing Automating the license checking in gitlab CI/CD pipeline

Bounty: 100

I am trying to implement the license checking of the installed packages in my react project on a GitLab CI/CD pipeline. Before the build stage, the pipeline should check all the available licenses and then whitelist or blacklist certain specified licenses.

I am using the license-checker package to implement a list of available licenses in a JSON file.
After executing the required command: license-checker --json > ./license.json, the output is:

license.json

{
  "@babel/plugin-transform-parameters@7.10.1": {
    "licenses": "MIT",
    "repository": "https://github.com/babel/babel",
    "path": "..../node_modules/@babel/plugin-transform-parameters",
    "licenseFile": "...../node_modules/@babel/plugin-transform-parameters/LICENSE"
  },
  "@babel/plugin-transform-property-literals@7.10.1": {
    "licenses": "MIT",
    "repository": "https://github.com/babel/babel",
    "path": "..../node_modules/@babel/plugin-transform-property-literals",
    "licenseFile": "...../node_modules/@babel/plugin-transform-property-literals/LICENSE"
  },
  "@babel/plugin-transform-react-constant-elements@7.10.1": {
    "licenses": "MIT",
    "repository": "https://github.com/babel/babel",
    "path": "..../node_modules/@babel/plugin-transform-react-constant-elements",
    "licenseFile": "...../node_modules/@babel/plugin-transform-react-constant-elements/LICENSE"
  }
  // .........and list goes on
}

.gitlab-ci.yml

include:
  - local: license-checker-config.yml

stages: 
  - dependency

dependency:
  image: node:12
  stage: dependency
  script: 
    - npm ci
    - echo "main file...."

license-checker-config.yml

before_script: 
  - ./license.json
  - echo "Checking licenses..."

License scanning should be initiated before the build process, so I included as a part of before_script.
In license-checker-config.yml, I need to include my JSON file and then check by iterating over it, if it contains license like MIT, then only the build stage should continue otherwise the build should fail.

With my current code setup, I executed the pipeline and got the error:

Executing "step_script" stage of the job script
00:01
$ ./license.json
/bin/bash: line 99: ./license.json: Permission denied
ERROR: Job failed: exit code 1

Even though the file license.json exists in the same root folder, it shows permission denied. Further, I am unable to figure out how to implement JSON file looping inside the yml file and then achieve the required.

Any help to get me through this is highly appreciated.


Get this bounty!!!

#StackBounty: #reactjs #wordpress Shortcode attributes in WordPress plugin with React

Bounty: 200

I’m trying to figure out how to pass attributes into a react based plugin in WordPress(using @wordpress/scripts).

my main.php file:

<?php
defined( 'ABSPATH' ) or die( 'Direct script access disallowed.' );

define( 'ERW_WIDGET_PATH', plugin_dir_path( __FILE__ ) . '/widget' );
define( 'ERW_ASSET_MANIFEST', ERW_WIDGET_PATH . '/build/asset-manifest.json' );
define( 'ERW_INCLUDES', plugin_dir_path( __FILE__ ) . '/includes' );

add_shortcode( 'my_app', 'my_app' );
/**
 * Registers a shortcode that simply displays a placeholder for our React App.
 */
function my_app( $atts = array(), $content = null , $tag = 'my_app' ){
    ob_start();
    ?>
        <div id="app">Loading...</div>
        <?php wp_enqueue_script( 'my-app', plugins_url( 'build/index.js', __FILE__ ), array( 'wp-element' ), time(), true ); ?>
    <?php 
    return ob_get_clean();
}

So if I want to load the app with this shortcode [my_app form="login"], how do I pass this attribute to wp_enqueue_script() ? and how can I display a content according to this attribute in react side? I’m trying to display a register form if the attribute is ‘register’

my react main file:

import axios from 'axios';
const { Component, render } = wp.element;

class WP_App extends Component { 
constructor(props) {
    super(props);
    this.state = { username: '', password: '' };
    this.handleUsernameChange = this.handleUsernameChange.bind(this);
    this.handlePasswordChange = this.handlePasswordChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
}

render() {
    return (
        <div class="login">
            <form onSubmit={this.handleSubmit} class="justify-content-center">
            <div class="form-group">
                <label htmlFor="username">
                    Username
                </label>
                <input
                    class="form-control"
                    id="username"
                    onChange={this.handleUsernameChange}
                    value={this.state.username}
                    type="email"
                />
             </div>
            <div class="form-group">
                <label htmlFor="password">
                    Password
                </label>
                <input
                    class="form-control"
                    id="password"
                    onChange={this.handlePasswordChange}
                    value={this.state.password}
                    type="password"
                />
            </div>
            <button class="btn btn-primary">
                Submit
            </button>
            </form>
        </div>
    );
}

handleUsernameChange(e) {
    this.setState({ username: e.target.value });
}

handlePasswordChange(e) {
    this.setState({ password: e.target.value });
}

handleSubmit(e) {
    e.preventDefault();
    if (!this.state.username.length) {
        return;
    }
    if (!this.state.password.length) {
        return;
    }
    const creds = { username: this.state.username,
                    password: this.state.password };
    axios.post('https://example.com:8443/login', creds)
        .then(response => {
                console.log("SUCCESSS")
                window.open('https://example.com/login?t=' + response.data.token, "_blank")  
            }
        )
        .catch(error => {
            if (error.response && error.response.data){
                if (error.response.data === "USER_DISABLED"){
                    console.log("User account disabled."
                    )
                }
                if (error.response.data === "ACCOUNT_LOCKED"){
                    console.log("User account is locked probably due to too many failed login attempts."
                    )
                }
                else{
                    console.log("Login failed."
                    )
                }
            }
            else{
                console.log("Login failed."
                )
                
            }
            console.log(error.response)
        });
}
}


render(
    <WP_App />,
    document.getElementById('app')
);


Get this bounty!!!

#StackBounty: #reactjs #data-structures #refactoring #javascript-objects #solid-principles How to refactor a react component that is ha…

Bounty: 50

I’d like to apply SOLID principles with a react component that’s handling too many ‘use cases’. As an example let’s say I have a component that’s main responsibility is to render a table like so:

return (
   <Table dataSource="" name={tableName} />
)

This is a very simplistic representation of that table. But the main point of complexity is the prop dataSource. Inside this <Table> component, I actually have a lot of logic/if-else condition that’s catering for the dataSource flag littered within the component because the dataSource can take in many different shapes / object structure. Some are very similar that they can be abstracted, while some are quite specific (and may even just differ by one key).

For example:

const tableName = `${
    dataSource === 'dataSourceA'
        ? dataSourceName
        : dataSourceName.name
}`;

This is just one example. Imagine some dataSource has its name property nested 3 levels deep. Then other dataSource will even have different names for the keys (although the resulting data that I need to render are actually the same). Not only that, depending on the dataSource, I may need to call a different endpoints to execute some functionalities (again, the function is doing the same purpose, just the endpoint can be different). Hence within the same component I’ll have a function like:

const exportTable = () => {
    if(dataSource === 'dataSourceA') {
        // use endpoint A
    } else if (dataSource=== 'dataSourceB') {
        // use endpoint B
    } else {
         // use endpoint C
    }
}

What is the best way to refactor this kind of component and make it easier to maintain? Later on, we can have 10 types of dataSources and I can’t be doing if-else conditions within the component to cater for their differences.


Get this bounty!!!