A side project made for MTU IT that allows MTU IT to have memes or GIFs displayed on a monitor/display that updates in real-time when someone with admin permissions changes the content. Built with Next.js, MongoDB, and Google OAuth.
ShopGifs is a dual-interface web app:
- Player (
/) — A public full-screen display that polls for the latest GIF or video every second and updates automatically. Intended to be shown on a monitor in the shop. - Admin Panel (
/panel) — A Google OAuth-protected control panel where authorized users can update the displayed media, view an activity log, and manage users.
- An admin signs in via Google OAuth at
/panel - They upload a file or paste a URL in the Home tab
- Files are hosted via the Tixte API; URLs are validated and stored directly
- The player page polls
/api/getConfigevery second and displays whatever is currently set - All updates are logged with the user's name, timestamp, and media type — logs expire after 7 days
Only whitelisted emails (stored in MongoDB) can sign in. Admin users additionally have access to the Users tab to add or remove authorized users.
| Layer | Technology |
|---|---|
| Framework | Next.js 13 (React + TypeScript) |
| Styling | Tailwind CSS |
| Database | MongoDB |
| Auth | NextAuth.js (Google OAuth) |
| File Hosting | Tixte API |
| Data Fetching | SWR |
- Node.js 18+
- A MongoDB database
- A Google OAuth app (console.cloud.google.com)
- A Tixte account and API key (tixte.com)
Create a .env.local file in the root of the project:
# MongoDB
MONGODB_URI=mongodb+srv://...
DATABASE=shopgifs
# Google OAuth
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
# NextAuth
NEXTAUTH_SECRET=...
NEXTAUTH_URL=http://localhost:3000
# Tixte (file uploads)
NEXT_PUBLIC_TIXTEAPI=...
# Branding
NEXT_PUBLIC_SITENAME=ShopGifs# Install dependencies
npm install
# Start development server
npm run devThe app will be available at http://localhost:3000.
npm run build
npm startThe first authorized user must be added directly to MongoDB. Insert a document into the authorizedUsers collection:
{
"email": "you@example.com",
"name": "Your Name",
"admin": true
}After that, admins can manage users from the panel.
src/
├── pages/
│ ├── index.tsx # Public GIF/video player
│ ├── panel.tsx # Sign-in page
│ ├── panel/
│ │ ├── home.tsx # Upload/update media
│ │ ├── logs.tsx # Activity log viewer
│ │ ├── users.tsx # User management (admins only)
│ │ └── Header.tsx # Panel navigation
│ ├── components/
│ │ └── SignIn/SignInPage.tsx
│ └── api/
│ ├── auth/[...nextauth].js
│ ├── getConfig.js # Fetch current media config
│ ├── updateSource.js # Update media source
│ ├── getLogs.js # Activity logs
│ ├── getUsers.js # List users
│ ├── manageUserObjects.js # Create/delete users
│ └── lib/database.js # MongoDB connection
├── hooks/
│ └── useKeyboardShortcut.ts
├── middleware.ts # Route protection
└── styles/globals.css
| Shortcut | Action |
|---|---|
Ctrl+P |
Toggle between player and panel |
Ctrl+L |
Toggle easter egg image |
config — Stores the current media source:
{
"id": "main",
"player": {
"source": "https://...",
"type": "image"
}
}authorizedUsers — Whitelisted users:
{
"email": "user@mtu.edu",
"name": "Display Name",
"admin": false
}logs — Activity log (auto-deleted after 7 days):
{
"date": "1234567890",
"name": "User Name",
"type": "image",
"url": "https://...",
"expireDate": "1234567890"
}