Initial commit of testapi

This commit is contained in:
2025-06-20 13:33:07 +02:00
commit a455aba1d5
377 changed files with 30566 additions and 0 deletions
@@ -0,0 +1,83 @@
<script setup lang="ts">
import AppLayout from '@/layouts/AppLayout.vue';
import { type BreadcrumbItem } from '@/types';
import { Head, Link, useForm } from '@inertiajs/vue3';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { Plus } from 'lucide-vue-next';
const form = useForm({
username: '',
name: '',
});
const breadcrumbs: BreadcrumbItem[] = [
{ title: 'Dashbord', href: '/dashboard' },
{ title: 'Brukere', href: '/smartdok/profiles' },
{ title: 'Opprett', href: '/smartdok/profiles/create' },
];
function submit() {
form.post(route('smartdok.profiles.store'), {
onSuccess: () => {
// Optionally reset or navigate; Inertia will handle redirect
},
});
}
</script>
<template>
<Head title="Opprett bruker" />
<AppLayout :breadcrumbs="breadcrumbs">
<div class="mb-6 flex items-center justify-between p-6">
<h3 class="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-3xl">
Opprett bruker
</h3>
</div>
<div class="flex justify-center items-center">
<form @submit.prevent="submit" class="space-y-6 min-w-2xl lg:min-w-3xl xl:min-w-4xl">
<!-- Brukernavn -->
<div>
<Label for="username">Brukernavn:</Label>
<Input
id="username"
v-model="form.username"
type="text"
placeholder="Skriv inn brukernavn"
class="mt-2"
/>
<p v-if="form.errors.username" class="mt-1 text-sm text-red-600">
{{ form.errors.username }}
</p>
</div>
<!-- Navn -->
<div>
<Label for="name">Navn:</Label>
<Input
id="name"
v-model="form.name"
type="text"
placeholder="Skriv inn fullt navn"
class="mt-2"
/>
<p v-if="form.errors.name" class="mt-1 text-sm text-red-600">
{{ form.errors.name }}
</p>
</div>
<!-- Actions -->
<div class="flex items-center justify-end space-x-4">
<Link href="/smartdok/profiles">
<Button variant="outline">
Avbryt
</Button>
</Link>
<Button type="submit" :disabled="form.processing">
Opprett
</Button>
</div>
</form>
</div>
</AppLayout>
</template>
@@ -0,0 +1,99 @@
<script setup lang="ts">
import { computed } from 'vue';
import AppLayout from '@/layouts/AppLayout.vue';
import { type BreadcrumbItem } from '@/types';
import { Head, Link, usePage, useForm } from '@inertiajs/vue3';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
interface Profile {
id: string
username: string
name: string
};
// Grab the Inertia page props
const page = usePage<{ profile: Profile }>();
// Reactive profile object
const profile = computed(() => page.props.profile);
// Setup the form with existing values
const form = useForm({
username: profile.value.username,
name: profile.value.name,
});
const breadcrumbs: BreadcrumbItem[] = [
{ title: 'Dashbord', href: '/dashboard' },
{ title: 'Brukere', href: '/smartdok/profiles' },
{ title: 'Rediger', href: route('smartdok.profiles.edit', profile.value.id) },
];
function submit() {
form.put(
route('smartdok.profiles.update', profile.value.id),
{ onSuccess: () => {/* Inertia redirect back to index */} }
);
}
</script>
<template>
<Head title="Rediger bruker" />
<AppLayout :breadcrumbs="breadcrumbs">
<div class="p-6 space-y-8">
<!-- Header and actions -->
<div class="flex items-center justify-between">
<h3 class="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-3xl">
Rediger bruker
</h3>
</div>
<div class="flex justify-center items-center">
<!-- Edit form -->
<form @submit.prevent="submit" class="space-y-6 min-w-2xl lg:min-w-3xl xl:min-w-4xl">
<div>
<Label for="username">Brukernavn:</Label>
<Input
id="username"
v-model="form.username"
type="text"
placeholder="Skriv inn brukernavn"
class="mt-2"
/>
<p v-if="form.errors.username" class="mt-1 text-sm text-red-600">
{{ form.errors.username }}
</p>
</div>
<div>
<Label for="name">Navn:</Label>
<Input
id="name"
v-model="form.name"
type="text"
placeholder="Skriv inn fullt navn"
class="mt-2"
/>
<p v-if="form.errors.name" class="mt-1 text-sm text-red-600">
{{ form.errors.name }}
</p>
</div>
<!-- Actions -->
<div class="flex items-center justify-end space-x-4">
<Link :href="route('smartdok.profiles.index')">
<Button variant="outline">
Avbryt
</Button>
</Link>
<Button type="submit" :disabled="form.processing">
Oppdater
</Button>
</div>
</form>
</div>
</div>
</AppLayout>
</template>
@@ -0,0 +1,110 @@
<script setup lang="ts">
import { computed } from 'vue';
import AppLayout from '@/layouts/AppLayout.vue';
import { type BreadcrumbItem } from '@/types';
import { Head, Link, usePage } from '@inertiajs/vue3';
import {
Table,
TableBody,
TableCaption,
TableCell,
TableHead,
TableHeader,
TableRow,
} from '@/components/ui/table';
import { Button } from '@/components/ui/button';
import { Plus } from 'lucide-vue-next';
import UserProfileDropdown from './UserProfileDropdown.vue';
interface Profile {
id: string
username: string
name: string
};
const page = usePage<{
profiles: {
data: Profile[]
current_page: number
last_page: number
per_page: number
total: number
}
}>();
// Reactive list of profiles
const profiles = computed(() => page.props.profiles.data);
const breadcrumbs: BreadcrumbItem[] = [
{ title: 'Dashbord', href: '/dashboard' },
{ title: 'Brukere', href: '/smartdok/profiles' },
];
// pagination meta
const currentPage = computed(() => page.props.profiles.current_page);
const lastPage = computed(() => page.props.profiles.last_page);
const prevPage = computed(() => currentPage.value > 1 ? currentPage.value - 1 : 1);
const nextPage = computed(() => currentPage.value < lastPage.value ? currentPage.value + 1 : lastPage.value);
</script>
<template>
<Head title="Brukere" />
<AppLayout :breadcrumbs="breadcrumbs">
<div class="mb-6 flex items-center justify-between p-6">
<h3 class="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-3xl">
Brukere
</h3>
<Link :href="route('smartdok.profiles.create')">
<Button variant="outline">
<Plus class="mr-2 h-4 w-4" />
Opprett
</Button>
</Link>
</div>
<div class="px-6 overflow-auto">
<Table>
<TableCaption>En liste over brukere.</TableCaption>
<TableHeader>
<TableRow>
<TableHead>Brukernavn</TableHead>
<TableHead>Navn</TableHead>
<TableHead class="text-right">Handlinger</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow v-for="profile in profiles" :key="profile.id">
<TableCell class="font-medium">{{ profile.username }}</TableCell>
<TableCell>{{ profile.name }}</TableCell>
<TableCell class="text-right">
<UserProfileDropdown :profile="profile" />
</TableCell>
</TableRow>
</TableBody>
</Table>
</div>
<!-- Pagination controls -->
<div class="flex items-center justify-between p-6">
<div class="text-sm text-gray-600">
Side {{ currentPage }} av {{ lastPage }} &middot;
Totalt {{ page.props.profiles.total }} brukere
</div>
<div class="space-x-2">
<Link :href="route('smartdok.profiles.index', { page: prevPage })">
<Button variant="outline" :disabled="currentPage === 1">
Forrige
</Button>
</Link>
<Link :href="route('smartdok.profiles.index', { page: nextPage })">
<Button variant="outline" :disabled="currentPage === lastPage">
Neste
</Button>
</Link>
</div>
</div>
</AppLayout>
</template>
@@ -0,0 +1,72 @@
<script setup lang="ts">
import { computed } from 'vue';
import AppLayout from '@/layouts/AppLayout.vue';
import { type BreadcrumbItem } from '@/types';
import { Head, Link, usePage } from '@inertiajs/vue3';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
interface Profile {
id: string
username: string
name: string
};
// Grab the Inertia page props
const page = usePage<{ profile: Profile }>();
// Reactive profile object
const profile = computed(() => page.props.profile);
// Breadcrumbs: Dashbord > Brukere > [username]
const breadcrumbs: BreadcrumbItem[] = [
{ title: 'Dashbord', href: '/dashboard' },
{ title: 'Brukere', href: '/smartdok/profiles' },
{ title: profile.value.username, href: route('smartdok.profiles.show', profile.value.id) },
];
</script>
<template>
<Head title="Vis bruker" />
<AppLayout :breadcrumbs="breadcrumbs">
<div class="p-6 space-y-8">
<!-- Heading and action buttons -->
<div class="flex items-center justify-between">
<h3 class="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-3xl">
Vis bruker
</h3>
<div class="flex space-x-2">
<Link :href="route('smartdok.profiles.index')">
<Button variant="outline">Tilbake</Button>
</Link>
<Link :href="route('smartdok.profiles.edit', profile.id)">
<Button>Rediger</Button>
</Link>
</div>
</div>
<!-- Profile details -->
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div>
<Label for="username">ID</Label>
<p id="username" class="mt-1 text-base">
{{ profile.id }}
</p>
</div>
<div>
<Label for="username">Brukernavn</Label>
<p id="username" class="mt-1 text-base">
{{ profile.username }}
</p>
</div>
<div>
<Label for="name">Navn</Label>
<p id="name" class="mt-1 text-base">
{{ profile.name }}
</p>
</div>
</div>
</div>
</AppLayout>
</template>
@@ -0,0 +1,92 @@
<script setup lang="ts">
import { Button } from '@/components/ui/button';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuLabel,
DropdownMenuSeparator,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { MoreHorizontal } from 'lucide-vue-next';
import {
AlertDialog,
AlertDialogTrigger,
AlertDialogContent,
AlertDialogHeader,
AlertDialogTitle,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogCancel,
AlertDialogAction,
} from '@/components/ui/alert-dialog';
import { Link } from '@inertiajs/vue3';
defineProps<{
profile: {
id: string
}
}>();
function copy(id: string) {
navigator.clipboard.writeText(id);
}
</script>
<template>
<DropdownMenu>
<DropdownMenuTrigger as-child>
<Button variant="ghost" class="w-8 h-8 p-0">
<span class="sr-only">Åpne meny</span>
<MoreHorizontal class="w-4 h-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
<DropdownMenuLabel>Handlinger</DropdownMenuLabel>
<DropdownMenuItem @click="copy(profile.id)">
Kopier ID
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem as-child>
<Link :href="route('smartdok.profiles.show', profile.id)">Vis profil</Link>
</DropdownMenuItem>
<DropdownMenuItem as-child>
<Link :href="route('smartdok.profiles.edit', profile.id)">Rediger</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<AlertDialog>
<AlertDialogTrigger asChild>
<DropdownMenuItem
className="text-red-600 rounded-sm hover:!bg-zinc-800 cursor-pointer flex items-center py-1 px-2"
:onSelect="(e) => e.preventDefault()"
>Slett</DropdownMenuItem>
</AlertDialogTrigger>
<!-- Confirmation dialog -->
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Er du sikker på at du vil slette denne brukeren?</AlertDialogTitle>
<AlertDialogDescription>
Denne handlingen kan ikke angres.
</AlertDialogDescription>
</AlertDialogHeader>
<AlertDialogFooter>
<AlertDialogCancel>Avbryt</AlertDialogCancel>
<AlertDialogAction as-child>
<Link
method="delete"
:href="route('smartdok.profiles.destroy', profile.id)"
class="text-red-600"
as="button"
>
Slett
</Link>
</AlertDialogAction>
</AlertDialogFooter>
</AlertDialogContent>
</AlertDialog>
</DropdownMenuContent>
</DropdownMenu>
</template>