From 7375079a9b68ee111ae1f7b61852917db86e823b Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Thu, 19 Mar 2026 10:38:29 +0000 Subject: [PATCH] Autosave: 20260319-103829 --- backend/src/index.js | 2 + backend/src/routes/public_campaigns.js | 14 ++++ .../components/WebPageComponents/Footer.tsx | 11 +++ .../components/WebPageComponents/Header.tsx | 16 ++++ frontend/src/pages/watch-ads.tsx | 79 +++++++++++++++++++ 5 files changed, 122 insertions(+) create mode 100644 backend/src/routes/public_campaigns.js create mode 100644 frontend/src/components/WebPageComponents/Footer.tsx create mode 100644 frontend/src/components/WebPageComponents/Header.tsx create mode 100644 frontend/src/pages/watch-ads.tsx diff --git a/backend/src/index.js b/backend/src/index.js index 1cd6945..6645b61 100644 --- a/backend/src/index.js +++ b/backend/src/index.js @@ -38,6 +38,7 @@ const commuter_profilesRoutes = require('./routes/commuter_profiles'); const reward_catalog_itemsRoutes = require('./routes/reward_catalog_items'); const campaignsRoutes = require('./routes/campaigns'); +const publicCampaignsRoutes = require('./routes/public_campaigns'); const ad_creativesRoutes = require('./routes/ad_creatives'); @@ -130,6 +131,7 @@ app.use('/api/commuter_profiles', passport.authenticate('jwt', {session: false}) app.use('/api/reward_catalog_items', passport.authenticate('jwt', {session: false}), reward_catalog_itemsRoutes); app.use('/api/campaigns', passport.authenticate('jwt', {session: false}), campaignsRoutes); +app.use('/api/public-campaigns', publicCampaignsRoutes); app.use('/api/ad_creatives', passport.authenticate('jwt', {session: false}), ad_creativesRoutes); diff --git a/backend/src/routes/public_campaigns.js b/backend/src/routes/public_campaigns.js new file mode 100644 index 0000000..bf96ca5 --- /dev/null +++ b/backend/src/routes/public_campaigns.js @@ -0,0 +1,14 @@ +const express = require('express'); +const CampaignsDBApi = require('../db/api/campaigns'); +const wrapAsync = require('../helpers').wrapAsync; +const router = express.Router(); + +router.get('/', wrapAsync(async (req, res) => { + // Public access: fetch active campaigns + // Assuming a findAll method exists in CampaignsDBApi + // We bypass auth for this specific route + const payload = await CampaignsDBApi.findAll(req.query, true, { public: true }); + res.status(200).send(payload); +})); + +module.exports = router; diff --git a/frontend/src/components/WebPageComponents/Footer.tsx b/frontend/src/components/WebPageComponents/Footer.tsx new file mode 100644 index 0000000..79eddc6 --- /dev/null +++ b/frontend/src/components/WebPageComponents/Footer.tsx @@ -0,0 +1,11 @@ +import React from 'react'; + +export default function WebSiteFooter({ projectName }: { projectName: string }) { + return ( + + ); +} diff --git a/frontend/src/components/WebPageComponents/Header.tsx b/frontend/src/components/WebPageComponents/Header.tsx new file mode 100644 index 0000000..40a7a1a --- /dev/null +++ b/frontend/src/components/WebPageComponents/Header.tsx @@ -0,0 +1,16 @@ +import React from 'react'; +import Link from 'next/link'; + +export default function WebSiteHeader({ projectName }: { projectName: string }) { + return ( +
+
+
{projectName}
+ +
+
+ ); +} diff --git a/frontend/src/pages/watch-ads.tsx b/frontend/src/pages/watch-ads.tsx new file mode 100644 index 0000000..5f90888 --- /dev/null +++ b/frontend/src/pages/watch-ads.tsx @@ -0,0 +1,79 @@ +import React, { useEffect, useState } from 'react'; +import type { ReactElement } from 'react'; +import Head from 'next/head'; +import axios from 'axios'; +import LayoutGuest from '../layouts/Guest'; +import WebSiteHeader from '../components/WebPageComponents/Header'; +import WebSiteFooter from '../components/WebPageComponents/Footer'; +import BaseButton from '../components/BaseButton'; +import { mdiPlayCircle } from '@mdi/js'; + +interface Campaign { + id: string; + campaign_name: string; + notes_internal: string; +} + +export default function WatchAdsPage() { + const projectName = 'CommuterAds'; + const [campaigns, setCampaigns] = useState([]); + const [loading, setLoading] = useState(true); + + useEffect(() => { + // Log the request to see what's happening + console.log('Fetching campaigns...'); + axios.get('/public-campaigns') + .then(response => { + console.log('Campaigns response:', response.data); + // Based on Campaign API, payload is in .rows + setCampaigns(response.data.rows || []); + setLoading(false); + }) + .catch(error => { + console.error('Error fetching campaigns:', error); + setLoading(false); + }); + }, []); + + return ( + <> + + Watch Ads | CommuterAds + + +
+
+

Watch & Earn

+ {loading ? ( +

Loading campaigns...

+ ) : campaigns.length > 0 ? ( +
+ {campaigns.map((campaign) => ( +
+
+ {campaign.campaign_name.charAt(0)} +
+

{campaign.campaign_name}

+

{campaign.notes_internal || 'Watch to earn rewards!'}

+ +
+ ))} +
+ ) : ( +

No campaigns available right now.

+ )} +
+
+ + + ); +} + +WatchAdsPage.getLayout = function getLayout(page: ReactElement) { + return {page}; +}; \ No newline at end of file