diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..45e53b8 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,5 @@ +node_modules +.next +.git +Dockerfile +npm-debug.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f42c1e6 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +# 1. Base image +FROM node:20-alpine + +# 2. Set working directory +WORKDIR /app + +# 3. Copy package files +COPY package*.json ./ + +# 4. Install dependencies +RUN npm install + +# 5. Copy all project files +COPY . . + +# 6. Build Next.js app +RUN npm run build + +# 7. Expose port +EXPOSE 3000 + +# 8. Start app +CMD ["npm", "run", "start"] diff --git a/database/database.js b/database/database.js index 29a422e..315c8d9 100644 --- a/database/database.js +++ b/database/database.js @@ -1,5 +1,8 @@ import mongoose from "mongoose"; +const MONGO_URL = process.env.MONGO_URL; + + let cached = global.mongoose; if (!cached) { @@ -7,8 +10,9 @@ if (!cached) { } export async function connectDatabase() { - if (!process.env.MONGO_URL) { - throw new Error("Couldn't find MONGO_URL in environment variables"); + if (!MONGO_URL) { + console.log("Skipping mongo connection."); + return null; } // Prevent reconnecting to mongoose on every request @@ -17,7 +21,7 @@ export async function connectDatabase() { } if (!cached.promise) { - cached.promise = mongoose.connect(process.env.MONGO_URL, { + cached.promise = mongoose.connect(MONGO_URL, { // Prevent queries from hanging when mongodb isn't connected bufferCommands: false, }); diff --git a/pages/api/artworks.js b/pages/api/artworks.js new file mode 100644 index 0000000..dbad535 --- /dev/null +++ b/pages/api/artworks.js @@ -0,0 +1,26 @@ +import { connectDatabase } from '@/database/database'; +import Post from '@/database/schemas/Post'; + +export default async function handler (req, res) { + try { + if (!process.env.MONGO_URL) { + return res.status(200).json([]); + } + await connectDatabase(); + + const limit = parseInt(req.query.limit); + + const artworksRaw = await Post.find( + { type: 'art' }, + { _id: 0, metadata: 0, type: 0, page: 0, hype: 0, __v: 0 } + ) + .sort({ date: -1 }) + .limit(limit) + .lean(); + + res.status(200).json(artworksRaw); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Failed to fetch artworks' }); + } +} diff --git a/pages/api/members.js b/pages/api/members.js new file mode 100644 index 0000000..6beda0f --- /dev/null +++ b/pages/api/members.js @@ -0,0 +1,23 @@ +import { connectDatabase } from '@/database/database'; +import Member from '@/database/schemas/Member'; + +export default async function handler (req, res) { + try { + if (!process.env.MONGO_URL) { + return res.status(200).json([]); + } + await connectDatabase(); + + + const membersData = await Member.find( + {}, + { _id: 0 } + ) + .lean(); + + res.status(200).json(membersData); + } catch (err) { + console.error(err); + res.status(500).json({ error: 'Failed to fetch members' }); + } +} diff --git a/pages/art.jsx b/pages/art.jsx index 138ae16..8376e63 100644 --- a/pages/art.jsx +++ b/pages/art.jsx @@ -4,38 +4,26 @@ import SeasonFilter from '@/components/ArtSeasonFilter'; import Carousel from '@/components/Carousel'; import ArtCarouselCard from '@/components/ArtCarosuelCard'; import styles from '@/styles/ArtPage.module.css'; -import { connectDatabase } from '@/database/database'; -import Post from '@/database/schemas/Post'; - -export async function getStaticProps () { - await connectDatabase(); - let artworksRaw = await Post.find( - { type: 'art' }, - { _id: 0, metadata: 0, type: 0, page: 0, hype: 0, __v: 0 } - ).sort({ date: -1 }).lean(); - artworksRaw = artworksRaw.map(item => ({ - ...item, - date: item.date instanceof Date ? item.date.toISOString() : item.date - })); + +export async function getServerSideProps (context) { + const host = context.req.headers.host; + const res = await fetch(`http://${host}/api/artworks`); + const artworksRaw = await res.json(); const artworks = artworksRaw.map(item => { - const d = new Date(item.date); - - return { - src: `/assets/art/${item.link}`, - year: String(d.getFullYear()), - author: item.attr?.join(', ') || '', - description: item.name, - season: getSeason(d.getMonth()) - }; - }); + const d = new Date(item.date); - return { - props: { artworks }, + return { + src: `/assets/art/${item.link}`, + year: String(d.getFullYear()), + author: item.attr?.join(', ') || '', + description: item.name, + season: getSeason(d.getMonth()) + }; + }); - revalidate: process.env.NODE_ENV === 'production' - ? 60 * 60 // Once per hour - : 1 // every second for development + return { + props: { artworks } }; } diff --git a/pages/index.jsx b/pages/index.jsx index e9ccf83..7ff94dc 100644 --- a/pages/index.jsx +++ b/pages/index.jsx @@ -4,35 +4,26 @@ import RecentEventsSection from '@/components/home/RecentEventsSection'; import FanartSection from '@/components/home/FanartSection'; import AMVSection from '@/components/home/AMVSection'; import AboutUsSection from '@/components/home/AboutUsSection'; -import { connectDatabase } from '@/database/database'; -import Post from '@/database/schemas/Post'; // TODO: Move this to database import events from '@/data/Events.json'; -export async function getStaticProps () { - await connectDatabase(); - const artworksRaw = await Post.find( - { type: 'art' }, - { _id: 0, metadata: 0, type: 0, page: 0, hype: 0, __v: 0 } - ).sort({ date: -1 }).limit(6).lean(); +export async function getServerSideProps (context) { + const host = context.req.headers.host; + const res = await fetch(`http://${host}/api/artworks?limit=6`); + const artworksRaw = await res.json(); const artworks = artworksRaw.map(item => { - const d = item.date instanceof Date ? item.date : new Date(item.date); return { src: `/assets/art/${item.link}` }; }); return { - props: { artworks, events }, - - revalidate: process.env.NODE_ENV === 'production' - ? 60 * 60 - : 1 + props: { artworks } }; } -export default function Home ({ artworks, events }) { +export default function Home ({ artworks }) { return (