Initial commit of testapi
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
<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({
|
||||
name: '',
|
||||
});
|
||||
|
||||
const breadcrumbs: BreadcrumbItem[] = [
|
||||
{ title: 'Dashbord', href: '/dashboard' },
|
||||
{ title: 'Avdelinger', href: '/smartdok/departments' },
|
||||
{ title: 'Opprett', href: '/smartdok/departments/create' },
|
||||
];
|
||||
|
||||
function submit() {
|
||||
form.post(route('smartdok.departments.store'));
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head title="Opprett avdeling" />
|
||||
<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 avdeling
|
||||
</h3>
|
||||
</div>
|
||||
<div class="flex justify-center">
|
||||
<form
|
||||
@submit.prevent="submit"
|
||||
class="space-y-6 min-w-full sm:min-w-[400px] md:min-w-[600px] lg:min-w-[800px] p-6"
|
||||
>
|
||||
<!-- Navn -->
|
||||
<div>
|
||||
<Label for="name">Navn</Label>
|
||||
<Input
|
||||
id="name"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
placeholder="Skriv inn avdelingsnavn"
|
||||
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.departments.index')">
|
||||
<Button variant="outline">
|
||||
Avbryt
|
||||
</Button>
|
||||
</Link>
|
||||
<Button type="submit" :disabled="form.processing">
|
||||
Opprett
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,96 @@
|
||||
<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<{
|
||||
department: {
|
||||
id: number
|
||||
}
|
||||
}>();
|
||||
|
||||
function copy(id: number) {
|
||||
navigator.clipboard.writeText(id.toString());
|
||||
}
|
||||
</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(department.id)">
|
||||
Kopier ID
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem as-child>
|
||||
<Link :href="route('smartdok.departments.show', department.id)">
|
||||
Vis avdeling
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem as-child>
|
||||
<Link :href="route('smartdok.departments.edit', department.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 avdelingen?</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Denne handlingen kan ikke angres.
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Avbryt</AlertDialogCancel>
|
||||
<AlertDialogAction as-child>
|
||||
<Link
|
||||
method="delete"
|
||||
:href="route('smartdok.departments.destroy', department.id)"
|
||||
class="text-red-600"
|
||||
as="button"
|
||||
>
|
||||
Slett
|
||||
</Link>
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</template>
|
||||
@@ -0,0 +1,87 @@
|
||||
<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 Department {
|
||||
id: number
|
||||
name: string
|
||||
};
|
||||
|
||||
// Hent Inertia-props
|
||||
const page = usePage<{ department: Department }>();
|
||||
|
||||
// Reaktiv avdeling
|
||||
const department = computed(() => page.props.department);
|
||||
|
||||
// Sett opp skjema med eksisterende verdier
|
||||
const form = useForm({
|
||||
name: department.value.name,
|
||||
});
|
||||
|
||||
// Breadcrumbs (Dashbord > Avdelinger > Rediger)
|
||||
const breadcrumbs: BreadcrumbItem[] = [
|
||||
{ title: 'Dashbord', href: '/dashboard' },
|
||||
{ title: 'Avdelinger', href: '/smartdok/departments' },
|
||||
{
|
||||
title: 'Rediger',
|
||||
href: route('smartdok.departments.edit', department.value.id),
|
||||
},
|
||||
];
|
||||
|
||||
function submit() {
|
||||
form.put(
|
||||
route('smartdok.departments.update', department.value.id),
|
||||
{ onSuccess: () => { /* Inertia håndterer redirect */ } }
|
||||
);
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head title="Rediger avdeling" />
|
||||
<AppLayout :breadcrumbs="breadcrumbs">
|
||||
<div class="p-6 space-y-8">
|
||||
<!-- Header -->
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-3xl">
|
||||
Rediger avdeling
|
||||
</h3>
|
||||
</div>
|
||||
<!-- Centered form -->
|
||||
<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"
|
||||
>
|
||||
<!-- Navn -->
|
||||
<div>
|
||||
<Label for="name">Navn</Label>
|
||||
<Input
|
||||
id="name"
|
||||
v-model="form.name"
|
||||
type="text"
|
||||
placeholder="Skriv inn avdelingsnavn"
|
||||
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.departments.index')">
|
||||
<Button variant="outline">Avbryt</Button>
|
||||
</Link>
|
||||
<Button type="submit" :disabled="form.processing">
|
||||
Oppdater
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,121 @@
|
||||
<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 DepartmentDropdown from './DepartmentDropdown.vue';
|
||||
|
||||
interface Department {
|
||||
id: number
|
||||
name: string
|
||||
};
|
||||
|
||||
const page = usePage<{
|
||||
departments: {
|
||||
data: Department[]
|
||||
current_page: number
|
||||
last_page: number
|
||||
per_page: number
|
||||
total: number
|
||||
}
|
||||
}>();
|
||||
|
||||
// Reactive list of departments
|
||||
const departments = computed(() => page.props.departments.data);
|
||||
|
||||
// Breadcrumbs
|
||||
const breadcrumbs: BreadcrumbItem[] = [
|
||||
{ title: 'Dashbord', href: '/dashboard' },
|
||||
{ title: 'Avdelinger', href: '/smartdok/departments' },
|
||||
];
|
||||
|
||||
// Pagination meta
|
||||
const currentPage = computed(() => page.props.departments.current_page);
|
||||
const lastPage = computed(() => page.props.departments.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="Avdelinger" />
|
||||
<AppLayout :breadcrumbs="breadcrumbs">
|
||||
<!-- Header + Create-button -->
|
||||
<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">
|
||||
Avdelinger
|
||||
</h3>
|
||||
<Link :href="route('smartdok.departments.create')">
|
||||
<Button variant="outline">
|
||||
<Plus class="mr-2 h-4 w-4" />
|
||||
Opprett
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
<!-- Table -->
|
||||
<div class="px-6 overflow-auto">
|
||||
<Table>
|
||||
<TableCaption>En liste over avdelinger.</TableCaption>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Navn</TableHead>
|
||||
<TableHead class="text-right">Handlinger</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow
|
||||
v-for="dept in departments"
|
||||
:key="dept.id"
|
||||
>
|
||||
<TableCell class="font-medium">
|
||||
{{ dept.name }}
|
||||
</TableCell>
|
||||
<TableCell class="text-right">
|
||||
<DepartmentDropdown :department="dept" />
|
||||
</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 }} ·
|
||||
Totalt {{ page.props.departments.total }} avdelinger
|
||||
</div>
|
||||
<div class="space-x-2">
|
||||
<Link
|
||||
:href="route('smartdok.departments.index', { page: prevPage })"
|
||||
>
|
||||
<Button variant="outline" :disabled="currentPage === 1">
|
||||
Forrige
|
||||
</Button>
|
||||
</Link>
|
||||
<Link
|
||||
:href="route('smartdok.departments.index', { page: nextPage })"
|
||||
>
|
||||
<Button variant="outline" :disabled="currentPage === lastPage">
|
||||
Neste
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
@@ -0,0 +1,66 @@
|
||||
<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 Department {
|
||||
id: number
|
||||
name: string
|
||||
};
|
||||
|
||||
// Hent Inertia-props
|
||||
const page = usePage<{ department: Department }>();
|
||||
|
||||
// Reaktiv avdeling
|
||||
const department = computed(() => page.props.department);
|
||||
|
||||
// Breadcrumbs: Dashbord > Avdelinger > [navn]
|
||||
const breadcrumbs: BreadcrumbItem[] = [
|
||||
{ title: 'Dashbord', href: '/dashboard' },
|
||||
{ title: 'Avdelinger', href: '/smartdok/departments' },
|
||||
{
|
||||
title: department.value.name,
|
||||
href: route('smartdok.departments.show', department.value.id),
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Head title="Vis avdeling" />
|
||||
<AppLayout :breadcrumbs="breadcrumbs">
|
||||
<div class="p-6 space-y-8">
|
||||
<!-- Overskrift + handlinger -->
|
||||
<div class="flex items-center justify-between">
|
||||
<h3 class="scroll-m-20 text-2xl font-extrabold tracking-tight lg:text-3xl">
|
||||
Vis avdeling
|
||||
</h3>
|
||||
<div class="flex space-x-2">
|
||||
<Link :href="route('smartdok.departments.index')">
|
||||
<Button variant="outline">Tilbake</Button>
|
||||
</Link>
|
||||
<Link :href="route('smartdok.departments.edit', department.id)">
|
||||
<Button>Rediger</Button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Avdelingsdetaljer -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<Label for="id">ID</Label>
|
||||
<p id="id" class="mt-1 text-base">
|
||||
{{ department.id }}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label for="name">Navn</Label>
|
||||
<p id="name" class="mt-1 text-base">
|
||||
{{ department.name }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</AppLayout>
|
||||
</template>
|
||||
Reference in New Issue
Block a user