Initialize HemHub project foundation

This commit is contained in:
Urban Modig
2026-07-23 22:06:56 +02:00
commit 9957383e88
23 changed files with 2430 additions and 0 deletions

13
frontend/index.html Normal file
View File

@ -0,0 +1,13 @@
<!doctype html>
<html lang="sv">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>HemHub</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

27
frontend/package.json Normal file
View File

@ -0,0 +1,27 @@
{
"name": "hemhub-frontend",
"private": true,
"version": "0.0.1",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"test": "vitest run"
},
"dependencies": {
"react": "19.2.8",
"react-dom": "19.2.8"
},
"devDependencies": {
"@testing-library/jest-dom": "7.0.0",
"@testing-library/react": "16.3.2",
"@types/react": "19.2.17",
"@types/react-dom": "19.2.3",
"@vitejs/plugin-react": "6.0.4",
"jsdom": "29.1.1",
"typescript": "7.0.2",
"vite": "8.1.5",
"vitest": "4.1.10"
},
"packageManager": "pnpm@11.17.0"
}

1567
frontend/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

21
frontend/src/App.test.tsx Normal file
View File

@ -0,0 +1,21 @@
import { render, screen } from '@testing-library/react'
import { afterEach, expect, test, vi } from 'vitest'
import App from './App'
afterEach(() => {
vi.restoreAllMocks()
})
test('visar sidans rubrik', () => {
vi.spyOn(globalThis, 'fetch').mockResolvedValue(
new Response(JSON.stringify({ status: 'UP' }), {
status: 200,
headers: { 'Content-Type': 'application/json' },
}),
)
render(<App />)
expect(screen.getByRole('heading', { name: 'HemHub' })).toBeInTheDocument()
})

48
frontend/src/App.tsx Normal file
View File

@ -0,0 +1,48 @@
import { useEffect, useState } from 'react'
type HealthResponse = {
status: string
}
function App() {
const [backendStatus, setBackendStatus] = useState<string | null>(null)
const [hasError, setHasError] = useState(false)
useEffect(() => {
const loadHealth = async () => {
try {
const response = await fetch('/api/health')
if (!response.ok) {
throw new Error(`Backend svarade med status ${response.status}`)
}
const health = (await response.json()) as HealthResponse
setBackendStatus(health.status)
} catch {
setHasError(true)
}
}
void loadHealth()
}, [])
let statusMessage = 'Kontrollerar backend…'
if (hasError) {
statusMessage = 'Backend kunde inte nås'
} else if (backendStatus) {
statusMessage = `Backend: ${backendStatus}`
}
return (
<main>
<h1>HemHub</h1>
<p>Frontend har startat.</p>
<p aria-live="polite">{statusMessage}</p>
</main>
)
}
export default App

11
frontend/src/main.tsx Normal file
View File

@ -0,0 +1,11 @@
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App'
import './styles.css'
createRoot(document.getElementById('root')!).render(
<StrictMode>
<App />
</StrictMode>,
)

23
frontend/src/styles.css Normal file
View File

@ -0,0 +1,23 @@
:root {
font-family: system-ui, sans-serif;
color: #1f2937;
background: #f3f4f6;
}
body {
margin: 0;
}
main {
max-width: 40rem;
margin: 6rem auto;
padding: 2rem;
border-radius: 0.75rem;
background: white;
box-shadow: 0 0.25rem 1rem rgb(0 0 0 / 8%);
}
h1 {
margin-top: 0;
}

View File

@ -0,0 +1,2 @@
import '@testing-library/jest-dom/vitest'

1
frontend/src/vite-env.d.ts vendored Normal file
View File

@ -0,0 +1 @@
/// <reference types="vite/client" />

View File

@ -0,0 +1,22 @@
{
"compilerOptions": {
"target": "ES2022",
"useDefineForClassFields": true,
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"allowJs": false,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"types": ["vitest/globals", "@testing-library/jest-dom"]
},
"include": ["src"]
}

8
frontend/tsconfig.json Normal file
View File

@ -0,0 +1,8 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}

View File

@ -0,0 +1,12 @@
{
"compilerOptions": {
"composite": true,
"skipLibCheck": true,
"module": "ESNext",
"moduleResolution": "Bundler",
"allowImportingTsExtensions": true,
"noEmit": true
},
"include": ["vite.config.ts"]
}

16
frontend/vite.config.ts Normal file
View File

@ -0,0 +1,16 @@
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vitest/config'
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
proxy: {
'/api': 'http://localhost:8080',
},
},
test: {
environment: 'jsdom',
setupFiles: './src/test/setup.ts',
},
})