community-content VS Strapi-Forumapp

Compare community-content vs Strapi-Forumapp and see what are their differences.

community-content

Contribute and collaborate on educational content for the Strapi Community (by strapi)

Strapi-Forumapp

Built a forum application with NextJs and Strapi (by Victory-ET)
SurveyJS - Open-Source JSON Form Builder to Create Dynamic Forms Right in Your App
With SurveyJS form UI libraries, you can build and style forms in a fully-integrated drag & drop form builder, render them in your JS app, and store form submission data in any backend, inc. PHP, ASP.NET Core, and Node.js.
surveyjs.io
featured
InfluxDB - Power Real-Time Data Analytics at Scale
Get real-time insights from all types of time series data with InfluxDB. Ingest, query, and analyze billions of data points in real-time with unbounded cardinality.
www.influxdata.com
featured
community-content Strapi-Forumapp
12 2
563 18
1.4% -
8.1 0.0
28 days ago almost 2 years ago
JavaScript JavaScript
- -
The number of mentions indicates the total number of mentions that we've tracked plus the number of user suggested alternatives.
Stars - the number of stars that a project has on GitHub. Growth - month over month growth in stars.
Activity is a relative number indicating how actively a project is being developed. Recent commits have higher weight than older ones.
For example, an activity of 9.0 indicates that a project is amongst the top 10% of the most actively developed projects that we are tracking.

community-content

Posts with mentions or reviews of community-content. We have used some of these posts to build our list of alternatives and similar projects. The last one was on 2023-01-30.
  • Goodbye 2022, Hello 2023! Strapi Wrapped in One Year
    6 projects | dev.to | 30 Jan 2023
    Strapi wouldn’t be anything without its community, which is very much represented by its Community Stars. The Write for the Community program resulted in 148 new articles being published, for a total of 1.3M views. 2022 was also the year of the launch of the Strapi Community Organization, a group of community members dedicated to empowering initiatives and highlighting them. Boaz, Mattie, Sacha, and Simen have been invaluable contributors to the Strapi Community, going above and beyond by developing open-source plugins and tools. Strapi config-sync plugin, mattie-strapi-bundle (for search), Strapi REST cache plugin, Dockerize tool, and more!
  • Celebrating 50K GitHub Stars
    1 project | dev.to | 22 Nov 2022
    None of this would have been possible without the amazing Strapi community. To reinforce our commitment to open-source, we’d like to highlight the amazing work made by the Strapi Community Organization, thank the organizers of Strapi events, and acknowledge the amazing content made by the creators of the Write for the Community program.
  • Best Practices for Onboarding Content Managers to Your Strapi CMS
    3 projects | dev.to | 3 Nov 2022
    💡 Tips: Instead of creating all your components from scratch, you can pick up examples directly from the strapi.io website and the official FoodAdvisor Demo.
  • A Guide to Technical Writing
    5 projects | dev.to | 11 Oct 2022
    With practice comes perfection. The only way to be a great technical writer is to write more. The more you write, the more you learn and get better. Once you are comfortable writing for the Write For the Community program at Strapi, you may also venture into contributing to making our documentation better.
  • How to Build a Forum App with NextJs and Strapi CMS
    4 projects | dev.to | 16 Nov 2021
    While programming, programmers encounter various challenges, which make them solicit help with solving these problems. Forums provide a tech community of enthusiasts who can assist with these problems. We will be building a forum site with NextJs on the Front-end and Strapi for content management
  • Get Paid to Write for These 45+ Websites
    3 projects | dev.to | 22 Sep 2021
    Strapi
  • Create a Preview Button in Strapi V3 for Next.js
    3 projects | dev.to | 23 Aug 2021
    I'm taking this opportunity to thank them because this use case is very requested and their articles answer to a lot of questions. I want to emphasize that this type of contribution is very important for the Strapi community and if you wish to be part of it, I invite you to join our Write for the Community Program.
  • How the Strapi Marketing Team Uses Strapi
    8 projects | dev.to | 29 Jul 2021
    Open-Source: Anyone can contribute to the source code and thus help, improve, fix issues, propose ideas, etc... Thanks to the community efforts, Strapi will always stay updated and product requests have more chance to be met. The project evolves next to the community and it is priceless. Beyond the code contributions, our community create a lot of educational resources like articles thanks to our Write for the Community program, videos on youtube, webinars, or plugins & providers that you'll probably use at some point: Awesome Strapi repository
  • How to Implement Previews with Next Applications using a Strapi backend
    6 projects | dev.to | 29 Jun 2021
    . ## Conclusion The preview mode is an essential Static site generator tool that can improve the content editor experience when using the Jamstack architecture. To learn more about Next.js preview mode, visit this link - [](https://nextjs.org/docs/advanced-features/preview-mode)https://nextjs.org/docs/advanced-features/preview-mode [](https://nextjs.org/docs/advanced-features/preview-mode). Source Code - https://github.com/Quadrisheriff/previews-tutorial- >This article is a guest post by [**Quadri Sheriff**](http://twitter.com/QuadriSheriff3). He wrote this blog post through the [Write for the Community](https://strapi.io/write-for-the-community) program.
  • Strapi Draft System Explained
    3 projects | dev.to | 24 Feb 2021
    This article is a guest post by Precious Luke. He wrote this blog post through the Write for the Community program.

Strapi-Forumapp

Posts with mentions or reviews of Strapi-Forumapp. We have used some of these posts to build our list of alternatives and similar projects. The last one was on 2022-06-20.
  • How to Build a Forum App with Next.Js and Strapi CMS
    4 projects | dev.to | 20 Jun 2022
    The source code used in this tutorial can be found in the GitHub repo: Forum Application.
  • How to Build a Forum App with NextJs and Strapi CMS
    4 projects | dev.to | 16 Nov 2021
    import React, { useState } from "react"; import style from "../../styles/Home.module.css"; import Link from "next/link"; function Displayforum() { const [show, setShow] = useState(false); return ( Display forum Ask a question Login Questions Posted By: Victory Tuduo Description of the Question Answers Post setShow(!show)}> {show ? "Hide Answers" : "Show Answers"} {show ? (

    Miracle

    Try doing it Like this

    ) : null} ); } export default Displayforum;
    Enter fullscreen mode Exit fullscreen mode

    This component handles the layout of our display forum page. We also have a button here that directs the user to the page to upload new questions.

    Meanwhile, in upload.js we have the following:

        import React from "react";
        import Uploadforum from "./Components/Uploadforum";
        function upload() {
          return (
            
    ); } export default upload;
    Enter fullscreen mode Exit fullscreen mode

    Here, we simply added an import for the Uploadforum component into our page. In Uploadforum.js file we have a simple form to create new questions:

        import React from "react";
        import style from "../../styles/Home.module.css";
        import Link from "next/Link";
        function Uploadforum() {
          return (
            

    Ask a question

    Forum
    <button>Submit Question</button> </form> </div> </div> ); } export default Uploadforum; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Finally, we have the following styles in <code>Home.module.css</code><br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> .container { min-height: 100vh; padding: 0 0.5rem; height: 100vh; font-family: monospace; } /* display forum page */ .topcont { display: flex; justify-content: space-between; align-items: center; padding: 5px 8px; } .topcont button, .inputanswer button, .formcont button, .showanswer { border: none; color: #fff; background: dodgerblue; border-radius: 8px; padding: 10px 15px; outline: none; margin: 8px; } .topcont button:hover { cursor: pointer; transform: scale(1.2); } .heading { font-weight: bold; } .subheading { font-weight: 500; text-transform: uppercase; } .userinfo { font-size: 18px; font-weight: 600; } .questioncont { min-height: 300px; padding: 15px 14px; box-shadow: 12px 12px 36px rgba(0, 0, 0, 0.12); } .answercont { min-height: 300px; padding: 5px 3px 5px 15px; } .answers { height: 300px; overflow-x: scroll; } .inputanswer { margin-bottom: 8px; } .inputanswer textarea { width: 100%; resize: none; padding: 5px 8px; } .showanswer { border: 1px solid dodgerblue; background: #fff; color: dodgerblue; transition: 0.4s ease-in-out; } .showanswer:hover { background: dodgerblue; color: #fff; } .eachanswer { border-radius: 15px; background: #e7e7e7; padding: 8px 15px; margin-bottom: 10px; } .username { font-weight: bold; text-transform: uppercase; } .answertext { font-family: Montserrat; font-size: 14px; font-weight: 500; } /* upload a question page */ .uploadpage { min-height: 100vh; } .formcont { min-width: 100vw; display: flex; justify-content: center; align-items: center; } .uploadform { display: flex; flex-direction: column; min-width: 500px; padding-top: 10px; } .uploadform input, .uploadform textarea { resize: none; width: 100%; margin: 8px; padding: 5px; } </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>All of this makes up the layout of our pages.</p> <h2> <a name="getting-data-from-strapi" href="#getting-data-from-strapi"> </a> Getting data from Strapi: </h2> <h2> <a name="setting-up-our-fetch-request" href="#setting-up-our-fetch-request"> </a> Setting up our Fetch Request </h2> <p>In this section, we will fetch our data from Strapi and display it in our app. We will be using <a href="https://axios-http.com/docs/intro">Axios</a> to perform our fetch operations.</p> <p>We will install this via CLI:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm <span class="nb">install </span>axios </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Create a file <code>index.js</code> in the API folder. Here, we will set up our fetch request:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import axios from "axios"; const url = "http://localhost:1337/strapi-forums"; export const readForum = () => axios.get(url); export const createQuestion = (newQuestion) => axios.post(url, newQuestion); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Above, we added import for <code>axios</code>, the URL to fetch our data, and exported functions to read and create data from our forum.</p> <p>We’ll import these functions into our app in our <code>index.js</code> file:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { readForum, createQuestion } from "./api"; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <h2> <a name="fetching-data-from-strapi" href="#fetching-data-from-strapi"> </a> Fetching Data from Strapi </h2> <p>We will fetch the data from Strapi in our <code>index.js</code> file and pass it to <code>Displayforum.js</code> component to display it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { react, useState, useEffect } from "react"; ... const [question, setQuestions] = useState({}); const [response, setResponse] = useState([]); useEffect(() => { const fetchData = async () => { const result = await readForum(); setResponse(result.data); }; fetchData(); }, []); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Here, we fetched our data from Strapi and assigned it to <code>response</code> with the React <code>useState</code> hook. We have a <code>useEffect</code> function that makes the request when our component mounts.</p> <p>Now, we pass this <code>response</code> down to our <code>Displayforum</code> component.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <Displayforum response={response} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <h2> <a name="displaying-data-from-strap" href="#displaying-data-from-strap"> </a> Displaying Data from Strap </h2> <p>To display our data in our <code>Displayforum.js</code> file, we will map our responses and render our components. Before we do this, we will create two additional text fields in our Strapi CollectionCollection: <code>Username</code> and <code>Answername</code>.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--c2XelJbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635543765246_created%2Bnew%2Bfields.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--c2XelJbV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635543765246_created%2Bnew%2Bfields.jpg" alt="" loading="lazy" width="792" height="468"></a></p> <p>Back in our <code>Displayforum</code> component we will proceed with displaying our data:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... function Displayforum({ response }) { ... {response.map((response, index) => ( <div key={index}> <div className={style.userinfo}> ... <p className={style.answertext}>Try doing it Like this</p> </div> </div> ) : null} </div> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Here, we wrapped up our components to map through <code>response</code> and display this component as many times as the number of responses. To display our Strapi data, we simply reference it. We can get our <code>Username</code> with this code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> response.Username </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now add this to our component and display it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <p>Posted By: {response.Username}</p> ... <p className={style.question}>{response.Questions}</p> ... <p className={style.username}>{response.Answername}</p> <p className={style.answertext}>{response.Answers}</p> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We have successfully added the data from our CollectionCollection to our <code>front-end</code> to view this in the browser. Run the following command in the CLI:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm run dev </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>In your browser, you will have an output similar to the image below:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0X_EJPA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635545169076_got%2Bdata%2Bfrom%2BStrapi.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0X_EJPA4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635545169076_got%2Bdata%2Bfrom%2BStrapi.jpg" alt="" loading="lazy" width="880" height="399"></a></p> <p>After this, we will add functionality to add new questions to Strapi.</p> <h2> <a name="adding-data-to-strapi" href="#adding-data-to-strapi"> </a> Adding data to Strapi </h2> <p>In our <code>Uploadforum.js</code> file, we will add functionality to upload the contents of the form to Strapi. First, we will create two state variables to store the text from our <code>inputs</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { React, useState } from "react"; ... const [name, setName] = useState(""); const [description, setDescription] = useState(""); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we set these variables to the value of our form <code>input</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <input type="text" placeholder="Enter your title" maxLength="74" value={name} onChange={(e) => setName(e.target.value)} /> <textarea type="text" placeholder="Enter your description" rows="8" value={description} onChange={(e) => setDescription(e.target.value)} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Also we will a function to send these variables when we click our <code>button</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <button onClick={() => sendData()}>Submit Question</button> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can create the <code>sendData</code> function above our <code>return</code>.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const sendData = () => { }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>For our create functionality we will import the <code>createQuestion</code> function we defined in our <code>api</code> folder.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { createQuestion } from "../api"; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we pass in our data to this function.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const sendData = () => { const newQuestion = { Title: name, Questions: description, }; createQuestion(newQuestion); }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now upload new questions to our Strapi <code>collection</code>. We will add the <code>Username</code> when we cover user authentication.</p> <p>Next up, we will add functionality to answer questions in our <code>Displayforum</code> component.</p> <h2> <a name="adding-functionality-to-answer-questions" href="#adding-functionality-to-answer-questions"> </a> Adding Functionality to Answer Questions </h2> <p>Since we set a text field for our answers in our <code>collection</code>, it can only take in one value. To have multiple answers for a question, we will delete the Answers field and create another field for our Answers of type <code>json</code>.</p> <p>With that done, here is an example of what a response from our API would look like:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6ji2Py_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635601446784_new%2Bresponse.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6ji2Py_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635601446784_new%2Bresponse.jpg" alt="" loading="lazy" width="586" height="423"></a></p> <p>To display our answers, we will map through <code>Answers</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> {response.Answers.map((answers, i) => ( <div className={style.eachanswer} key={i}> <p className={style.username}>{response.Answername}</p> <p className={style.answertext}>{answers}</p> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now in our browser, if we add more <code>answers</code> to our JSON collection, we can see them displayed on our page.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jt0sMsr0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635602131051_added%2Banswers%2Bjson.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jt0sMsr0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635602131051_added%2Banswers%2Bjson.jpg" alt="" loading="lazy" width="880" height="335"></a></p> <h2> <a name="adding-new-answers" href="#adding-new-answers"> </a> Adding New Answers </h2> <p>We will repeat the same method as we did with our Upload <code>Question</code> functionality for the add answer functionality, but with a minor difference. In your <code>Displayforum</code> component, add the following code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import axios from "axios"; ... const [answer, setAnswer] = useState("") const [id, setId] = useState(""); const [a, formerArray] = useState([]); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will store the input from the <code>textarea</code> in <code>answer</code>. We will use the <code>id</code> variable to reference the collection we want to add the answer to.</p> <p>Then in our form <code>textarea</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <textarea type="text" placeholder="Enter your answer" rows="5" value={answer} onChange={(e) => setAnswer(e.target.value)} /> <button onClick={() => { setId(response.id); formerArray(response.Answers); submitAnswer() }}>Post</button> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then in the <code>submitAnswer</code> function:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const submitAnswer = () => { try { axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, answer], }); } catch (error) { console.log(error); } }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>With this, we can now add answers through our form to our collection.</p> <h2> <a name="user-authentication-with-nextauth" href="#user-authentication-with-nextauth"> </a> User Authentication with NextAuth </h2> <p>This section will use <a href="https://next-auth.js.org/">Nextauth</a>, a NextJs package for authentication, to implement Google login for our application. We will also set up protected routes so that only authenticated users can create questions and view them.</p> <p>To install <code>next-auth</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight shell"><code> npm i next-auth </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>For our authentication, we will make use of <a href="https://jwt.io/introduction">JWT token</a> . JWT is a standard used to create access tokens for an application.</p> <p>We will create a file to handle user authentication. To do this, create a folder named <code>auth</code> in your <code>api</code> folder and within it, create a file <code>[...nextauth].js</code> with the following code in it:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import NextAuth from "next-auth"; import GoogleProvider from 'next-auth/providers/google' export default NextAuth({ providers: [ GoogleProvider({ clientId: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, authorizationUrl: 'https://accounts.google.com/o/oauth2/v2/auth?prompt=consent&access_type=offline&response_type=code', }) ], jwt: { encryption: true }, secret: process.env.secret, callbacks: { async jwt(token, account) { if (account ?.accessToken) { token.accessToken = account.accessToken } return token; }, redirect: async (url, _baseUrl)=>{ if (url === '/check') { return Promise.resolve('/') } return Promise.resolve('/') } } }); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>The code above sets up our <code>Google Authentication</code> for our app. To use it, we need to wrap up our application in <code>_app.js</code> with the Google Provider component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... import {Provider} from 'next-auth/client' function MyApp({ Component, pageProps }) { return ( <Provider session={pageProps.session}> <Component {...pageProps} /> </Provider> ); } export default MyApp; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Next, we will modify our <code>Displayforum</code> component in to return to our component if the user is authenticated, else it returns a button that leads to an authentication page:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import {signIn, signOut, useSession} from 'next-auth/client' ... const [session, loadingSession] = useSession(); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will use <code>useSession</code> to know if our user has been authorized.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> if (loadingSession) { <> <p>logging in</p> </>; } return( ... </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>The above code simply returns “logging in” if <code>loadingSession</code> is true. If there is <code>session</code>, we will return the rest of the component and if there is no <code>session</code> we will render a button to <code>sign in</code> to access the app.<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> return( <div> {!session && ( <> <h1>Sign in to access forum</h1> <button onClick={() => signIn()}>Sign In</button> </> )} {session && ( <> {/*rest of our app*/} </> )} </div> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We will also set our button to <code>Sign out</code>:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... <Link href="/upload"> <button>Ask a question</button> </Link> <button onClick={() => signOut()}>Signout</button> ... </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>To make use of <code>Google authentication</code> in our app, we will require access credentials from Google Cloud console. To get this, navigate in your browser to <a href="https://console.developers.google.com/apis/credentials.">Google Cloud</a>.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8fyVQQWR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626385264_create%2Bkey.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8fyVQQWR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626385264_create%2Bkey.jpg" alt="" loading="lazy" width="488" height="309"></a></p> <p>Click on <code>OAuth Client ID</code> and Fill out the fields on the new page that opens.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jdbKsofe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626440061_create%2Bkey2.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jdbKsofe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635626440061_create%2Bkey2.jpg" alt="" loading="lazy" width="880" height="455"></a></p> <p>Finally, set the redirect URL to: <a href="http://localhost/api/auth/callback/google">http://localhost/api/auth/callback/google</a></p> <p>To use the credentials in the <code>[…nextauth].js</code> file, you can create a <code>.env</code> file and set up your environmental variables:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> GOOGLE_CLIENT_ID: id GOOGLE_CLIENT_SECRET: secret secret: any string </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Next, we will set up our <code>Uploadforum.js</code> component on our <code>upload</code> page as a protected route so that unauthorized users can’t access the route. To do this, in <code>upload.js</code> add the following code:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> import { getSession, useSession } from 'next-auth/client' </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then at the bottom:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> export async function getServerSideProps(context) { const session = await getSession(context); if (!session) { context.res.writeHead(302, { Location: '/' }); context.res.end(); return {}; } return { props: { user: session.user, } } } export default Upload; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now, if you run the app with <code>npm run dev</code> in CLI, we have <code>Google authentication</code> implemented. Also we can’t access the <code>/upload</code> path without logging in.</p> <h2> <a name="adding-user-name-to-collection" href="#adding-user-name-to-collection"> </a> Adding User name to Collection </h2> <p>Now that we have added authentication to our app, we can add the <code>username</code> received from the <code>Google Login</code> as the <code>Answername</code> field when we answer a question:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, answer], Answername: session.user.name, }); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Now, if I add a new answer to the form:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lnTi91zI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629050599_before%2Bpost.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lnTi91zI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629050599_before%2Bpost.jpg" alt="" loading="lazy" width="880" height="272"></a></p> <p>When I click on the <code>Post</code> button, I get:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DOQyNCJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629083784_After%2Bsubmission.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DOQyNCJQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635629083784_After%2Bsubmission.jpg" alt="" loading="lazy" width="880" height="169"></a></p> <p>The answer has been added and the <code>Answername</code> field has been set to my <code>user.name</code> form our <code>session</code>.</p> <p>Finally, we will also add the <code>username</code> when posting a question to our <code>collection</code>. We will do this in our <code>upload.js</code> file:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> const [session, loadingSession] = useSession(); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Then we pass the value of <code>session</code> to our <code>Uploadforum</code> Component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <Uploadforum session={session} /> </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now use <code>session</code> data in our <code>Uploadforum</code> component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> function Uploadforum({session}) { ... const newQuestion = { Title: name, Questions: description, Answers: [""], Username: session.user.name, }; </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>Any new questions added now take the <code>Username</code> field to be the <code>username</code> received from <code>session</code>.</p> <p>If we add new answers, since the <code>Answername</code> is a field, it overwrites the previous data and all the <code>answers</code> use the same name. To fix this, we will simply modify our <code>Answers</code> field of type JSON to contain both the answers and the username of the person providing the answers.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XNbqg2mj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635678809482_compounded%2Banswers%2Band%2Busername.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XNbqg2mj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635678809482_compounded%2Banswers%2Band%2Busername.jpg" alt="" loading="lazy" width="880" height="406"></a></p> <p>Then, we can get this data and display it in our <code>Displayforum</code> component:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> <div className={style.answers}> {response.Answers.map((answers, i) => ( <div className={style.eachanswer} key={i}> <p className={style.username}>{answers[0]}</p> <p className={style.answertext}>{answers[1]}</p> </div> ))} </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p><code>answer[0]</code> is the name of the user, while <code>answers[1]</code> is the answer.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gkFoOjyL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679166354_compounded%2Banswers%2B.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gkFoOjyL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679166354_compounded%2Banswers%2B.jpg" alt="" loading="lazy" width="880" height="339"></a></p> <p>Finally, we will modify the code to add new answers:<br> </p> <div class="highlight js-code-highlight"> <pre class="highlight plaintext"><code> ... axios.put(`http://localhost:1337/forums/${id}`, { Answers: [...a, [session.user.name, answer]], }); } catch (error) { console.log(error); </code></pre> <div class="highlight__panel js-actions-panel"> <div class="highlight__panel-action js-fullscreen-code-action"> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-on"><title>Enter fullscreen mode</title> <path d="M16 3h6v6h-2V5h-4V3zM2 3h6v2H4v4H2V3zm18 16v-4h2v6h-6v-2h4zM4 19h4v2H2v-6h2v4z"></path> </svg> <svg xmlns="http://www.w3.org/2000/svg" width="20px" height="20px" viewbox="0 0 24 24" class="highlight-action crayons-icon highlight-action--fullscreen-off"><title>Exit fullscreen mode</title> <path d="M18 7h4v2h-6V3h2v4zM8 9H2V7h4V3h2v6zm10 8v4h-2v-6h6v2h-4zM8 15v6H6v-4H2v-2h6z"></path> </svg> </div> </div> </div> <p>We can now add new answers to our questions without overwriting previous data.</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--g5whN-Z9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679343611_final%2Btest.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--g5whN-Z9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679343611_final%2Btest.jpg" alt="" loading="lazy" width="880" height="453"></a></p> <p>When I click on post I get a new answer:</p> <p><a href="https://res.cloudinary.com/practicaldev/image/fetch/s--KEWj1FXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679382631_final%2Bresult.jpg" class="article-body-image-wrapper"><img src="https://res.cloudinary.com/practicaldev/image/fetch/s--KEWj1FXK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://paper-attachments.dropbox.com/s_C85777D6DFCF98E4EF331F9FA47DA97E3213CAFEB9DAD61A99F14E2CE8154E5F_1635679382631_final%2Bresult.jpg" alt="" loading="lazy" width="880" height="478"></a></p> <h2> <a name="conclusion" href="#conclusion"> </a> Conclusion </h2> <p>We have come to the end of this tutorial. In this tutorial, we learned how to use Strapi CMS and connect it to NextJ's front-end. In this process, we built a forum site and implemented user authentication and authorization on it.</p> <h2> <a name="resources" href="#resources"> </a> Resources </h2> <p>The source code used in this tutorial can be found in the GitHub repo: <a href="https://github.com/Victory-ET/Strapi-Forumapp">Forum Application</a>.</p>

What are some alternatives?

When comparing community-content and Strapi-Forumapp you can also consider the following projects:

reactour - Tourist Guide into your React Components

Next.js - The React Framework

strapi-template-blog - Template to create Strapi projects pre-configured for blogs

next-auth - Authentication for the Web.

strapi-starter-gatsby-blog - Updated version of the first Gatsby starter with much more features

Strapi - 🚀 Strapi is the leading open-source headless CMS. It’s 100% JavaScript/TypeScript, fully customizable and developer-first.

jamstack.org - The official Jamstack site

awesome-strapi - A curated list of awesome things related to Strapi

engineering-education - “Section's Engineering Education (EngEd) Program is dedicated to offering a unique quality community experience for computer science university students."

foodadvisor - 🥘 THE Strapi demo application

Tailwind CSS - A utility-first CSS framework for rapid UI development.

strapi-plugin-config-sync - :recycle: CLI & GUI for continuous migration of config data across environments