A responsive task management application built using Next.js and Supabase. This app allows users to efficiently create, organize, and track their tasks. It features user authentication via Supabase with Google Sign-In, drag-and-drop functionality, task categorization, due dates, and more.
-
User Authentication:
- Sign in with Google using Supabase Authentication.
- Manage user profiles.
-
Task Management:
- Create, edit, and delete tasks.
- Categorize tasks (e.g., Work, Personal).
- Set due dates for tasks.
- Drag-and-drop functionality to rearrange tasks.
- Sort tasks by due dates (ascending/descending).
-
Batch Actions:
- Delete multiple tasks at once.
- Mark multiple tasks as complete.
-
Task History and Activity Log:
- Track changes made to tasks (creation, edits, deletions).
- Display an activity log for each task.
-
File Attachments:
- Attach files or documents to tasks.
- File upload feature in the task creation/editing form.
-
Filter Options:
- Filter tasks by tags, category, and date range.
- Search tasks by title.
-
Board/List View:
- Switch between a Kanban-style board view and a list view.
-
Responsive Design:
- Fully responsive design for mobile, tablet, and desktop.
- Frontend: Next.js, TypeScript, Tailwind CSS
- Backend: Supabase (Authentication, Database, Storage)
- State Management: Tanstack Query
- Drag-and-Drop:
@dnd-kit
Before running the project, ensure you have the following:
- Node.js installed (v16 or higher).
- Yarn installed.
- A Supabase project set up.
- A Google OAuth Client ID for authentication.
- Go to Supabase and create a new project.
- After creating the project, navigate to the Project Settings > API section.
- Copy the Project URL and anon/public key. These will be used to connect your app to Supabase.
-
Go to the Google Cloud Console.
-
Create a new project or select an existing one.
-
Navigate to APIs & Services > Credentials.
-
Click Create Credentials and select OAuth Client ID.
-
Set the Authorized Redirect URIs to:
-
Copy the Client ID and Client Secret.
- Go to your Supabase project dashboard.
- Navigate to Authentication > Providers.
- Enable Google and paste the Client ID and Client Secret from Google Cloud Console.
- Save the changes.
Create a .env.local
file in the root of your project and add the following variables:
NEXT_PUBLIC_SUPABASE_URL=your_supabase_project_url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your_supabase_anon_key
yarn install
yarn dev
The app will be running at: http://localhost:3000
task-management-app/
├── components/ # Reusable components
├── hooks/ # Custom hooks
├── lib/ # Utility functions
├── pages/ # Next.js pages
├── styles/ # Global styles
├── types/ # TypeScript types
├── .env.local # Environment variables
├── next.config.js # Next.js configuration
├── package.json # Project dependencies
├── README.md # Project documentation
└── tsconfig.json # TypeScript configuration
create table profiles (
id uuid references auth.users on delete cascade not null primary key,
updated_at timestamp with time zone,
username text unique,
full_name text,
avatar_url text,
website text,
constraint username_length check (char_length(username) >= 3)
);
-- Enable Row Level Security (RLS)
alter table profiles enable row level security;
-- Policies
create policy "Public profiles are viewable by everyone." on profiles
for select using (true);
create policy "Users can insert their own profile." on profiles
for insert with check ((select auth.uid()) = id);
create policy "Users can update own profile." on profiles
for update using ((select auth.uid()) = id);
-- Trigger to create a profile when a new user signs up
create function public.handle_new_user()
returns trigger
set search_path = ''
as $$
begin
insert into public.profiles (id, full_name, avatar_url)
values (new.id, new.raw_user_meta_data->>'full_name', new.raw_user_meta_data->>'avatar_url');
return new;
end;
$$ language plpgsql security definer;
create trigger on_auth_user_created
after insert on auth.users
for each row execute procedure public.handle_new_user();
create table tasks (
id uuid default gen_random_uuid() primary key,
user_id uuid references auth.users on delete cascade not null,
title text not null,
description text,
category text check (category in ('Work', 'Personal')) not null,
due_date date not null,
status text check (status in ('To Do', 'In Progress', 'Completed')) not null,
position integer not null default 0,
created_at timestamp with time zone default now(),
updated_at timestamp with time zone default now()
);
-- Enable RLS and policies
alter table tasks enable row level security;
create policy "Users can view their own tasks." on tasks
for select using (auth.uid() = user_id);
create policy "Users can insert their own tasks." on tasks
for insert with check (auth.uid() = user_id);
create policy "Users can update their own tasks." on tasks
for update using (auth.uid() = user_id);
create policy "Users can delete their own tasks." on tasks
for delete using (auth.uid() = user_id);
-- Indexes for sorting
create index on tasks (due_date);
create index on tasks (status, position);
-- Trigger to update `updated_at` timestamp
create function public.handle_task_update()
returns trigger
set search_path = ''
as $$
begin
new.updated_at = now();
return new;
end;
$$ language plpgsql security definer;
create trigger on_task_updated
before update on tasks
for each row execute procedure public.handle_task_update();
create table task_tags (
id uuid default gen_random_uuid() primary key,
task_id uuid references tasks on delete cascade not null,
tag text not null
);
-- Index for faster tag queries
create index on task_tags (task_id);
create table task_attachments (
id uuid default gen_random_uuid() primary key,
task_id uuid references tasks on delete cascade not null,
file_url text not null,
uploaded_at timestamp with time zone default now()
);
-- Set up Storage for task attachments
insert into storage.buckets (id, name)
values ('task_attachments', 'task_attachments');
-- Policies for task attachments
create policy "Users can upload task attachments." on storage.objects
for insert with check (bucket_id = 'task_attachments');
create policy "Users can view their own task attachments." on storage.objects
for select using (bucket_id = 'task_attachments');``
create table activity_logs (
id uuid default gen_random_uuid() primary key,
task_id uuid references tasks on delete cascade not null,
user_id uuid references auth.users on delete cascade not null,
action text check (action in ('Created', 'Updated', 'Deleted')) not null,
description text not null,
created_at timestamp with time zone default now()
);
-- Enable RLS and policies
alter table activity_logs enable row level security;
create policy "Users can view their own activity logs." on activity_logs
for select using (auth.uid() = user_id);
create policy "Users can insert activity logs for their own tasks." on activity_logs
for insert with check (auth.uid() = user_id);
create function public.log_task_activity()
returns trigger
language plpgsql
as $$
declare
action_text text;
description_text text;
begin
if (tg_op = 'INSERT') then
action_text := 'Created';
description_text := 'Task "' || new.title || '" was created.';
elsif (tg_op = 'UPDATE') then
action_text := 'Updated';
description_text := 'Task "' || new.title || '" was updated.';
end if;
insert into activity_logs (task_id, user_id, action, description)
values (coalesce(new.id, old.id), coalesce(new.user_id, old.user_id), action_text, description_text);
return new;
end;
$$ security definer;
create trigger on_task_change
after insert or update on tasks
for each row
execute function public.log_task_activity();
Setting up Google OAuth with Supabase required careful configuration of redirect URIs and client IDs.
Solution: Followed Supabase and Google Cloud documentation to ensure proper setup.
Implementing drag-and-drop for tasks was challenging due to state management and reordering logic.
Solution: Used @dnd-kit
library, which provided a robust and flexible API for drag-and-drop.
Ensuring the app worked seamlessly across devices required careful use of Tailwind CSS and media queries.
Solution: Adopted a mobile-first approach and tested on multiple screen sizes.
The app is deployed on Netlify. You can access the live version here:
Live Demo
Contributions are welcome! Please follow these steps:
- Fork the repository.
- Create a new branch:
git checkout -b feature/your-feature
- Commit your changes:
git commit -m 'Add some feature'
- Push to the branch:
git push origin feature/your-feature
- Open a pull request.
This project is licensed under the MIT License. See the LICENSE file for details.
Check out the source code on GitHub:
Task Buddy GitHub Repository