From 5cbd80326ffa36f5ee6740e49180ca8e8c5467e5 Mon Sep 17 00:00:00 2001 From: AyrisAI Date: Thu, 20 Aug 2026 17:30:22 +0300 Subject: [PATCH] feat: setup Supabase Storage bucket for restaurant assets and add mobile upload helper --- apps/mobile/src/lib/storage.ts | 36 +++++++++++++++++++ apps/web/next.config.mjs | 12 +++++++ .../20260820000000_storage_buckets.sql | 27 ++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 apps/mobile/src/lib/storage.ts create mode 100644 supabase/migrations/20260820000000_storage_buckets.sql diff --git a/apps/mobile/src/lib/storage.ts b/apps/mobile/src/lib/storage.ts new file mode 100644 index 0000000..0ce023b --- /dev/null +++ b/apps/mobile/src/lib/storage.ts @@ -0,0 +1,36 @@ +import { supabase } from "./supabase"; + +export const BUCKET_NAME = "restaurant-assets"; + +export type AssetFolder = "logos" | "covers" | "items"; + +/** + * Uploads an image file (logo, cover banner, item photo) to Supabase Storage + * and returns the public CDN URL. + */ +export async function uploadImageToSupabase( + fileUri: string, + folder: AssetFolder = "items" +): Promise { + const response = await fetch(fileUri); + const blob = await response.blob(); + const fileExt = fileUri.split(".").pop()?.toLowerCase() || "jpg"; + const fileName = `${folder}/${Date.now()}-${Math.random().toString(36).substring(2, 9)}.${fileExt}`; + + const { data, error } = await supabase.storage + .from(BUCKET_NAME) + .upload(fileName, blob, { + contentType: `image/${fileExt === "png" ? "png" : "jpeg"}`, + upsert: true, + }); + + if (error) { + throw new Error(`Resim yükleme hatası: ${error.message}`); + } + + const { data: publicUrlData } = supabase.storage + .from(BUCKET_NAME) + .getPublicUrl(data.path); + + return publicUrlData.publicUrl; +} diff --git a/apps/web/next.config.mjs b/apps/web/next.config.mjs index 01761fd..d4b62ab 100644 --- a/apps/web/next.config.mjs +++ b/apps/web/next.config.mjs @@ -2,6 +2,18 @@ const nextConfig = { reactStrictMode: true, output: "standalone", + images: { + remotePatterns: [ + { + protocol: "https", + hostname: "*.supabase.co", + }, + { + protocol: "https", + hostname: "images.unsplash.com", + }, + ], + }, }; export default nextConfig; diff --git a/supabase/migrations/20260820000000_storage_buckets.sql b/supabase/migrations/20260820000000_storage_buckets.sql new file mode 100644 index 0000000..a454e26 --- /dev/null +++ b/supabase/migrations/20260820000000_storage_buckets.sql @@ -0,0 +1,27 @@ +-- Supabase Storage Bucket Setup for Restaurant Assets (Logos, Cover Banners, Menu Items) +insert into storage.buckets (id, name, public) +values ('restaurant-assets', 'restaurant-assets', true) +on conflict (id) do update set public = true; + +-- Enable Public Read Access Policy for restaurant-assets bucket +create policy "Public Access for Restaurant Assets" +on storage.objects for select +using ( bucket_id = 'restaurant-assets' ); + +-- Enable Authenticated User Upload Policy for restaurant-assets bucket +create policy "Authenticated User Upload for Restaurant Assets" +on storage.objects for insert +to authenticated +with check ( bucket_id = 'restaurant-assets' ); + +-- Enable Authenticated User Update Policy for restaurant-assets bucket +create policy "Authenticated User Update for Restaurant Assets" +on storage.objects for update +to authenticated +using ( bucket_id = 'restaurant-assets' ); + +-- Enable Authenticated User Delete Policy for restaurant-assets bucket +create policy "Authenticated User Delete for Restaurant Assets" +on storage.objects for delete +to authenticated +using ( bucket_id = 'restaurant-assets' );