Sunday, May 5, 2024
HomeJavaScriptConstruct a Job Board with VueJS and GraphQL

Construct a Job Board with VueJS and GraphQL


Job board functions are sensible for employers to seek out potential candidates for roles inside their group, and for the freelancer or job seeker they could be a nice supply for locating work.

On this tutorial we will likely be constructing a Job Board Utility, which is an Upwork, Certainly or Fiverr clone, and within the course of we’ll discover ways to combine the Webiny CMS right into a Vue.js software utilizing GraphQL.

This job board software will can help you create and handle job vacancies utilizing Webiny CMS on the backend. We will likely be making our personal stylesheet versus utilizing some other CSS expertise, as we’ll primarily be focusing of the code slightly than the styling.

Step 1: Create a Webiny Mission

As beforehand talked about with a view to begin utilizing the Webiny CMS you could be create a brand new app in your native machine, then deploy it to AWS. The documentation discovered on the Webiny web site is properly detailed and can information you thru the set up course of in case you have not already accomplished so.

After you have all of the stipulations for Webiny CMS we will begin to create your new undertaking. Open your terminal and navigate to the folder you wish to retailer your undertaking. Subsequent utilizing the command beneath create your undertaking.

npx create-webiny-project my-webiny-project

As soon as the deployment is finished, you’ll be introduced with a URL the place you may entry your Admin Dashboard as proven beneath:




Screenshot of the admin panel when you create a new project

Step 2: Create Content material Fashions

Now that you’ve got the Webiny CMS put in we’ll begin to create our Content material Fashions that may maintain the information we want to see in our Vue.js Utility.

Utilizing the menu icon navigate to Headless CMS > Fashions, the place we’ll create a brand new Content material Mannequin known as Job. That is at it’s core a knowledge container that may maintain the template for the parameters of what qualifies as a job.

Choose Fashions from the Content material Fashions navigation merchandise as proven beneath:




Untitled

Create your Mannequin as proven within the picture beneath:




image11.png

Fill within the description that can assist you bear in mind what the job mannequin will comprise.

Subsequent, you may drag and drop completely different area varieties into the Edit space to create your structured content material:




Content Model drag & drop UI

We’ll first drag and drop a TEXT area from the left to create our first content material.

We’ll give it a label Job Function and save the sphere. Discover that the Subject IDs will likely be used for accessing through GraphQL later.




field settings

Create these fields – you may rename them in the event you like. Right here is an instance of the all of the fields:




Screenshot of the fields within our content model

  • Job FunctionTextual content
  • Job ContactTextual content (Sample – E-mail)
  • Job LocationTextual content
  • Job Reference URLTextual content (Sample-URL)
  • Job Begin DateDate/Time (Date Solely)

For sure fields I’ve additionally added setting within the validators part. This can guarantee the right values are entered into the backend. We will even examine the validation within the frontend too.




Pattern validator UI

NOTE: In case you have any errors when pushing content material to the backend it could possibly be that you’ve got outlined validations that aren’t being adhered to on the front-end.

After you have saved your mannequin, return to Headless CMS and you will note the brand new mannequin underneath Ungrouped.




Content models in the flyout menu

We’ll create a New Entry and can fill out all of the fields with dummy knowledge as we can take away it from the CMS later. As soon as you’re completely satisfied together with your entry, save and publish it.




Adding an entry into the CMS

Step 3: Creating the Vue.js App

In a separate folder in your native machine, we’ll create the Vue undertaking utilizing Vite.js. Vite is tremendous quick and top-of-the-line instruments for prototyping an software. You should use frameworks like React and Svelte with Vite as properly, nonetheless on this article we will likely be specializing in Vue.js.

npm create vite@newest [PUT YOUR OWN PROJECT NAME HERE]




options selected after running the vite command

After you have chosen your framework and the installer has accomplished, go into the listing and set up the dependencies:

cd [project name]
npm set up

Open the undertaking in your code editor. We’ll first take away all of the boilerplate code within the App.vue file, then change with this code.

<script setup>
import { reactive } from "@vue/reactivity";

/* Array to comprise our job date */
const jobs = reactive([]);

</script>

<template>
{ /* container for the whole web page /* }
<div class="container">
{ /* a div to format all the roles in our database /* }
<div class="jobs">
<h1>JOBS</h1>
<div class="job" v-for="job in jobs" :key="job.jobUrl">
<div class="header">
<h2>{{ job.title }}</h2>
<span class="material-icons"> delete </span>
</div>

<h4>{{ job.jobUrl }}</h4>
<p>
{{ job.desc }}
</p>
<h3>{{ job.location }}</h3>
<h3>{{ job.contact }}</h3>
<h3>{{ job.expires }}</h3>
<span>posted on {{ job.createdOn}}</span>
</div>
</div>
{ /* a div to format our type sidebar /* }
<div class="facet">
</div>
</div>
</template>

{ /* A lot of the kinds are in kinds.css. Listed here are some only for this web page. /* }
<type scoped>
/* These two courses are to format the title and the delete button on a job */
.header {
show: flex;
justify-content: space-between;
}
.header span {
padding: 15px;
font-size: 2em;
cursor: pointer;
}
</type>

Styling the Utility

Within the type.css file in your supply folder, add this CSS on the finish.

.container {
width:100%;
show: grid;
grid-template-columns: 66% 33%;
hole: 10px;
padding: 0px;
colour:#000;
box-sizing: border-box;
text-align: left;

}
.jobs{
padding: 5px;
}
.facet{
min-height: 100vh;
padding-left: 10px;
background-color:#FFE8A3;
}
.job,.jobForm {
show: inline-block;
margin: 5px;
}
textarea{
background-color: #fff;
border-radius: 10px;
border: none;
margin: 5px;
show: block;
colour: #000;
width: 100%;
}
enter {
background-color: #fff;
border-radius: 10px;
border: none;
margin: 5px;
colour: #000;
show: block;
width:300px;
padding: 20px;
peak: 1em;
}
button{
width: 100%;
background-color: orange;
peak: 4rem;
}
.job {
width: 40%;
border-radius: 20px;
colour: #000;
padding-left:10px;
background-color: #fff;
}

/**When the applying is seen on a cellular **/

@media solely display and (max-width: 640px) {
.container {
show: inline-block;
}
.job{
width: 90%;
}
}

Including Google Icons

I’ve additionally added the stylesheet to allow us to have Materials Icons by Google in our software. Within the index.html file add the hyperlink to the Materials Icons stylesheet as proven beneath:

<head>
<meta charset="UTF-8" />
<hyperlink href="https://fonts.googleapis.com/icon?household=Materials+Icons" rel="stylesheet">
<hyperlink rel="icon" kind="picture/svg+xml" href="/vite.svg" />
<meta title="viewport" content material="width=device-width, initial-scale=1.0" />
<title>Job Board Utility</title>
</head>

That is the naked construction of our software, presently we shouldn’t have any knowledge to visualise our software. Let’s repair that however integrating Webiny CMS in order that we will view the entries we created in our Webiny CMS undertaking.

Step 4: Integrating Our Headless CMS

Earlier than we will entry the Headless CMS from Vue we’d like a token and the URL for the API. Right here’s how you can get the URL:

https://www.webiny.com/docs/headless-cms/fundamentals/graphql-api

Alternatively you may open your Webiny undertaking and run this command

# Returns info for the "dev" surroundings.
yarn webiny data --env dev

Subsequent we’ll create a brand new API Key and provides the Headless CMS all of the permissions as we’d like to have the ability to push content material to the backend and never simply learn it.

Choose API Keys from the Settings menu:




API Keys area in the admin panel UI

The Token will likely be displayed right here when you save your permissions:




Where to find token

NOTE: Ensure you save your API token in a protected place

We have to add entry to our Headless CMS in order that we will entry it utilizing GraphQL, change the entry stage to the settings beneath:




Access levels for the Headless CMS

Create an .env file within the root of your Vue undertaking and add your knowledge beneath:

VITE_WEBINY_API=YOUR WEBINY CMS URL HERE
VITE_TOKEN=YOUR WEBINY CMS TOKEN API HERE

IMPORTANT NOTE: This .env file with the uncovered API Key and token is okay when testing regionally in your machine. If you find yourself internet hosting your software someplace it may be accessed on the net, it might be finest to make use of a server-side perform for knowledge fetching as this instance code could be unsafe to make use of.

Including GraphQL Utilizing URQL

We will likely be utilizing URQL to assist us hyperlink the Webiny CMS to our Vue software. Let’s add URQL to our Vue JS software.

The total documentation for URQL may be discovered right here: https://formidable.com/open-source/urql/docs/fundamentals/vue/

In your undertaking folder, open the terminal and run this command:

npm set up --save @urql/vue graphql

Replace your foremost.js file

import { createApp } from 'vue'
import './type.css'
import App from './App.vue'
import urql from '@urql/vue';
const app = createApp(App);
app.use(urql, {
url: import.meta.env.VITE_WEBINY_API,
fetchOptions: () => {
const token = import.meta.env.VITE_TOKEN;
return {
headers: { authorization: token ? `Bearer ${token}` : '' },

};
},
})
app.mount('#app')

GraphQL – View All Jobs

Now we have now come to the part the place we’ll begin utilizing GraphQL. The perfect practices is to check queries on the API itself earlier than placing them into our software.

Webiny gives a superb API Playground the place can check the backend.
Open your browser navigate to your Webiny Admin Dashboard and open the API Playground




API Playground navigation item

Navigate to the Webiny Handle API and enter the values on the left beneath. Run the code to see your outcome.




API Playground area

Right here is the code for the above question:

question {
listJobs {
knowledge {
jobRole
jobContact
jobDescription
jobLocation
jobUrl
createdOn
}
}

Now that we all know the question returns the information we require, let’s add it to our Vue.js software.

As we will likely be utilizing Dates in our software we’ll set up second.js for date styling. Open the terminal and run the command beneath:

npm set up second --save

Open your App.vue file and enter the code beneath which incorporates our second.js import and our GraphQL question utilizing useQuery from URQL:

import { reactive } from "@vue/reactivity";
import second from "second";
import { useQuery } from "@urql/vue";
/* Array to comprise our jobs */
const jobs = reactive([]);
const currentDate = second(Date.now()).format("Do MMMM Y");

/* * This perform will entry the Webiny CMS utilizing GraphQL to return all the roles posted.
*/
const outcome = useQuery({
question: `
{
listJobs {
knowledge {
id
jobRole
jobContact
jobDescription
jobLocation
jobUrl
startDate
createdOn
}
}
}
`,
}).then((outcome) => {

// get the listing of outcome from the CMS
let jobResult = outcome.knowledge.worth.listJobs.knowledge;

// if any knowledge is returned push every outcome into the roles array
jobResult.forEach((factor) => {
jobs.push(factor);
});
});

</script>

<template>
{ /* container for the whole web page /* }
<div class="container">
{ /* a div to format all the roles in our database /* }
<div class="jobs">
<date class="currentDate">{{ currentDate }}</date>
<h1>JOBS</h1>
{ /* for every job in our database show /* }
<div class="job" v-for="job in jobs" :key="job.id">
<div class="header">
<h2>{{ job.jobRole }}</h2>
</div>
<h4>{{ job.jobUrl }}</h4>
<p>
{{ job.jobDescription }}
</p>
<h3><span class="material-icons"> map </span>{{ job.jobLocation }}</h3>
<h3><span class="material-icons"> mail </span>{{ job.jobContact }}</h3>
<h3>Expires: {{ second(job.startDate).format("Do MMMM Y") }}</h3>
<span>posted on {{ second(job.createdOn).format("Do MMMM Y") }}</span>
</div>
</div>
{ /* a div to format our type sidebar /* }
<div class="facet">
</div>
</div>
</template>

As soon as you’ve got added the code, open the terminal and run

npm run dev

In case you have set every little thing us appropriately, you must now be capable of see an inventory of Job entries that you simply created utilizing the Headless CMS within the Admin Dashboard.

Step 5: Managing Jobs

Now that we will see all the roles on our backend, let’s take a look at deleting them. In GraphQL, every time we need to manipulate current knowledge we have to use a mutation.

Within the template part add the brand new button to the div with a category of header. We will even add an onclick occasion for the perform we’ll write for eradicating a single job by taking in it’s ID as a parameter.

<div class="header">
<span>posted on {{ second(job.createdOn).format("Do MMMM Y") }}</span>
<button class="icon" @click on="removeJob(job.id)">
<span class="material-icons"> delete </span>
</button>
</div>

Delete a Job

As with the earlier question we check our mutation first on the backend. Record all the roles and this time we’ll return the ID together with some other knowledge. Copy one of many entries ID’s from one of many outcomes.




Listing all of the existing jobs

Subsequent we’ll write our GraphQL mutation including the ID we copied earlier then we’ll execute the code to see the outcome.

mutation($ID: ID!){
deleteJob(revision:$ID) {
knowledge
}
}

You must be capable of see the outcomes just like the screenshot beneath:




Job has been deleted

The check on the Webiny API Playground was successfull so now we will write our mutation in our Vue.js app. Within the script part of the App.vue file enter the code beneath:

import { useQuery, useMutation } from "@urql/vue"; //

/** DELETING A JOB * */
const deleteJobResult = useMutation(`
mutation($ID: ID!){
deleteJob(revision:$ID)
{
knowledge
}
}
`);

/* Operate we'll name from the span onclick occasion */
/* Has a parameter of ID to get the related job within the backend */
const removeJob = (id) => {
const variables = {
ID: id,
};
deleteJobResult.executeMutation(variables).then((outcome) => {
if (outcome.error) {
console.error("There was an error:", outcome.error);
} else {
location.reload(); // refresh the web page
}
});
};

Congratulations! Now we have efficiently eliminated a job, utilizing it’s id, from Webiny CMS utilizing GraphQL mutation.

Including New Jobs

Now we have seen how we’re in a position to view all of the content material on the backend and even handle a particular factor in our CMS. Nonetheless, it might be good to not must all the time create our knowledge on the backend however as an alternative create a type that permits us to push knowledge into our CMS from our Vue software.

Let’s do that by making a brand new element known as Create.vue within the elements folder. In that file, enter the code beneath:

<script setup>
import { reactive } from "@vue/reactivity";

const newJob = reactive({
title: "",
desc: "",
jobUrl: "",
location: "",
contact: "",
expires: ""
})

/* Reset all of the dynamic fields after submitting the shape */

perform resetFields(newJob) {
newJob.title = "";
newJob.jobUrl = "";
newJob.desc = "";
newJob.location = "";
newJob.contact = "";
newJob.expires = "";
}

</script>
<template>
<div>
<h1>CREATE JOB</h1>
{ /* Type for making a job. This can push entered values into the CMS /* }
<type class="jobForm" @submit.stop="checkFields(newJob)">
<label for="title">Title</label>
<enter kind="textual content" title="title" v-model="newJob.title" />
<label for="desc">Job Description</label>
<textarea title="desc" class="jobDesc" rows="5" v-model="newJob.desc"> </textarea>
<label for="URL">Job Reference URL</label>
<enter kind="url" title="URL" placeholder="https://" sample="https://.*" v-model="newJob.jobUrl" />
<label for="contact">Job Contact E-mail</label>
<enter kind="e mail" title="contact" v-model="newJob.contact" />
<label for="location">Job Location</label>
<enter kind="textual content" title="location" v-model="newJob.location" />
<label for="expiry">Job Begin Date</label>
<enter kind="date" v-model="newJob.expires" title="expiry" />
<button kind="submit" worth="Submit">ADD JOB</button>
</type>
</div>
</template>

NOTE: In the event you study the HTML within the template part you’ll discover that the EMAIL and URL inputs have patterns hooked up to them which corresponds to the validator fields on the Webiny CMS.

Including Jobs to Webiny CMS

Earlier than we create the mutation we have to add a brand new job we’ll as soon as once more do a check on Webiny CMS.

Let’s check the backend by inserting some dummy knowledge and seeing what’s returned. Open API Playground in your Webiny CMS and underneath the Handle API enter some knowledge just like the one beneath:

mutation {
createJob(
knowledge: {
jobRole:"Internet Developer"
jobContact:"joe@joebloggs.com"
jobDescription:"Develop web sites with Webiny CMS"
jobLocation:"Distant"
jobUrl:"http://www.google.com"
startDate:"2022-09-01"
}
)
{
knowledge {
jobRole
jobDescription
jobContact
jobLocation
jobUrl
startDate
createdOn
}
}
}

When you enter that code within the API Playground, you must see the outcome as beneath:




Screenshot of the graphql create job mutation

Now that we now have efficiently created a brand new entry on our CMS we’ll use this code to create our GraphQL mutation.

Let’s convert this utilizing the useMutation perform from URQL in our Vue.js software. We will add the code beneath to the <script> part of our Create.vue file.

import { reactive} from "@vue/reactivity"; // import ref from vue
import { useMutation } from "@urql/vue";
/* Create area for job type - corresponds to the fields we now have in our Webiny CMS */
const newJob = reactive({
title: "",
desc: "",
jobUrl: "",
location: "",
contact: "",
expires: ""
})

/**We'll use variables to gather from the shape fields*/
const createJobResult = useMutation(`
mutation(
$title:String!,
$contact:String!,
$desc:String!,
$location:String!,
$url:String!,$expiry:Date!) {

createJob(
knowledge:{
jobRole:$title
jobContact:$contact
jobDescription:$desc
jobLocation:$location
jobUrl:$url
startDate:$expiry
})
{
knowledge {
jobRole
jobDescription
jobContact
jobLocation
jobUrl
startDate
}
}
}
`);

/* This perform will take all of the enter from the shape and push it into an object.
/* Then it'll push the thing to the roles array and reset all of the enter fields.

const addJob = () => {
const variables = {
title: newJob.title,
contact: newJob.contact,
desc: newJob.desc,
location: newJob.location,
url: newJob.jobUrl,
expiry: new Date(newJob.expires).toISOString().break up("T")[0], // WEBINY CMS accepts a selected format for sending Dates
}
};
createJobResult.executeMutation(variables).then((outcome) => {
if (outcome.error) {
alert(outcome.error.title);
} else {
window.location.reload();
}
});
};

Now that we now have setup our Create.vue let’s import it into App.vue and add it to the sidebar within the template part.

import Create from "./elements/Create.vue";

{ /*} a div to format our type sidebar /* }
<div class="facet">
<Create></Create>
</div>

This could outcome within the type being rendered within the sidebar like so:




Jobs board UI in the browser

You must now see the element on the facet of the display when your run the next command within the terminal:

npm run dev

Fill out all of the fields to confirm that we now have related the applying efficiently. The web page will reload and the brand new entry will seem on the left with all the knowledge you entered.

Conclusion

On this article we now have learnt how you can use the Webiny Headless CMS, how you can arrange up Content material Fashions, how you can create Tokens, Handle Permissions and how you can check GraphQL question and mutations utilizing the API Playground.

Now we have additionally learnt how you can use GraphQL with URQL together with Vue.js to attach our Webiny CMS to our working Job Board software.

Thanks for studying!

Full supply code: https://github.com/webiny/write-with-webiny/tree/foremost/tutorials/job-board-vue-graphql


This text was written by a contributor to the Write with Webiny program. Would you want to jot down a technical article like this and receives a commission to take action? Try the Write with Webiny GitHub repo.



RELATED ARTICLES

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Most Popular

Recent Comments