Building a Custom Scheduler Using React and Supabase
Introduction
Scheduling is one of the critical features of modern applications. It can enable us to run periodic task that can be automated. Task such as such as sending reminders, scheduling posts, updating data, or automating workflows.
So, In this article, we are going to build a scheduler to post articles on dev.to. Although, dev.to has scheduling features but we are going to implement them in our way, which can be used to build any kind of scheduler application.
So, let’s get started.
Tech Stack
We are going to use the following tech stack:
- React: We are going to use React, particularly ViteJS with React to build the fronted.
-
Supabase: It provides an all-in-one solution for building applications. It provides a database, auth, storage, edge function, and many more. We are going to use the following from Supbase:
- Database: This is used to store the article information and schedule time.
- Cron Job: For running periodically to call the Edge function
- Edge Function: This will check if any article has the current time as the scheduled time. If then it will post the article.
That will be enough to build a scheduler application with ease.
Working on the Application
Let’s discuss how the application works, which makes it quite easy to understand the flow of the application. Here is the flow one by one:
- Adding articles to the database through the front end.
- The Cron job will run every minute to call the edge function.
- An edge function will be executed to check the current time as scheduled article. If there is an article it will post the article.
- Article data in the post table will be updated. # Building the Frontend
The building frontend has become quiet lately with a lot of generative AI. One of the such AI we are going to use is bolt.new. Why bolt.new? It can generate complete React applications with dependencies and all the configurations such as tailwindcss. You can directly edit articles using StackBlitz and also deploy the application. If you require you can download the code to run locally. The bonus point is that it integrate with Supabase quite well so you can generate a working React application with the Supbase integration.
I have used it to generate the front. Here are all the pages.
App.tsx
This will handle the page for displaying components and providing the landing page.
function App() { const [posts, setPosts] = useState<ScheduledPost[]>([]); const handleSchedulePost = async (data: CreatePostData) => { // In a real app, this would make an API call to your edge function const newPost: ScheduledPost = { content: data.content, scheduled_time: data.scheduledTime, status: 'pending', title: data.title, tags: data.tags }; const { error } = await supabase .from('scheduled_posts') .insert(newPost) if (error){ alert(`Erorr: ${error}`) return } // setPosts((prev) => [...prev, newPost]); }; const fetchScheduedPost = async () => { const { data, error } = await supabase .from('scheduled_posts') .select() if(error){ alert(`Erorr Fetching Data: ${error}`) return } setPosts(data) } useEffect(() => { fetchScheduedPost() },[]) return ( <div className="min-h-screen bg-gray-50"> <header className="bg-white shadow-sm"> <div className="max-w-4xl mx-auto px-4 py-4"> <div className="flex items-center gap-2"> <Newspaper className="h-8 w-8 text-blue-500" /> <h1 className="text-xl font-bold text-gray-900">Dev.to Post Scheduler</h1> </div> </div> </header> <main className="max-w-4xl mx-auto px-4 py-8"> <div className="grid gap-8 md:grid-cols-2"> <div> <h2 className="text-xl font-semibold text-gray-800 mb-4">Schedule New Post</h2> <PostForm onSubmit={handleSchedulePost} /> </div> <div> <ScheduledPosts posts={posts} /> </div> </div> </main> </div> ); } export default App;
SchudledPost.tsx
This displays the scheduled articles.
const StatusIcon = ({ status }: { status: ScheduledPost['status'] }) => { switch (status) { case 'posted': return <CheckCircle className="h-5 w-5 text-green-500" />; case 'failed': return <XCircle className="h-5 w-5 text-red-500" />; default: return <Clock3 className="h-5 w-5 text-yellow-500" />; } }; export function ScheduledPosts({ posts }: ScheduledPostsProps) { return ( <div className="space-y-4"> <h2 className="text-xl font-semibold text-gray-800">Scheduled Posts</h2> {posts.length === 0 ? ( <p className="text-gray-500 text-center py-8">No scheduled posts yet</p> ) : ( <div className="space-y-4"> {posts.map((post, index) => ( <div key={index} className="bg-white p-4 rounded-lg shadow-md border border-gray-100" > <div className="flex items-start justify-between"> <div className="flex-1"> <p className="text-gray-800 mb-2">{post.title}</p> <div className="flex items-center gap-4 text-sm text-gray-500"> <div className="flex items-center gap-1"> <Calendar className="h-4 w-4" /> {new Date(post.scheduled_time).toLocaleDateString()} </div> <div className="flex items-center gap-1"> <Clock className="h-4 w-4" /> {new Date(post.scheduled_time).toLocaleTimeString()} </div> </div> </div> <StatusIcon status={post.status} /> </div> </div> ))} </div> )} </div> ); }
PostForm.tsx
This will handle the form where the user can give information about the article.
function App() { const [posts, setPosts] = useState<ScheduledPost[]>([]); const handleSchedulePost = async (data: CreatePostData) => { // In a real app, this would make an API call to your edge function const newPost: ScheduledPost = { content: data.content, scheduled_time: data.scheduledTime, status: 'pending', title: data.title, tags: data.tags }; const { error } = await supabase .from('scheduled_posts') .insert(newPost) if (error){ alert(`Erorr: ${error}`) return } // setPosts((prev) => [...prev, newPost]); }; const fetchScheduedPost = async () => { const { data, error } = await supabase .from('scheduled_posts') .select() if(error){ alert(`Erorr Fetching Data: ${error}`) return } setPosts(data) } useEffect(() => { fetchScheduedPost() },[]) return ( <div className="min-h-screen bg-gray-50"> <header className="bg-white shadow-sm"> <div className="max-w-4xl mx-auto px-4 py-4"> <div className="flex items-center gap-2"> <Newspaper className="h-8 w-8 text-blue-500" /> <h1 className="text-xl font-bold text-gray-900">Dev.to Post Scheduler</h1> </div> </div> </header> <main className="max-w-4xl mx-auto px-4 py-8"> <div className="grid gap-8 md:grid-cols-2"> <div> <h2 className="text-xl font-semibold text-gray-800 mb-4">Schedule New Post</h2> <PostForm onSubmit={handleSchedulePost} /> </div> <div> <ScheduledPosts posts={posts} /> </div> </div> </main> </div> ); } export default App;
Edge Function
Edge Functions are server-side TypeScript functions, distributed globally at the edge—close to your users. They can be used for listening to webhooks or integrating your Supabase project with third parties like Stripe. Edge Functions are developed using Deno.
For running and deploying the edge function locally you need to have the following:
- Supbase CLI: You can install CLI locally using this guide. It is simple just using the npm and npx.
- Docker Desktop: Install the docker desktop from here.
So, after installing this, you can use your frontend code directory or other to create the Supabase Edge Function.
Run the below command to initiate a supabase project:
const StatusIcon = ({ status }: { status: ScheduledPost['status'] }) => { switch (status) { case 'posted': return <CheckCircle className="h-5 w-5 text-green-500" />; case 'failed': return <XCircle className="h-5 w-5 text-red-500" />; default: return <Clock3 className="h-5 w-5 text-yellow-500" />; } }; export function ScheduledPosts({ posts }: ScheduledPostsProps) { return ( <div className="space-y-4"> <h2 className="text-xl font-semibold text-gray-800">Scheduled Posts</h2> {posts.length === 0 ? ( <p className="text-gray-500 text-center py-8">No scheduled posts yet</p> ) : ( <div className="space-y-4"> {posts.map((post, index) => ( <div key={index} className="bg-white p-4 rounded-lg shadow-md border border-gray-100" > <div className="flex items-start justify-between"> <div className="flex-1"> <p className="text-gray-800 mb-2">{post.title}</p> <div className="flex items-center gap-4 text-sm text-gray-500"> <div className="flex items-center gap-1"> <Calendar className="h-4 w-4" /> {new Date(post.scheduled_time).toLocaleDateString()} </div> <div className="flex items-center gap-1"> <Clock className="h-4 w-4" /> {new Date(post.scheduled_time).toLocaleTimeString()} </div> </div> </div> <StatusIcon status={post.status} /> </div> </div> ))} </div> )} </div> ); }
The below command can be used to create the Edge function
export function PostForm({ onSubmit }: PostFormProps) { const [content, setContent] = useState(''); const [title, setTitle] = useState(''); const [tags, setTags] = useState<string[]>(['javascript', 'react']); const [scheduledTime, setScheduledTime] = useState(''); const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); onSubmit({ content, title, scheduledTime, tags }); setContent(''); setTitle(''); setScheduledTime(''); setTags([]); }; const handleTagChange = (e: React.ChangeEvent<HTMLSelectElement>) => { const selectedOptions = Array.from(e.target.selectedOptions); const selectedTags = selectedOptions.map(option => option.value); if(tags.length<4){ setTags(prevTags => { const newTags = selectedTags.filter(tag => !prevTags.includes(tag)); return [...prevTags, ...newTags]; }); } }; const removeTag = (tagToRemove: string) => { setTags(tags.filter(tag => tag !== tagToRemove)); }; return ( <form onSubmit={handleSubmit} className="space-y-4 bg-white p-6 rounded-lg shadow-md"> <div> <label htmlFor="title" className="block text-sm font-medium text-gray-700 mb-2"> Post Title </label> <input type="text" > <p>I will provide the whole code as a GitHub repository at the end. </p> <p>Now, let’s look at Supbase Integration.</p> <h2> Supabase </h2> <p>First create an account on supabase, if you don’t have one. You can look at this article to get information about the creating an account on Supbase, Using ChatGPT with Your Own Data using LangChain and Supabase.</p> <p>Create the table scheduled_post. You can use the below SQL code to run in the SQL Editor to create the table or you can create the table with Table Editor.<br> </p> <pre class="brush:php;toolbar:false"> create table public.scheduled_posts ( id serial not null, content text not null, scheduled_time timestamp with time zone not null, status text null default 'pending'::text, created_at timestamp without time zone null default now(), title character varying null, devto_article_id character varying null, posted_at character varying null, tags character varying[] null, error_message character varying null, constraint scheduled_posts_pkey primary key (id) ) tablespace pg_default; create index if not exists idx_scheduled_time_status on public.scheduled_posts using btree (scheduled_time, status) tablespace pg_default;
The above command will create a directory functions/xscheduler inside the supabase. There you can find the index.ts. Edge function uses Deno environment.
The below code is for the edge function:
npx supabase init
For the ENV such as SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY are automatically available to you. For DEVTO_ACCESS_TOKEN, you can generate it from here, and go to Project Setting → Edge Functions to add the token. This token will be available in the Deno environment.
You can use this guide for deploying the edge function, which is needed.
Cron Job
Supbase recently updated the Cron job functionality. Now you can use the dashboard to create the corn job previously you had to write code for that. You can create a job that can run the following:
- SQL Snippet
- Database Function
- HTTP Request
- Supbase Edge Function
We are going to use the Edge Function, You can add the details of the Edge function such as name and Authorization with the Anon key as a Bearer Token.
Working of the Application
Now, that we have created the application let’s look at the working now. Run the fronted with the below command:
supabase functions new xscheduler
Add the details such as Title, Content, Time, and Tags. Once added click on the Schedule Post. The cron job will run every minute once the article’s scheduled time matches the current time. It will be posted.
The article will be posted on the dev.to when the time range matches.
Additional Features
Using the above technique you can build a scheduler application for anything such as X, Instagram, LinkedIn, etc. You can work on it and add functionality such as the following:
- Image: Use the supabase storage to upload and fetch images for thumbnails.
- Edge function invoke from SQL: You can make it even more efficient by calling the edge function from an SQL snippet or Database function. This is so that only when the article matches the current time is the edge function invoked.
You can look into the code of this project on GitHub here.
Conclusion
Creating a scheduler application simplifies automating tasks like posting articles, sending reminders, and managing workflows. Using React for the frontend and Supabase for the backend, we built a scalable solution that leverages databases, cron jobs, and edge functions. This approach can be adapted for various use cases, enabling efficient automation. With these tools, you’re equipped to build powerful scheduler applications tailored to your needs.
I hope this article has provided you with an understanding of the cron job. Thanks for reading the article.
The above is the detailed content of Building a Custom Scheduler Using React and Supabase. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics

Frequently Asked Questions and Solutions for Front-end Thermal Paper Ticket Printing In Front-end Development, Ticket Printing is a common requirement. However, many developers are implementing...

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

There is no absolute salary for Python and JavaScript developers, depending on skills and industry needs. 1. Python may be paid more in data science and machine learning. 2. JavaScript has great demand in front-end and full-stack development, and its salary is also considerable. 3. Influencing factors include experience, geographical location, company size and specific skills.

Learning JavaScript is not difficult, but it is challenging. 1) Understand basic concepts such as variables, data types, functions, etc. 2) Master asynchronous programming and implement it through event loops. 3) Use DOM operations and Promise to handle asynchronous requests. 4) Avoid common mistakes and use debugging techniques. 5) Optimize performance and follow best practices.

Discussion on the realization of parallax scrolling and element animation effects in this article will explore how to achieve similar to Shiseido official website (https://www.shiseido.co.jp/sb/wonderland/)...

How to merge array elements with the same ID into one object in JavaScript? When processing data, we often encounter the need to have the same ID...

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

In-depth discussion of the root causes of the difference in console.log output. This article will analyze the differences in the output results of console.log function in a piece of code and explain the reasons behind it. �...
