diff --git a/App.tsx b/App.tsx index 90e1d8fa..28cab8c6 100644 --- a/App.tsx +++ b/App.tsx @@ -6,7 +6,8 @@ import { PriceChart } from './components/PriceChart'; import { ErrorDisplay } from './components/ErrorDisplay'; import { Header } from './components/Header'; import { isImageAFlyer, extractCoreDataFromImage, extractAddressFromImage, extractLogoFromImage } from './services/geminiService'; -import type { FlyerItem, Flyer, MasterGroceryItem, DealItem, ProcessingStage, StageStatus, Store, Profile, ShoppingList, ShoppingListItem, Database } from './types'; +import type { FlyerItem, Flyer, MasterGroceryItem, DealItem, ProcessingStage, StageStatus, Store, Profile, ShoppingList, ShoppingListItem } from './types'; +import type { Database } from './types/supabase'; // Correctly import the Database type import { BulkImporter } from './components/BulkImporter'; import { PriceHistoryChart } from './components/PriceHistoryChart'; import { supabase, uploadFlyerImage, createFlyerRecord, saveFlyerItems, getFlyers, getFlyerItems, findFlyerByChecksum, getWatchedItems, addWatchedItem, getAllMasterItems, getFlyerItemsForFlyers, countFlyerItemsForFlyers, getUserProfile, updateUserPreferences, removeWatchedItem, getShoppingLists, createShoppingList, addShoppingListItem, updateShoppingListItem, removeShoppingListItem, deleteShoppingList, uploadLogoAndUpdateStore } from './services/supabaseClient'; @@ -316,7 +317,7 @@ function App() { price_display: item.price_display, price_in_cents: item.price_in_cents, quantity: item.quantity, - storeName: flyerIdToStoreName.get(item.flyer_id!) || 'Unknown Store', + storeName: (flyerIdToStoreName.get(item.flyer_id!) || 'Unknown Store') as string, master_item_name: item.master_item_name, unit_price: item.unit_price, })); diff --git a/services/supabaseClient.ts b/services/supabaseClient.ts index ebe8c436..36f8a03f 100644 --- a/services/supabaseClient.ts +++ b/services/supabaseClient.ts @@ -13,7 +13,7 @@ if (!supabaseUrl || !supabaseAnonKey) { // Create and export the Supabase client. // If the keys are missing, this will be null, and features requiring it will be disabled. -export const supabase = (supabaseUrl && supabaseAnonKey) +export let supabase = (supabaseUrl && supabaseAnonKey) ? createClient(supabaseUrl, supabaseAnonKey) : null; @@ -199,15 +199,22 @@ export const saveFlyerItems = async (items: Omit ({ ...item, flyer_id: flyerId })); + const itemsToInsert = items.map(item => { + // Create a new object without the properties that don't exist in the DB table + const { master_item_name, ...rest } = item; + return { ...rest, flyer_id: flyerId }; + }); const { data: savedItems, error } = await supabase .from('flyer_items') - .insert(itemsToInsert) + // We cast to `any` here to bypass the strict type check on the `unit_price` (Json vs UnitPrice) + // This is safe because UnitPrice is a valid JSONB structure. + .insert(itemsToInsert as any) .select(); if (error) throw new Error(`Failed to save flyer items: ${error.message}`); - return savedItems; + // Cast the result back to the expected application type + return savedItems as unknown as FlyerItem[]; }; /** @@ -223,7 +230,8 @@ export const getFlyers = async (): Promise => { .order('created_at', { ascending: false }); if (error) throw new Error(`Failed to get flyers: ${error.message}`); - return data || []; + // Cast the result back to the expected application type + return (data as Flyer[]) || []; }; /** @@ -241,7 +249,8 @@ export const getFlyerItems = async (flyerId: number): Promise => { .order('item', { ascending: true }); if (error) throw new Error(`Failed to get flyer items: ${error.message}`); - return data || []; + // Cast the result back to the expected application type + return (data as unknown as FlyerItem[]) || []; }; /** @@ -457,7 +466,8 @@ export const getFlyerItemsForFlyers = async (flyerIds: number[]): Promise => console.error("Error fetching user profile:", error.message); return null; } - return data; + // Cast the result back to the expected application type + return data as Profile | null; }; /** @@ -528,12 +539,14 @@ export const updateUserProfile = async (userId: string, updates: { full_name?: s if (!supabase) throw new Error("Supabase client not initialized"); const { data, error } = await supabase .from('profiles') - .update(updates) + // Cast to `any` to handle potential JSONB type mismatches if more fields are added + .update(updates as any) .eq('id', userId) .select() .single(); if (error) throw new Error(`Error updating profile: ${error.message}`); - return data; + // Cast the result back to the expected application type + return data as Profile; }; /** @@ -546,12 +559,14 @@ export const updateUserPreferences = async (userId: string, preferences: Profile if (!supabase) throw new Error("Supabase client not initialized"); const { data, error } = await supabase .from('profiles') - .update({ preferences }) + // Cast to `any` to handle the JSONB type mismatch for `preferences` + .update({ preferences: preferences as any }) .eq('id', userId) .select() .single(); if (error) throw new Error(`Error updating preferences: ${error.message}`); - return data; + // Cast the result back to the expected application type + return data as Profile; }; /** @@ -770,14 +785,16 @@ export const addShoppingListItem = async (listId: number, { masterItemId, custom */ export const updateShoppingListItem = async (itemId: number, updates: Partial): Promise => { if (!supabase) throw new Error("Supabase client not initialized"); + // The 'id' cannot be part of the update payload. + const { id, ...updateData } = updates; const { data, error } = await supabase .from('shopping_list_items') - .update(updates) + .update(updateData) .eq('id', itemId) .select('*, master_item:master_grocery_items(name)') .single(); if (error) throw new Error(`Error updating shopping list item: ${error.message}`); - return data; + return data as ShoppingListItem; }; /** diff --git a/supabase/.temp/cli-latest b/supabase/.temp/cli-latest new file mode 100644 index 00000000..11335d2f --- /dev/null +++ b/supabase/.temp/cli-latest @@ -0,0 +1 @@ +v2.54.11 \ No newline at end of file diff --git a/tailwind.config.js b/tailwind.config.js index d25373a3..0ca752de 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -3,7 +3,8 @@ export default { // Configure files to scan for Tailwind classes content: [ "./index.html", - "./*.{js,ts,jsx,tsx}", // Scans for files in the root directory + "./*.{js,ts,jsx,tsx}", // Scans for files in the root directory like index.tsx + "./components/**/*.{js,ts,jsx,tsx}", // Scans all component files ], // Enable dark mode using a class darkMode: 'class', diff --git a/types/supabase.ts b/types/supabase.ts new file mode 100644 index 00000000..cc84215b Binary files /dev/null and b/types/supabase.ts differ