diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml new file mode 100644 index 00000000..ce5a9005 --- /dev/null +++ b/.github/workflows/go.yml @@ -0,0 +1,318 @@ +# T// FILE: README.md +# Firebase React Full App (Single Copy/Paste) + +This repository contains a minimal React app configured to run entirely on Firebase: Authentication (Email/Password + Google), Firestore (simple notes collection), and Hosting — ready for one-command deploy. + +## Quick steps (summary) +2. Create a Firebase project in the Firebase Console. +3. Replace the Firebase config in `src/firebaseConfig.js` with your project's values (or set env variables for production). +4. Login to Firebase CLI: `firebase login` +5. Initialize (only once if not already): `firebase init` — choose Hosting, Firestore, and (optional) Functions if you want server code. +6. Build & deploy: `npm run build && firebase deploy --only hosting` + +Full instructions are in the file `DEPLOY_INSTRUCTIONS.md` in this repo. + +--- + +// FILE: DEPLOY_INSTRUCTIONS.md +# Deploy Instructions (Detailed) + +1. Install Node.js (16+) and npm/yarn. +2. From project root: `npm install`. +3. Create a Firebase project at https://console.firebase.google.com/ and note the config values. +4. Open `src/firebaseConfig.js` and paste your config object (replace placeholders) OR set environment variables and use them. +5. Install Firebase CLI if you don't have it: `npm install -g firebase-tools`. +6. Login: `firebase login`. +7. Initialize (only if you haven't): `firebase init`. + - Choose **Hosting** and **Firestore**. + - For Hosting: set `build` as the public directory (the build output from `npm run build`). + - Configure as single-page app? Yes (rewrite all URLs to /index.html). +8. Build and Deploy: + ```bash + npm run build + firebase deploy --only hosting + ``` + +Notes: +- If you want to use Firebase Functions later (for server-side logic), re-run `firebase init functions` and move any server code to `functions/`. + +--- + +// FILE: package.json +{ + "name": "firebase-react-full-app", + "version": "1.0.0", + "private": true, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test", + "eject": "react-scripts eject" + }, + "dependencies": { + "firebase": "^9.23.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-scripts": "5.0.1" + } +} + +// FILE: .gitignore +node_modules/ +build/ +.env +/.firebase + +// FILE: firebase.json +{ + "hosting": { + "public": "build", + "ignore": ["firebase.json", "**/.*", "**/node_modules/**"], + "rewrites": [ + { + "source": "**", + "destination": "/index.html" + } + ] + } +} + +// FILE: .firebaserc +{ + "projects": { + "default": "YOUR_FIREBASE_PROJECT_ID" + } +} + +// FILE: public/index.html + + + + + + Firebase React Full App + + +
+ + + +// FILE: src/index.js +import React from 'react'; +import { createRoot } from 'react-dom/client'; +import App from './App'; +import './index.css'; + +const container = document.getElementById('root'); +const root = createRoot(container); +root.render(); + +// FILE: src/index.css +body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial; margin:0; padding:0; } +.app { padding: 20px; max-width: 800px; margin: 0 auto; } +.header { display:flex; justify-content:space-between; align-items:center; } +.card { border:1px solid #ddd; padding:16px; border-radius:8px; margin-top:12px } +input, textarea { width:100%; padding:8px; margin-top:8px; box-sizing:border-box } +button { padding:8px 12px; margin-top:8px } + +// FILE: src/firebaseConfig.js +// Replace the placeholder values below with your Firebase project's config. +// You can also load them from environment variables if deploying with CI. + +const firebaseConfig = { + apiKey: "YOUR_API_KEY", + authDomain: "YOUR_PROJECT.firebaseapp.com", + projectId: "YOUR_PROJECT_ID", + storageBucket: "YOUR_PROJECT.appspot.com", + messagingSenderId: "YOUR_MESSAGING_SENDER_ID", + appId: "YOUR_APP_ID" +}; + +export default firebaseConfig; + +// FILE: src/firebaseClient.js +import { initializeApp } from 'firebase/app'; +import { getAuth } from 'firebase/auth'; +import { getFirestore } from 'firebase/firestore'; +import firebaseConfig from './firebaseConfig'; + +const app = initializeApp(firebaseConfig); +export const auth = getAuth(app); +export const db = getFirestore(app); + +// FILE: src/App.js +import React, { useState } from 'react'; +import Auth from './components/Auth'; +import Notes from './components/Notes'; +import { auth } from './firebaseClient'; + +export default function App(){ + const [user, setUser] = useState(null); + + // Simple listener (keeps UI minimal) + auth.onAuthStateChanged((u) => setUser(u)); + + return ( +
+
+

Firebase All-in-One App

+ {user ?
Welcome, {user.email}
:
Not signed in
} +
+ +
+ +
+ + {user && ( +
+ +
+ )} +
+ ); +} + +// FILE: src/components/Auth.js +import React, { useState } from 'react'; +import { auth } from '../firebaseClient'; +import { createUserWithEmailAndPassword, signInWithEmailAndPassword, signOut, GoogleAuthProvider, signInWithPopup } from 'firebase/auth'; + +export default function Auth(){ + const [mode, setMode] = useState('login'); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [error, setError] = useState(''); + + async function handleEmailAuth(e){ + e.preventDefault(); + setError(''); + try{ + if(mode === 'login'){ + await signInWithEmailAndPassword(auth, email, password); + } else { + await createUserWithEmailAndPassword(auth, email, password); + } + }catch(err){ + setError(err.message); + } + } + + async function handleGoogle(){ + const provider = new GoogleAuthProvider(); + try{ + await signInWithPopup(auth, provider); + }catch(err){ setError(err.message); } + } + + function handleSignOut(){ signOut(auth); } + + return ( +
+

{mode === 'login' ? 'Sign In' : 'Create Account'}

+
+ setEmail(e.target.value)} /> + setPassword(e.target.value)} /> + +
+ +
+ +
+ +
+ +
+ +
+ +
+ + {error &&
{error}
} +
+ ); +} + +// FILE: src/components/Notes.js +import React, { useEffect, useState } from 'react'; +import { db } from '../firebaseClient'; +import { collection, addDoc, query, where, onSnapshot, orderBy, deleteDoc, doc } from 'firebase/firestore'; + +export default function Notes({ user }){ + const [text, setText] = useState(''); + const [notes, setNotes] = useState([]); + + useEffect(()=>{ + if(!user) return; + const q = query(collection(db, 'notes'), where('uid', '==', user.uid), orderBy('createdAt', 'desc')); + const unsub = onSnapshot(q, (snap)=>{ + const arr = []; + snap.forEach(d => arr.push({ id: d.id, ...d.data() })); + setNotes(arr); + }); + return ()=>unsub(); + }, [user]); + + async function addNote(){ + if(!text.trim()) return; + await addDoc(collection(db, 'notes'), { uid: user.uid, text: text.trim(), createdAt: Date.now() }); + setText(''); + } + + async function removeNote(id){ + await deleteDoc(doc(db, 'notes', id)); + } + + return ( +
+

Your Notes

+