feat(frontend): Prettier, add openapi client generation

This commit is contained in:
2025-02-21 12:17:36 +01:00
parent d6effcd1d5
commit 31ff737221
20 changed files with 3840 additions and 4861 deletions

3
.gitignore vendored
View File

@@ -56,3 +56,6 @@ bin/
### Kotlin ### ### Kotlin ###
.kotlin .kotlin
### OpenAPI ###
.api-client

View File

@@ -3,3 +3,4 @@ build
coverage coverage
.nuxt .nuxt
.output .output
.api-client

View File

@@ -1 +1,6 @@
{} {
"trailingComma": "none",
"semi": false,
"singleQuote": true,
"printWidth": 120
}

View File

@@ -0,0 +1,3 @@
import { ApplicationFormApi } from '#build/.api-client'
export const applicationFormApiClient = new ApplicationFormApi()

View File

@@ -1,8 +1,8 @@
export default defineAppConfig({ export default defineAppConfig({
ui: { ui: {
colors: { colors: {
primary: "green", primary: 'green',
neutral: "zinc", neutral: 'zinc'
}, }
}, }
}); })

View File

@@ -9,35 +9,32 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const colorMode = useColorMode(); const colorMode = useColorMode()
const color = computed(() => const color = computed(() => (colorMode.value === 'dark' ? '#111827' : 'white'))
colorMode.value === "dark" ? "#111827" : "white",
);
useHead({ useHead({
meta: [ meta: [
{ charset: "utf-8" }, { charset: 'utf-8' },
{ name: "viewport", content: "width=device-width, initial-scale=1" }, { name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ key: "theme-color", name: "theme-color", content: color }, { key: 'theme-color', name: 'theme-color', content: color }
], ],
link: [{ rel: "icon", href: "/favicon.ico" }], link: [{ rel: 'icon', href: '/favicon.ico' }],
htmlAttrs: { htmlAttrs: {
lang: "en", lang: 'en'
}, }
}); })
const title = "LegalConsentHub"; const title = 'LegalConsentHub'
const description = const description = 'Das Tool für die Einführung von mitbestimmungspflichtigen digitalen Lösungen.'
"Das Tool für die Einführung von mitbestimmungspflichtigen digitalen Lösungen.";
useSeoMeta({ useSeoMeta({
title, title,
description, description,
ogTitle: title, ogTitle: title,
ogDescription: description, ogDescription: description,
ogImage: "https://dashboard-template.nuxt.dev/social-card.png", ogImage: 'https://dashboard-template.nuxt.dev/social-card.png',
twitterImage: "https://dashboard-template.nuxt.dev/social-card.png", twitterImage: 'https://dashboard-template.nuxt.dev/social-card.png',
twitterCard: "summary_large_image", twitterCard: 'summary_large_image'
}); })
</script> </script>

View File

@@ -1,2 +1,2 @@
@import "tailwindcss"; @import 'tailwindcss';
@import "@nuxt/ui-pro"; @import '@nuxt/ui-pro';

View File

@@ -9,12 +9,7 @@
<div class="form-group"> <div class="form-group">
<label for="password-login">Passwort:</label> <label for="password-login">Passwort:</label>
<input <input type="password" id="password-login" v-model="password" required />
type="password"
id="password-login"
v-model="password"
required
/>
</div> </div>
<button type="submit">Login</button> <button type="submit">Login</button>
@@ -23,34 +18,34 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref } from 'vue'
const email = ref(""); const email = ref('')
const password = ref(""); const password = ref('')
const handleLogin = () => { const handleLogin = () => {
if (!email.value || !password.value) { if (!email.value || !password.value) {
alert("Bitte alle Felder ausfüllen"); alert('Bitte alle Felder ausfüllen')
return; return
} }
authClient.signIn.email( authClient.signIn.email(
{ {
email: email.value, email: email.value,
password: password.value, password: password.value
}, },
{ {
onRequest: (ctx) => { onRequest: (ctx) => {
console.log("Sending login request", ctx); console.log('Sending login request', ctx)
}, },
onSuccess: (ctx) => { onSuccess: (ctx) => {
console.log("Successfully logged in!"); console.log('Successfully logged in!')
}, },
onError: (ctx) => { onError: (ctx) => {
console.log(ctx.error.message); console.log(ctx.error.message)
}, }
}, }
); )
}; }
</script> </script>
<style scoped> <style scoped>

View File

@@ -19,12 +19,7 @@
<div class="form-group"> <div class="form-group">
<label for="confirmPassword">Passwort bestätigen:</label> <label for="confirmPassword">Passwort bestätigen:</label>
<input <input type="password" id="confirmPassword" v-model="confirmPassword" required />
type="password"
id="confirmPassword"
v-model="confirmPassword"
required
/>
</div> </div>
<button type="submit">Registrieren</button> <button type="submit">Registrieren</button>
@@ -33,46 +28,41 @@
</template> </template>
<script setup> <script setup>
import { ref } from "vue"; import { ref } from 'vue'
const username = ref(""); const username = ref('')
const email = ref(""); const email = ref('')
const password = ref(""); const password = ref('')
const confirmPassword = ref(""); const confirmPassword = ref('')
const handleRegister = () => { const handleRegister = () => {
if ( if (!username.value || !email.value || !password.value || !confirmPassword.value) {
!username.value || alert('Bitte alle Felder ausfüllen')
!email.value || return
!password.value ||
!confirmPassword.value
) {
alert("Bitte alle Felder ausfüllen");
return;
} }
if (password.value !== confirmPassword.value) { if (password.value !== confirmPassword.value) {
alert("Passwörter stimmen nicht überein"); alert('Passwörter stimmen nicht überein')
return; return
} }
authClient.signUp.email( authClient.signUp.email(
{ {
email: email.value, email: email.value,
password: password.value, password: password.value,
name: username.value, name: username.value
}, },
{ {
onRequest: (ctx) => { onRequest: (ctx) => {
console.log("Sending register request", ctx); console.log('Sending register request', ctx)
}, },
onSuccess: (ctx) => { onSuccess: (ctx) => {
console.log("Successfully registered!"); console.log('Successfully registered!')
}, },
onError: (ctx) => { onError: (ctx) => {
console.log(ctx.error.message); console.log(ctx.error.message)
}, }
}, }
); )
}; }
</script> </script>
<style scoped> <style scoped>

View File

@@ -5,20 +5,20 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import type { NuxtError } from "#app"; import type { NuxtError } from '#app'
defineProps<{ defineProps<{
error: NuxtError; error: NuxtError
}>(); }>()
useSeoMeta({ useSeoMeta({
title: "Page not found", title: 'Page not found',
description: "We are sorry but this page could not be found.", description: 'We are sorry but this page could not be found.'
}); })
useHead({ useHead({
htmlAttrs: { htmlAttrs: {
lang: "en", lang: 'en'
}, }
}); })
</script> </script>

View File

@@ -1,6 +1,6 @@
import withNuxt from "./.nuxt/eslint.config.mjs"; import withNuxt from './.nuxt/eslint.config.mjs'
export default withNuxt(); export default withNuxt()
// your custom flat configs go here, for example: // your custom flat configs go here, for example:
// { // {
// files: ['**/*.ts', '**/*.tsx'], // files: ['**/*.ts', '**/*.tsx'],

View File

@@ -13,23 +13,11 @@
</template> </template>
<template #default="{ collapsed }"> <template #default="{ collapsed }">
<UDashboardSearchButton <UDashboardSearchButton :collapsed="collapsed" class="bg-transparent ring-(--ui-border)" />
:collapsed="collapsed"
class="bg-transparent ring-(--ui-border)"
/>
<UNavigationMenu <UNavigationMenu :collapsed="collapsed" :items="links[0]" orientation="vertical" />
:collapsed="collapsed"
:items="links[0]"
orientation="vertical"
/>
<UNavigationMenu <UNavigationMenu :collapsed="collapsed" :items="links[1]" orientation="vertical" class="mt-auto" />
:collapsed="collapsed"
:items="links[1]"
orientation="vertical"
class="mt-auto"
/>
</template> </template>
<template #footer="{ collapsed }"> <template #footer="{ collapsed }">
@@ -45,116 +33,115 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const route = useRoute(); const route = useRoute()
const toast = useToast(); const toast = useToast()
const links = [ const links = [
[ [
{ {
label: "Home", label: 'Home',
icon: "i-lucide-house", icon: 'i-lucide-house',
to: "/", to: '/'
}, },
{ {
label: "Inbox", label: 'Inbox',
icon: "i-lucide-inbox", icon: 'i-lucide-inbox',
to: "/inbox", to: '/inbox',
badge: "4", badge: '4'
}, },
{ {
label: "Customers", label: 'Customers',
icon: "i-lucide-users", icon: 'i-lucide-users',
to: "/customers", to: '/customers'
}, },
{ {
label: "Settings", label: 'Settings',
to: "/settings", to: '/settings',
icon: "i-lucide-settings", icon: 'i-lucide-settings',
defaultOpen: true, defaultOpen: true,
children: [ children: [
{ {
label: "General", label: 'General',
to: "/settings", to: '/settings',
exact: true, exact: true
}, },
{ {
label: "Members", label: 'Members',
to: "/settings/members", to: '/settings/members'
}, },
{ {
label: "Notifications", label: 'Notifications',
to: "/settings/notifications", to: '/settings/notifications'
}, },
{ {
label: "Security", label: 'Security',
to: "/settings/security", to: '/settings/security'
}, }
], ]
}, }
], ],
[ [
{ {
label: "Feedback", label: 'Feedback',
icon: "i-lucide-message-circle", icon: 'i-lucide-message-circle',
to: "https://github.com/nuxt-ui-pro/dashboard", to: 'https://github.com/nuxt-ui-pro/dashboard',
target: "_blank", target: '_blank'
}, },
{ {
label: "Help & Support", label: 'Help & Support',
icon: "i-lucide-info", icon: 'i-lucide-info',
to: "https://github.com/nuxt/ui-pro", to: 'https://github.com/nuxt/ui-pro',
target: "_blank", target: '_blank'
}, }
], ]
]; ]
const groups = computed(() => [ const groups = computed(() => [
{ {
id: "links", id: 'links',
label: "Go to", label: 'Go to',
items: links.flat(), items: links.flat()
}, },
{ {
id: "code", id: 'code',
label: "Code", label: 'Code',
items: [ items: [
{ {
id: "source", id: 'source',
label: "View page source", label: 'View page source',
icon: "i-simple-icons-github", icon: 'i-simple-icons-github',
to: `https://github.com/nuxt-ui-pro/dashboard/blob/v3/app/pages${route.path === "/" ? "/index" : route.path}.vue`, to: `https://github.com/nuxt-ui-pro/dashboard/blob/v3/app/pages${route.path === '/' ? '/index' : route.path}.vue`,
target: "_blank", target: '_blank'
}, }
], ]
}, }
]); ])
onMounted(async () => { onMounted(async () => {
const cookie = useCookie("cookie-consent"); const cookie = useCookie('cookie-consent')
if (cookie.value === "accepted") { if (cookie.value === 'accepted') {
return; return
} }
toast.add({ toast.add({
title: title: 'We use first-party cookies to enhance your experience on our website.',
"We use first-party cookies to enhance your experience on our website.",
duration: 0, duration: 0,
close: false, close: false,
actions: [ actions: [
{ {
label: "Accept", label: 'Accept',
color: "neutral", color: 'neutral',
variant: "outline", variant: 'outline',
onClick: () => { onClick: () => {
cookie.value = "accepted"; cookie.value = 'accepted'
}, }
}, },
{ {
label: "Opt out", label: 'Opt out',
color: "neutral", color: 'neutral',
variant: "ghost", variant: 'ghost'
}, }
], ]
}); })
}); })
</script> </script>

View File

@@ -1,6 +1,6 @@
export default defineNuxtConfig({ export default defineNuxtConfig({
modules: ["@nuxt/ui-pro", "@nuxt/eslint"], modules: ['@nuxt/ui-pro', '@nuxt/eslint'],
css: ["~/assets/css/main.css"], css: ['~/assets/css/main.css'],
devtools: { enabled: true }, devtools: { enabled: true },
compatibilityDate: "2024-11-01", compatibilityDate: '2024-11-01'
}); })

View File

@@ -0,0 +1,7 @@
{
"$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json",
"spaces": 2,
"generator-cli": {
"version": "7.11.0"
}
}

View File

@@ -11,6 +11,7 @@
"format": "prettier . --write", "format": "prettier . --write",
"lint": "eslint .", "lint": "eslint .",
"lint:fix": "eslint . --fix", "lint:fix": "eslint . --fix",
"api:generate": "openapi-generator-cli generate -i ../legalconsenthub-backend/api/legalconsenthub.yml -g typescript-fetch -o .api-client",
"fix:bettersqlite": "cd node_modules/better-sqlite3 && npx node-gyp rebuild && cd ../.." "fix:bettersqlite": "cd node_modules/better-sqlite3 && npx node-gyp rebuild && cd ../.."
}, },
"dependencies": { "dependencies": {
@@ -23,6 +24,7 @@
}, },
"devDependencies": { "devDependencies": {
"@nuxt/eslint": "^1.1.0", "@nuxt/eslint": "^1.1.0",
"@openapitools/openapi-generator-cli": "^2.16.3",
"@types/better-sqlite3": "^7.6.12", "@types/better-sqlite3": "^7.6.12",
"eslint": "^9.20.1", "eslint": "^9.20.1",
"prettier": "3.5.1", "prettier": "3.5.1",

View File

@@ -34,10 +34,8 @@
<template #body> <template #body>
<div> <div>
<pre>{{ session }}</pre> <pre>{{ session }}</pre>
<h1>{{ session.data ? "Du bist eingeloggt" : "Nicht eingeloggt" }}</h1> <h1>{{ session.data ? 'Du bist eingeloggt' : 'Nicht eingeloggt' }}</h1>
<button v-if="session?.data" @click="authClient.signOut()"> <button v-if="session?.data" @click="authClient.signOut()">Sign out</button>
Sign out
</button>
</div> </div>
<Register /> <Register />
<Login /> <Login />
@@ -50,26 +48,26 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
const session = authClient.useSession(); const session = authClient.useSession()
const items = [ const items = [
[ [
{ {
label: "New mail", label: 'New mail',
icon: "i-lucide-send", icon: 'i-lucide-send',
to: "/inbox", to: '/inbox'
}, },
{ {
label: "New customer", label: 'New customer',
icon: "i-lucide-user-plus", icon: 'i-lucide-user-plus',
to: "/customers", to: '/customers'
}, }
], ]
]; ]
const range = shallowRef({ const range = shallowRef({
start: new Date(), start: new Date(),
end: new Date(), end: new Date()
}); })
const period = ref<string>("daily"); const period = ref<string>('daily')
</script> </script>

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
import { auth } from "../../utils/auth"; import { auth } from '../../utils/auth'
import { H3Event } from "h3"; import { H3Event } from 'h3'
export default defineEventHandler((event: H3Event) => { export default defineEventHandler((event: H3Event) => {
return auth.handler(toWebRequest(event)); return auth.handler(toWebRequest(event))
}); })

View File

@@ -1,11 +1,11 @@
import { betterAuth } from "better-auth"; import { betterAuth } from 'better-auth'
import Database from "better-sqlite3"; import Database from 'better-sqlite3'
export const auth = betterAuth({ export const auth = betterAuth({
database: new Database("./sqlite.db"), database: new Database('./sqlite.db'),
emailAndPassword: { enabled: true, autoSignIn: false }, emailAndPassword: { enabled: true, autoSignIn: false },
user: { modelName: "better_auth_user" }, user: { modelName: 'better_auth_user' },
session: { modelName: "better_auth_session" }, session: { modelName: 'better_auth_session' },
account: { modelName: "better_auth_account" }, account: { modelName: 'better_auth_account' },
verification: { modelName: "better_auth_verification" }, verification: { modelName: 'better_auth_verification' }
}); })

View File

@@ -1,5 +1,5 @@
import { createAuthClient } from "better-auth/vue"; import { createAuthClient } from 'better-auth/vue'
export const authClient = createAuthClient({ export const authClient = createAuthClient({
baseURL: "http://localhost:3000", baseURL: 'http://localhost:3000'
}); })