eksplicit mapping af envs
Some checks failed
Backend CI / test (push) Has been cancelled
Flutter CI / analyze-and-test (push) Has been cancelled

This commit is contained in:
Henrik Jess Nielsen
2026-05-12 18:21:25 +02:00
parent b7a435f8b9
commit 99e9b509a0
67 changed files with 8060 additions and 9 deletions

19
admin/Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
FROM node:20-alpine AS deps
WORKDIR /app
COPY package.json package-lock.json* ./
RUN npm ci
FROM node:20-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next/standalone ./
COPY --from=builder /app/.next/static ./.next/static
COPY --from=builder /app/public ./public
EXPOSE 3000
CMD ["node", "server.js"]

14
admin/README.md Normal file
View File

@@ -0,0 +1,14 @@
# admin
Next.js admin dashboard for Social Proximity. Anonymised stats only.
See [Docs/ADMIN.md](../Docs/ADMIN.md) for full documentation.
## Quick start
```bash
npm install
npm run dev
```
Runs on `localhost:3000`. Requires backend running on port 8000.

9
admin/next.config.js Normal file
View File

@@ -0,0 +1,9 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
output: "standalone",
env: {
API_URL: process.env.API_URL ?? "http://localhost:8000",
},
};
module.exports = nextConfig;

5324
admin/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
admin/package.json Normal file
View File

@@ -0,0 +1,24 @@
{
"name": "sighej-admin",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"next": "14.2.3",
"react": "^18.3.1",
"react-dom": "^18.3.1"
},
"devDependencies": {
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^5",
"eslint": "^8",
"eslint-config-next": "14.2.3"
}
}

0
admin/public/.gitkeep Normal file
View File

13
admin/src/app/layout.tsx Normal file
View File

@@ -0,0 +1,13 @@
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body style={{ fontFamily: "system-ui, sans-serif", padding: "2rem", maxWidth: 800, margin: "0 auto" }}>
<header style={{ marginBottom: "2rem" }}>
<h1 style={{ margin: 0 }}>SigHej · Admin</h1>
<p style={{ color: "#666", marginTop: 4 }}>Anonymised usage stats no personal data</p>
</header>
<main>{children}</main>
</body>
</html>
);
}

52
admin/src/app/page.tsx Normal file
View File

@@ -0,0 +1,52 @@
import { StatCard } from "@/components/StatCard";
interface StatsData {
active_sessions_now: number;
total_sessions_today: number;
total_matches_today: number;
top_interest_categories: string[];
}
async function fetchStats(): Promise<StatsData | null> {
try {
const res = await fetch(`${process.env.API_URL}/stats`, { next: { revalidate: 30 } });
if (!res.ok) return null;
return res.json();
} catch {
return null;
}
}
export default async function StatsPage() {
const stats = await fetchStats();
if (!stats) {
return <p> Could not reach backend. Is it running?</p>;
}
return (
<div>
<div
style={{
display: "grid",
gridTemplateColumns: "repeat(auto-fit, minmax(160px, 1fr))",
gap: "1rem",
marginBottom: "2rem",
}}
>
<StatCard label="Active sessions" value={stats.active_sessions_now} />
<StatCard label="Sessions today" value={stats.total_sessions_today} />
<StatCard label="Matches today" value={stats.total_matches_today} />
</div>
<section>
<h2>Top interest categories</h2>
<ol>
{stats.top_interest_categories.map((interest) => (
<li key={interest}>{interest}</li>
))}
</ol>
</section>
</div>
);
}

View File

@@ -0,0 +1,20 @@
interface StatCardProps {
label: string;
value: number | string;
}
export function StatCard({ label, value }: StatCardProps) {
return (
<div
style={{
border: "1px solid #e0e0e0",
borderRadius: 8,
padding: "1.5rem",
textAlign: "center",
}}
>
<div style={{ fontSize: "2rem", fontWeight: 700 }}>{value}</div>
<div style={{ color: "#666", marginTop: 4 }}>{label}</div>
</div>
);
}

23
admin/tsconfig.json Normal file
View File

@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "ES2017",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"plugins": [{ "name": "next" }],
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]
}