Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions components/SupabaseConnectionTest.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
'use client'

import { useEffect, useState } from 'react'
import { supabase } from '@/lib/supabase/client'
import { supabase, isSupabaseConfigured } from '@/lib/supabase/client'

export function SupabaseConnectionTest() {
const [connectionStatus, setConnectionStatus] = useState<'testing' | 'connected' | 'error'>('testing')
const [error, setError] = useState<string | null>(null)

useEffect(() => {
const testConnection = async () => {
if (!isSupabaseConfigured) {
setConnectionStatus('error')
setError('Supabase not configured')
return
}

try {
console.log('🔗 Testing Supabase connection...')

// Test basic connection
const { data, error } = await supabase
.from('profiles')
Expand Down
15 changes: 10 additions & 5 deletions contexts/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import { createContext, useContext, useEffect, useState, ReactNode } from 'react'
import { authService } from '@/lib/auth/auth.service'
import { isSupabaseConfigured } from '@/lib/supabase/client'
import { AuthContextType, AuthUser, SignInCredentials, SignUpCredentials, UserProfile } from '@/lib/auth/auth.types'

const AuthContext = createContext<AuthContextType | undefined>(undefined)
Expand All @@ -19,11 +20,15 @@ export function AuthProvider({ children }: AuthProviderProps) {
// Check for existing session on mount
checkUser()

// Listen for auth state changes
const { data: { subscription } } = authService.onAuthStateChange((authUser) => {
setUser(authUser)
setLoading(false)
})
// Listen for auth state changes when configured
let subscription: any
if (isSupabaseConfigured) {
const { data } = authService.onAuthStateChange((authUser) => {
setUser(authUser)
setLoading(false)
})
subscription = data?.subscription
}

return () => {
subscription?.unsubscribe()
Expand Down
37 changes: 31 additions & 6 deletions lib/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { supabase } from '@/lib/supabase/client'
import { supabase, isSupabaseConfigured } from '@/lib/supabase/client'
import { AuthUser, UserProfile, SignInCredentials, SignUpCredentials } from './auth.types'
import { AuthError, User } from '@supabase/supabase-js'

Expand All @@ -7,11 +7,15 @@ class AuthService {
* Transform Supabase user to our AuthUser type
*/
private async transformUser(user: User): Promise<AuthUser> {
const { data: profile } = await supabase
.from('profiles')
.select('*')
.eq('id', user.id)
.single()
let profile: any = null
if (isSupabaseConfigured) {
const { data } = await supabase
.from('profiles')
.select('*')
.eq('id', user.id)
.single()
profile = data
}

return {
id: user.id,
Expand All @@ -33,6 +37,9 @@ class AuthService {
* Get current user session
*/
async getCurrentUser(): Promise<AuthUser | null> {
if (!isSupabaseConfigured) {
return null
}
try {
const { data: { user }, error } = await supabase.auth.getUser()

Expand All @@ -51,6 +58,9 @@ class AuthService {
* Sign in with email and password
*/
async signIn(credentials: SignInCredentials): Promise<AuthUser> {
if (!isSupabaseConfigured) {
throw new Error('Supabase not configured')
}
try {
const { data, error } = await supabase.auth.signInWithPassword({
email: credentials.email,
Expand All @@ -76,6 +86,9 @@ class AuthService {
* Sign up with email and password
*/
async signUp(credentials: SignUpCredentials): Promise<AuthUser> {
if (!isSupabaseConfigured) {
throw new Error('Supabase not configured')
}
try {
const { data, error } = await supabase.auth.signUp({
email: credentials.email,
Expand Down Expand Up @@ -106,6 +119,9 @@ class AuthService {
* Sign out current user
*/
async signOut(): Promise<void> {
if (!isSupabaseConfigured) {
throw new Error('Supabase not configured')
}
try {
const { error } = await supabase.auth.signOut()

Expand All @@ -122,6 +138,9 @@ class AuthService {
* Reset password
*/
async resetPassword(email: string): Promise<void> {
if (!isSupabaseConfigured) {
throw new Error('Supabase not configured')
}
try {
const { error } = await supabase.auth.resetPasswordForEmail(email, {
redirectTo: `${window.location.origin}/auth/reset-password`
Expand All @@ -140,6 +159,9 @@ class AuthService {
* Update user profile
*/
async updateProfile(userId: string, updates: Partial<UserProfile>): Promise<UserProfile> {
if (!isSupabaseConfigured) {
throw new Error('Supabase not configured')
}
try {
const { data, error } = await supabase
.from('profiles')
Expand Down Expand Up @@ -199,6 +221,9 @@ class AuthService {
* Listen to auth state changes
*/
onAuthStateChange(callback: (user: AuthUser | null) => void) {
if (!isSupabaseConfigured) {
return { data: null }
}
return supabase.auth.onAuthStateChange(async (event, session) => {
if (session?.user) {
const authUser = await this.transformUser(session.user)
Expand Down
21 changes: 20 additions & 1 deletion lib/services/blog.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { supabase } from '@/lib/supabase/client'
import { supabase, isSupabaseConfigured } from '@/lib/supabase/client'
import {
BlogPost,
BlogCategory,
Expand Down Expand Up @@ -81,6 +81,10 @@ export class BlogService {

// Get posts with filtering and pagination
async getPosts(params: BlogSearchParams = {}): Promise<BlogPaginatedResponse> {
if (!isSupabaseConfigured) {

Copilot AI Jul 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of repeated if (!isSupabaseConfigured) boilerplate across service methods. Consider extracting this pattern into a higher-order function or wrapper to reduce duplication and improve readability.

Copilot uses AI. Check for mistakes.
console.warn('Supabase not configured: returning empty posts')
return { posts: [], total: 0, hasMore: false }
}
const {
status = 'published',
category,
Expand Down Expand Up @@ -163,6 +167,10 @@ export class BlogService {

// Get single post by slug
async getPostBySlug(slug: string): Promise<BlogPost | null> {
if (!isSupabaseConfigured) {
console.warn('Supabase not configured: cannot fetch post')
return null
}
const { data, error } = await supabase
.from('blog_posts')
.select(`
Expand Down Expand Up @@ -193,6 +201,10 @@ export class BlogService {

// Get all categories
async getCategories(): Promise<BlogCategory[]> {
if (!isSupabaseConfigured) {
console.warn('Supabase not configured: returning empty categories')
return []
}
const { data, error } = await supabase
.from('blog_categories')
.select('*')
Expand All @@ -208,6 +220,10 @@ export class BlogService {

// Search posts
async searchPosts(query: string, limit = 10): Promise<BlogPost[]> {
if (!isSupabaseConfigured) {
console.warn('Supabase not configured: returning empty search results')
return []
}
const { data, error } = await supabase
.from('blog_posts')
.select(`
Expand Down Expand Up @@ -254,6 +270,9 @@ export class BlogService {
}

async incrementViewCount(slug: string): Promise<void> {
if (!isSupabaseConfigured) {
return
}
const { error } = await supabase.rpc('increment_view_count', { post_slug: slug })

if (error) {
Expand Down
19 changes: 14 additions & 5 deletions lib/supabase/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,25 @@ import { createClient } from '@supabase/supabase-js'
import { createBrowserClient } from '@supabase/ssr'
import { Database } from '@/lib/types/supabase.types'

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL!
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
const supabaseUrl =
process.env.NEXT_PUBLIC_SUPABASE_URL || 'https://example.supabase.co'
const supabaseAnonKey =
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY || 'public-anon-key'

// Client-side Supabase client
export const isSupabaseConfigured =
!!process.env.NEXT_PUBLIC_SUPABASE_URL &&
!!process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY

// Client-side Supabase client (uses placeholder when not configured)
export const supabase = createBrowserClient<Database>(
supabaseUrl,
supabaseAnonKey
)

// Server-side Supabase client (for API routes, etc.)
export const createServerClient = () => {
return createClient<Database>(supabaseUrl, supabaseAnonKey)
}
if (!isSupabaseConfigured) {
throw new Error('Supabase environment variables are not configured')
}
return createClient<Database>(supabaseUrl!, supabaseAnonKey!)

Copilot AI Jul 4, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The non-null assertions (!) on supabaseUrl and supabaseAnonKey are redundant since they always have a fallback string value. You can remove the ! operators.

Suggested change
return createClient<Database>(supabaseUrl!, supabaseAnonKey!)
return createClient<Database>(supabaseUrl, supabaseAnonKey)

Copilot uses AI. Check for mistakes.
}
Loading