diff --git a/src/App.js b/src/App.js
index fc47d12..7d088d1 100644
--- a/src/App.js
+++ b/src/App.js
@@ -6,17 +6,53 @@ import { onAuthStateChanged, signOut } from "firebase/auth";
function App() {
const [user, setUser] = useState(null);
+ const [userStats, setUserStats] = useState({
+ articles: 0,
+ likes: 0,
+ dislikes: 0,
+ credibility: 50,
+ });
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (firebaseUser) => {
- setUser(firebaseUser);
+ if (firebaseUser) {
+ setUser(firebaseUser);
+
+ // ✅ Simulate API call to get user stats (or fallback to default)
+ setTimeout(() => {
+ const simulatedStats = {
+ articles: Math.floor(Math.random() * 50),
+ likes: Math.floor(Math.random() * 500),
+ dislikes: Math.floor(Math.random() * 100),
+ credibility: Math.floor(50 + Math.random() * 70), // can go up to 120
+ };
+ setUserStats(simulatedStats);
+ }, 500);
+ } else {
+ setUser(null);
+ setUserStats({
+ articles: 0,
+ likes: 0,
+ dislikes: 0,
+ credibility: 50, // ✅ fallback default
+ });
+ }
});
+
return () => unsubscribe();
}, []);
const handleSignOut = () => {
signOut(auth)
- .then(() => setUser(null))
+ .then(() => {
+ setUser(null);
+ setUserStats({
+ articles: 0,
+ likes: 0,
+ dislikes: 0,
+ credibility: 50,
+ });
+ })
.catch((error) => console.error("Error signing out:", error));
};
@@ -53,7 +89,11 @@ function App() {
{/* Map or Auth */}
- {user ? : }
+ {user ? (
+
+ ) : (
+
+ )}
);
diff --git a/src/components/Features/DisplayControls.js b/src/components/Features/DisplayControls.js
index baa870e..5eb5894 100644
--- a/src/components/Features/DisplayControls.js
+++ b/src/components/Features/DisplayControls.js
@@ -100,7 +100,7 @@ const DisplayControls = ({
@@ -140,12 +140,12 @@ const styles = {
marginTop: "8px",
display: "flex",
flexDirection: "column",
- gap: "14px",
+ gap: "10px", // 🔽 change from 14px to 10px
},
section: {
display: "flex",
flexDirection: "column",
- gap: "6px",
+ gap: "4px", // 🔽 tighter gap between label and control
},
label: {
fontSize: "13px",
diff --git a/src/components/Features/NewsFilters.js b/src/components/Features/NewsFilters.js
index 92f4dc1..4859efa 100644
--- a/src/components/Features/NewsFilters.js
+++ b/src/components/Features/NewsFilters.js
@@ -159,13 +159,13 @@ const styles = {
marginTop: "8px",
display: "flex",
flexDirection: "column",
- gap: "12px",
+ gap: "10px",
},
label: {
fontSize: "13px",
fontWeight: "bold",
color: "#333",
- marginBottom: "4px",
+ marginBottom: "2px",
},
input: {
width: "100%",
@@ -178,8 +178,8 @@ const styles = {
chipContainer: {
display: "flex",
flexWrap: "wrap",
- gap: "6px",
- marginBottom: "4px",
+ gap: "4px",
+ marginBottom: "2px",
},
chip: {
display: "flex",
@@ -200,12 +200,12 @@ const styles = {
overflowY: "auto",
border: "1px solid #ddd",
borderRadius: "6px",
- padding: "6px",
+ padding: "4px",
backgroundColor: "#f9f9f9",
},
checkboxLabel: {
display: "block",
- marginBottom: "6px",
+ marginBottom: "4px",
fontSize: "13px",
color: "#333",
},
diff --git a/src/components/Map/HeatMap.js b/src/components/Map/HeatMap.js
index 1b1dd36..c3ef7cc 100644
--- a/src/components/Map/HeatMap.js
+++ b/src/components/Map/HeatMap.js
@@ -6,7 +6,8 @@ import DisplayControls from "../Features/DisplayControls";
import NewsFilters from "../Features/NewsFilters";
import HeatLayers from "./HeatLayers";
import PopupCard from "./PopupCard";
-import AddNewsModal from "../User/AddNewsModal";
+import UserDetailsPanel from "../User/UserStatsPanel";
+import AddNewsButton from "../User/AddNewsButton";
const MAPBOX_ACCESS_TOKEN = process.env.REACT_APP_MAPBOX_ACCESS_TOKEN;
@@ -36,7 +37,6 @@ class HeatMap extends Component {
sortedNearbyNews: [],
currentNewsIndex: 0,
showPopup: false,
- showAddModal: false,
circleRadius: 0,
keyword: "",
selectedCategories: [],
@@ -101,9 +101,24 @@ class HeatMap extends Component {
};
handleKeywordChange = (keyword) => this.setState({ keyword });
-
handleCategoryChange = (selectedCategories) => this.setState({ selectedCategories });
+ handleResetView = () => {
+ const viewState = {
+ longitude: -105.0,
+ latitude: 39.7392,
+ zoom: viewZoomMap.world,
+ };
+ this.setState({
+ viewLevel: "world",
+ zoom: viewZoomMap.world,
+ viewState,
+ });
+ if (this.mapRef.current) {
+ this.mapRef.current.flyTo({ center: [-105.0, 39.7392], zoom: viewZoomMap.world, duration: 300 });
+ }
+ };
+
getFilteredFeatures = () => {
const { geoJsonData, keyword, selectedCategories } = this.state;
if (!geoJsonData) return [];
@@ -160,7 +175,7 @@ class HeatMap extends Component {
const {
theme, viewLevel, zoom, viewState,
clickedLocation, sortedNearbyNews, currentNewsIndex,
- showPopup, circleRadius, keyword, selectedCategories, showAddModal
+ showPopup, circleRadius, keyword, selectedCategories
} = this.state;
const selectedNews = sortedNearbyNews[currentNewsIndex];
@@ -179,7 +194,7 @@ class HeatMap extends Component {
onThemeChange={this.handleThemeChange}
onViewLevelChange={this.handleViewLevelChange}
onZoomChange={this.handleZoomChange}
- onResetView={() => this.handleViewLevelChange("world")}
+ onResetView={this.handleResetView}
/>
+
+
+
+
-
-
- {showAddModal && (
- this.setState({ showAddModal: false })} />
- )}
+
);
}
@@ -271,6 +278,16 @@ const styles = {
gap: "12px",
width: "260px",
},
+ rightPanel: {
+ position: "absolute",
+ top: "12px",
+ right: "10px",
+ zIndex: 2,
+ width: "260px",
+ display: "flex",
+ flexDirection: "column",
+ gap: "12px",
+ },
};
export default HeatMap;
\ No newline at end of file
diff --git a/src/components/Map/PopupCard.js b/src/components/Map/PopupCard.js
index 6caf581..808c298 100644
--- a/src/components/Map/PopupCard.js
+++ b/src/components/Map/PopupCard.js
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from "react";
-import styles from "./styles";
+import styles from "../../styles";
import { getAuth } from "firebase/auth";
const PopupCard = ({ selectedNews, multipleNews, onClose, onNext }) => {
const [userVote, setUserVote] = useState(null); // "like" | "fake" | null
diff --git a/src/components/User/AddNewsButton.js b/src/components/User/AddNewsButton.js
index 94cd370..b8f2b94 100644
--- a/src/components/User/AddNewsButton.js
+++ b/src/components/User/AddNewsButton.js
@@ -1,90 +1,21 @@
-// Floating Button + News Form Modal
import React, { useState } from "react";
+import AddNewsModal from "./AddNewsModal";
const AddNewsButton = () => {
const [showModal, setShowModal] = useState(false);
- const [formData, setFormData] = useState({
- title: "",
- summary: "",
- category: "",
- link: ""
- });
-
- const handleInputChange = (e) => {
- const { name, value } = e.target;
- setFormData((prev) => ({ ...prev, [name]: value }));
- };
-
- const handleSubmit = (e) => {
- e.preventDefault();
- console.log("Submitting News:", formData);
- setShowModal(false);
- setFormData({ title: "", summary: "", category: "", link: "" });
- };
return (
<>
- {showModal && (
-
- )}
+ {showModal && setShowModal(false)} />}
>
);
};
@@ -92,85 +23,21 @@ const AddNewsButton = () => {
const styles = {
fab: {
position: "fixed",
- bottom: "20px",
- right: "20px",
+ bottom: "80px",
+ right: "10px",
+ width: "260px",
backgroundColor: "#e53935",
color: "#fff",
border: "none",
- borderRadius: "50px",
- padding: "12px 20px",
- fontSize: "14px",
- fontWeight: "bold",
- boxShadow: "0 2px 8px rgba(0, 0, 0, 0.2)",
- cursor: "pointer",
- zIndex: 1000
- },
- overlay: {
- position: "fixed",
- top: 0,
- left: 0,
- width: "100vw",
- height: "100vh",
- backgroundColor: "rgba(0,0,0,0.4)",
- display: "flex",
- justifyContent: "center",
- alignItems: "center",
- zIndex: 1001
- },
- modal: {
- backgroundColor: "#fff",
- padding: "24px",
borderRadius: "10px",
- width: "400px",
- boxShadow: "0 4px 10px rgba(0, 0, 0, 0.3)"
- },
- modalTitle: {
- fontSize: "18px",
+ padding: "14px 0",
+ fontSize: "15px",
fontWeight: "bold",
- marginBottom: "12px",
- color: "#333"
- },
- form: {
- display: "flex",
- flexDirection: "column",
- gap: "12px"
- },
- input: {
- padding: "8px 10px",
- borderRadius: "6px",
- border: "1px solid #ccc",
- fontSize: "14px"
- },
- textarea: {
- padding: "8px 10px",
- borderRadius: "6px",
- border: "1px solid #ccc",
- fontSize: "14px",
- minHeight: "80px"
- },
- buttonRow: {
- display: "flex",
- justifyContent: "space-between",
- marginTop: "10px"
- },
- submitButton: {
- backgroundColor: "#4caf50",
- color: "#fff",
- padding: "8px 14px",
- border: "none",
- borderRadius: "6px",
- fontWeight: "bold",
- cursor: "pointer"
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.3)",
+ cursor: "pointer",
+ zIndex: 1000,
+ transition: "all 0.2s ease",
},
- cancelButton: {
- backgroundColor: "#ccc",
- color: "#333",
- padding: "8px 14px",
- border: "none",
- borderRadius: "6px",
- fontWeight: "bold",
- cursor: "pointer"
- }
};
export default AddNewsButton;
diff --git a/src/components/User/AddNewsModal.js b/src/components/User/AddNewsModal.js
index caf58a1..a942053 100644
--- a/src/components/User/AddNewsModal.js
+++ b/src/components/User/AddNewsModal.js
@@ -1,6 +1,4 @@
-// ✅ Add this new component: AddNewsModal.jsx
import React, { useState } from "react";
-import styles from "../Map/styles";
import { getAuth } from "firebase/auth";
import { v4 as uuidv4 } from "uuid";
@@ -8,116 +6,129 @@ const AddNewsModal = ({ onClose }) => {
const [title, setTitle] = useState("");
const [summary, setSummary] = useState("");
const [link, setLink] = useState("");
- const [category, setCategory] = useState("");
-
const handleSubmit = () => {
+ if (!title.trim() || !summary.trim()) {
+ alert("Title and Summary are required.");
+ return;
+ }
+
if (!navigator.geolocation) {
alert("Geolocation not supported.");
return;
}
navigator.geolocation.getCurrentPosition(
- async (position) => {
- const now = new Date();
- const isoString = now.toISOString();
- const [date, time] = isoString.split("T");
- const formattedTime = time.split(".")[0];
+ async (position) => {
+ const now = new Date();
+ const isoString = now.toISOString();
+ const [date, time] = isoString.split("T");
+ const formattedTime = time.split(".")[0];
+ const lat = position.coords.latitude;
+ const lng = position.coords.longitude;
- const lat = position.coords.latitude;
- const lng = position.coords.longitude;
+ const payload = {
+ uri: uuidv4(),
+ lang: "eng",
+ isDuplicate: false,
+ date,
+ time: formattedTime,
+ dateTime: isoString,
+ dateTimePub: isoString,
+ dataType: "news",
+ sim: 0,
+ url: link,
+ title,
+ body: summary,
+ userid: getAuth().currentUser?.uid || "anonymous",
+ coordinates: { lat, lng },
+ geoJson: {
+ type: "Location",
+ geometry: { type: "Point", coordinates: [lng, lat] },
+ properties: { name: "Unknown" },
+ },
+ // category: "User-Generated",
+ };
- const payload = {
- uri: uuidv4(),
- lang: "eng",
- isDuplicate: false,
- date,
- time: formattedTime,
- dateTime: isoString,
- dateTimePub: isoString,
- dataType: "news",
- sim: 0,
- url: link,
- title,
- body: summary,
- userid: getAuth().currentUser?.uid || "anonymous",
- coordinates: {
- lat,
- lng,
- },
- geoJson: {
- type: "Location",
- geometry: {
- type: "Point",
- coordinates: [lng, lat], // GeoJSON format = [longitude, latitude]
- },
- properties: {
- name: "Unknown" // you can replace this with a reverse geocode API if needed
- }
- }
- };
+ try {
+ await fetch("https://sqs-backend-573766487049.us-central1.run.app/user_news", {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(payload),
+ });
- try {
- await fetch("https://sqs-backend-573766487049.us-central1.run.app/user_news", {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify(payload),
- });
-
- console.log("Submitted with geoJson:", payload);
- onClose();
- } catch (err) {
- console.error("Submission failed:", err);
- alert("Failed to submit news.");
- }
- },
- (error) => {
- console.error("Geolocation error:", error);
- alert("Location permission is required to submit.");
+ alert("✅ News Submitted!");
+ onClose();
+ } catch (err) {
+ alert("Failed to submit news.");
+ console.error(err);
}
+ },
+ (error) => {
+ alert("Location permission is required to submit.");
+ console.error(error);
+ }
);
};
return (
-
-
-
📝 Submit News Article
+
+
+
📝 Submit News
-
setTitle(e.target.value)}
- style={styles.input}
- />
-