diff --git a/.github/workflows/firebase-rules.yml b/.github/workflows/firebase-rules.yml new file mode 100644 index 0000000..4f7fdca --- /dev/null +++ b/.github/workflows/firebase-rules.yml @@ -0,0 +1,17 @@ +name: Test Firebase rules on PR +'on': pull_request +jobs: + test_rules: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-java@v3 + with: + distribution: 'temurin' + java-version: '21' + - uses: actions/setup-node@v3 + with: + node-version: '20' + - run: npm install -g firebase-tools + - run: npm ci + - run: npm run test:rules \ No newline at end of file diff --git a/src/App.tsx b/src/App.tsx index 7825dde..b36e47f 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -6,8 +6,6 @@ import Login from "./pages/Login"; import Navbar from "./components/Navbar"; import Dashboard from "./pages/Dashboard"; -import { devTesting } from "./config"; - function App() { const { user, authIsReady } = useAuthContext(); @@ -32,12 +30,10 @@ function AppRoutes({ user }: { user: any }) { {!location.pathname.includes("/dashboard") && } } /> - {devTesting && ( - <> - : } /> - : } /> - - )} + <> + : } /> + : } /> + ); diff --git a/src/components/Events.tsx b/src/components/Events.tsx index 914fef8..0595383 100644 --- a/src/components/Events.tsx +++ b/src/components/Events.tsx @@ -11,10 +11,12 @@ export default function Events() { const filteredEvents = useMemo(() => { if (!events) return []; - const now = new Date(); + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + return events.filter(event => { const eventDate = event.date.toDate(); - return showUpcoming ? eventDate >= now : eventDate < now; + return showUpcoming ? eventDate >= yesterday : eventDate < yesterday; }); }, [events, showUpcoming]); diff --git a/src/components/Navbar.tsx b/src/components/Navbar.tsx index af5bdbc..1776090 100644 --- a/src/components/Navbar.tsx +++ b/src/components/Navbar.tsx @@ -1,7 +1,6 @@ import React, { useState } from "react"; import { Link, useNavigate } from "react-router-dom"; import { useAuthContext } from "@/hooks/useAuthContext"; -import { devTesting } from "@/config"; import { IconMenu2, IconX } from "@tabler/icons-react"; import wccLogo from "@/assets/WCC-logo-symbol.png"; @@ -60,25 +59,23 @@ const Navbar: React.FC = () => { ))} - {devTesting && ( -
  • - {user ? ( - - Dashboard - - ) : ( - - Login - - )} -
  • - )} +
  • + {user ? ( + + Dashboard + + ) : ( + + Login + + )} +
  • {/* Hamburger button for (collections.carpoolCollection, null, ['targetDate', 'asc'], true); + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + const { documents: carpools } = useCollection(collections.carpoolCollection, ['targetDate', '>=', yesterday], ['targetDate', 'asc'], true); const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [isInboxModalOpen, setIsInboxModalOpen] = useState(false); const { user: currentUser } = useAuthContext(); @@ -29,8 +31,19 @@ export default function Carpool() { const joinedCarpools: CarpoolPost[] = []; const requestedCarpools: CarpoolPost[] = []; const availableCarpools: CarpoolPost[] = []; + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); carpools.forEach((carpool) => { + // Hide carpools that aren't yours and have passed their targetDate + const isOwner = carpool.userId === currentUser.uid; + const targetDate = carpool.targetDate.toDate(); + const hasPassed = targetDate
    -

    +

    Available Carpools

    diff --git a/src/features/carpool/components/CarpoolDetails.tsx b/src/features/carpool/components/CarpoolDetails.tsx index c126b01..2bc2294 100644 --- a/src/features/carpool/components/CarpoolDetails.tsx +++ b/src/features/carpool/components/CarpoolDetails.tsx @@ -1,7 +1,7 @@ import { useParams, Link, useNavigate } from "react-router-dom"; import { useCarpoolWithUser } from "@/hooks/useCarpoolWithUser"; import { CarpoolStatusEnum } from "../enums/CarpoolStatusEnum"; -import { IconArrowLeft, IconCalendar, IconUser, IconUsers, IconMapPin, IconClock, IconFileText, IconEdit, IconTrash, IconChevronDown, IconPhone, IconMail, IconX, IconAlertTriangle } from "@tabler/icons-react"; +import { IconArrowLeft, IconCalendar, IconUser, IconUsers, IconMapPin, IconClock, IconFileText, IconEdit, IconTrash, IconChevronDown, IconPhone, IconMail, IconX, IconAlertTriangle, IconMailForward } from "@tabler/icons-react"; import { convertTimestampToDate } from "@/utils/firebaseDateConvert"; import { useAuthContext } from "@/hooks/useAuthContext"; import { doc, updateDoc, arrayUnion, arrayRemove, deleteDoc } from "firebase/firestore"; @@ -380,6 +380,44 @@ export default function CarpoolDetails() { window.location.reload(); }; + // Function to handle emailing all carpool members + const handleEmailAll = () => { + if (!carpoolUsers || carpoolUsers.length === 0) { + setMessage({ text: "No participants to email.", type: 'info' }); + return; + } + + if (!carpool) return; + // Collect all emails from carpool users + const emails = carpoolUsers + .map(user => user.email) + .filter(email => email); // Filter out undefined/null emails + + if (emails.length === 0) { + setMessage({ text: "No email addresses available for participants.", type: 'error' }); + return; + } + + // Create subject and body for the email + const subject = encodeURIComponent(`Carpool Update: ${carpool.location} → ${carpool.destination}`); + const body = encodeURIComponent( + `Hello everyone,\n\n` + + `This is an update about our carpool:\n\n` + + `From: ${carpool.location}\n` + + `To: ${carpool.destination}\n` + + `Date: ${convertTimestampToDate(carpool.targetDate).date}\n` + + `Time: ${convertTimestampToDate(carpool.targetDate).time}\n\n` + + `[Your message here]\n\n` + + `Best regards` + ); + + // Create mailto link with all emails in TO field + const mailtoLink = `mailto:${emails.join(',')}?subject=${subject}&body=${body}`; + + // Open the mailto link + window.location.href = mailtoLink; + }; + // Function to render the appropriate action button based on carpool status and user relationship const renderActionButton = () => { if (!carpool) return null; @@ -587,7 +625,7 @@ export default function CarpoolDetails() {
    -

    +

    Carpool Details

    @@ -600,6 +638,14 @@ export default function CarpoolDetails() { {/* Owner Actions */} {currentUser && carpool.userId === currentUser.uid && (

    +