Skip to content
This repository was archived by the owner on Oct 19, 2024. It is now read-only.

Commit 5d53188

Browse files
authored
Merge pull request #269 from Dino-Kupinic/develop
v0.15.0
2 parents 247390b + a5c145d commit 5d53188

File tree

11 files changed

+555
-275
lines changed

11 files changed

+555
-275
lines changed

backend/src/Controller/YearController.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ public function getYearsForImport(YearService $yearsService): Response
121121
* )
122122
* )
123123
*/
124-
#[Route(path: "/{id}", name: "index", methods: ["GET"])]
124+
#[Route(path: "/{id}", name: "select", methods: ["GET"])]
125125
public function getYear(YearService $yearsService, int $id): Response
126126
{
127127
$context = (new ObjectNormalizerContextBuilder())

backend/src/DataFixtures/SchoolClassFixture.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public function load(ObjectManager $manager): void
2323
$schoolClass->setRepetents(2);
2424
$schoolClass->setBudget(500);
2525
$schoolClass->setUsedBudget(250);
26+
$schoolClass->setRepetents(2);
2627
$manager->persist($schoolClass);
2728
$this->addReference('schoolClass ' . $i, $schoolClass);
2829
}

frontend/components/data-table/BookOrderTable.vue

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
import type { BookOrder } from "~/types/bookorder"
88
import type { Book } from "~/types/book"
99
import type { Department } from "~/types/department"
10+
import type { SchoolClass } from "~/types/schoolclass"
1011
1112
const columns = ref([
1213
{
@@ -71,7 +72,7 @@ const items = (row: BookOrder) => [
7172
],
7273
[
7374
{
74-
label: t("orderList.deleteOrder.delete"),
75+
label: t("actions.delete"),
7576
slot: "delete",
7677
icon: "i-heroicons-trash-20-solid",
7778
click: () => {
@@ -220,7 +221,7 @@ const { data: books } = await useLazyFetch<APIResponsePaginated<Book>>(
220221
},
221222
)
222223
223-
const { data: schoolClasses } = await useLazyFetch<APIResponse<Department[]>>(
224+
const { data: schoolClasses } = await useLazyFetch<APIResponse<SchoolClass[]>>(
224225
"/schoolClasses",
225226
{
226227
baseURL: config.public.baseURL,

frontend/components/data-table/BookOverviewTable.vue

Lines changed: 248 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
<script setup lang="ts">
22
import type { Book } from "~/types/book"
3-
import type { APIResponsePaginated } from "~/types/response"
3+
import type { APIResponseArray, APIResponsePaginated } from "~/types/response"
4+
import type { SchoolClass } from "~/types/schoolclass"
5+
import type { BookOrderDTO } from "~/types/bookorder"
6+
import { z } from "zod"
7+
import type { FormSubmitEvent } from "#ui/types"
8+
import type { Year } from "~/types/year"
9+
10+
const { t, locale } = useI18n()
411
512
const columns = ref([
613
{
@@ -42,6 +49,58 @@ const columns = ref([
4249
key: "actions",
4350
},
4451
])
52+
53+
watch(
54+
locale,
55+
() => {
56+
columns.value = [
57+
{
58+
key: "orderNumber",
59+
label: t("book.orderNumber"),
60+
sortable: true,
61+
},
62+
{
63+
key: "title",
64+
label: t("book.title"),
65+
sortable: true,
66+
},
67+
{
68+
key: "publisher",
69+
label: t("book.publisher"),
70+
sortable: true,
71+
},
72+
{
73+
key: "subject",
74+
label: t("book.subject"),
75+
sortable: true,
76+
},
77+
{
78+
key: "grade",
79+
label: t("book.grade"),
80+
sortable: true,
81+
},
82+
{
83+
key: "ebook",
84+
label: t("book.ebook"),
85+
sortable: true,
86+
},
87+
{
88+
key: "ebookPlus",
89+
label: t("book.ebookPlus"),
90+
sortable: true,
91+
},
92+
{
93+
key: "bookPrice",
94+
label: t("book.price"),
95+
sortable: true,
96+
},
97+
{
98+
key: "actions",
99+
},
100+
]
101+
},
102+
{ immediate: true },
103+
)
45104
const columnsBackup = ref(columns.value)
46105
const config = useRuntimeConfig()
47106
@@ -136,59 +195,101 @@ function resetFilters() {
136195
selectedColumns.value = columnsBackup.value
137196
}
138197
139-
const { t, locale } = useI18n()
198+
const { data: schoolClasses, pending: schoolClassesPending } =
199+
await useLazyFetch<APIResponseArray<SchoolClass>>("/schoolClasses", {
200+
baseURL: config.public.baseURL,
201+
pick: ["data"],
202+
})
140203
141-
watch(
142-
locale,
143-
() => {
144-
columns.value = [
145-
{
146-
key: "orderNumber",
147-
label: t("book.orderNumber"),
148-
sortable: true,
149-
},
150-
{
151-
key: "title",
152-
label: t("book.title"),
153-
sortable: true,
154-
},
155-
{
156-
key: "publisher",
157-
label: t("book.publisher"),
158-
sortable: true,
159-
},
160-
{
161-
key: "subject",
162-
label: t("book.subject"),
163-
sortable: true,
164-
},
165-
{
166-
key: "grade",
167-
label: t("book.grade"),
168-
sortable: true,
169-
},
170-
{
171-
key: "ebook",
172-
label: t("book.ebook"),
173-
sortable: true,
174-
},
175-
{
176-
key: "ebookPlus",
177-
label: t("book.ebookPlus"),
178-
sortable: true,
179-
},
180-
{
181-
key: "bookPrice",
182-
label: t("book.price"),
183-
sortable: true,
184-
},
185-
{
186-
key: "actions",
187-
},
188-
]
189-
},
190-
{ immediate: true },
191-
)
204+
const isVisible = ref(false)
205+
206+
const teacherCopy = ref<boolean>(false)
207+
208+
const schema = z.object({
209+
schoolClass: z.object({
210+
id: z.number(),
211+
name: z.string(),
212+
grade: z.number(),
213+
students: z.number(),
214+
repetents: z.number(),
215+
budget: z.number(),
216+
usedBudget: z.number(),
217+
}),
218+
repetents: z.string(),
219+
teacherCopy: z.boolean(),
220+
})
221+
222+
type Schema = z.output<typeof schema>
223+
224+
const state = reactive({
225+
schoolClass: undefined,
226+
repetents: undefined,
227+
teacherCopy: undefined,
228+
})
229+
230+
const { data: years } = await useLazyFetch<APIResponseArray<Year>>("/years", {
231+
baseURL: config.public.baseURL,
232+
})
233+
234+
async function addBookOrder(event: FormSubmitEvent<Schema>) {
235+
if (years.value == null || years.value.data == undefined) {
236+
return
237+
}
238+
239+
const bookOrders: BookOrderDTO[] = []
240+
241+
selectedRows.value.forEach((row) => {
242+
let count = 0
243+
244+
switch (event.data.repetents) {
245+
case "With":
246+
count =
247+
event.data.schoolClass.students + event.data.schoolClass.repetents
248+
break
249+
case "Without":
250+
count = event.data.schoolClass.students
251+
break
252+
case "Only":
253+
count = event.data.schoolClass.repetents
254+
break
255+
}
256+
257+
if (event.data.teacherCopy) count++
258+
259+
bookOrders.push({
260+
count: count,
261+
teacherCopy: event.data.teacherCopy,
262+
schoolClass: event.data.schoolClass.id,
263+
book: row.id,
264+
year: row.year.id,
265+
lastUser: "User 0",
266+
creationUser: "User 0",
267+
})
268+
})
269+
270+
for (const bookOrder of bookOrders) {
271+
await $fetch("bookOrders/create", {
272+
method: "POST",
273+
body: bookOrder,
274+
baseURL: config.public.baseURL,
275+
})
276+
}
277+
isVisible.value = false
278+
279+
const toast = useToast()
280+
281+
toast.add({
282+
title: t("bookList.order.success"),
283+
description: t("bookList.order.successDescription"),
284+
icon: "i-heroicons-check-circle",
285+
})
286+
}
287+
288+
const repententOptions = [
289+
{ label: "With", value: 1 },
290+
{ label: "Without", value: 2 },
291+
{ label: "Only", value: 3 },
292+
]
192293
</script>
193294

194295
<template>
@@ -215,6 +316,13 @@ watch(
215316
icon="i-heroicons-magnifying-glass-20-solid"
216317
:placeholder="$t('bookList.searchForBooks')"
217318
/>
319+
<UButton
320+
label="Order"
321+
class="ml-2"
322+
size="md"
323+
:disabled="selectedRows.length === 0"
324+
@click="isVisible = true"
325+
/>
218326
</div>
219327

220328
<div class="flex items-center gap-2">
@@ -260,7 +368,7 @@ watch(
260368
:progress="{ color: 'primary', animation: 'carousel' }"
261369
:columns="columnsTable"
262370
:ui="{
263-
wrapper: 'relative overflow-x-auto h-[500px] overflow-y-auto',
371+
wrapper: 'relative overflow-x-auto h-[450px] overflow-y-auto',
264372
td: {
265373
padding: 'py-1',
266374
},
@@ -374,4 +482,90 @@ watch(
374482
</div>
375483
</template>
376484
</UCard>
485+
<UModal v-model="isVisible" class="bg-opacity-0">
486+
<UCard>
487+
<template #header>
488+
<div class="flex items-center">
489+
<span
490+
class="text-base font-semibold leading-6 text-red-600 dark:text-white"
491+
>
492+
Ordering
493+
</span>
494+
<UButton
495+
color="gray"
496+
variant="ghost"
497+
icon="i-heroicons-x-mark-20-solid"
498+
class="ml-auto"
499+
@click="isVisible = false"
500+
/>
501+
</div>
502+
</template>
503+
<h1>Books</h1>
504+
<UTable
505+
class="mb-4 rounded-lg border-2"
506+
:rows="selectedRows"
507+
:loading-state="{
508+
icon: 'i-heroicons-arrow-path-20-solid',
509+
label: 'Loading...',
510+
}"
511+
:loading="pending"
512+
:progress="{ color: 'primary', animation: 'carousel' }"
513+
:columns="[
514+
{
515+
key: 'title',
516+
},
517+
]"
518+
:ui="{
519+
wrapper: 'relative overflow-x-auto h-[150px] overflow-y-auto',
520+
td: {
521+
padding: 'py-1',
522+
},
523+
th: {
524+
base: 'hidden',
525+
},
526+
}"
527+
/>
528+
529+
<UForm
530+
:schema="schema"
531+
:state="state"
532+
class="space-y-4"
533+
@submit="addBookOrder"
534+
>
535+
<UFormGroup label="Class" name="schoolClass">
536+
<USelectMenu
537+
v-if="!schoolClassesPending"
538+
v-model="state.schoolClass"
539+
placeholder="Select a class"
540+
:options="schoolClasses?.data"
541+
option-attribute="name"
542+
searchable
543+
/>
544+
</UFormGroup>
545+
546+
<UFormGroup label="Repetents" name="repetents">
547+
<USelectMenu
548+
v-model="state.repetents"
549+
class="mt-4"
550+
placeholder="Order for repetents"
551+
:options="repententOptions"
552+
option-attribute="label"
553+
value-attribute="label"
554+
/>
555+
</UFormGroup>
556+
557+
<UFormGroup label="Teacher copy" name="teacherCopy">
558+
<UCheckbox
559+
v-model="state.teacherCopy"
560+
class="mt-4"
561+
color="blue"
562+
label="Teacher copy"
563+
help="Get an extra copy for the teacher"
564+
/>
565+
</UFormGroup>
566+
567+
<UButton type="submit"> Submit</UButton>
568+
</UForm>
569+
</UCard>
570+
</UModal>
377571
</template>

0 commit comments

Comments
 (0)