initial commit: rocket.new export of broadcastbeat

This commit is contained in:
Ryan Salazar
2026-05-07 16:39:17 +00:00
commit 70aa1ad46e
302 changed files with 60710 additions and 0 deletions

View File

@@ -0,0 +1,273 @@
'use client';
import { createContext, useContext, useEffect, useState } from 'react';
import { createClient } from '../lib/supabase/client';
const AuthContext = createContext<any>({});
export const useAuth = () => {
const context = useContext(AuthContext);
if (!context) {
throw new Error('useAuth must be used within AuthProvider');
}
return context;
};
export const AuthProvider = ({ children }: { children: React.ReactNode }) => {
const [user, setUser] = useState<any>(null);
const [session, setSession] = useState<any>(null);
const [loading, setLoading] = useState(true);
const supabase = createClient();
useEffect(() => {
supabase.auth.getSession().then(({ data: { session } }) => {
setSession(session);
setUser(session?.user ?? null);
setLoading(false);
});
const {
data: { subscription }
} = supabase.auth.onAuthStateChange((_event, session) => {
setSession(session);
setUser(session?.user ?? null);
setLoading(false);
});
return () => subscription.unsubscribe();
}, []);
// Email/Password Sign Up
const signUp = async (email: string, password: string, metadata = {}) => {
const { data, error } = await supabase.auth.signUp({
email,
password,
options: {
data: {
full_name: (metadata as any)?.fullName || '',
avatar_url: (metadata as any)?.avatarUrl || ''
},
emailRedirectTo: `${window.location.origin}/auth/callback`
}
});
if (error) throw error;
return data;
};
// Email/Password Sign In
const signIn = async (email: string, password: string) => {
const { data, error } = await supabase.auth.signInWithPassword({
email,
password
});
if (error) throw error;
return data;
};
// Sign Out
const signOut = async () => {
const { error } = await supabase.auth.signOut();
if (error) throw error;
};
// Get Current User
const getCurrentUser = async () => {
const { data: { user }, error } = await supabase.auth.getUser();
if (error) throw error;
return user;
};
// Check if Email is Verified
const isEmailVerified = () => {
return user?.email_confirmed_at !== null;
};
// Get User Profile from Database
const getUserProfile = async () => {
if (!user) return null;
const { data, error } = await supabase
.from('user_profiles')
.select('*')
.eq('id', user.id)
.single();
if (error) throw error;
return data;
};
// ── Bookmarks (reading_list) ──────────────────────────────
const getBookmarks = async () => {
if (!user) return [];
const { data, error } = await supabase
.from('reading_list')
.select('*')
.eq('user_id', user.id)
.order('saved_at', { ascending: false });
if (error) throw error;
return data || [];
};
const addBookmark = async (article: {
slug: string;
title: string;
excerpt?: string;
image?: string;
alt?: string;
category?: string;
author?: string;
readTime?: string;
date?: string;
}) => {
if (!user) throw new Error('Not authenticated');
const { error } = await supabase.from('reading_list').insert({
user_id: user.id,
article_slug: article.slug,
article_title: article.title,
article_excerpt: article.excerpt ?? null,
article_image: article.image ?? null,
article_image_alt: article.alt ?? null,
article_category: article.category ?? null,
article_author: article.author ?? null,
article_read_time: article.readTime ?? null,
article_date: article.date ?? null,
});
if (error) throw error;
};
const removeBookmark = async (articleSlug: string) => {
if (!user) throw new Error('Not authenticated');
const { error } = await supabase
.from('reading_list')
.delete()
.eq('user_id', user.id)
.eq('article_slug', articleSlug);
if (error) throw error;
};
const isBookmarked = async (articleSlug: string): Promise<boolean> => {
if (!user) return false;
const { data } = await supabase
.from('reading_list')
.select('id')
.eq('user_id', user.id)
.eq('article_slug', articleSlug)
.maybeSingle();
return !!data;
};
// ── Reading History ───────────────────────────────────────
const getReadingHistory = async () => {
if (!user) return [];
const { data, error } = await supabase
.from('reading_history')
.select('*')
.eq('user_id', user.id)
.order('viewed_at', { ascending: false });
if (error) throw error;
return data || [];
};
const trackArticleView = async (article: {
slug: string;
title: string;
excerpt?: string;
image?: string;
alt?: string;
category?: string;
author?: string;
readTime?: string;
date?: string;
}) => {
if (!user) return;
// Upsert so each article appears once (most recent view)
const { error } = await supabase.from('reading_history').upsert(
{
user_id: user.id,
article_slug: article.slug,
article_title: article.title,
article_excerpt: article.excerpt ?? null,
article_image: article.image ?? null,
article_image_alt: article.alt ?? null,
article_category: article.category ?? null,
article_author: article.author ?? null,
article_read_time: article.readTime ?? null,
article_date: article.date ?? null,
viewed_at: new Date().toISOString(),
},
{ onConflict: 'user_id,article_slug' }
);
if (error) {
// Silent fail — history tracking should not break the page
}
};
const clearReadingHistory = async () => {
if (!user) throw new Error('Not authenticated');
const { error } = await supabase
.from('reading_history')
.delete()
.eq('user_id', user.id);
if (error) throw error;
};
// ── Topic Preferences ─────────────────────────────────────
const getTopicPreferences = async () => {
if (!user) return [];
const { data, error } = await supabase
.from('user_topic_preferences')
.select('*')
.eq('user_id', user.id)
.order('view_count', { ascending: false });
if (error) throw error;
return data || [];
};
const trackTopicView = async (topic: string) => {
if (!user || !topic) return;
// Upsert: increment view_count if topic already exists
const { error } = await supabase.rpc
? await supabase
.from('user_topic_preferences')
.upsert(
{
user_id: user.id,
topic: topic.toLowerCase().trim(),
view_count: 1,
last_viewed_at: new Date().toISOString(),
},
{ onConflict: 'user_id,topic' }
)
: { error: null };
if (error) {
// Silent fail
}
};
const value = {
user,
session,
loading,
signUp,
signIn,
signOut,
getCurrentUser,
isEmailVerified,
getUserProfile,
// Bookmarks
getBookmarks,
addBookmark,
removeBookmark,
isBookmarked,
// Reading History
getReadingHistory,
trackArticleView,
clearReadingHistory,
// Topic Preferences
getTopicPreferences,
trackTopicView,
};
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};