Add support for sqlite
This commit is contained in:
+143
@@ -0,0 +1,143 @@
|
||||
// Local SQLite API instead of Firebase
|
||||
|
||||
const API_URL = "/api";
|
||||
|
||||
export async function suscribirLocales(onData, onError) {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/locales`);
|
||||
const data = await response.json();
|
||||
onData(data);
|
||||
// Simulate real-time by polling every 5 seconds
|
||||
const interval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/locales`);
|
||||
const newData = await res.json();
|
||||
onData(newData);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}, 5000);
|
||||
return () => clearInterval(interval);
|
||||
} catch (err) {
|
||||
onError(err);
|
||||
}
|
||||
}
|
||||
|
||||
export async function suscribirPendientes(onData, onError) {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/pendientes`);
|
||||
const data = await response.json();
|
||||
onData(data);
|
||||
// Simulate real-time by polling every 5 seconds
|
||||
const interval = setInterval(async () => {
|
||||
try {
|
||||
const res = await fetch(`${API_URL}/pendientes`);
|
||||
const newData = await res.json();
|
||||
onData(newData);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}, 5000);
|
||||
return () => clearInterval(interval);
|
||||
} catch (err) {
|
||||
onError(err);
|
||||
}
|
||||
}
|
||||
|
||||
export async function enviarPropuesta(local) {
|
||||
const { id: _x, ...datos } = local;
|
||||
const response = await fetch(`${API_URL}/propuestas`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(datos),
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function aprobarPropuesta(p) {
|
||||
const response = await fetch(`${API_URL}/aprobar/${p.id}`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function rechazarPropuesta(id) {
|
||||
const response = await fetch(`${API_URL}/rechazar/${id}`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function deleteLocal(id) {
|
||||
const response = await fetch(`${API_URL}/locales/${id}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function obtenerPalabrasFiltradas() {
|
||||
try {
|
||||
const response = await fetch(`${API_URL}/config/filtro_palabras`);
|
||||
const data = await response.json();
|
||||
return data.palabras || [];
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
export async function guardarPalabrasFiltradas(palabras) {
|
||||
const response = await fetch(`${API_URL}/config/filtro_palabras`, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify({ palabras }),
|
||||
});
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export function contienepalabrasProhibidas(texto, lista) {
|
||||
if (!lista?.length) return false;
|
||||
const norm = s => s.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "");
|
||||
const t = norm(texto);
|
||||
return lista.some(p => t.includes(norm(p)));
|
||||
}
|
||||
|
||||
// Auth helpers (local implementation)
|
||||
let currentUser = null;
|
||||
|
||||
export function escucharAuth(cb) {
|
||||
// Simple localStorage-based auth
|
||||
const user = localStorage.getItem("user");
|
||||
currentUser = user ? JSON.parse(user) : null;
|
||||
cb(currentUser);
|
||||
|
||||
// Listen for storage changes
|
||||
const handleStorageChange = () => {
|
||||
const user = localStorage.getItem("user");
|
||||
currentUser = user ? JSON.parse(user) : null;
|
||||
cb(currentUser);
|
||||
};
|
||||
window.addEventListener("storage", handleStorageChange);
|
||||
return () => window.removeEventListener("storage", handleStorageChange);
|
||||
}
|
||||
|
||||
export async function loginAdmin(email, password) {
|
||||
// Simple email/password check (in production use proper auth)
|
||||
if (email && password) {
|
||||
const user = { email, uid: email };
|
||||
localStorage.setItem("user", JSON.stringify(user));
|
||||
currentUser = user;
|
||||
return user;
|
||||
}
|
||||
throw new Error("Invalid email or password");
|
||||
}
|
||||
|
||||
export async function registrarAdmin(email, password) {
|
||||
return loginAdmin(email, password);
|
||||
}
|
||||
|
||||
export async function cerrarSesion() {
|
||||
localStorage.removeItem("user");
|
||||
currentUser = null;
|
||||
}
|
||||
+16
-112
@@ -1,112 +1,16 @@
|
||||
// firebase.js
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
// PASO 1 — Pega tu config de Firebase (Configuración ⚙️ → Tu app → Web)
|
||||
// PASO 2 — Activa Authentication → Sign-in method → Email/Password
|
||||
// PASO 3 — Crea Firestore Database en modo producción (región: eur3)
|
||||
// PASO 4 — Pega estas Reglas en Firestore → Reglas y publica:
|
||||
//
|
||||
// rules_version = '2';
|
||||
// service cloud.firestore {
|
||||
// match /databases/{database}/documents {
|
||||
// // Locales aprobados: solo lectura pública, escritura solo autenticados
|
||||
// match /locales/{id} {
|
||||
// allow read: if true;
|
||||
// allow write: if request.auth != null;
|
||||
// }
|
||||
// // Propuestas pendientes: cualquiera puede crear, solo admin gestiona
|
||||
// match /pendientes/{id} {
|
||||
// allow create: if true;
|
||||
// allow read, update, delete: if request.auth != null;
|
||||
// }
|
||||
// // Config (filtro de palabras): lectura pública, escritura solo admin
|
||||
// match /config/{id} {
|
||||
// allow read: if true;
|
||||
// allow write: if request.auth != null;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// ─────────────────────────────────────────────────────────────────────────────
|
||||
|
||||
import { initializeApp } from "firebase/app";
|
||||
import {
|
||||
getFirestore, collection, addDoc, deleteDoc,
|
||||
doc, onSnapshot, query, orderBy, getDoc, setDoc,
|
||||
} from "firebase/firestore";
|
||||
import {
|
||||
getAuth, signInWithEmailAndPassword, createUserWithEmailAndPassword,
|
||||
signOut, onAuthStateChanged,
|
||||
} from "firebase/auth";
|
||||
|
||||
// ▼▼▼ PEGA AQUÍ TU CONFIG DE FIREBASE ▼▼▼
|
||||
const firebaseConfig = {
|
||||
apiKey: "PEGA_TU_API_KEY",
|
||||
authDomain: "PEGA_TU_AUTH_DOMAIN",
|
||||
projectId: "PEGA_TU_PROJECT_ID",
|
||||
storageBucket: "PEGA_TU_STORAGE_BUCKET",
|
||||
messagingSenderId: "PEGA_TU_SENDER_ID",
|
||||
appId: "PEGA_TU_APP_ID",
|
||||
};
|
||||
// ▲▲▲ ─────────────────────────────── ▲▲▲
|
||||
|
||||
const fbApp = initializeApp(firebaseConfig);
|
||||
export const db = getFirestore(fbApp);
|
||||
export const auth = getAuth(fbApp);
|
||||
|
||||
// ── Auth ──────────────────────────────────────────────────────────────────────
|
||||
export const escucharAuth = (cb) => onAuthStateChanged(auth, cb);
|
||||
export const loginAdmin = (e, p) => signInWithEmailAndPassword(auth, e, p);
|
||||
export const registrarAdmin = (e, p) => createUserWithEmailAndPassword(auth, e, p);
|
||||
export const cerrarSesion = () => signOut(auth);
|
||||
|
||||
// ── Locales aprobados (público, solo lectura) ─────────────────────────────────
|
||||
export function suscribirLocales(onData, onError) {
|
||||
const q = query(collection(db, "locales"), orderBy("fecha", "desc"));
|
||||
return onSnapshot(q, snap => onData(snap.docs.map(d => ({ id: d.id, ...d.data() }))), onError);
|
||||
}
|
||||
export const deleteLocal = (id) => deleteDoc(doc(db, "locales", id));
|
||||
|
||||
// ── Propuestas pendientes ─────────────────────────────────────────────────────
|
||||
/** Cualquier visitante puede enviar una propuesta */
|
||||
export async function enviarPropuesta(local) {
|
||||
const { id: _x, ...datos } = local;
|
||||
return addDoc(collection(db, "pendientes"), {
|
||||
...datos,
|
||||
estado: "pendiente",
|
||||
fechaPropuesta: new Date().toISOString(),
|
||||
});
|
||||
}
|
||||
|
||||
/** Solo el admin suscribe y gestiona pendientes */
|
||||
export function suscribirPendientes(onData, onError) {
|
||||
const q = query(collection(db, "pendientes"), orderBy("fechaPropuesta", "desc"));
|
||||
return onSnapshot(q, snap => onData(snap.docs.map(d => ({ id: d.id, ...d.data() }))), onError);
|
||||
}
|
||||
|
||||
/** Admin aprueba: mueve a /locales y borra de /pendientes */
|
||||
export async function aprobarPropuesta(p) {
|
||||
const { id, estado, fechaPropuesta, ...datos } = p;
|
||||
await addDoc(collection(db, "locales"), { ...datos, fecha: new Date().toISOString() });
|
||||
await deleteDoc(doc(db, "pendientes", id));
|
||||
}
|
||||
|
||||
/** Admin rechaza: borra de /pendientes */
|
||||
export const rechazarPropuesta = (id) => deleteDoc(doc(db, "pendientes", id));
|
||||
|
||||
// ── Filtro de palabras ────────────────────────────────────────────────────────
|
||||
export async function obtenerPalabrasFiltradas() {
|
||||
try {
|
||||
const snap = await getDoc(doc(db, "config", "filtro_palabras"));
|
||||
if (snap.exists()) return snap.data().palabras || [];
|
||||
} catch {}
|
||||
return [];
|
||||
}
|
||||
export const guardarPalabrasFiltradas = (palabras) =>
|
||||
setDoc(doc(db, "config", "filtro_palabras"), { palabras });
|
||||
|
||||
/** Devuelve true si el texto contiene alguna palabra prohibida */
|
||||
export function contienepalabrasProhibidas(texto, lista) {
|
||||
if (!lista?.length) return false;
|
||||
const norm = s => s.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
const t = norm(texto);
|
||||
return lista.some(p => t.includes(norm(p)));
|
||||
}
|
||||
// firebase.js - Re-exports local API instead of Firebase
|
||||
export {
|
||||
escucharAuth,
|
||||
loginAdmin,
|
||||
registrarAdmin,
|
||||
cerrarSesion,
|
||||
suscribirLocales,
|
||||
deleteLocal,
|
||||
enviarPropuesta,
|
||||
suscribirPendientes,
|
||||
aprobarPropuesta,
|
||||
rechazarPropuesta,
|
||||
obtenerPalabrasFiltradas,
|
||||
guardarPalabrasFiltradas,
|
||||
contienepalabrasProhibidas,
|
||||
} from "./api.js";
|
||||
|
||||
Reference in New Issue
Block a user