Building a React employee database page using Airtable and Quarkly

Have you heard about a tool like Airtable, but didn’t know where to start? Then we invite you to the world of visual programming building a database!

With this post, we begin a series of tutorials in which we will give practical examples of working with our Quarkly tool. In this tutorial, we will make a simple web application that will display company employees. When creating the application, not a single Russian Railways employee was hurt.

The front will be done using Quarkly, and the data will be pulled from the database into Airtable. At the output, we get a react application synchronized with the database.

Preamble. Why Airtable

Airtable is a popular no-code tool where you can make your databases large. They look like tables, but they have much more powerful functionality. In particular, for our lesson, Airtable was chosen because of the easy way to transfer data through the API.

If this is your first time hearing about Airtable, it will not be superfluous to read before starting. official guide on the company’s website. We also advise you not to be shy and ask questions in the chat. Airtable Chat & Community in telegrams.

The front-end part of the work will be done in Quarkly, and for this we will use only two components:

  • Employee card… It will contain a photo, text data and two buttons: send an email and call. The card will receive this data from the parent component – the wrapper.
  • Wrapper… It will receive data from Airtable, generate cards and transfer data to them.

For those who do not have time to delve into the post in print format, we have prepared a video with subtitles and timecodes:

Part 1. Making visuals in Quarkly

Card creation:

  1. Let’s create a new project in Quarkly, let’s name it Airtable Example;
  2. Let’s go inside the project;
  3. Let’s add a ready-made block with employee cards. To do this, click on the black + button in the middle and select a block from the category Team;

  4. Select the first card on the layers panel (StackItem) and transform it into a component;

    To do this, click on the “three dots” and select the item Convert to Component… Let’s call this component EmployeeCard

  5. Now we can freely edit the code of this react component, but for now we will not do this and move on to creating the wrapper component.

Creating a wrapper:

  1. Let’s prepare the wrapper for transformation into a component. To do this, first remove the remaining three cards, we do not need them;

  2. Now let’s pull out EmployeeCard of Stack… Then we transform Stack into the component as we did earlier with EmployeeCard: right panel, ellipsis button and Convert to Component… The component is called EmployeeTable

    That’s all for now, the preparatory stage is over. Let’s leave the components and go to the base in Airtable.

Part 2. Create a database in Airtable

Go to the site Airtable and register / log in.

  1. Click on the button Add a baseto create a new base. From the drop-down menu, select Start with a template;

  2. Choosing a category HR & Recruiting and template Employee directory… Next, click on the button Use template;

  3. Go to the created project;

At this stage, we will not change anything here; in its current form, the database is already fine with us.

Part 3. Getting access to the API

Initially, Airtable is interesting to us precisely because of its convenient API. At the same time, which is important, Airtable provides the ability to take data and send it to our database free of charge.

  1. Go to the page for selecting API projects: https://airtable.com/api

  2. Choosing our project Employee directory… In the documentation that appears, go to the section AUTHENTICATION

  3. Copy the two lines below the heading EXAMPLE USING BEARER TOKEN (RECOMMENDED)

    They look like this to me:

    $ curl https://api.airtable.com/v0/app2MdLITmRTBsrkg/Employee%20directory
    -H "Authorization: Bearer YOUR_API_KEY"

  4. Now we need YOUR_API_KEY… This is a unique access key that is generated for each account. You can find it in the settings.

  5. On the page that opens, go to the API section and click on the button Generate API key;

  6. Copy the key. Save it next to the lines from step 3. They will be useful to us later.

Part 4. Integrating the Airtable database into Quarkly

At this stage, we will add to the component EmployeeTable code that will fetch data from the API.

  1. Let’s go to editing the component code. To do this, open the tab Components and click on the <> button EmployeeTable (it will appear when you hover over the component);

  2. Now the component code looks like this:

  3. Let’s replace:
    import React from "react";

    on:

    import React, { useEffect, useState } from "react";

    This will import the useEffect and useState hooks to help us further;

  4. Below we add a line to import our component EmployeeCard:
    import EmployeeCard from "./EmployeeCard";
  5. Replace children (we don’t need them yet) on override (useful for selecting elements and styling them on the page):
    const EmployeeTable = props => {
    	const {
    		children,
    		rest
    	} = useOverrides(props, overrides, defaultProps);

    on:

    const EmployeeTable = props => {
    	const {
    		override,
    		rest
    	} = useOverrides(props, overrides, defaultProps);
  6. Below we add a hook call useStatewhich will keep track of the state:
    const [employees, setEmployees] = useState([]);
  7. Next, add a hook useEffect, which will make requests to the Airtable API and put the received data into our state through a function setEmployees

    We add here the lines that we copied earlier. IN fetch we add the url to our base by adding a parameter ? view = All% 20employees… IN headers we add authorization parameters and the API key itself, which we generated in part 3 of this article, subparagraph 4.

    useEffect(() => {
    			fetch("https://api.airtable.com/v0/appWw7KBKSc9bPjZE/Employee%20directory?view=All%20employees", {
    				headers: {
    					'Authorization': 'Bearer YOUR_API_KEY'
    				}
    			})
    			.then(response => response.json())
    			.then(data => setEmployees(data.records.map(({ fields }) => fields)));
    	}, []);
  8. Now we will generate cards from the received data, passing them props with data and override… It is needed to select and style elements on the page.

    We change:

    return <Stack {...rest}>
    		{children}
    	</Stack>;
    };

    on:

    return <Stack {...rest}>
    		{
    			employees.map(employee => <EmployeeCard  {...override("employeeCard")}  employee={employee} />)
    		}
    	</Stack>;
    };
  9. Press Ctrl + S (or Cmd + S on Mac). The final code looks like this:
    import React, { useEffect, useState } from "react";
    import { useOverrides, Stack } from "@quarkly/components";
    import EmployeeCard from "./EmployeeCard";
    const defaultProps = {
    	"margin-top": "40px"
    };
    const overrides = {};
    
    const EmployeeTable = props => {
    	const {
    		override,
    		rest
    	} = useOverrides(props, overrides, defaultProps);
    
    	const [employees, setEmployees] = useState([]);
    
    	useEffect(() => {
    			fetch("https://api.airtable.com/v0/appWw7KBKSc9bPjZE/Employee%20directory?view=All%20employees", {
    				headers: {
    					'Authorization': 'Bearer YOUR_API_KEY'
    				}
    			})
    			.then(response => response.json())
    			.then(data => setEmployees(data.records.map(({ fields }) => fields)));
    	}, []);
    	
    	return <Stack {...rest}>
    		{
    			employees.map(employee => <EmployeeCard  {...override("employeeCard")} employee={employee} />)
    		}
    	</Stack>;
    };
    
    Object.assign(EmployeeTable, {
    	...Stack,
    	defaultProps,
    	overrides
    });
    export default EmployeeTable;

    Important: don’t forget to insert your unique API key instead of text YOUR_API_KEY

Done! Now we get data from Airtable, put it in employees and go through it using the method map… For each entry in employees we create , into which we pass specific data as a props.

It remains to teach EmpolyeeCard take this data and display it in the right place.

Part 5. Teaching EmpolyeeCard to work with a database

Here we will teach the employee card to accept data and display it.

  1. Let’s open the component code. To do this, go to the tab Componentslooking there EmployeeCard, point the cursor and click on the <> button.
  2. Now the component code looks like this:
    import React from "react";
    import { useOverrides, Override, StackItem } from "@quarkly/components";
    import { Box, Text } from "@quarkly/widgets";
    const defaultProps = {
    	"width": "25%",
    	"lg-width": "50%",
    	"sm-width": "100%"
    };
    const overrides = {
    	"box": {
    		"kind": "Box",
    		"props": {
    			"height": "0",
    			"margin": "0 0 20px 0",
    			"padding-bottom": "100%",
    			"background": "url(https://images.unsplash.com/photo-1503443207922-dff7d543fd0e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=582&q=80) 50% 0/cover no-repeat"
    		}
    	},
    	"text": {
    		"kind": "Text",
    		"props": {
    			"color": "--grey",
    			"margin": "0",
    			"children": "CEO"
    		}
    	},
    	"text1": {
    		"kind": "Text",
    		"props": {
    			"as": "h3",
    			"font": "--headline3",
    			"margin": "5px 0 20px 0",
    			"children": "Nathan K. Joe"
    		}
    	},
    	"text2": {
    		"kind": "Text",
    		"props": {
    			"as": "p",
    			"margin": "20px 0 5px 0",
    			"children": "This space is 100% editable. Use it to introduce a team member, describe their work experience and role within the company. This is also a great place to highlight a team member's strong sides."
    		}
    	}
    };
    
    const EmployeeCard = props => {
    	const {
    		override,
    		children,
    		rest
    	} = useOverrides(props, overrides, defaultProps);
    	return <StackItem {...rest}>
    		<Override slot="StackItemContent" flex-direction="column" />
    		<Box {...override("box")} />
    		<Text {...override("text")} />
    		<Text {...override("text1")} />
    		<Text {...override("text2")} />
    		{children}
    	</StackItem>;
    };
    
    Object.assign(EmployeeCard, { ...StackItem,
    	defaultProps,
    	overrides
    });
    export default EmployeeCard;
  3. We are looking for the line:
    } = useOverrides(props, overrides, defaultProps);

    and add below:

    const { employee = {} } = rest;

    Into object employee we put our data.

  4. Using the example of a photo of an employee, we will check that everything works as it should. We look for a line and change:
    <Box {...override("box")} />

    on:

    <Box {...override("box")} background-image={`url(${employee.Photo && employee.Photo[0] && employee.Photo[0].url})`}/>

    We are also looking for:

    "background": "url(https://images.unsplash.com/photo-1503443207922-dff7d543fd0e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=582&q=80) 50% 0/cover no-repeat"

    and change to:

    "background-size": "cover",
    "background-position": "center",
    "background-image": "url(https://images.unsplash.com/photo-1503443207922-dff7d543fd0e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=582&q=80) 50% 0/cover no-repeat"

    It should look like this:

  5. Let’s see what fields we have. The documentation for the API in Airtable is very well done. The name of the fields can be found in https://airtable.com/apiby choosing your base.

    Next, we are looking for the section EMPLOYEE DIRECTORY TABLE

    So we have:

    Name
    Department
    Home address
    Email address
    DOB
    Start date
    Phone
    Reports to
    Title
    Status
    Photo
    Location

  6. Let’s add Title. To do this, replace:
    <Text {...override("text")} />

    on:

    <Text {...override("title")} children={employee.Title} />

    And let’s not forget to edit overrides of this component so that we can select and edit it on the page.

    We change:

    "text": {
    	"kind": "Text",
    	"props": {
    		"color": "--grey",
    		"margin": "0",
    		"children": "CEO"
    	}
    },

    on:

    "title": {
    	"kind": "Text",
    	"props": {
    		"color": "--grey",
    		"margin": "0",
    		"children": "Title"
    	}
    },

    We save and check:

    Result: A line with a profession has been added to cards.

  7. Let’s repeat the same steps for Name and Home address

    Let’s replace:

    <Text {...override("text1")} />
    <Text {...override("text2")} />

    on:

    <Text {...override("name")} children={employee.Name} />
    <Text {...override("address")} children={employee['Home address']} />

    And fix them overrides… To do this, replace:

    "text1": {
    	"kind": "Text",
    	"props": {
    		"as": "h3",
    		"font": "--headline3",
    		"margin": "5px 0 20px 0",
    		"children": "Nathan K. Joe"
    	}
    },
    "text2": {
    	"kind": "Text",
    	"props": {
    		"as": "p",
    		"margin": "20px 0 5px 0",
    		"children": "This space is 100% editable. Use it to introduce a team member, describe their work experience and role within the company. This is also a great place to highlight a team member's strong sides."
    	}
    }

    on:

    "name": {
    	"kind": "Text",
    	"props": {
    		"as": "h3",
    		"font": "--headline3",
    		"margin": "5px 0 5px 0",
    		"children": "Name"
    	}
    },
    "address": {
    	"kind": "Text",
    	"props": {
    		"as": "p",
    		"margin": "10px 0 5px 0",
    		"children": "Home address"
    	}
    },

    Save and check again:

  8. Let’s add a few more Text Similarly. For simplicity, we will not take Department and Reports tobecause this data is in a different database DEPARTMENTS TABLE

    Add:

    <Text {...override("address")} children={employee['Home address']} />
    <Text {...override("Start date")} children={`Start date: ${employee['Start date']}`} />
    <Text {...override("Status")} children={employee['Status']} />
    <Text {...override("DOB")} children={`Birth date: ${employee['DOB']}`} />

    and

    "address": {
    	"kind": "Text",
    	"props": {
    		"as": "p",
    		"margin": "10px 0 5px 0",
    		"children": "Home address"
    	}
    },
    "Start date": {
    	"kind": "Text",
    	"props": {
    		"as": "p",
    		"margin": "10px 0 5px 0",
    		"children": "Start date"
    	
    	}
    },
    "Status": {
    	"kind": "Text",
    	"props": {
    		"as": "p",
    		"margin": "10px 0 5px 0",
    		"children": "Status"
    	}
    },
    "DOB": {
    	"kind": "Text",
    	"props": {
    		"as": "p",
    		"margin": "10px 0 5px 0",
    		"children": "Birth date"
    	}
    },

    Checking the result:

  9. Now let’s add two components Linkin which we will have Phone and Email:
    import { Box, Text } from "@quarkly/widgets";

    change to:

    import { Box, Text, Link } from "@quarkly/widgets";

    And add the following lines:

    <Link {...override("Email address")} children={employee['Email address']} href={`mailto:${employee['Email address']}`} />
    <Link {...override("Phone")} children={employee['Phone']} href={`tel:${employee['Phone']}`}/>

    Not forgetting about them overrides:

    "Email address": {
    	"kind": "Link",
    	"props": {
    		"margin": "10px 0 5px 0",
    		"color": "--primary",
    		"text-decoration": "none",
    		"children": "Email"
    	}
    },
    "Phone": {
    	"kind": "Link",
    	"props": {
    		"margin": "10px 0 5px 0",
    		"color": "--primary",
    		"text-decoration": "none",
    		"children": "Phone"
    	}
    },

    Checking the result:

Our final code looks like this:

import React from "react";
import { useOverrides, Override, StackItem } from "@quarkly/components";
import { Box, Text, Link } from "@quarkly/widgets";
const defaultProps = {
	"width": "25%",
	"lg-width": "50%",
	"sm-width": "100%"
};
const overrides = {
	"box": {
		"kind": "Box",
		"props": {
			"height": "0",
			"margin": "0 0 20px 0",
			"padding-bottom": "100%",
			"background-size": "cover",
			"background-position": "center",
			"background-image": "url(https://images.unsplash.com/photo-1503443207922-dff7d543fd0e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=582&q=80) 50% 0/cover no-repeat"
		}
	},
	"title": {
		"kind": "Text",
		"props": {
			"color": "--grey",
			"margin": "0",
			"children": "title"
		}
	},
	"name": {
		"kind": "Text",
		"props": {
			"as": "h3",
			"font": "--headline3",
			"margin": "5px 0 5px 0",
			"children": "Name"
		}
	},
	"address": {
		"kind": "Text",
		"props": {
			"as": "p",
			"margin": "10px 0 5px 0",
			"children": "Home address"
		}
	},
	"Start date": {
		"kind": "Text",
		"props": {
			"as": "p",
			"margin": "10px 0 5px 0",
			"children": "Start date"
		}
	},
	"Status": {
		"kind": "Text",
		"props": {
			"as": "p",
			"margin": "10px 0 5px 0",
			"children": "Status"
		}
	},
	"DOB": {
		"kind": "Text",
		"props": {
			"as": "p",
			"margin": "10px 0 5px 0",
			"children": "Birth date"
		}
	},
	"Email address": {
		"kind": "Link",
		"props": {
			"margin": "10px 0 5px 0",
			"color": "--primary",
			"text-decoration": "none",
			"children": "Email"
		}
	},
	"Phone": {
		"kind": "Link",
		"props": {
			"margin": "10px 0 5px 0",
			"color": "--primary",
			"text-decoration": "none",
			"children": "Phone"
		}
	},
};

const EmployeeCard = props => {
	const {
		override,
		children,
		rest
	} = useOverrides(props, overrides, defaultProps);
	
		const { employee = {} } = rest;

	
	return <StackItem {...rest}>
		<Override slot="StackItemContent" flex-direction="column" />
		<Box {...override("box")} background-image={`url(${employee.Photo[0].url})`}/>
		<Text {...override("title")} children={employee.Title} />
		<Text {...override("name")} children={employee.Name} />
		<Text {...override("address")} children={employee['Home address']} />
		<Text {...override("Start date")} children={`Start date: ${employee['Start date']}`} />
		<Text {...override("Status")} children={employee['Status']} />
		<Text {...override("DOB")} children={`Birth date: ${employee['DOB']}`} />
		<Link {...override("Email address")} children={employee['Email address']} href={`mailto:${employee['Email address']}`} />
		<Link {...override("Phone")} children={employee['Phone']} href={`tel:${employee['Phone']}`}/>
		{children}
	</StackItem>;
};

Object.assign(EmployeeCard, { ...StackItem,
	defaultProps,
	overrides
});
export default EmployeeCard;

We commit to GitHub and publish to Netlify:

We wait a few minutes and check: https://keen-varahamihira-c54ae1.netlify.app/

To check synchronization, change the data in the database:

They will now appear in the application:

In the future, we can style our elements with cards as we like, without breaking the configured import from Airtable. An example can be viewed here

GitHub repository: https://github.com/quarkly-dev/Getting-data-from-Airtable-tutorial

Thank you for attention!

If you have any questions, do not hesitate to ask them in the comments. In the next lesson, we will consider another example of working with data, we will show how to interactively visualize it, allowing the user to change filters right in the application.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *