{"id":27937,"date":"2022-04-19T08:25:34","date_gmt":"2022-04-19T08:25:34","guid":{"rendered":"http:\/\/make-a-community-events-calendar"},"modified":"2022-04-19T08:25:34","modified_gmt":"2022-04-19T08:25:34","slug":"make-a-community-events-calendar","status":"publish","type":"post","link":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/","title":{"rendered":"Make a Community Events Calendar"},"content":{"rendered":"<div class=\"wp-block-cloudinary-markdown \"><p>Raising awareness of things going on in your community is a great way to make people feel more connected and involved in what\u2019s going on around them. A community calendar where people can add events can help with that.<\/p>\n<p>We\u2019re going to build a calendar that uses Flask on the back-end to interact with a Postgres database and React on the front-end. Users will be able to upload event details, see which days have events, and more.<\/p>\n<h2>Setting up the project<\/h2>\n<p>We\u2019re going to need a root folder to hold the front-end and back-end of our project, so create a new folder called <code>events-calendar<\/code>. Inside this folder, add a new subfolder called <code>server<\/code>. We\u2019ll make the Flask app in the <code>server<\/code> folder.<\/p>\n<p>Now let\u2019s set up the local Postgres instance. You can download it <a href=\"https:\/\/www.postgresql.org\/download\/\">here<\/a>. Make sure you take note of your username and password because we\u2019ll need them in the connection string for the back-end. That\u2019s all the base setup we need and now we can start making the Flask app.<\/p>\n<h2>Working in the Flask environment<\/h2>\n<p>Since the back-end will use a Python framework, you\u2019ll need to create a virtual environment before we start installing packages. To do that, open your terminal, go to the <code>server<\/code> directory, and run the following commands:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ python3 -m venv .venv\n$ source .venv\/bin\/activate\n<\/code><\/span><\/pre>\n<p>Next, we\u2019ll install the <a href=\"https:\/\/flask.palletsprojects.com\/en\/2.0.x\/\">Flask<\/a> package and some others with the following command:<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ pip install flask flask_sqlalchemy flask_cors flask_migrate\n<\/code><\/span><\/pre>\n<p>With the environment set up and all of the packages installed, we\u2019re ready to create some files for our server.<\/p>\n<h3>Making the Flask API<\/h3>\n<p>Inside the <code>server<\/code> folder, add a new file called <code>api.py<\/code>. This is the file that will hold the different endpoints our front-end will call. Open this new file and add the following code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-1\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># api.py<\/span>\nimport json\nfrom flask import Flask, jsonify, request\nfrom flask_sqlalchemy import SQLAlchemy\nfrom flask_migrate import Migrate\nfrom flask_cors import CORS\n\napp = Flask(__name__)\n\nCORS(app)\n\napp.config&#91;\n    <span class=\"hljs-string\">\"SQLALCHEMY_DATABASE_URI\"<\/span>\n] = <span class=\"hljs-string\">\"postgresql:\/\/username:password@localhost:5432\/calendar\"<\/span>\n\ndb = SQLAlchemy(app)\n\nmigrate = Migrate(app, db)\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-1\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This brings in all of the packages we need and it creates the application. We\u2019re applying the CORS package to the app so that we can call the endpoint from a different domain. Then we\u2019re connecting the app to our Postgres database and getting it ready to migrate the schema. Make sure you put in your username and password for that connection string.<\/p>\n<h3>Database schema<\/h3>\n<p>We can add the schema for the one table we need below our app setup. Below the existing code, add the following.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-2\" data-shcb-language-name=\"HTML, XML\" data-shcb-language-slug=\"xml\"><span><code class=\"hljs language-xml shcb-wrap-lines\"># api.py\n\n...\nclass EventsModel(db.Model):\n    __tablename__ = \"events\"\n\n    id = db.Column(db.Integer, primary_key=True)\n    title = db.Column(db.String())\n    date = db.Column(db.Date())\n    time = db.Column(db.Time())\n    location = db.Column(db.String())\n    description = db.Column(db.String())\n\n    def __init__(self, title, date, time, location, description):\n        self.title = title\n        self.date = date\n        self.time = time\n        self.location = location\n        self.description = description\n\n    def __repr__(self):\n        return f\"<span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Event<\/span> {<span class=\"hljs-attr\">self.title<\/span>}&gt;<\/span>\"\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-2\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">HTML, XML<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">xml<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This describes the table that we want to add to the database. It will be the <code>events<\/code> table and it\u2019ll have six columns to hold details about every event we add. This is all we need to run the database migration. To do that, go to the <code>server<\/code> directory in your terminal and run the following.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ flask db init\n<\/code><\/span><\/pre>\n<p>This will add a <code>migrations<\/code> folder to your project. Next, we need to generate the migration for our model with the following command.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-3\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\">$ flask db migrate -m <span class=\"hljs-string\">\"added events table\"<\/span>\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-3\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>Finally, we can run this migration and make these changes in the database with the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ flask db upgrade\n<\/code><\/span><\/pre>\n<p>If you take a look in your Postgres instance, you\u2019ll see the new table and all of the fields we defined in the model. Now we can start creating the endpoints that will work with the data we store in this table.<\/p>\n<h3>Create an event<\/h3>\n<p>Let\u2019s start with the endpoint that will allow users to create new events on the calendar. Below the events model, add the following code.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-4\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># api.py<\/span>\n\n...\n@app.route(<span class=\"hljs-string\">\"\/event\"<\/span>, methods=&#91;<span class=\"hljs-string\">\"POST\"<\/span>])\ndef create_event():\n    <span class=\"hljs-keyword\">if<\/span> request.is_json:\n        data = request.get_json()\n\n        new_event = EventsModel(\n            title=data&#91;<span class=\"hljs-string\">\"title\"<\/span>],\n            date=data&#91;<span class=\"hljs-string\">\"date\"<\/span>],\n            time=data&#91;<span class=\"hljs-string\">\"time\"<\/span>],\n            location=data&#91;<span class=\"hljs-string\">\"location\"<\/span>],\n            description=data&#91;<span class=\"hljs-string\">\"description\"<\/span>],\n        )\n\n        db.session.add(new_event)\n        db.session.commit()\n\n        <span class=\"hljs-keyword\">return<\/span> {<span class=\"hljs-string\">\"message\"<\/span>: f<span class=\"hljs-string\">\"event {new_event.title} has been created successfully.\"<\/span>}\n    <span class=\"hljs-keyword\">else<\/span>:\n        <span class=\"hljs-keyword\">return<\/span> {<span class=\"hljs-string\">\"error\"<\/span>: <span class=\"hljs-string\">\"The request payload is not in JSON format\"<\/span>}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-4\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>When a <code>POST<\/code> request is made to the <code>\/event<\/code> endpoint with the correct data, it will add a new record to the events table in the database and send a success message with the event title in the response.<\/p>\n<h3>Get all of the events<\/h3>\n<p>We\u2019ll need to be able to get all of the events that are in the calendar so that we can render them correctly. To fetch all of the events from the database, add the following code to your <code>api.py<\/code> file below the create event endpoint.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-5\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># api.py<\/span>\n\n...\n@app.route(<span class=\"hljs-string\">\"\/events\"<\/span>, methods=&#91;<span class=\"hljs-string\">\"GET\"<\/span>])\ndef get_events():\n    eventsData = EventsModel.query.all()\n    events = &#91;\n        {\n            <span class=\"hljs-string\">\"id\"<\/span>: event.id,\n            <span class=\"hljs-string\">\"title\"<\/span>: event.title,\n            <span class=\"hljs-string\">\"date\"<\/span>: event.date,\n            <span class=\"hljs-string\">\"time\"<\/span>: event.time,\n            <span class=\"hljs-string\">\"location\"<\/span>: event.location,\n            <span class=\"hljs-string\">\"description\"<\/span>: event.description,\n        }\n        <span class=\"hljs-keyword\">for<\/span> event in eventsData\n    ]\n\n    <span class=\"hljs-keyword\">return<\/span> {<span class=\"hljs-string\">\"events\"<\/span>: json.dumps(events, <span class=\"hljs-keyword\">default<\/span>=str)}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-5\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This creates a new <code>GET<\/code> route called <code>\/events<\/code>. Anytime this endpoint is called with a <code>GET<\/code> request, it will go to the database and retrieve all of the records from the events table and return it as a JSON string.<\/p>\n<h3>Get and update an event<\/h3>\n<p>We can take advantage of the request type to use the same endpoint to handle different functionality. There will be times we want to look at or edit a particular event. We could use separate endpoints for this, but we\u2019re going to use different request types to distinguish which type of call is being made. Add the following code below the endpoint to get all of the events.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-6\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># api.py<\/span>\n\n...\n@app.route(<span class=\"hljs-string\">\"\/event\/&lt;event_id&gt;\"<\/span>, methods=&#91;<span class=\"hljs-string\">\"GET\"<\/span>, <span class=\"hljs-string\">\"PUT\"<\/span>])\ndef event(event_id):\n    event = EventsModel.query.get_or_404(event_id)\n\n    <span class=\"hljs-keyword\">if<\/span> request.method == <span class=\"hljs-string\">\"GET\"<\/span>:\n        response = {\n            <span class=\"hljs-string\">\"id\"<\/span>: event.id,\n            <span class=\"hljs-string\">\"title\"<\/span>: event.title,\n            <span class=\"hljs-string\">\"date\"<\/span>: event.date,\n            <span class=\"hljs-string\">\"time\"<\/span>: event.time,\n            <span class=\"hljs-string\">\"location\"<\/span>: event.location,\n            <span class=\"hljs-string\">\"description\"<\/span>: event.description,\n        }\n\n        <span class=\"hljs-keyword\">return<\/span> {<span class=\"hljs-string\">\"message\"<\/span>: <span class=\"hljs-string\">\"success\"<\/span>, <span class=\"hljs-string\">\"event\"<\/span>: json.dumps(response, <span class=\"hljs-keyword\">default<\/span>=str)}\n    <span class=\"hljs-keyword\">else<\/span>:\n        data = request.get_json()\n\n        event.title = data&#91;<span class=\"hljs-string\">\"title\"<\/span>]\n        event.date = data&#91;<span class=\"hljs-string\">\"date\"<\/span>]\n        event.time = data&#91;<span class=\"hljs-string\">\"time\"<\/span>]\n        event.location = data&#91;<span class=\"hljs-string\">\"location\"<\/span>]\n        event.description = data&#91;<span class=\"hljs-string\">\"description\"<\/span>]\n\n        db.session.add(event)\n        db.session.commit()\n\n        <span class=\"hljs-keyword\">return<\/span> {<span class=\"hljs-string\">\"message\"<\/span>: f<span class=\"hljs-string\">\"event {event.title} successfully updated\"<\/span>}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-6\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This checks that the database has a record for the given event ID or it returns an error. If there is a record, the request type is checked and if it is a <code>GET<\/code> request, it will return a JSON string with that event\u2019s details. If it\u2019s a <code>POST<\/code> request, it will update the event record and save the changes to the database.<\/p>\n<h3>Run the file correctly<\/h3>\n<p>We\u2019re going to run this as the main program so we\u2019ll add this bit of code at the bottom of our file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-7\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\"># api.py<\/span>\n\n...\n<span class=\"hljs-keyword\">if<\/span> __name__ == <span class=\"hljs-string\">\"__main__\"<\/span>:\n    app.run()\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-7\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>You can test this out by running the app with the following command in your terminal.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ python api.py\n<\/code><\/span><\/pre>\n<p>You should see your server start on <code>localhost:5000<\/code> and try sending a request to the <code>\/event<\/code> endpoint to make a new record. This is actually everything we need for the API! We have the database connection and all of the endpoints we need to work with data on the front-end so we can switch our attention there.<\/p>\n<h2>Building the React App<\/h2>\n<p>Switching over to the front-end, go to the root directory in the terminal and run the following command.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ npx create-react-app client --template typescript\n<\/code><\/span><\/pre>\n<p>This will generate a new React project for you in a new directory called <code>client<\/code>. In your terminal, go to the <code>client<\/code> directory and run the following command to add the packages we\u2019ll use.<\/p>\n<pre class=\"js-syntax-highlighted\"><span><code class=\"hljs shcb-wrap-lines\">$ npm i axios react-calendar react-modal\n<\/code><\/span><\/pre>\n<p>With the packages installed, let\u2019s start by making the one component we need for this project.<\/p>\n<h3>Add the event modal<\/h3>\n<p>In the <code>client<\/code> folder, add a new subfolder called <code>components<\/code>. Inside that folder, add a new file called <code>Event.tsx<\/code>. This will be the modal that appears when users want to view or edit an individual event. Add the following code to that file.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-8\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ Event.tsx<\/span>\n<span class=\"hljs-keyword\">import<\/span> axios <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"axios\"<\/span>;\n<span class=\"hljs-keyword\">import<\/span> Modal <span class=\"hljs-keyword\">from<\/span> <span class=\"hljs-string\">\"react-modal\"<\/span>;\n\nModal.setAppElement(<span class=\"hljs-string\">\"#root\"<\/span>);\n\n<span class=\"hljs-keyword\">export<\/span> <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">Event<\/span>(<span class=\"hljs-params\">{\n  showModal,\n  setShowModal,\n  event,\n}: {\n  showModal: boolean;\n  setShowModal: (<\/span>) =&gt; <span class=\"hljs-title\">void<\/span>;\n  <span class=\"hljs-title\">event<\/span>?: <span class=\"hljs-title\">any<\/span>;\n}) <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> saveEvent = <span class=\"hljs-keyword\">async<\/span> (event: any) =&gt; {\n    event.preventDefault();\n    <span class=\"hljs-keyword\">const<\/span> eventData = {\n      <span class=\"hljs-attr\">title<\/span>: event.target.title.value,\n      <span class=\"hljs-attr\">date<\/span>: event.target.date.value,\n      <span class=\"hljs-attr\">time<\/span>: event.target.time.value,\n      <span class=\"hljs-attr\">location<\/span>: event.target.location.value,\n      <span class=\"hljs-attr\">description<\/span>: event.target.description.value,\n    };\n\n    <span class=\"hljs-keyword\">if<\/span> (!event) {\n      <span class=\"hljs-keyword\">await<\/span> axios.post(<span class=\"hljs-string\">\"http:\/\/localhost:5000\/event\"<\/span>, eventData);\n    } <span class=\"hljs-keyword\">else<\/span> {\n      <span class=\"hljs-keyword\">await<\/span> axios.put(<span class=\"hljs-string\">`http:\/\/localhost:5000\/event\/<span class=\"hljs-subst\">${event.id}<\/span>`<\/span>, eventData);\n    }\n  };\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    <span class=\"xml\"><span class=\"hljs-tag\">&lt;&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">Modal<\/span>\n        <span class=\"hljs-attr\">isOpen<\/span>=<span class=\"hljs-string\">{showModal}<\/span>\n        <span class=\"hljs-attr\">onRequestClose<\/span>=<span class=\"hljs-string\">{setShowModal}<\/span>\n        <span class=\"hljs-attr\">contentLabel<\/span>=<span class=\"hljs-string\">\"Event\"<\/span>\n      &gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>Event<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">form<\/span> <span class=\"hljs-attr\">onSubmit<\/span>=<span class=\"hljs-string\">{saveEvent}<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"title\"<\/span>&gt;<\/span>Event title<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n              <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"title\"<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"title\"<\/span>\n              <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{event?.title}<\/span>\n            \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"date\"<\/span>&gt;<\/span>Event dateime<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n              <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"date\"<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"date\"<\/span>\n              <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{event?.date}<\/span>\n            \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"time\"<\/span>&gt;<\/span>Event time<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n              <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"time\"<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"time\"<\/span>\n              <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{event?.time}<\/span>\n            \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"location\"<\/span>&gt;<\/span>Event location<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n              <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"location\"<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"location\"<\/span>\n              <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{event?.location}<\/span>\n            \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">label<\/span> <span class=\"hljs-attr\">htmlFor<\/span>=<span class=\"hljs-string\">\"description\"<\/span>&gt;<\/span>Event title<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">label<\/span>&gt;<\/span>\n            <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">input<\/span>\n              <span class=\"hljs-attr\">name<\/span>=<span class=\"hljs-string\">\"description\"<\/span>\n              <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"text\"<\/span>\n              <span class=\"hljs-attr\">id<\/span>=<span class=\"hljs-string\">\"description\"<\/span>\n              <span class=\"hljs-attr\">defaultValue<\/span>=<span class=\"hljs-string\">{event?.description}<\/span>\n            \/&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">div<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">onClick<\/span>=<span class=\"hljs-string\">{setShowModal}<\/span>&gt;<\/span>Close modal<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n          <span class=\"hljs-tag\">&lt;<span class=\"hljs-name\">button<\/span> <span class=\"hljs-attr\">type<\/span>=<span class=\"hljs-string\">\"submit\"<\/span>&gt;<\/span>Save event<span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">button<\/span>&gt;<\/span>\n        <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">form<\/span>&gt;<\/span>\n      <span class=\"hljs-tag\">&lt;\/<span class=\"hljs-name\">Modal<\/span>&gt;<\/span>\n    <span class=\"hljs-tag\">&lt;\/&gt;<\/span><\/span>\n  );\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-8\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This imports a few packages and sets up the modal element to target the root element. Then we have the <code>Event<\/code> component which takes a few props. Then there is a <code>saveEvent<\/code> method that will take the values from the form we have and either update or create a new event based on if there is any current event data available.<\/p>\n<p>Then we have the form that will either be blank or display the event information in the fields depending on if the <code>event<\/code> prop was passed to the modal. We also decide whether the modal should currently be showing or if it should be hidden based on the <code>showModal<\/code> prop.<\/p>\n<p>That\u2019s all for the modal to show, update, or create new events. Now we need the page that shows the calendar and all of the events we have.<\/p>\n<h3>The calendar page<\/h3>\n<p>We\u2019re going to modify the existing <code>App.tsx<\/code> file to render our calendar and the events. Here\u2019s what the new code will look like. There\u2019s a lot going on here so we\u2019ll walk through it.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-9\" data-shcb-language-name=\"PHP\" data-shcb-language-slug=\"php\"><span><code class=\"hljs language-php shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ App.tsx<\/span>\n\nimport axios from <span class=\"hljs-string\">\"axios\"<\/span>;\nimport { useEffect, useState } from <span class=\"hljs-string\">\"react\"<\/span>;\nimport Calendar from <span class=\"hljs-string\">\"react-calendar\"<\/span>;\nimport <span class=\"hljs-string\">\"react-calendar\/dist\/Calendar.css\"<\/span>;\nimport Event from <span class=\"hljs-string\">\".\/components\/Event\"<\/span>;\n\nexport <span class=\"hljs-keyword\">default<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">App<\/span><span class=\"hljs-params\">()<\/span> <\/span>{\n  <span class=\"hljs-keyword\">const<\/span> &#91;date, setDate] = useState(<span class=\"hljs-keyword\">new<\/span> Date());\n  <span class=\"hljs-keyword\">const<\/span> &#91;showModal, setShowModal] = useState&lt;boolean&gt;(<span class=\"hljs-keyword\">false<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;showEditModal, setShowEditModal] = useState&lt;boolean&gt;(<span class=\"hljs-keyword\">false<\/span>);\n  <span class=\"hljs-keyword\">const<\/span> &#91;event, setEvent] = useState({});\n  <span class=\"hljs-keyword\">const<\/span> &#91;events, setEvents] = useState&lt;any&gt;(&#91;]);\n\n  useEffect(() =&gt; {\n    axios.get(<span class=\"hljs-string\">\"http:\/\/localhost:5000\/events\"<\/span>).then((res) =&gt; {\n      setEvents(JSON.parse(res.data.events));\n    });\n  }, &#91;]);\n\n  <span class=\"hljs-function\"><span class=\"hljs-keyword\">function<\/span> <span class=\"hljs-title\">tileContent<\/span><span class=\"hljs-params\">({ date, view }: any)<\/span> <\/span>{\n    <span class=\"hljs-keyword\">const<\/span> display = events.map((event: any) =&gt; {\n      <span class=\"hljs-keyword\">const<\/span> eventDate = <span class=\"hljs-keyword\">new<\/span> Date(event.date);\n      eventDate.setDate(eventDate.getDate() + <span class=\"hljs-number\">1<\/span>);\n\n      <span class=\"hljs-keyword\">if<\/span> (date.toDateString() === eventDate.toDateString()) {\n        <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\" \"<\/span> + event.title + <span class=\"hljs-string\">\" \"<\/span>;\n      }\n      <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-string\">\"\"<\/span>;\n    });\n    <span class=\"hljs-keyword\">return<\/span> display;\n  }\n\n  <span class=\"hljs-keyword\">return<\/span> (\n    &lt;div&gt;\n      &lt;h1&gt;Event Calendar&lt;\/h1&gt;\n      &lt;Calendar\n        onChange={setDate}\n        value={date}\n        onClickDay={() =&gt; setShowModal(<span class=\"hljs-keyword\">true<\/span>)}\n        tileContent={tileContent}\n      \/&gt;\n      &lt;&gt;\n        {events &amp;&amp;\n          events.map((event: any) =&gt; (\n            &lt;div\n              key={event.title}\n              onClick={() =&gt; {\n                setEvent(event);\n                setShowEditModal(<span class=\"hljs-keyword\">true<\/span>);\n              }}\n              style={{ borderBottom: <span class=\"hljs-string\">\"1px solid grey\"<\/span>, padding: <span class=\"hljs-string\">\"18px\"<\/span> }}\n            &gt;\n              &lt;div&gt;{event.title}&lt;\/div&gt;\n              &lt;div&gt;\n                {event.date} - {event.time}\n              &lt;\/div&gt;\n              &lt;div&gt;{event.location}&lt;\/div&gt;\n              &lt;div&gt;{event.description}&lt;\/div&gt;\n            &lt;\/div&gt;\n          ))}\n      &lt;\/&gt;\n      {showEditModal &amp;&amp; (\n        &lt;Event\n          showModal={showEditModal}\n          setShowModal={() =&gt; setShowEditModal(<span class=\"hljs-keyword\">false<\/span>)}\n          event={event}\n        \/&gt;\n      )}\n      {showModal &amp;&amp; (\n        &lt;Event showModal={showModal} setShowModal={() =&gt; setShowModal(<span class=\"hljs-keyword\">false<\/span>)} \/&gt;\n      )}\n    &lt;\/div&gt;\n  );\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-9\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">PHP<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">php<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>We start off by importing the packages we need to get the calendar and the events data. Inside the <code>App<\/code> component we have some states that will control how elements are rendered on the page. After that, we have a <code>useEffect<\/code> hook that fetches all of the events from the database when the page is loaded.<\/p>\n<p>Then there\u2019s a function that adds the title of an event to the date on the calendar. Next, we render the <code>Calendar<\/code> component and pass it a few props. After that, we display a list of all of the events that are currently on the calendar. Finally, we conditionally show the event modal based on current states.<\/p>\n<p>The last thing we need to edit is the CSS so this looks a <em>little<\/em> better.<\/p>\n<h3>Style the calendar<\/h3>\n<p>There will be a lot of things you need to change stylistically before this goes to production, but we\u2019ll at least add a few things to get this to an MVP stage. Find the <code>index.scss<\/code> file in <code>client &gt; src<\/code> and add the following code at the bottom.<\/p>\n<pre class=\"js-syntax-highlighted\" aria-describedby=\"shcb-language-10\" data-shcb-language-name=\"JavaScript\" data-shcb-language-slug=\"javascript\"><span><code class=\"hljs language-javascript shcb-wrap-lines\"><span class=\"hljs-comment\">\/\/ index.scss<\/span>\n\n... .react-calendar {\n  <span class=\"hljs-attr\">width<\/span>: <span class=\"hljs-number\">100<\/span>% !important;\n  border: solid <span class=\"hljs-number\">1<\/span>px white;\n  border-radius: <span class=\"hljs-number\">12<\/span>px;\n}\n<\/code><\/span><small class=\"shcb-language\" id=\"shcb-language-10\"><span class=\"shcb-language__label\">Code language:<\/span> <span class=\"shcb-language__name\">JavaScript<\/span> <span class=\"shcb-language__paren\">(<\/span><span class=\"shcb-language__slug\">javascript<\/span><span class=\"shcb-language__paren\">)<\/span><\/small><\/pre>\n<p>This will at least make the calendar the full width of the page so people can see the event titles. Here\u2019s what the calendar page will look like if you run the front-end and back-end at the same time.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/res.cloudinary.com\/mediadevs\/image\/upload\/c_limit,w_2000\/f_auto\/q_auto\/v1650304252\/e-603fc55d218a650069f5228b\/wllg1728asy1a3l4rpfv.png\" alt=\"calendar page with events\" loading=\"lazy\" class=\"c-transformed-asset\"  width=\"2000\" height=\"1064\"\/><\/p>\n<p>Now you have a full-stack application ready to handle all of the events in your community!<\/p>\n<h2>Finished code<\/h2>\n<p>You can find the code for the finished project in <a href=\"https:\/\/github.com\/flippedcoder\/media-projects\/tree\/main\/events-calendar\">the <code>events-calendar<\/code> folder of this repo<\/a>. You can also check out <a href=\"https:\/\/codesandbox.io\/s\/frosty-grass-bh34cq\">this Code Sandbox<\/a> for the front-end.<\/p>\n<p>&lt;CodeSandBox\ntitle=\u201cfrosty-grass-bh34cq\u201d\nid=\u201cfrosty-grass-bh34cq\u201d\n\/&gt;<\/p>\n<h2>Conclusion<\/h2>\n<p>Planning events is hard enough without trying to figure out how to spread the word. This might be a way to encourage people to let others know what is going on and how they can participate. This project should be flexible enough that you can style it and expand the functionality in a number of ways.<\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"","protected":false},"author":41,"featured_media":27938,"comment_status":"","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"_cloudinary_featured_overwrite":false,"footnotes":""},"categories":[1],"tags":[332,134,246,371],"class_list":["post-27937","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-api","tag-guest-post","tag-react","tag-under-review"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.6 (Yoast SEO v26.9) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Make a Community Events Calendar<\/title>\n<meta name=\"description\" content=\"If you&#039;ve ever been frustrated about missing something going on in your community or city, this might be a way that you solve the problem. We&#039;re going to build an events calendar that people can add information to!\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Make a Community Events Calendar\" \/>\n<meta property=\"og:description\" content=\"If you&#039;ve ever been frustrated about missing something going on in your community or city, this might be a way that you solve the problem. We&#039;re going to build an events calendar that people can add information to!\" \/>\n<meta property=\"og:url\" content=\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/\" \/>\n<meta property=\"og:site_name\" content=\"Cloudinary Blog\" \/>\n<meta property=\"article:published_time\" content=\"2022-04-19T08:25:34+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA\" \/>\n\t<meta property=\"og:image:width\" content=\"2992\" \/>\n\t<meta property=\"og:image:height\" content=\"2000\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"NewsArticle\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/\"},\"author\":{\"name\":\"\",\"@id\":\"\"},\"headline\":\"Make a Community Events Calendar\",\"datePublished\":\"2022-04-19T08:25:34+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/\"},\"wordCount\":5,\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA\",\"keywords\":[\"API\",\"Guest Post\",\"React\",\"Under Review\"],\"inLanguage\":\"en-US\",\"copyrightYear\":\"2022\",\"copyrightHolder\":{\"@id\":\"https:\/\/cloudinary.com\/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/\",\"url\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/\",\"name\":\"Make a Community Events Calendar\",\"isPartOf\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA\",\"datePublished\":\"2022-04-19T08:25:34+00:00\",\"description\":\"If you've ever been frustrated about missing something going on in your community or city, this might be a way that you solve the problem. We're going to build an events calendar that people can add information to!\",\"breadcrumb\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#primaryimage\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA\",\"width\":2992,\"height\":2000},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/cloudinary.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Make a Community Events Calendar\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#website\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"name\":\"Cloudinary Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/cloudinary.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#organization\",\"name\":\"Cloudinary Blog\",\"url\":\"https:\/\/cloudinary.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"contentUrl\":\"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA\",\"width\":312,\"height\":60,\"caption\":\"Cloudinary Blog\"},\"image\":{\"@id\":\"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Make a Community Events Calendar","description":"If you've ever been frustrated about missing something going on in your community or city, this might be a way that you solve the problem. We're going to build an events calendar that people can add information to!","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/","og_locale":"en_US","og_type":"article","og_title":"Make a Community Events Calendar","og_description":"If you've ever been frustrated about missing something going on in your community or city, this might be a way that you solve the problem. We're going to build an events calendar that people can add information to!","og_url":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/","og_site_name":"Cloudinary Blog","article_published_time":"2022-04-19T08:25:34+00:00","og_image":[{"width":2992,"height":2000,"url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA","type":"image\/jpeg"}],"twitter_card":"summary_large_image","schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"NewsArticle","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#article","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/"},"author":{"name":"","@id":""},"headline":"Make a Community Events Calendar","datePublished":"2022-04-19T08:25:34+00:00","mainEntityOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/"},"wordCount":5,"publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA","keywords":["API","Guest Post","React","Under Review"],"inLanguage":"en-US","copyrightYear":"2022","copyrightHolder":{"@id":"https:\/\/cloudinary.com\/#organization"}},{"@type":"WebPage","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/","url":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/","name":"Make a Community Events Calendar","isPartOf":{"@id":"https:\/\/cloudinary.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#primaryimage"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#primaryimage"},"thumbnailUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA","datePublished":"2022-04-19T08:25:34+00:00","description":"If you've ever been frustrated about missing something going on in your community or city, this might be a way that you solve the problem. We're going to build an events calendar that people can add information to!","breadcrumb":{"@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#primaryimage","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA","width":2992,"height":2000},{"@type":"BreadcrumbList","@id":"https:\/\/cloudinary.com\/blog\/guest_post\/make-a-community-events-calendar\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/cloudinary.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Make a Community Events Calendar"}]},{"@type":"WebSite","@id":"https:\/\/cloudinary.com\/blog\/#website","url":"https:\/\/cloudinary.com\/blog\/","name":"Cloudinary Blog","description":"","publisher":{"@id":"https:\/\/cloudinary.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/cloudinary.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/cloudinary.com\/blog\/#organization","name":"Cloudinary Blog","url":"https:\/\/cloudinary.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","contentUrl":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1649718331\/Web_Assets\/blog\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877\/cloudinary_logo_for_white_bg_1937437aa7_19374666c7_193742f877.png?_i=AA","width":312,"height":60,"caption":"Cloudinary Blog"},"image":{"@id":"https:\/\/cloudinary.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":""}]}},"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cloudinary-marketing\/images\/f_auto,q_auto\/v1681925846\/Web_Assets\/blog\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b\/694bdee9c23c4b67e47229e2acc2728b376db20a-2992x2000-1_27938a700b.jpg?_i=AA","_links":{"self":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27937","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/users\/41"}],"replies":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/comments?post=27937"}],"version-history":[{"count":0,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/posts\/27937\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media\/27938"}],"wp:attachment":[{"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/media?parent=27937"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/categories?post=27937"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/cloudinary.com\/blog\/wp-json\/wp\/v2\/tags?post=27937"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}