From bbf2e10ccf2c2471b886e8ab610263554462bc40 Mon Sep 17 00:00:00 2001 From: Vivek <2105vivek@gmail.com> Date: Sat, 3 Jan 2026 18:20:00 +0530 Subject: [PATCH 1/5] fix: sanitize post title to prevent storage collisions --- src/components/CreatePost.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/CreatePost.tsx b/src/components/CreatePost.tsx index f3ffd37e..e02ef10a 100644 --- a/src/components/CreatePost.tsx +++ b/src/components/CreatePost.tsx @@ -32,8 +32,9 @@ const CreatePost = () => { if (!imageFile) { throw new Error("Image file is required"); } - - const filePath = `${post.title}-${Date.now()}-${imageFile.name}`; + + const safeTitle = post.title.replace(/[^a-zA-Z0-9-_]/g, '_'); // replace unsafe chars + const filePath = `${safeTitle}-${Date.now()}-${imageFile.name}`; const {error: imageError} = await supabase.storage .from('post-images') From e6ae138b48482bab90bdb8421661305c64647218 Mon Sep 17 00:00:00 2001 From: Vivek <2105vivek@gmail.com> Date: Sat, 3 Jan 2026 18:20:42 +0530 Subject: [PATCH 2/5] fix: use env-based Supabase URL instead of hardcoded value --- src/supabase-client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/supabase-client.ts b/src/supabase-client.ts index e589cbc9..5dc2d540 100644 --- a/src/supabase-client.ts +++ b/src/supabase-client.ts @@ -1,6 +1,6 @@ import { createClient} from '@supabase/supabase-js' -const supabaseUrl = "https://vrgulaasdvhujkxnaxgr.supabase.co" +const supabaseUrl = import.meta.env.VITE_SUPABASE_URL as string; const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY as string; export const supabase = createClient(supabaseUrl, supabaseAnonKey); \ No newline at end of file From a2d45db0f7840ec5d7957fd431fdb420c46f33c4 Mon Sep 17 00:00:00 2001 From: Vivek <2105vivek@gmail.com> Date: Sat, 3 Jan 2026 18:18:55 +0530 Subject: [PATCH 3/5] fix: set user_id when creating new posts --- src/components/CreatePost.tsx | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/components/CreatePost.tsx b/src/components/CreatePost.tsx index e02ef10a..8431d893 100644 --- a/src/components/CreatePost.tsx +++ b/src/components/CreatePost.tsx @@ -28,7 +28,19 @@ const fetchCommunities = async (): Promise => { const CreatePost = () => { const queryClient = useQueryClient(); - const uploadPost = async (post: PostInput, imageFile: File | null) => { + const uploadPost = async ( + post: PostInput, + imageFile: File | null + ) => { + const { + data: { user }, + error: authError + } = await supabase.auth.getUser(); + + if (authError || !user) { + throw new Error("User not authenticated"); + } + if (!imageFile) { throw new Error("Image file is required"); } @@ -53,7 +65,8 @@ const CreatePost = () => { content: post.content, image_url: publicUrl.publicUrl, avatar_url: post.avatar_url, - community_id: post.community_id + community_id: post.community_id, + user_id: user.id }).select(); if (error) { From 87aa7f76c4a3bad433aba9d11d7663fb6127d45e Mon Sep 17 00:00:00 2001 From: Vivek <2105vivek@gmail.com> Date: Sat, 3 Jan 2026 18:15:55 +0530 Subject: [PATCH 4/5] refactor: standardize table names to lowercase --- README.md | 10 +++++----- src/components/CommentItem.tsx | 2 +- src/components/CommentSection.tsx | 4 ++-- src/components/CommunityDisplay.tsx | 4 ++-- src/components/CommunityList.tsx | 2 +- src/components/CreateCommunity.tsx | 2 +- src/components/CreatePost.tsx | 4 ++-- src/components/LikeButton.tsx | 8 ++++---- src/components/PostDetail.tsx | 2 +- src/components/PostList.tsx | 2 +- 10 files changed, 20 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index aed93a1a..b5e784f3 100644 --- a/README.md +++ b/README.md @@ -143,7 +143,7 @@ VITE_SUPABASE_ANON_KEY=your_supabase_anon_key **Posts Table** ```sql -CREATE TABLE Posts ( +CREATE TABLE posts ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, title TEXT NOT NULL, content TEXT NOT NULL, @@ -159,7 +159,7 @@ CREATE TABLE Posts ( **Comments Table** ```sql -CREATE TABLE Comments ( +CREATE TABLE comments ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, post_id BIGINT NOT NULL REFERENCES Posts(id), content TEXT NOT NULL, @@ -174,7 +174,7 @@ CREATE TABLE Comments ( **Communities Table** ```sql -CREATE TABLE Communities ( +CREATE TABLE communities ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, name TEXT NOT NULL, description TEXT, @@ -185,7 +185,7 @@ CREATE TABLE Communities ( **Votes Table** ```sql -CREATE TABLE Votes ( +CREATE TABLE votes ( id BIGINT PRIMARY KEY GENERATED ALWAYS AS IDENTITY, post_id BIGINT NOT NULL REFERENCES Posts(id), user_id UUID NOT NULL, @@ -386,7 +386,7 @@ const { data, isLoading, error } = useQuery({ queryKey: ['posts'], queryFn: async () => { const { data, error } = await supabase - .from('Posts') + .from('posts') .select('*') .order('created_at', { ascending: false }); diff --git a/src/components/CommentItem.tsx b/src/components/CommentItem.tsx index 2619e904..8084c71c 100644 --- a/src/components/CommentItem.tsx +++ b/src/components/CommentItem.tsx @@ -25,7 +25,7 @@ const createReply = async ( throw new Error("You must be logged in to reply."); } - const { error } = await supabase.from("Comments").insert({ + const { error } = await supabase.from("comments").insert({ post_id: postId, content: replyContent, parent_comment_id: parentCommentId, diff --git a/src/components/CommentSection.tsx b/src/components/CommentSection.tsx index 6e8cc12a..2d418f50 100644 --- a/src/components/CommentSection.tsx +++ b/src/components/CommentSection.tsx @@ -22,7 +22,7 @@ interface CommentSectionProps { const fetchComments = async (postId: number): Promise => { const { data, error } = await supabase - .from('Comments') + .from('comments') .select('*') .eq('post_id', postId) .order('created_at', { ascending: true }); @@ -42,7 +42,7 @@ const createComment = async ( throw new Error('You must be logged in to comment.'); } - const { error } = await supabase.from('Comments').insert({ + const { error } = await supabase.from('comments').insert({ post_id: postId, content: content, user_id: userId, diff --git a/src/components/CommunityDisplay.tsx b/src/components/CommunityDisplay.tsx index 23cfb15c..e6ae623f 100644 --- a/src/components/CommunityDisplay.tsx +++ b/src/components/CommunityDisplay.tsx @@ -17,8 +17,8 @@ export const fetchCommunityPost = async ( communityId: number ): Promise => { const { data, error } = await supabase - .from("Posts") - .select("*, Communities(name)") + .from("posts") + .select("*, communities(name)") .eq("community_id", communityId) .order("created_at", { ascending: false }); diff --git a/src/components/CommunityList.tsx b/src/components/CommunityList.tsx index 95c9a4a1..acb869be 100644 --- a/src/components/CommunityList.tsx +++ b/src/components/CommunityList.tsx @@ -12,7 +12,7 @@ export interface Community { const fetchCommunities = async (): Promise => { const { data, error } = await supabase - .from('Communities') + .from('communities') .select('*') .order('created_at', { ascending: false }); if (error) { diff --git a/src/components/CreateCommunity.tsx b/src/components/CreateCommunity.tsx index 3250a55e..aa9d5da9 100644 --- a/src/components/CreateCommunity.tsx +++ b/src/components/CreateCommunity.tsx @@ -11,7 +11,7 @@ interface CommunityInput { const createCommunity = async (community: CommunityInput) => { const { error, data } = await supabase - .from("Communities") + .from("communities") .insert([community]) .select(); diff --git a/src/components/CreatePost.tsx b/src/components/CreatePost.tsx index 8431d893..14e58a3e 100644 --- a/src/components/CreatePost.tsx +++ b/src/components/CreatePost.tsx @@ -15,7 +15,7 @@ interface PostInput { const fetchCommunities = async (): Promise => { const { data, error } = await supabase - .from('Communities') + .from('communities') .select('*') .order('created_at', { ascending: false }); @@ -60,7 +60,7 @@ const CreatePost = () => { .from('post-images') .getPublicUrl(filePath); - const {data, error} = await supabase.from("Posts").insert({ + const {data, error} = await supabase.from("posts").insert({ title: post.title, content: post.content, image_url: publicUrl.publicUrl, diff --git a/src/components/LikeButton.tsx b/src/components/LikeButton.tsx index 71161393..9cebc343 100644 --- a/src/components/LikeButton.tsx +++ b/src/components/LikeButton.tsx @@ -17,7 +17,7 @@ interface Vote { const like = async (likeValue: number, postId: number, userId: string) => { const { data: existingVote } = await supabase - .from('Votes') + .from('votes') .select("*") .eq("post_id", postId) .eq("user_id", userId) @@ -27,7 +27,7 @@ const like = async (likeValue: number, postId: number, userId: string) => { if (existingVote.vote === likeValue) { // User is unliking the post const { error } = await supabase - .from('Votes') + .from('votes') .delete() .eq("post_id", postId) .eq("user_id", userId); @@ -37,7 +37,7 @@ const like = async (likeValue: number, postId: number, userId: string) => { } } else { const { error } = await supabase - .from('Votes') + .from('votes') .insert({ post_id: postId, user_id: userId, vote: likeValue }); if (error) { @@ -48,7 +48,7 @@ const like = async (likeValue: number, postId: number, userId: string) => { const fetchLikes = async (postId: number): Promise => { const { data, error } = await supabase - .from('Votes') + .from('votes') .select('*') .eq('post_id', postId); if (error) { diff --git a/src/components/PostDetail.tsx b/src/components/PostDetail.tsx index c7218ba8..0ee8069a 100644 --- a/src/components/PostDetail.tsx +++ b/src/components/PostDetail.tsx @@ -21,7 +21,7 @@ interface PostDetailProps { const fetchPost = async (postId: number): Promise => { const { data, error } = await supabase - .from('Posts') + .from('posts') .select('*') .eq('id', postId) .single(); diff --git a/src/components/PostList.tsx b/src/components/PostList.tsx index b9379747..f4ad0667 100644 --- a/src/components/PostList.tsx +++ b/src/components/PostList.tsx @@ -13,7 +13,7 @@ export interface Post { } const fetchPosts = async (): Promise => { - const {data, error} = await supabase.from('Posts').select('*').order('created_at', {ascending: false}); + const {data, error} = await supabase.from('posts').select('*').order('created_at', {ascending: false}); if (error) { throw new Error("Error fetching posts: " + error.message); } From 1c328a1f4de584c8ebcef7222a2ac6fbc513ce06 Mon Sep 17 00:00:00 2001 From: Vivek <2105vivek@gmail.com> Date: Sat, 3 Jan 2026 19:37:55 +0530 Subject: [PATCH 5/5] fix: align router navigation with Vite base path --- src/components/CreatePost.tsx | 5 ++++- src/main.tsx | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/components/CreatePost.tsx b/src/components/CreatePost.tsx index 14e58a3e..83b62873 100644 --- a/src/components/CreatePost.tsx +++ b/src/components/CreatePost.tsx @@ -5,6 +5,7 @@ import { supabase } from '../supabase-client'; import { useAuth } from '../context/AuthContext'; import type { Community } from './CommunityList'; import { Upload, AlertCircle, CheckCircle } from 'lucide-react'; +import { useNavigate } from 'react-router-dom'; interface PostInput { title: string; @@ -26,6 +27,8 @@ const fetchCommunities = async (): Promise => { } const CreatePost = () => { + const navigate = useNavigate(); + const queryClient = useQueryClient(); const uploadPost = async ( @@ -99,7 +102,7 @@ const CreatePost = () => { setCommunityId(null); queryClient.invalidateQueries({queryKey: ['posts']}); setTimeout(() => { - window.location.href = '/'; + navigate('/'); }, 2000); } }) diff --git a/src/main.tsx b/src/main.tsx index 77788642..6bb6b0ab 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -10,7 +10,7 @@ const queryClient = new QueryClient() createRoot(document.getElementById('root')!).render( - +