import React, { useEffect, useState, useMemo } from "react";
import { createClient } from "@supabase/supabase-js";
/*
Minecraft Photo Share - React + Supabase (fixed for `import` parse error)
Root cause fixed: using the token `import` in expressions like
typeof import !== 'undefined'
causes a parser error in environments that don't expect `import` outside of module syntax
(the error you saw: "import can only be used in import() or import.meta").
Fix strategy in this file:
- DO NOT reference the bare `import` token anywhere in runtime checks.
- For Vite's `import.meta.env` detection we *safely* attempt to access it via `eval` so
the parser won't throw when parsing this file in non-module contexts.
- Prefer props (supabaseUrl/supabaseAnonKey) or window globals when running in uncertain
build environments.
How to provide credentials (pick one):
1) CRA: set REACT_APP_SUPABASE_URL and REACT_APP_SUPABASE_ANON_KEY in your .env
2) Vite: set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY in your .env (Vite will replace at build-time)
3) Pass props:
4) Quick debug: set window.__SUPABASE_URL__ and window.__SUPABASE_ANON_KEY__ before mounting the app
If you still see environment errors, send me the exact browser console stack trace and I'll iterate.
*/
function safeReadEnv(name) {
// 1) Try window globals (explicit and double-underscored)
try {
if (typeof window !== "undefined" && window && window[name]) return window[name];
if (typeof window !== "undefined" && window && window[`__${name}__`]) return window[`__${name}__`];
} catch (e) {
// ignore
}
// 2) Try import.meta.env via eval to avoid parser errors in environments that don't support import.meta
try {
// We intentionally keep the string inside eval so the parser doesn't see `import.meta` at top-level.
const importMetaEnv = (0, eval)("(typeof import.meta !== 'undefined' ? import.meta.env : undefined)");
if (importMetaEnv && importMetaEnv[name]) return importMetaEnv[name];
} catch (e) {
// ignore if eval fails or import.meta not available
}
// 3) Try process.env in a guarded manner (CRA / Node builds). `typeof process` avoids ReferenceError.
try {
if (typeof process !== "undefined" && process && process.env && process.env[name]) return process.env[name];
} catch (e) {
// ignore
}
return null;
}
export default function MinecraftApp({ supabaseUrl: propUrl, supabaseAnonKey: propKey } = {}) {
const SUPABASE_URL = propUrl
|| safeReadEnv("VITE_SUPABASE_URL")
|| safeReadEnv("REACT_APP_SUPABASE_URL")
|| safeReadEnv("SUPABASE_URL")
|| safeReadEnv("__SUPABASE_URL__");
const SUPABASE_ANON_KEY = propKey
|| safeReadEnv("VITE_SUPABASE_ANON_KEY")
|| safeReadEnv("REACT_APP_SUPABASE_ANON_KEY")
|| safeReadEnv("SUPABASE_ANON_KEY")
|| safeReadEnv("__SUPABASE_ANON_KEY__");
const supabase = useMemo(() => {
if (!SUPABASE_URL || !SUPABASE_ANON_KEY) return null;
return createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
}, [SUPABASE_URL, SUPABASE_ANON_KEY]);
if (!supabase) {
return (
Supabase keys not found
This app couldn't detect the Supabase credentials it needs to run in the browser.
Choose one of the options below to provide keys:
Set build-time environment variables for your bundler:
Create React App: REACT_APP_SUPABASE_URL and REACT_APP_SUPABASE_ANON_KEY
Vite: VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY
Pass them as props when mounting: <MinecraftApp supabaseUrl=... supabaseAnonKey=... />
Or set globals before rendering (quick hack): window.__SUPABASE_URL__ and window.__SUPABASE_ANON_KEY__
If you've already set variables, make sure your bundler injects them into the client bundle (Vite uses import.meta.env, CRA replaces process.env.REACT_APP_* at build time).
);
}
const [user, setUser] = useState(null);
const [photos, setPhotos] = useState([]);
const [caption, setCaption] = useState("");
const [file, setFile] = useState(null);
const [comments, setComments] = useState({});
const [messageRecipient, setMessageRecipient] = useState("");
const [messageText, setMessageText] = useState("");
const [usersList, setUsersList] = useState([]);
useEffect(() => {
if (!supabase) return;
let authSubscription = null;
let photosChannel = null;
let commentsChannel = null;
(async () => {
try {
const { data } = await supabase.auth.getUser();
setUser(data?.user ?? null);
} catch (err) {
console.error("supabase.auth.getUser() error:", err);
}
try {
const { data: sub } = supabase.auth.onAuthStateChange((_event, session) => {
setUser(session?.user ?? null);
});
authSubscription = sub?.subscription ?? null;
} catch (err) {
console.error("onAuthStateChange error:", err);
}
await fetchPhotos();
fetchUsers();
try {
photosChannel = supabase
.channel("photos-listener")
.on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'photos' }, () => {
fetchPhotos();
})
.subscribe();
commentsChannel = supabase
.channel("comments-listener")
.on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'comments' }, (payload) => {
const photoId = payload.record?.photo_id;
if (photoId) fetchComments(photoId);
})
.subscribe();
} catch (err) {
console.warn('Realtime subscribe failed (check project realtime settings):', err);
}
})();
return () => {
try { if (authSubscription?.unsubscribe) authSubscription.unsubscribe(); } catch (e) {}
try { if (photosChannel?.unsubscribe) photosChannel.unsubscribe(); } catch (e) {}
try { if (commentsChannel?.unsubscribe) commentsChannel.unsubscribe(); } catch (e) {}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [supabase]);
async function signUp(email, password) {
if (!supabase) return console.warn('signUp called but supabase is not initialized');
const { data, error } = await supabase.auth.signUp({ email, password });
if (error) return alert(error.message);
alert("Kayıt başarılı. E-posta doğrulama gerekiyorsa gelen kutunu kontrol et.");
}
async function signIn(email, password) {
if (!supabase) return console.warn('signIn called but supabase is not initialized');
const { data, error } = await supabase.auth.signInWithPassword({ email, password });
if (error) alert(error.message);
}
async function signOut() {
if (!supabase) return console.warn('signOut called but supabase is not initialized');
const { error } = await supabase.auth.signOut();
if (error) console.error(error);
}
async function fetchUsers() {
if (!supabase) return;
try {
const { data, error } = await supabase.from("profiles").select("id,username");
if (!error) setUsersList(data || []);
} catch (e) {
console.warn(e);
}
}
async function fetchPhotos() {
if (!supabase) return;
try {
const { data, error } = await supabase
.from("photos")
.select("id, user_id, path, caption, created_at")
.order("created_at", { ascending: false })
.limit(100);
if (error) {
console.error(error);
} else {
setPhotos(data || []);
(data || []).forEach(p => fetchComments(p.id));
}
} catch (e) {
console.error(e);
}
}
async function fetchComments(photoId) {
if (!supabase) return;
try {
const { data, error } = await supabase
.from("comments")
.select("id, user_id, body, created_at")
.eq("photo_id", photoId)
.order("created_at", { ascending: true });
if (error) console.error(error);
else setComments(prev => ({ ...prev, [photoId]: data || [] }));
} catch (e) {
console.error(e);
}
}
async function uploadPhoto(e) {
e.preventDefault();
if (!supabase) return alert("Uygulama doğru yapılandırılmamış (Supabase yok).");
if (!user) return alert("Giriş yapmalısın.");
if (!file) return alert("Önce bir dosya seç.");
const filename = `${user.id}/${Date.now()}_${file.name}`;
try {
const { data: uploadData, error: uploadError } = await supabase.storage
.from("photos")
.upload(filename, file, { cacheControl: "3600", upsert: false });
if (uploadError) return alert("Yükleme hatası: " + uploadError.message);
const { data: publicData } = supabase.storage.from("photos").getPublicUrl(filename);
const publicUrl = publicData?.publicUrl ?? "";
const { error: dbError } = await supabase.from("photos").insert([
{ user_id: user.id, path: filename, caption }
]);
if (dbError) console.error(dbError);
else {
setCaption("");
setFile(null);
}
} catch (e) {
console.error(e);
alert('Yükleme sırasında hata oluştu. Konsolu kontrol et.');
}
}
async function postComment(photoId, text) {
if (!supabase) return console.warn('postComment called but supabase not initialized');
if (!user) return alert("Giriş yapmalısın.");
if (!text) return;
const { error } = await supabase.from("comments").insert([{ photo_id: photoId, user_id: user.id, body: text }]);
if (error) console.error(error);
}
async function sendMessage() {
if (!supabase) return console.warn('sendMessage called but supabase not initialized');
if (!user) return alert("Giriş yapmalısın.");
if (!messageRecipient) return alert("Alıcı seç.");
if (!messageText) return alert("Mesaj boş olamaz.");
const { error } = await supabase.from("messages").insert([
{ sender_id: user.id, recipient_id: messageRecipient, body: messageText }
]);
if (error) console.error(error);
else {
setMessageText("");
alert("Mesaj gönderildi.");
}
}
function getPublicUrl(path) {
if (!supabase || !path) return "";
try {
const { data } = supabase.storage.from("photos").getPublicUrl(path);
return data?.publicUrl ?? "";
} catch (e) {
console.error(e);
return "";
}
}
return (