#22 - wip
This commit is contained in:
parent
26a6d81dc2
commit
09b95602da
@ -7,7 +7,6 @@ namespace Toby\Infrastructure\Http\Controllers;
|
|||||||
use Carbon\CarbonImmutable;
|
use Carbon\CarbonImmutable;
|
||||||
use Carbon\CarbonInterface;
|
use Carbon\CarbonInterface;
|
||||||
use Carbon\CarbonPeriod;
|
use Carbon\CarbonPeriod;
|
||||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Inertia\Response;
|
use Inertia\Response;
|
||||||
use Toby\Domain\Enums\VacationRequestState;
|
use Toby\Domain\Enums\VacationRequestState;
|
||||||
@ -29,7 +28,7 @@ class VacationCalendarController extends Controller
|
|||||||
->with([
|
->with([
|
||||||
"vacations" => fn($query) => $query
|
"vacations" => fn($query) => $query
|
||||||
->whereBetween("date", [$period->start, $period->end])
|
->whereBetween("date", [$period->start, $period->end])
|
||||||
->whereRelation("vacationRequest", "state", VacationRequestState::APPROVED->value)
|
->whereRelation("vacationRequest", "state", VacationRequestState::APPROVED->value),
|
||||||
])
|
])
|
||||||
->orderBy("last_name")
|
->orderBy("last_name")
|
||||||
->orderBy("first_name")
|
->orderBy("first_name")
|
||||||
|
@ -80,7 +80,7 @@ class VacationRequestController extends Controller
|
|||||||
$days = $vacationDaysCalculator->calculateDays(
|
$days = $vacationDaysCalculator->calculateDays(
|
||||||
$vacationRequest->yearPeriod,
|
$vacationRequest->yearPeriod,
|
||||||
$vacationRequest->from,
|
$vacationRequest->from,
|
||||||
$vacationRequest->to
|
$vacationRequest->to,
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach ($days as $day) {
|
foreach ($days as $day) {
|
||||||
|
@ -13,9 +13,11 @@ class VacationRequestActivityResource extends JsonResource
|
|||||||
public function toArray($request): array
|
public function toArray($request): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
"date" => $this->created_at->toDisplayString(),
|
"date" => $this->created_at->format("d.m.Y"),
|
||||||
"who" => $this->user ? $this->user->fullName : __("System"),
|
"time" => $this->created_at->format("H:i"),
|
||||||
"to" => $this->to->label(),
|
"user" => $this->user ? $this->user->fullName : __("System"),
|
||||||
|
"state" => $this->to,
|
||||||
|
"text" => $this->to->label(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ class VacationRequestResource extends JsonResource
|
|||||||
"name" => $this->name,
|
"name" => $this->name,
|
||||||
"user" => new UserResource($this->user),
|
"user" => new UserResource($this->user),
|
||||||
"type" => $this->type->label(),
|
"type" => $this->type->label(),
|
||||||
"state" => $this->state->label(),
|
"state" => $this->state,
|
||||||
"from" => $this->from->toDisplayString(),
|
"from" => $this->from->toDisplayString(),
|
||||||
"to" => $this->to->toDisplayString(),
|
"to" => $this->to->toDisplayString(),
|
||||||
"comment" => $this->comment,
|
"comment" => $this->comment,
|
||||||
|
@ -96,8 +96,8 @@
|
|||||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
{{ request.days.length }}
|
{{ request.days.length }}
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500 flex items-center">
|
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
<ThumbDownIcon class="w-4 h-4 text-rose-600 mr-1" /> <span>{{ request.state }}</span>
|
<Status :status="request.state" />
|
||||||
</td>
|
</td>
|
||||||
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500">
|
||||||
<InertiaLink
|
<InertiaLink
|
||||||
@ -184,6 +184,7 @@ import {
|
|||||||
CheckIcon,
|
CheckIcon,
|
||||||
DocumentTextIcon,
|
DocumentTextIcon,
|
||||||
} from '@heroicons/vue/solid'
|
} from '@heroicons/vue/solid'
|
||||||
|
import Status from '@/Shared/Status'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'VacationRequestIndex',
|
name: 'VacationRequestIndex',
|
||||||
@ -198,6 +199,7 @@ export default {
|
|||||||
CheckIcon,
|
CheckIcon,
|
||||||
DocumentTextIcon,
|
DocumentTextIcon,
|
||||||
ThumbDownIcon,
|
ThumbDownIcon,
|
||||||
|
Status,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
requests: {
|
requests: {
|
||||||
|
@ -26,6 +26,14 @@
|
|||||||
{{ request.type }}
|
{{ request.type }}
|
||||||
</dd>
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
|
<dt class="text-sm font-medium text-gray-500">
|
||||||
|
Obecny status
|
||||||
|
</dt>
|
||||||
|
<dd class="mt-1 text-sm text-gray-900 sm:mt-0 sm:col-span-2">
|
||||||
|
<Status :status="request.state" />
|
||||||
|
</dd>
|
||||||
|
</div>
|
||||||
<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
<div class="py-4 sm:py-5 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6">
|
||||||
<dt class="text-sm font-medium text-gray-500">
|
<dt class="text-sm font-medium text-gray-500">
|
||||||
Urlop od
|
Urlop od
|
||||||
@ -192,74 +200,15 @@
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="border-t border-gray-200 px-4 py-4">
|
<div class="border-t border-gray-200 px-4 py-4">
|
||||||
<!-- <ul>-->
|
|
||||||
<!-- <li-->
|
|
||||||
<!-- v-for="(activity, index) in activities.data"-->
|
|
||||||
<!-- :key="activity.id"-->
|
|
||||||
<!-- >-->
|
|
||||||
<!-- <div :class="{'relative pb-8': index !== activities.data.length - 1}">-->
|
|
||||||
<!-- <span-->
|
|
||||||
<!-- v-if="(index !== activities.data.length - 1)"-->
|
|
||||||
<!-- class="absolute top-4 left-4 -ml-px h-full w-0.5 bg-gray-200"-->
|
|
||||||
<!-- />-->
|
|
||||||
<!-- <div class="relative flex space-x-3">-->
|
|
||||||
<!-- <div>-->
|
|
||||||
<!-- <span-->
|
|
||||||
<!-- class="bg-blumilk-500 h-8 w-8 rounded-full flex items-center justify-center ring-8 ring-white">-->
|
|
||||||
<!-- <ThumbUpIcon class="w-5 h-5 text-white"/>-->
|
|
||||||
<!-- </span>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div class="min-w-0 flex-1 pt-1.5 flex justify-between space-x-4">-->
|
|
||||||
<!-- <div>-->
|
|
||||||
<!-- <p class="text-sm text-gray-500">-->
|
|
||||||
<!-- {{ activity.to }}-->
|
|
||||||
<!-- </p>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- <div class="text-right text-sm whitespace-nowrap text-gray-500">-->
|
|
||||||
<!-- <time>{{ activity.date }}</time>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </div>-->
|
|
||||||
<!-- </li>-->
|
|
||||||
<!-- </ul>-->
|
|
||||||
<ul>
|
<ul>
|
||||||
<li
|
<li
|
||||||
v-for="(status, index) in statuses"
|
v-for="(activity, index) in activities.data"
|
||||||
:key="status.name"
|
:key="index"
|
||||||
>
|
>
|
||||||
<div :class="{'relative pb-8': index !== statuses.length - 1}">
|
<Activity
|
||||||
<span
|
:activity="activity"
|
||||||
v-if="(index !== statuses.length - 1)"
|
:last="index !== activities.data.length - 1"
|
||||||
class="absolute top-4 left-4 -ml-px h-full w-0.5 bg-gray-200"
|
|
||||||
/>
|
/>
|
||||||
<div class="relative flex space-x-3">
|
|
||||||
<div>
|
|
||||||
<span
|
|
||||||
:class="[status.iconBackground, status.iconForeground, 'h-8 w-8 rounded-full flex items-center justify-center ring-8 ring-white']"
|
|
||||||
>
|
|
||||||
<component
|
|
||||||
:is="status.icon"
|
|
||||||
class="w-5 h-5 text-white"
|
|
||||||
/>
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="min-w-0 flex-1 pt-1.5 flex justify-between space-x-4">
|
|
||||||
<div class="flex flex-col items-start">
|
|
||||||
<div class="text-sm font-medium text-gray-700">
|
|
||||||
{{ status.name }}
|
|
||||||
</div>
|
|
||||||
<div class="text-right text-sm whitespace-nowrap font-medium text-gray-400">
|
|
||||||
Jan Kowalski
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="text-right text-sm whitespace-nowrap text-gray-500 flex flex-col">
|
|
||||||
<time>29.10.2022</time>
|
|
||||||
<time>09:04</time>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -269,21 +218,16 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import {
|
import {PaperClipIcon} from '@heroicons/vue/outline'
|
||||||
CheckIcon,
|
import Activity from '@/Shared/Activity'
|
||||||
ClockIcon,
|
import Status from '@/Shared/Status'
|
||||||
DocumentTextIcon,
|
|
||||||
PaperClipIcon,
|
|
||||||
ThumbDownIcon,
|
|
||||||
ThumbUpIcon,
|
|
||||||
XIcon,
|
|
||||||
} from '@heroicons/vue/outline'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'VacationRequestShow',
|
name: 'VacationRequestShow',
|
||||||
components: {
|
components: {
|
||||||
ThumbUpIcon,
|
Activity,
|
||||||
PaperClipIcon,
|
PaperClipIcon,
|
||||||
|
Status,
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
request: {
|
request: {
|
||||||
@ -295,62 +239,5 @@ export default {
|
|||||||
default: () => null,
|
default: () => null,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
setup() {
|
|
||||||
const statuses = [
|
|
||||||
{
|
|
||||||
icon: DocumentTextIcon,
|
|
||||||
name: 'Utworzony',
|
|
||||||
iconForeground: 'text-white',
|
|
||||||
iconBackground: 'bg-gray-400',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: ClockIcon,
|
|
||||||
name: 'Czeka na akceptację od technicznego',
|
|
||||||
iconForeground: 'text-white',
|
|
||||||
iconBackground: 'bg-amber-400',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: ClockIcon,
|
|
||||||
name: 'Czeka na akceptację od administracyjnego',
|
|
||||||
iconForeground: 'text-white',
|
|
||||||
iconBackground: 'bg-amber-400',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: ThumbDownIcon,
|
|
||||||
name: 'Odrzucony',
|
|
||||||
iconForeground: 'text-white',
|
|
||||||
iconBackground: 'bg-rose-600',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: ThumbUpIcon,
|
|
||||||
name: 'Zaakceptowany przez technicznego',
|
|
||||||
iconForeground: 'text-white',
|
|
||||||
iconBackground: 'bg-green-500',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: ThumbUpIcon,
|
|
||||||
name: 'Zaakceptowany przez administracyjnego',
|
|
||||||
iconForeground: 'text-white',
|
|
||||||
iconBackground: 'bg-green-500',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: CheckIcon,
|
|
||||||
name: 'Zatwierdzony',
|
|
||||||
iconForeground: 'text-white',
|
|
||||||
iconBackground: 'bg-blumilk-500',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
icon: XIcon,
|
|
||||||
name: 'Anulowany',
|
|
||||||
iconForeground: 'text-white',
|
|
||||||
iconBackground: 'bg-gray-900',
|
|
||||||
},
|
|
||||||
|
|
||||||
]
|
|
||||||
|
|
||||||
return {
|
|
||||||
statuses,
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
116
resources/js/Shared/Activity.vue
Normal file
116
resources/js/Shared/Activity.vue
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
<template>
|
||||||
|
<div :class="{'relative pb-8': last}">
|
||||||
|
<span
|
||||||
|
v-if="last"
|
||||||
|
class="absolute top-4 left-4 -ml-px h-full w-0.5 bg-gray-200"
|
||||||
|
/>
|
||||||
|
<div class="relative flex space-x-3">
|
||||||
|
<div>
|
||||||
|
<span :class="[statusInfo.iconBackground, statusInfo.iconForeground, 'h-8 w-8 rounded-full flex items-center justify-center ring-8 ring-white']">
|
||||||
|
<component
|
||||||
|
:is="statusInfo.icon"
|
||||||
|
class="w-5 h-5 text-white"
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="min-w-0 flex-1 pt-1.5 flex justify-between space-x-4">
|
||||||
|
<div class="flex flex-col items-start">
|
||||||
|
<div class="text-sm font-medium text-gray-700">
|
||||||
|
{{ statusInfo.text }}
|
||||||
|
</div>
|
||||||
|
<div class="text-right text-sm whitespace-nowrap font-medium text-gray-400">
|
||||||
|
{{ activity.user }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-right text-sm whitespace-nowrap text-gray-500 flex flex-col">
|
||||||
|
<time>{{ activity.date }}</time>
|
||||||
|
<time>{{ activity.time }}</time>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {CheckIcon, ClockIcon, DocumentTextIcon, ThumbDownIcon, ThumbUpIcon, XIcon} from '@heroicons/vue/outline'
|
||||||
|
import {computed} from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VacationRequestActivity',
|
||||||
|
props: {
|
||||||
|
activity: {
|
||||||
|
type: Object,
|
||||||
|
default: () => null,
|
||||||
|
},
|
||||||
|
last: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const statuses = [
|
||||||
|
{
|
||||||
|
text: 'Utworzony',
|
||||||
|
icon: DocumentTextIcon,
|
||||||
|
value: 'created',
|
||||||
|
iconForeground: 'text-white',
|
||||||
|
iconBackground: 'bg-gray-400',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Czeka na akceptację od technicznego',
|
||||||
|
icon: ClockIcon,
|
||||||
|
value: 'waiting_for_technical',
|
||||||
|
iconForeground: 'text-white',
|
||||||
|
iconBackground: 'bg-amber-400',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Czeka na akceptację od administracyjnego',
|
||||||
|
icon: ClockIcon,
|
||||||
|
value: 'waiting_for_administrative',
|
||||||
|
iconForeground: 'text-white',
|
||||||
|
iconBackground: 'bg-amber-400',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Odrzucony',
|
||||||
|
icon: ThumbDownIcon,
|
||||||
|
value: 'rejected',
|
||||||
|
iconForeground: 'text-white',
|
||||||
|
iconBackground: 'bg-rose-600',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Zaakceptowany przez technicznego',
|
||||||
|
icon: ThumbUpIcon,
|
||||||
|
value: 'accepted_by_technical',
|
||||||
|
iconForeground: 'text-white',
|
||||||
|
iconBackground: 'bg-green-500',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Zaakceptowany przez administracyjnego',
|
||||||
|
icon: ThumbUpIcon,
|
||||||
|
value: 'accepted_by_administrative',
|
||||||
|
iconForeground: 'text-white',
|
||||||
|
iconBackground: 'bg-green-500',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Zatwierdzony',
|
||||||
|
icon: CheckIcon,
|
||||||
|
value: 'approved',
|
||||||
|
iconForeground: 'text-white',
|
||||||
|
iconBackground: 'bg-blumilk-500',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Anulowany',
|
||||||
|
icon: XIcon,
|
||||||
|
value: 'canceled',
|
||||||
|
iconForeground: 'text-white',
|
||||||
|
iconBackground: 'bg-gray-900',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const statusInfo = computed(() => statuses.find(status => status.value === props.activity.state))
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusInfo,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
85
resources/js/Shared/Status.vue
Normal file
85
resources/js/Shared/Status.vue
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
<template>
|
||||||
|
<div class="flex items-center">
|
||||||
|
<component
|
||||||
|
:is="statusInfo.icon"
|
||||||
|
:class="[statusInfo.color ,'w-5 h-5 mr-1']"
|
||||||
|
/>
|
||||||
|
<span>{{ statusInfo.text }}</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import {CheckIcon, ClockIcon, DocumentTextIcon, ThumbDownIcon, ThumbUpIcon, XIcon} from '@heroicons/vue/solid'
|
||||||
|
import {computed} from 'vue'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'VacationRequestStatus',
|
||||||
|
props: {
|
||||||
|
status: {
|
||||||
|
type: String,
|
||||||
|
default: () => null,
|
||||||
|
},
|
||||||
|
last: {
|
||||||
|
type: Boolean,
|
||||||
|
default: () => false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
setup(props) {
|
||||||
|
const statuses = [
|
||||||
|
{
|
||||||
|
text: 'Utworzony',
|
||||||
|
icon: DocumentTextIcon,
|
||||||
|
value: 'created',
|
||||||
|
color: 'text-gray-400',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Czeka na akceptację od technicznego',
|
||||||
|
icon: ClockIcon,
|
||||||
|
value: 'waiting_for_technical',
|
||||||
|
color: 'text-amber-400',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Czeka na akceptację od administracyjnego',
|
||||||
|
icon: ClockIcon,
|
||||||
|
value: 'waiting_for_administrative',
|
||||||
|
color: 'text-amber-400',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Odrzucony',
|
||||||
|
icon: ThumbDownIcon,
|
||||||
|
value: 'rejected',
|
||||||
|
color: 'text-rose-600',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Zaakceptowany przez technicznego',
|
||||||
|
icon: ThumbUpIcon,
|
||||||
|
value: 'accepted_by_technical',
|
||||||
|
color: 'text-green-500',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Zaakceptowany przez administracyjnego',
|
||||||
|
icon: ThumbUpIcon,
|
||||||
|
value: 'accepted_by_administrative',
|
||||||
|
color: 'text-green-500',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Zatwierdzony',
|
||||||
|
icon: CheckIcon,
|
||||||
|
value: 'approved',
|
||||||
|
color: 'text-blumilk-500',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Anulowany',
|
||||||
|
icon: XIcon,
|
||||||
|
value: 'canceled',
|
||||||
|
color: 'text-gray-900',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
const statusInfo = computed(() => statuses.find(status => status.value === props.status))
|
||||||
|
|
||||||
|
return {
|
||||||
|
statusInfo,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
Loading…
x
Reference in New Issue
Block a user