Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 8 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,14 @@
# User Engagement Project
# Project Description

Your final project for the class will incorporate deeper user engegement. The project should build upon many of the concepts learned throughout the class, incorporate some significant amount of interactivity, and storing and recalling data in a way that multiple users of the application can benefit from. _The focus of this project will be on engagement -- i.e. inviting members of the public to create or add to a dataset in some way._
This project showcases the site locations, serving hours, and contact information of the DC Summer Meal Program. It is designed to help both providers and beneficiaries access relevant information easily and interact efficiently:

For this project you may extend your story map or your dashboard, as long as you have some realistic addition of functionality that allows for user engagement. You may also start a new project.
- For Providers: Program providers can log in to publish updates or announcements directly on the platform.
- For Beneficiaries: Beneficiaries can browse all available information without needing to log in. They can also anonymously leave comments or feedback and read reviews left by others.

## Timeline
# Purpose of the Project

- This project will take us through the end of the semester on **December 4**, when we will have project presentations.
- To help you with your timeline, here are some milestones:
- **October 30**: Project proposal due
- **November 6**: Initial wireframes due
- **November 20**: Plan for completion
- **December 4**: Project presentations
The DC Summer Meal Program plays a critical role in addressing food insecurity by providing free meals to children during the summer. This project enhances accessibility by centralizing meal program information, making it easier for families in need to locate resources quickly. Additionally, the anonymous comment feature encourages users to share their experiences and suggestions without fear of judgment, fostering community engagement and improving the program's outreach.

## Instructions
# Team Members

Fork this repository, and add your project code to it. When you are ready to submit your project, refer to the Submission Checklist below.

## Project Proposal

You proposal doesn't have to be deep. It should:
1. Make clear who the user of your project is. This should be more specific that "the general public". Refer to the [18F Method Card on Personas](https://guides.18f.gov/methods/decide/personas/) or the Digtal.gov article on [Improving Customer Experience with Digital Personas](https://digital.gov/2017/06/20/improving-customer-experience-with-digital-personas/).
2. Describe what you'll be doing in your tool to meet your user's needs.
3. Describe any datasets that you will be working with, including any data that users will put in.

## Initial Wireframes

Use wireframes to show what your project or your new feature will look like. You can use any tool you like to create these wireframes.

## Plan for Completion

Describe what you will need to do to complete your project. This should include a list of tasks that you will need to complete, and a timeline for when you will complete them. I suggest using a tool like GitHub Projects to list out and manage your tasks/issues.

## Submission Checklist

- [ ] Pushed latest code to the `main` branch of your repository
- [ ] Linted JS and CSS code
- [ ] Turned on GitHub Pages for the repository and verified that your site works when deployed
- [ ] Submitted a pull request to the original repository in the class organization
- [ ] In the PR **title**, included your name at least
- [ ] In the PR **description**, included a brief description of your topic, and your target audience
E Chin Li & Yuan Ji
179 changes: 179 additions & 0 deletions announcement.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Announcements</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Itim&family=Quicksand:wght@300..700&family=Shadows+Into+Light&display=swap" rel="stylesheet">
<link rel="stylesheet" href="css/announcement.css">
<script src="js/announcement.js" type="module"></script>
</head>
<body>
<h1>Announcements</h1>

<!-- login/logout -->
<div id="login-section">
<button id="login-btn">Admin Login</button>
<button id="logout-btn" style="display: none;">Logout</button>
</div>

<div id="login-popup" style="display: none;">
<h2>Login</h2>
<form id="login-form">
<label for="email">Username:</label>
<input type="email" id="email" placeholder="Enter your email" required>
<label for="password">Password:</label>
<input type="password" id="password" placeholder="Enter your password" required>
<button type="submit">Login</button>
</form>
<button id="close-popup">Close</button>
</div>

<!-- submit announce: only login user -->
<div id="announcement-form" style="display: none;">
<h2>Post Announcement</h2>
<form id="announcement-form">
<textarea id="announcement" rows="4" placeholder="Write your announcement here..." required></textarea>
<button type="submit">Submit Announcement</button>
</form>
</div>

<!-- show announce -->
<div id="announcements-display"></div>

<a href="index.html">
<button class="back-button">Back</button>
</a>

<!-- Firebase -->
<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-auth.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-storage.js"></script>

<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-app.js";
import { getAuth, signInWithEmailAndPassword, signOut } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-auth.js";
import { getFirestore, addDoc, collection, getDocs, query, orderBy, limit } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore.js";

var firebaseConfig = {
apiKey: "AIzaSyDaaXvC97Bhu7JWizvEETPxjLi81jQ4jLg",
authDomain: "fsmp-dashboard.firebaseapp.com",
projectId: "fsmp-dashboard",
storageBucket: "fsmp-dashboard.firebasestorage.app",
messagingSenderId: "709451842996",
appId: "1:709451842996:web:2b2872cb010510ba6c5ee1",
measurementId: "G-6MJ1Z4W38K"
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);

const loginBtn = document.getElementById("login-btn");
const logoutBtn = document.getElementById("logout-btn");
const loginPopup = document.getElementById("login-popup");
const announcementForm = document.getElementById("announcement-form");
const announcementsDisplay = document.getElementById("announcements-display");
const closePopupBtn = document.getElementById("close-popup");
const loginForm = document.getElementById("login-form");

// show login popup
loginBtn.addEventListener("click", () => {
loginPopup.style.display = "block";
});

// close popup
closePopupBtn.addEventListener("click", () => {
loginPopup.style.display = "none";
});

// login
// Username: admin@fsmp.com
// Password: password123
loginForm.addEventListener("submit", async (e) => {
e.preventDefault();
const email = document.getElementById("email").value;
const password = document.getElementById("password").value;

try {
await signInWithEmailAndPassword(auth, email, password);
alert("Logged in successfully!");
loginPopup.style.display = "none";
} catch (error) {
alert("Login failed: " + error.message);
}
});

// logout
logoutBtn.addEventListener("click", () => {
signOut(auth).then(() => {
alert("Logged out successfully!");
}).catch((error) => {
alert("Logout failed: " + error.message);
});
});

// show/hide
auth.onAuthStateChanged(user => {
if (user) {
loginBtn.style.display = "none";
logoutBtn.style.display = "inline-block";
announcementForm.style.display = "block";
} else {
loginBtn.style.display = "inline-block";
logoutBtn.style.display = "none";
announcementForm.style.display = "none";
}
});

// sumbit
document.getElementById('announcement-form').addEventListener('submit', async (e) => {
e.preventDefault();

const announcement = document.getElementById('announcement').value;

try {
await addDoc(collection(db, 'announcements'), {
announcement,
timestamp: new Date(),
});
alert('Announcement posted!');
e.target.reset();
} catch (error) {
console.error("Error posting announcement:", error);
}
});

// show announce
async function displayAnnouncements() {
const q = query(collection(db, 'announcements'), orderBy('timestamp', 'desc'), limit(5));
const querySnapshot = await getDocs(q);
const announcements = [];
querySnapshot.forEach((doc) => {
announcements.push(doc.data());
});

if (announcements.length === 0) {
announcementsDisplay.innerHTML = '<p>No announcements yet!</p>';
return;
}

announcements.forEach(({ announcement }) => {
const announcementItem = document.createElement('div');
announcementItem.className = 'announcement-item';

const announcementText = document.createElement('p');
announcementText.textContent = announcement;

announcementItem.appendChild(announcementText);
announcementsDisplay.appendChild(announcementItem);
});
}

displayAnnouncements();
</script>
</body>
</html>
108 changes: 108 additions & 0 deletions comment.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Summer Meals Comments</title>
<link rel="stylesheet" href="css/comment.css">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Itim&family=Quicksand:wght@300..700&family=Shadows+Into+Light&display=swap" rel="stylesheet">
<script src="js/comments.js" type="module"></script>
</head>
<body>
<h1>Share your ideas and express your thanks!</h1>

<form id="comment-form">
<label for="comment">Leave your comments here:</label>
<textarea id="comment" rows="4" placeholder="Write your comment here..." required></textarea>

<button type="submit">Submit</button>
</form>
<div id="comments-display"></div>
<a href="index.html">
<button class="back-button">Back</button>
</a>

<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-app.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/11.0.2/firebase-storage.js"></script>
<script type="module">
import { initializeApp } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-app.js";
import { addDoc, collection, getDocs } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore.js";
import { getFirestore } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore.js";
import { getStorage } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-storage.js";
import { query, orderBy, limit } from "https://www.gstatic.com/firebasejs/11.0.2/firebase-firestore.js";
var firebaseConfig = {
apiKey: "AIzaSyDaaXvC97Bhu7JWizvEETPxjLi81jQ4jLg",
authDomain: "fsmp-dashboard.firebaseapp.com",
projectId: "fsmp-dashboard",
storageBucket: "fsmp-dashboard.firebasestorage.app",
messagingSenderId: "709451842996",
appId: "1:709451842996:web:2b2872cb010510ba6c5ee1",
measurementId: "G-6MJ1Z4W38K"
};

const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const storage = getStorage(app);

console.log("Firebase initialized successfully:", app);
console.log("Firestore and Storage are ready for use.");

document.getElementById('comment-form').addEventListener('submit', async (e) => {
e.preventDefault();

const comment = document.getElementById('comment').value;

try {
await addDoc(collection(db, 'comments'), {
comment,
timestamp: new Date(),
});
alert('Comment submitted!');
e.target.reset();
} catch (error) {
console.error("Error adding comment:", error);
}
});

// Show Comments
async function displayComments() {
const commentsDisplay = document.getElementById('comments-display');

// limited to 10
const q = query(collection(db, 'comments'), orderBy('timestamp', 'desc'), limit(10));
const querySnapshot = await getDocs(q);

const comments = [];
querySnapshot.forEach((doc) => {
comments.push(doc.data());
});

if (comments.length === 0) {
commentsDisplay.innerHTML = '<p>Share your ideas and express your thanks!</p>';
return;
}

// random
comments.sort(() => 0.5 - Math.random());

// show
comments.slice(0, 5).forEach(({ comment }) => {
const commentItem = document.createElement('div');
commentItem.className = 'comment-item';

const commentText = document.createElement('p');
commentText.textContent = comment;

commentItem.appendChild(commentText);
commentsDisplay.appendChild(commentItem);
});
}

displayComments();
</script>
<script src="js/comments.js"></script>
</body>
</html>
Loading