Close Menu
Soshace Digital Blog

    Subscribe to Updates

    Get The Latest News, Updates, And Amazing Offers

    What's Hot
    Programming

    Programming Patterns. Strategy, Observer, Iterator

    Programming

    18. Уроки Node.js. Работа с Файлами, Модуль fs

    Beginners

    Bootstrap: TOP 5 Free Bootstrap Editors & Tools

    Important Pages:
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Today's Picks:
    • Scaling Success: Monitoring Indexation of Programmatic SEO Content
    • Leveraging Influencers: Key Drivers in New Product Launches
    • How Privacy-First Marketing Will Transform the Industry Landscape
    • The Impact of Social Proof on Thought Leadership Marketing
    • Balancing Value-Driven Content and Promotional Messaging Strategies
    • Top Influencer Marketing Platforms to Explore in 2025
    • Emerging Trends in Marketing Automation and AI Tools for 2023
    • Strategies to Mitigate Duplicate Content in Programmatic SEO
    Wednesday, September 10
    Facebook X (Twitter) Instagram LinkedIn YouTube
    Soshace Digital Blog
    • Home
    • About
    • Services
    • Contact Us
    • Privacy Policy
    • Terms & Conditions
    Services
    • SaaS & Tech

      Maximizing Efficiency: How SaaS Lowers IT Infrastructure Costs

      August 27, 2025

      Navigating Tomorrow: Innovations Shaping the Future of SaaS

      August 27, 2025

      Maximizing Impact: Strategies for SaaS & Technology Marketing

      August 27, 2025
    • AI & Automation

      Enhancing Customer Feedback Analysis Through AI Innovations

      August 27, 2025

      Navigating the Impact of AI on SEO and Search Rankings

      August 27, 2025

      5 Automation Hacks Every Home Service Business Needs to Know

      May 3, 2025
    • Finance & Fintech

      Critical Missteps in Finance Marketing: What to Avoid

      August 27, 2025

      Analyzing Future Fintech Marketing Trends: Insights Ahead

      August 27, 2025

      Navigating the Complex Landscape of Finance and Fintech Marketing

      August 27, 2025
    • Legal & Compliance

      Exploring Thought Leadership’s Impact on Legal Marketing

      August 27, 2025

      Maximizing LinkedIn: Strategies for Legal and Compliance Marketing

      August 27, 2025

      Why Transparency Matters in Legal Advertising Practices

      August 27, 2025
    • Medical Marketing

      Enhancing Online Reputation Management in Hospitals: A Guide

      August 27, 2025

      Analyzing Emerging Trends in Health and Medical Marketing

      August 27, 2025

      Exploring Innovative Content Ideas for Wellness Blogs and Clinics

      August 27, 2025
    • E-commerce & Retail

      Strategic Seasonal Campaign Concepts for Online and Retail Markets

      August 27, 2025

      Emerging Trends in E-commerce and Retail Marketing Strategies

      August 27, 2025

      Maximizing Revenue: The Advantages of Affiliate Marketing for E-Commerce

      August 27, 2025
    • Influencer & Community

      Leveraging Influencers: Key Drivers in New Product Launches

      August 27, 2025

      Top Influencer Marketing Platforms to Explore in 2025

      August 27, 2025

      Key Strategies for Successful Influencer Partnership Negotiations

      August 27, 2025
    • Content & Leadership

      The Impact of Social Proof on Thought Leadership Marketing

      August 27, 2025

      Balancing Value-Driven Content and Promotional Messaging Strategies

      August 27, 2025

      Analyzing Storytelling’s Impact on Content Marketing Effectiveness

      August 27, 2025
    • SEO & Analytics

      Scaling Success: Monitoring Indexation of Programmatic SEO Content

      August 27, 2025

      Strategies to Mitigate Duplicate Content in Programmatic SEO

      August 27, 2025

      Effective Data Visualization Techniques for SEO Reporting

      August 27, 2025
    • Marketing Trends

      How Privacy-First Marketing Will Transform the Industry Landscape

      August 27, 2025

      Emerging Trends in Marketing Automation and AI Tools for 2023

      August 27, 2025

      Maximizing ROI: Key Trends in Paid Social Advertising

      August 27, 2025
    Soshace Digital Blog
    Blog / JavaScript / React / Working with Jotai as your next state management in React
    JavaScript

    Working with Jotai as your next state management in React

    peterBy peterMay 26, 2023Updated:May 26, 2023No Comments12 Mins Read
    Facebook Twitter Pinterest Telegram LinkedIn Tumblr Email Reddit
    Working with Jotai as your next state management in React
    Share
    Facebook Twitter LinkedIn Pinterest Email Copy Link

    Working with Jotai as your next state management in React

    Working with Jotai as your next state management in React

    Introduction

    Data is critical to the operation of a React application, so it is necessary to maintain track of it as well as pass it properly through components in a React application. Prop drilling allows data to be passed from a parent component to a child component and has thus been widely utilized in the development of React apps. However, as the complexity of a React application grows and there are several child components from a parent component, data flow becomes cumbersome and less scalable. This issue prompted the introduction of state management into building applications. Despite being efficient and scalable, most common state management needed additional boilerplate code on setup. As a developer who is continually looking for efficient and user-friendly options, I came across Jotai, a minimalistic state management tool that can be used in constructing scalable react applications. In this tutorial, I will walk you through the Jotai library as well as teach you how to utilize Jotai to build a simple application.

    Jotai

    Jotai is a state management library that follows the “atomic” state pattern introduced by the Recoil Library. In Jotai, data is stored an independent state known as an atom which is merely an object that holds values. Jotai uses atoms to replace the local state variables in React components. This object is then supplied to Jotai’s useAtom() hook, allowing your components to consume and update the value it currently stores.

    // import atoms and useAtom from jotai library
    import { atom, useAtom } from "jotai";
    
    const age = atom(10);
    
    
    // obtain getter and setter methods from atom using useAtom() hook
    const [readOnlyAge, setAge] = useAtom(ageAtom);
    
    
    // read value of an atom
    console.log(readOnlyAge) // 10
    
    
    // update the value of an atom
    setAge(20)
    console.log(readOnlyAge) // 20
    
    
    
    

    Building an Application Using Jotai

    In this article, we will illustrate the power of Jotai by utilizing it to build a simple task application. This application simply creates, updates, and deletes tasks. With this application, we will showcase how to create atoms as global states and update atoms.

    Installation

    first and foremost, create a react application using Vite. Navigate to your terminal and type the following commands:

    for yarn

    yarn create vite

    for npm

    npm create vite@latest
    A screenshot showing the process of installing our application
    A screenshot showing the process of installing our application

    After installation, open the application using your code editor of choice, then run the commands shown on the terminal after installation.

    Create Global atom for the Application

    Before creating an atom, we will wrap the application with Jotai’s provider component. The provider components work like a regular context provider which aids in passing down values through the application’s component tree. This ensures that the atoms are accessible throughout the application. In order to use the provider, we will import the provider from Jotai into the entry file(main. tsx) of our application as shown below:

    // main.tsx
    import { Provider } from 'jotai';

    next, I will then wrap the application with the provider as shown below:

    // main.tsx
    import React from 'react'
    import ReactDOM from 'react-dom/client'
    import App from './App'
    import './index.css'
    // Jotai provider
    import { Provider } from 'jotai';
    
    ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
      <React.StrictMode>
        <Provider>
          <App />
        </Provider>
      </React.StrictMode>,
    )
    

    After adding the provider, we will create a centralized atom that will hold the task data of the application. create a store folder on the src directory of the application. and add a file called taskStore.ts to that folder. add the code below to the file.

    import { atom } from "jotai";
    
    export interface singleTask {
        id: string;
        title: string;
        description: string;
        completed: boolean;
    }
    
    export interface TaskAtomInterface {
        tasks: singleTask[]
    }
    
    const taskAtom = atom<TaskAtomInterface>({
        tasks: JSON.parse(localStorage.getItem('j-tasks') as string) || []
    })
    
    export default taskAtom

    The code above simply shows a taskAtom created which comprises an object with a tasks property. the tasks property will hold the task data of the entire application. we also added interfaces that specify the properties that would be contained in a single task.

    List Tasks

    We will create a component that lista all tasks. To do this create a file called AllTasks.tsx in the Task folder under the components folder under the src directory of the project. In doing this, add the code below to the file.

    import React from "react";
    import FloatingButton from "../FloatingButton";
    import { useAtom } from "jotai";
    import taskAtom from "../../store/taskStore";
    import { Link } from "react-router-dom";
    
    const AllTasks = () => {
      const [tasks, setTasks] = useAtom(taskAtom)
      
      return (
        <div className="App">
          <div className="-my-2">
            {tasks.tasks
              .map((curr, idx) => {
                return (
                  <div className="py-2" key={curr.id}>
                    <div className="card md:mx-auto px-0 md:px-0 w-full md:w-9/12">
                      <div className="py-2">
                        <div className="flex items-center justify-between px-2 py-4">
                          <div>
                            <h5 className="w-full break-word">
                              { curr.title }
                            </h5>
                          </div>
    
                          <div className="flex justify-between">
                            <button className="inline-block px-2 py-4 text-[#D60000] border-radius">
                              Delete
                            </button>
                            <Link
                              to={"/edit/" + curr.id}
                              className="inline-block px-2 py-4 text-[#515151] border-radius"
                            >
                              Edit
                            </Link>
                            <Link
                              to={"/view/" + curr.id}
                              className="inline-block px-2 py-4 text-[#0e9f64] border-radius"
                            >
                              View
                            </Link>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                );
              })}
    
            {
              tasks.tasks && tasks.tasks.length === 0 ? (
                <div className="mx-auto md:w-9/12">
                  <h1 className="card flex items-center justify-center h-screen">
                    No Tasks Added
                  </h1>
                </div>
              ):(
                null
              )
            }
          </div>
          <FloatingButton />
        </div>
      );
    };
    
    export default AllTasks;
    

    From the code above:

    • we import the global taskAtom from the taskStore.ts file and supply it to the useAtom() hook in order to obtain the tasks value and a setter function that can update the value of the tasks.
    • On getting the value of the tasks, we display them on the component by mapping through the tasks in the array. In our case, we haven’t included a task so the tasks will be an empty array and will only display a “No Tasks Added” text.
    Read More:  Create simple POS with React.js, Node.js, and MongoDB #17: Stat screen
    An image of the All Tasks component which shows a list of tasks
    An image of the All Tasks component which shows a list of tasks

    We also included a floating button which when clicked, will route the user to a page that creates a task.

    Create Task

    We will create a component that allows a user to create a task. To do this create a file called createTask.tsx in the Task folder under the components folder under the src directory of the project. In doing this, add the code below to the file.

    import { useAtom } from "jotai";
    import React, { useState } from "react";
    import taskAtom, { singleTask } from "../../store/taskStore";
    import { useNavigate } from "react-router-dom";
    import { v4 as uuidv4 } from 'uuid';
    
    const CreateTask = () => {
      const navigate = useNavigate();
      const [tasks, setTasks] = useAtom(taskAtom)
      const [task, setSingleTask] = useState<singleTask>({
        id: uuidv4(),
        title: '',
        description: '',
        completed: false
      })
    
      const onChange = (type: any, value: any)=> {
        switch(type){
          case "title":
            setSingleTask({...task, title: value})
            break;
          case "description":
            setSingleTask({...task, description: value})
            break;
          default:
            break
        }
      }
      
      const submitTask = ()=> {
        let allTasks: singleTask[] = tasks.tasks || [];
        allTasks = [...allTasks, task];
        setTasks({ ...tasks, tasks: allTasks});
        localStorage.setItem('j-tasks', JSON.stringify(allTasks));
        navigate('/')
      };
    
      return (
        <div>
          <div className="md:mx-auto px-6 md:px-0 mt-10 md:w-9/12">
            <h1 className="my-4 text-center">Create Task</h1>
    
            <form onSubmit={submitTask}>
              <div className="mt-8">
                <label className="text-white mb-2"> Title </label>
                <input 
                  type="text" 
                  className="edge-input" 
                  placeholder="" required 
                  onChange={(e)=> onChange("title", e.target.value)}
                />
              </div>
    
              <div className="mt-8">
                <label className="text-white mb-2">
                  {" "}
                  Add your Task description{" "}
                </label>
                <textarea
                  className="edge-input"
                  required
                  onChange={(e)=> onChange("description", e.target.value)}
                ></textarea>
              </div>
    
              <div className="flex justify-end mt-8">
                <button
                  type="submit"
                  className="px-4 py-4 bg-[#0e9f64] c-white border-radius"
                >
                  Create Task
                </button>
              </div>
            </form>
          </div>
        </div>
      );
    };
    
    export default CreateTask;
    

    In the code above:

    • We imported our global taskAtom to the CreateTask component and supplied it to the useAtom() hook.
    • we created an onChange function that handles the addition of values to the form in the component.
    • We created a submitTask function which is invoked on the submission of a task. this function also appends the tasks and updates the global tasksAtom with the newly inserted task. It also persists the tasks to localStorage and routes the user back to the page that shows all tasks.
    An image of the process of creating a task
    An image of the process of creating a task

    Edit Task

    We will create a component that allows a user to edit an existing task. To do this create a file called editTask.tsx in the Task folder under the components folder under the src directory of the project. In doing this, add the code below to the file.

    import { useAtom } from "jotai";
    import React, { useEffect, useState } from "react";
    import taskAtom, { singleTask } from "../../store/taskStore";
    import { useNavigate, useParams } from "react-router-dom";
    
    const EditTask = () => {
      const navigate = useNavigate();
      const [tasks, setTasks] = useAtom(taskAtom)
      const [task, setSingleTask] = useState<singleTask>({
        id: '',
        title: '',
        description: '',
        completed: false
      })
      const { id } = useParams();
    
    
      const onChange = (type: any, value: any)=> {
        switch(type){
          case "title":
            setSingleTask({...task, title: value})
            break;
          case "description":
            setSingleTask({...task, description: value})
            break;
          default:
            break
        }
      }
      
      const editTask = ()=> {
        let tasks: any[] = JSON.parse(localStorage.getItem('j-tasks') as string) || [];
        const taskIndex = tasks.findIndex((curr)=> curr?.id === id);
        taskIndex > -1 && (tasks[taskIndex] = task);
        setTasks({...tasks, tasks})
        localStorage.setItem('j-tasks', JSON.stringify(tasks));
        navigate('/')
      };
    
      useEffect(() => {
        const task = tasks.tasks.find((curr)=> curr?.id === id);
        task && setSingleTask(task);
      }, [id, tasks.tasks])
      
    
      return (
        <div>
          <div className="md:mx-auto px-6 md:px-0 mt-10 md:w-9/12">
            <h1 className="my-4 text-center">Edit Task</h1>
    
            <form className="" onSubmit={editTask}>
              <div className="mt-8">
                <label className="text-white mb-2"> Title </label>
                <input 
                  type="text" 
                  className="edge-input" 
                  placeholder="" 
                  value={task.title}
                  required 
                  onChange={(e)=> onChange("title", e.target.value)}
                />
              </div>
    
              <div className="mt-8">
                <label className="text-white mb-2">
                  Add your note description
                </label>
                <textarea
                  className="edge-input"
                  data-provide="markdown"
                  required
                  value={task.description}
                  onChange={(e)=> onChange("description", e.target.value)}
                ></textarea>
              </div>
    
              <div className="flex justify-end mt-8">
                <button
                  type="submit"
                  className="px-4 py-4 bg-[#0e9f64] c-white border-radius"
                >
                  Edit Task
                </button>
              </div>
            </form>
          </div>
        </div>
      );
    };
    
    export default EditTask;
    

    In the code above:

    • We imported our global taskAtom to the EditTask component and supplied it to the useAtom() hook.
    • On the useEffect hook, we find the specific task to edit using its id which was passed through the route.
    • We created an onChange function that handles the addition of values to the form in the component.
    • We created an editTask function which is invoked on the editing of a task. this function also appends the tasks and updates the global tasksAtom with the new edited task. It also persists the tasks to localStorage and routes the user back to the page that shows all tasks.                                     
    An image of the process of editing a task
    An image of the process of editing a task

    View Task

    We will create a component that allows a user to view a task. To do this create a file called viewTask.tsx in the Task folder under the components folder under the src directory of the project. after creating the file, add the code below to the file.

    import { useAtom } from "jotai";
    import React, { useEffect, useState } from "react";
    import taskAtom, { singleTask } from "../../store/taskStore";
    import { useParams } from "react-router-dom";
    
    const ViewTask = () => {
      const [tasks, setTasks] = useAtom(taskAtom)
      const [task, setSingleTask] = useState<singleTask>({
        id: '',
        title: '',
        description: '',
        completed: false
      })
      const { id } = useParams();
    
      useEffect(() => {
        const task = tasks.tasks.find((curr)=> curr?.id === id);
        task && setSingleTask(task);
      }, [id, tasks.tasks])
    
      return (
        <div>
          <div className="md:mx-auto px-6 md:px-0 mt-10 md:w-9/12">
            <h1 className="my-4 text-center">View Task</h1>
    
            <form className="">
              <div className="mt-8">
                <label className="text-white mb-2"> Title </label>
                <input 
                  type="text" 
                  className="edge-input" 
                  placeholder="" 
                  value={task.title}
                />
              </div>
    
              <div className="mt-8">
                <label className="text-white mb-2">
                  Add your note description
                </label>
                <textarea
                  className="edge-input"
                  data-provide="markdown"
                  required
                  value={task.description}
                ></textarea>
              </div>
            </form>
          </div>
        </div>
      );
    };
    
    export default ViewTask;
    

    In the code above:

    • We imported our global taskAtom to the ViewTask component and supplied it to the useAtom() hook.
    • On the useEffect hook, we find the specific task we want to view using its id which was passed through the route.
    Read More:  Fames Acturpis Egestas Sed Tempus Etpharetra Pharetra
    An image of the process of viewing a task
    An image of the process of viewing a task

    Delete Task

    We will implement the deletion of a task. This will be done on the AllTasks.tsx component which renders all tasks. update the file with the code below:

    import React from "react";
    import FloatingButton from "../FloatingButton";
    import { useAtom } from "jotai";
    import taskAtom from "../../store/taskStore";
    import { Link } from "react-router-dom";
    
    const AllTasks = () => {
      const [tasks, setTasks] = useAtom(taskAtom)
    
      const deleteTask = (id: string)=> {
        try {
          const newTasks = tasks.tasks.filter((curr)=> curr.id !== id);
          setTasks({ ...tasks, tasks: newTasks});
          localStorage.setItem('j-tasks', JSON.stringify(newTasks));
          alert('task deleted');
        }catch(err: any) {
          alert(`unable to delete task ${err}`);
        };
      }
      
      return (
        <div className="App">
          <div className="-my-2">
            {tasks.tasks
              .map((curr, idx) => {
                return (
                  <div className="py-2" key={curr.id}>
                    <div className="card md:mx-auto px-0 md:px-0 w-full md:w-9/12">
                      <div className="py-2">
                        <div className="flex items-center justify-between px-2 py-4">
                          <div>
                            <h5 className="w-full break-word">
                              { curr.title }
                            </h5>
                          </div>
    
                          <div className="flex justify-between">
                            <button onClick={()=> deleteTask(curr.id)} className="inline-block px-2 py-4 text-[#D60000] border-radius">
                              Delete
                            </button>
                            <Link
                              to={"/edit/" + curr.id}
                              className="inline-block px-2 py-4 text-[#515151] border-radius"
                            >
                              Edit
                            </Link>
                            <Link
                              to={"/view/" + curr.id}
                              className="inline-block px-2 py-4 text-[#0e9f64] border-radius"
                            >
                              View
                            </Link>
                          </div>
                        </div>
                      </div>
                    </div>
                  </div>
                );
              })}
    
            {
              tasks.tasks && tasks.tasks.length === 0 ? (
                <div className="mx-auto md:w-9/12">
                  <h1 className="card flex items-center justify-center h-screen">
                    No Tasks Added
                  </h1>
                </div>
              ):(
                null
              )
            }
          </div>
          <FloatingButton />
        </div>
      );
    };
    
    export default AllTasks;
    

    In the code above, we created a deleteTask function that deletes a task using its id. the function also appends the tasks and updates the global tasksAtom with the task. It also persists the updated tasks to localStorage.

                                       

    An image of the process of deleting a task
    An image of the process of deleting a task

    Sample code Repository

    • https://github.com/Gitarackur/task-app-jotai

    Reference Links

    • https://jotai.org/
    • https://github.com/pmndrs/jotai
    • https://egghead.io/lessons/react-derive-state-from-a-jotai-atom-in-react

    Conclusion

    In this tutorial, We learned how Jotai as a state management system works as well as illustrated how to build a simple task application with Jotai. Seeing the capabilities of Jotai shown in this article will encourage you to adopt Jotai as a state management solution for building your React application.

    Share. Facebook Twitter Pinterest LinkedIn Tumblr Email
    peter

      Related Posts

      Streamlining Resource Allocation for Enhanced Project Success

      December 18, 2024

      Conducting Effective Post-Project Evaluations: A Guide

      December 16, 2024

      Strategies for Keeping Projects on Track and Meeting Deadlines

      December 10, 2024
      Leave A Reply Cancel Reply

      You must be logged in to post a comment.

      Stay In Touch
      • Facebook
      • Twitter
      • Pinterest
      • Instagram
      • YouTube
      • Vimeo
      Don't Miss
      Python April 28, 2020

      Adding backend to CodePen snippet using Python/Django | Question-Answering Application

      A few days ago, I used a simple UI “search-box” design to create a Question-Answering Application. Even this kind of small designs can be turned into an application.

      Automated Postgresql Backups with NodeJS and Bash

      November 20, 2020

      Progressive Web Applications and Service Workers

      December 17, 2019

      Technical Writing: Practical & Theoretical Advice

      November 8, 2019

      Categories

      • AI & Automation
      • Angular
      • ASP.NET
      • AWS
      • B2B Leads
      • Beginners
      • Blogs
      • Business Growth
      • Case Studies
      • Comics
      • Consultation
      • Content & Leadership
      • CSS
      • Development
      • Django
      • E-commerce & Retail
      • Entrepreneurs
      • Entrepreneurship
      • Events
      • Express.js
      • Facebook Ads
      • Finance & Fintech
      • Flask
      • Flutter
      • Franchising
      • Funnel Strategy
      • Git
      • GraphQL
      • Home Services Marketing
      • Influencer & Community
      • Interview
      • Java
      • Java Spring
      • JavaScript
      • Job
      • Laravel
      • Lead Generation
      • Legal & Compliance
      • LinkedIn
      • Machine Learning
      • Marketing Trends
      • Medical Marketing
      • MSP Lead Generation
      • MSP Marketing
      • NestJS
      • Next.js
      • Node.js
      • Node.js Lessons
      • Paid Advertising
      • PHP
      • Podcasts
      • POS Tutorial
      • Programming
      • Programming
      • Python
      • React
      • React Lessons
      • React Native
      • React Native Lessons
      • Recruitment
      • Remote Job
      • SaaS & Tech
      • SEO & Analytics
      • Soshace
      • Startups
      • Swarm Intelligence
      • Tips
      • Trends
      • Vue
      • Wiki
      • WordPress
      Top Posts

      How to build complex layouts with CSS Grid

      CSS August 28, 2020

      Build Real-World React Native App #9 : Implementing Remove Ads Feature

      JavaScript January 19, 2021

      Transforming Software Development: The Strategic Impact of Microservices

      Development December 7, 2024

      Effective Strategies for Managing Project Dependencies

      JavaScript November 24, 2024

      Subscribe to Updates

      Get The Latest News, Updates, And Amazing Offers

      About Us
      About Us

      Soshace Digital delivers comprehensive web design and development solutions tailored to your business objectives. Your website will be meticulously designed and developed by our team of seasoned professionals, who combine creative expertise with technical excellence to transform your vision into a high-impact, user-centric digital experience that elevates your brand and drives measurable results.

      7901 4th St N, Suite 28690
      Saint Petersburg, FL 33702-4305
      Phone: 1(877)SOSHACE

      Facebook X (Twitter) Instagram Pinterest YouTube LinkedIn
      Our Picks
      Interview

      Conducting a Better Technical Interview: Problems and Solutions

      Beginners

      Three Essential Rules for Architecting iOS Unit Tests in 2020

      JavaScript

      Create simple POS with React, Node and MongoDB #2: Auth state, Logout, Update Profile

      Most Popular

      Programming Patterns. Introduction

      Programming

      Interview With Oleg – Soshace Team

      Interview

      The Impact of Integrated Development Environments on Coding

      Programming
      © 2025 Soshace Digital.
      • Home
      • About
      • Services
      • Contact Us
      • Privacy Policy
      • Terms & Conditions

      Type above and press Enter to search. Press Esc to cancel.