- vue composition api (#91)
* wip * fix Co-authored-by: EwelinaLasowy <ewelina.lasowy@blumilk.pl>
This commit is contained in:
@@ -322,128 +322,94 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {useForm} from '@inertiajs/inertia-vue3'
|
||||
<script setup>
|
||||
import { useForm } from '@inertiajs/inertia-vue3'
|
||||
import FlatPickr from 'vue-flatpickr-component'
|
||||
import {Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions, Switch} from '@headlessui/vue'
|
||||
import {CheckIcon, SelectorIcon, XCircleIcon} from '@heroicons/vue/solid'
|
||||
import {reactive, ref, watch} from 'vue'
|
||||
import { Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions, Switch } from '@headlessui/vue'
|
||||
import { CheckIcon, SelectorIcon, XCircleIcon } from '@heroicons/vue/solid'
|
||||
import { reactive, ref, watch } from 'vue'
|
||||
import axios from 'axios'
|
||||
import useCurrentYearPeriodInfo from '@/Composables/yearPeriodInfo'
|
||||
import VacationChart from '@/Shared/VacationChart'
|
||||
|
||||
export default {
|
||||
name: 'VacationRequestCreate',
|
||||
components: {
|
||||
VacationChart,
|
||||
Switch,
|
||||
FlatPickr,
|
||||
Listbox,
|
||||
ListboxButton,
|
||||
ListboxLabel,
|
||||
ListboxOption,
|
||||
ListboxOptions,
|
||||
CheckIcon,
|
||||
SelectorIcon,
|
||||
XCircleIcon,
|
||||
},
|
||||
props: {
|
||||
auth: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
users: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
vacationTypes: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
holidays: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const form = useForm({
|
||||
user: props.can.createOnBehalfOfEmployee
|
||||
? props.users.data.find(user => user.id === props.auth.user.id) ?? props.users.data[0]
|
||||
: props.auth.user,
|
||||
from: null,
|
||||
to: null,
|
||||
type: props.vacationTypes[0],
|
||||
comment: null,
|
||||
flowSkipped: false,
|
||||
})
|
||||
|
||||
const estimatedDays = ref([])
|
||||
const props = defineProps({
|
||||
auth: Object,
|
||||
users: Object,
|
||||
vacationTypes: Object,
|
||||
holidays: Object,
|
||||
can: Object,
|
||||
})
|
||||
|
||||
const stats = ref({
|
||||
used: 0,
|
||||
pending: 0,
|
||||
remaining: 0,
|
||||
})
|
||||
const form = useForm({
|
||||
user: props.can.createOnBehalfOfEmployee
|
||||
? props.users.data.find(user => user.id === props.auth.user.id) ?? props.users.data[0]
|
||||
: props.auth.user,
|
||||
from: null,
|
||||
to: null,
|
||||
type: props.vacationTypes[0],
|
||||
comment: null,
|
||||
flowSkipped: false,
|
||||
})
|
||||
|
||||
const {minDate, maxDate} = useCurrentYearPeriodInfo()
|
||||
const estimatedDays = ref([])
|
||||
|
||||
const disableDates = [
|
||||
date => (date.getDay() === 0 || date.getDay() === 6),
|
||||
]
|
||||
const stats = ref({
|
||||
used: 0,
|
||||
pending: 0,
|
||||
remaining: 0,
|
||||
})
|
||||
|
||||
const fromInputConfig = reactive({
|
||||
minDate: minDate,
|
||||
maxDate: maxDate,
|
||||
disable: disableDates,
|
||||
})
|
||||
const { minDate, maxDate } = useCurrentYearPeriodInfo()
|
||||
|
||||
const toInputConfig = reactive({
|
||||
minDate: minDate,
|
||||
maxDate: maxDate,
|
||||
disable: disableDates,
|
||||
})
|
||||
const disableDates = [
|
||||
date => (date.getDay() === 0 || date.getDay() === 6),
|
||||
]
|
||||
|
||||
watch(() => form.user, user => {
|
||||
axios.post('/api/calculate-vacations-stats', {user: user.id})
|
||||
.then(res => stats.value = res.data)
|
||||
}, {immediate: true})
|
||||
const fromInputConfig = reactive({
|
||||
minDate,
|
||||
maxDate,
|
||||
disable: disableDates,
|
||||
})
|
||||
|
||||
return {
|
||||
form,
|
||||
estimatedDays,
|
||||
stats,
|
||||
fromInputConfig,
|
||||
toInputConfig,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
createForm() {
|
||||
this.form
|
||||
.transform(data => ({
|
||||
...data,
|
||||
type: data.type.value,
|
||||
user: data.user.id,
|
||||
}))
|
||||
.post('/vacation-requests')
|
||||
},
|
||||
onFromChange(selectedDates, dateStr) {
|
||||
this.form.to = dateStr
|
||||
const toInputConfig = reactive({
|
||||
minDate,
|
||||
maxDate,
|
||||
disable: disableDates,
|
||||
})
|
||||
|
||||
this.refreshEstimatedDays(this.form.from, this.form.to)
|
||||
},
|
||||
onToChange() {
|
||||
this.refreshEstimatedDays(this.form.from, this.form.to)
|
||||
},
|
||||
refreshEstimatedDays(from, to) {
|
||||
if (from && to) {
|
||||
axios.post('/api/calculate-vacation-days', {from, to})
|
||||
.then(res => this.estimatedDays = res.data)
|
||||
}
|
||||
},
|
||||
},
|
||||
watch(() => form.user, async user => {
|
||||
const res = await axios.post('/api/calculate-vacations-stats', { user: user.id })
|
||||
|
||||
stats.value = res.data
|
||||
}, { immediate: true })
|
||||
|
||||
function createForm() {
|
||||
form
|
||||
.transform(data => ({
|
||||
...data,
|
||||
type: data.type.value,
|
||||
user: data.user.id,
|
||||
}))
|
||||
.post('/vacation-requests')
|
||||
}
|
||||
|
||||
function onFromChange(selectedDates, dateStr) {
|
||||
form.to = dateStr
|
||||
|
||||
refreshEstimatedDays(form.from, form.to)
|
||||
}
|
||||
|
||||
function onToChange() {
|
||||
refreshEstimatedDays(form.from, form.to)
|
||||
}
|
||||
|
||||
async function refreshEstimatedDays(from, to) {
|
||||
if (from && to) {
|
||||
const res = await axios.post('/api/calculate-vacation-days', { from, to })
|
||||
|
||||
estimatedDays.value = res.data
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
@@ -118,9 +118,7 @@
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-if="! requests.data.length"
|
||||
>
|
||||
<tr v-if="! requests.data.length">
|
||||
<td
|
||||
colspan="100%"
|
||||
class="text-center py-4 text-xl leading-5 text-gray-700"
|
||||
@@ -130,131 +128,39 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div
|
||||
v-if="requests.data.length && requests.meta.last_page !== 1"
|
||||
class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6 rounded-b-lg"
|
||||
>
|
||||
<div class="flex-1 flex justify-between sm:hidden">
|
||||
<InertiaLink
|
||||
:is="requests.links.prev ? 'InertiaLink': 'span'"
|
||||
:href="requests.links.prev"
|
||||
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
|
||||
>
|
||||
Poprzednia
|
||||
</InertiaLink>
|
||||
<Component
|
||||
:is="requests.links.next ? 'InertiaLink': 'span'"
|
||||
:href="requests.links.next"
|
||||
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
|
||||
>
|
||||
Następna
|
||||
</Component>
|
||||
</div>
|
||||
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||
<div class="text-sm text-gray-700">
|
||||
Wyświetlanie
|
||||
<span class="font-medium">{{ requests.meta.from }}</span>
|
||||
od
|
||||
<span class="font-medium">{{ requests.meta.to }}</span>
|
||||
do
|
||||
<span class="font-medium">{{ requests.meta.total }}</span>
|
||||
wyników
|
||||
</div>
|
||||
<nav class="relative z-0 inline-flex space-x-1">
|
||||
<template
|
||||
v-for="(link, index) in requests.meta.links"
|
||||
:key="index"
|
||||
>
|
||||
<Component
|
||||
:is="link.url ? 'InertiaLink' : 'span'"
|
||||
:href="link.url"
|
||||
:preserve-scroll="true"
|
||||
class="relative inline-flex items-center px-4 py-2 border rounded-md text-sm font-medium"
|
||||
:class="{ 'z-10 bg-blumilk-25 border-blumilk-500 text-blumilk-600': link.active, 'bg-white border-gray-300 text-gray-500': !link.active, 'hover:bg-blumilk-25': link.url, 'border-none': !link.url}"
|
||||
v-text="link.label"
|
||||
/>
|
||||
</template>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<Pagination :pagination="requests.meta" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
ChevronRightIcon,
|
||||
ClockIcon,
|
||||
DotsVerticalIcon,
|
||||
PencilIcon,
|
||||
ThumbDownIcon,
|
||||
ThumbUpIcon,
|
||||
TrashIcon,
|
||||
XIcon,
|
||||
CheckIcon,
|
||||
DocumentTextIcon,
|
||||
} from '@heroicons/vue/solid'
|
||||
<script setup>
|
||||
import { ChevronRightIcon } from '@heroicons/vue/solid'
|
||||
import Status from '@/Shared/Status'
|
||||
import VacationType from '@/Shared/VacationType'
|
||||
import Pagination from '@/Shared/Pagination'
|
||||
|
||||
export default {
|
||||
name: 'VacationRequestIndex',
|
||||
components: {
|
||||
DotsVerticalIcon,
|
||||
PencilIcon,
|
||||
TrashIcon,
|
||||
ChevronRightIcon,
|
||||
ThumbUpIcon,
|
||||
ClockIcon,
|
||||
XIcon,
|
||||
CheckIcon,
|
||||
DocumentTextIcon,
|
||||
ThumbDownIcon,
|
||||
Status,
|
||||
VacationType,
|
||||
},
|
||||
props: {
|
||||
requests: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
stats: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
all: 0,
|
||||
pending: 0,
|
||||
success: 0,
|
||||
failed: 0,
|
||||
}),
|
||||
},
|
||||
filters: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const statuses = [
|
||||
{
|
||||
name: 'Wszystkie',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
name: 'W trakcie',
|
||||
value: 'pending',
|
||||
},
|
||||
{
|
||||
name: 'Zatwierdzone',
|
||||
value: 'success',
|
||||
},
|
||||
{
|
||||
name: 'Odrzucone/anulowane',
|
||||
value: 'failed',
|
||||
},
|
||||
]
|
||||
defineProps({
|
||||
requests: Object,
|
||||
stats: Object,
|
||||
filters: Object,
|
||||
})
|
||||
|
||||
return {
|
||||
statuses,
|
||||
}
|
||||
const statuses = [
|
||||
{
|
||||
name: 'Wszystkie',
|
||||
value: 'all',
|
||||
},
|
||||
}
|
||||
{
|
||||
name: 'W trakcie',
|
||||
value: 'pending',
|
||||
},
|
||||
{
|
||||
name: 'Zatwierdzone',
|
||||
value: 'success',
|
||||
},
|
||||
{
|
||||
name: 'Odrzucone/anulowane',
|
||||
value: 'failed',
|
||||
},
|
||||
]
|
||||
</script>
|
||||
|
@@ -93,7 +93,9 @@
|
||||
:src="user.avatar"
|
||||
class="flex-shrink-0 h-6 w-6 rounded-full"
|
||||
>
|
||||
<span :class="[form.user?.id === user.id ? 'font-semibold' : 'font-normal', 'ml-3 block truncate']">
|
||||
<span
|
||||
:class="[form.user?.id === user.id ? 'font-semibold' : 'font-normal', 'ml-3 block truncate']"
|
||||
>
|
||||
{{ user.name }}
|
||||
</span>
|
||||
</div>
|
||||
@@ -123,9 +125,7 @@
|
||||
<ListboxButton
|
||||
class="bg-white relative w-full max-w-lg border rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default sm:text-sm focus:ring-1 focus:ring-blumilk-500 focus:border-blumilk-500 sm:text-sm border-gray-300"
|
||||
>
|
||||
<span
|
||||
class="flex items-center"
|
||||
>
|
||||
<span class="flex items-center">
|
||||
{{ form.status.name }}
|
||||
</span>
|
||||
<span class="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
|
||||
@@ -274,9 +274,7 @@
|
||||
/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr
|
||||
v-if="! requests.data.length"
|
||||
>
|
||||
<tr v-if="! requests.data.length">
|
||||
<td
|
||||
colspan="100%"
|
||||
class="text-center py-4 text-xl leading-5 text-gray-700"
|
||||
@@ -286,153 +284,59 @@
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div
|
||||
v-if="requests.data.length && requests.meta.last_page !== 1"
|
||||
class="bg-white px-4 py-3 flex items-center justify-between border-t border-gray-200 sm:px-6 rounded-b-lg"
|
||||
>
|
||||
<div class="flex-1 flex justify-between sm:hidden">
|
||||
<InertiaLink
|
||||
:is="requests.links.prev ? 'InertiaLink': 'span'"
|
||||
:href="requests.links.prev"
|
||||
class="relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
|
||||
>
|
||||
Poprzednia
|
||||
</InertiaLink>
|
||||
<Component
|
||||
:is="requests.links.next ? 'InertiaLink': 'span'"
|
||||
:href="requests.links.next"
|
||||
class="ml-3 relative inline-flex items-center px-4 py-2 border border-gray-300 text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50"
|
||||
>
|
||||
Następna
|
||||
</Component>
|
||||
</div>
|
||||
<div class="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||
<div class="text-sm text-gray-700">
|
||||
Wyświetlanie
|
||||
<span class="font-medium">{{ requests.meta.from }}</span>
|
||||
od
|
||||
<span class="font-medium">{{ requests.meta.to }}</span>
|
||||
do
|
||||
<span class="font-medium">{{ requests.meta.total }}</span>
|
||||
wyników
|
||||
</div>
|
||||
<nav class="relative z-0 inline-flex space-x-1">
|
||||
<template
|
||||
v-for="(link, index) in requests.meta.links"
|
||||
:key="index"
|
||||
>
|
||||
<Component
|
||||
:is="link.url ? 'InertiaLink' : 'span'"
|
||||
:href="link.url"
|
||||
:preserve-scroll="true"
|
||||
class="relative inline-flex items-center px-4 py-2 border rounded-md text-sm font-medium"
|
||||
:class="{ 'z-10 bg-blumilk-25 border-blumilk-500 text-blumilk-600': link.active, 'bg-white border-gray-300 text-gray-500': !link.active, 'hover:bg-blumilk-25': link.url, 'border-none': !link.url}"
|
||||
v-text="link.label"
|
||||
/>
|
||||
</template>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
<Pagination :pagination="requests.meta" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {
|
||||
CheckIcon,
|
||||
ChevronRightIcon,
|
||||
ClockIcon,
|
||||
DocumentTextIcon,
|
||||
DotsVerticalIcon,
|
||||
PencilIcon,
|
||||
SelectorIcon,
|
||||
ThumbDownIcon,
|
||||
ThumbUpIcon,
|
||||
TrashIcon,
|
||||
XCircleIcon,
|
||||
XIcon,
|
||||
} from '@heroicons/vue/solid'
|
||||
<script setup>
|
||||
import { CheckIcon, ChevronRightIcon, SelectorIcon } from '@heroicons/vue/solid'
|
||||
import Status from '@/Shared/Status'
|
||||
import VacationType from '@/Shared/VacationType'
|
||||
import {watch, reactive} from 'vue'
|
||||
import {debounce} from 'lodash'
|
||||
import {Inertia} from '@inertiajs/inertia'
|
||||
import {Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions} from '@headlessui/vue'
|
||||
import { watch, reactive } from 'vue'
|
||||
import { debounce } from 'lodash'
|
||||
import { Inertia } from '@inertiajs/inertia'
|
||||
import { Listbox, ListboxButton, ListboxLabel, ListboxOption, ListboxOptions } from '@headlessui/vue'
|
||||
import Pagination from '@/Shared/Pagination'
|
||||
|
||||
export default {
|
||||
name: 'VacationRequestIndex',
|
||||
components: {
|
||||
Listbox,
|
||||
ListboxButton,
|
||||
ListboxLabel,
|
||||
ListboxOption,
|
||||
ListboxOptions,
|
||||
DotsVerticalIcon,
|
||||
PencilIcon,
|
||||
TrashIcon,
|
||||
ChevronRightIcon,
|
||||
ThumbUpIcon,
|
||||
ClockIcon,
|
||||
XIcon,
|
||||
CheckIcon,
|
||||
DocumentTextIcon,
|
||||
ThumbDownIcon,
|
||||
Status,
|
||||
VacationType,
|
||||
SelectorIcon,
|
||||
XCircleIcon,
|
||||
const props = defineProps({
|
||||
requests: Object,
|
||||
users: Object,
|
||||
filters: Object,
|
||||
})
|
||||
|
||||
const statuses = [
|
||||
{
|
||||
name: 'Wszystkie',
|
||||
value: 'all',
|
||||
},
|
||||
props: {
|
||||
requests: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
users: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
filters: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
{
|
||||
name: 'Oczekujące na akcje',
|
||||
value: 'waiting_for_action',
|
||||
},
|
||||
setup(props) {
|
||||
const statuses = [
|
||||
{
|
||||
name: 'Wszystkie',
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
name: 'Oczekujące na akcje',
|
||||
value: 'waiting_for_action',
|
||||
},
|
||||
{
|
||||
name: 'W trakcie',
|
||||
value: 'pending',
|
||||
},
|
||||
{
|
||||
name: 'Zatwierdzone',
|
||||
value: 'success',
|
||||
},
|
||||
{
|
||||
name: 'Odrzucone/anulowane',
|
||||
value: 'failed',
|
||||
},
|
||||
]
|
||||
|
||||
const form = reactive({
|
||||
user: props.users.data.find(user => user.id === props.filters.user) ?? null,
|
||||
status: statuses.find(status => status.value === props.filters.status) ?? statuses[0],
|
||||
})
|
||||
|
||||
watch(form, debounce(() => {
|
||||
Inertia.get('/vacation-requests', {user: form.user?.id, status: form.status.value}, {
|
||||
preserveState: true,
|
||||
replace: true,
|
||||
})
|
||||
}, 300))
|
||||
|
||||
return {form, statuses}
|
||||
{
|
||||
name: 'W trakcie',
|
||||
value: 'pending',
|
||||
},
|
||||
}
|
||||
{
|
||||
name: 'Zatwierdzone',
|
||||
value: 'success',
|
||||
},
|
||||
{
|
||||
name: 'Odrzucone/anulowane',
|
||||
value: 'failed',
|
||||
},
|
||||
]
|
||||
|
||||
const form = reactive({
|
||||
user: props.users.data.find(user => user.id === props.filters.user) ?? null,
|
||||
status: statuses.find(status => status.value === props.filters.status) ?? statuses[0],
|
||||
})
|
||||
|
||||
watch(form, debounce(() => {
|
||||
Inertia.get('/vacation-requests', { user: form.user?.id, status: form.status.value }, {
|
||||
preserveState: true,
|
||||
replace: true,
|
||||
})
|
||||
}, 300))
|
||||
</script>
|
||||
|
@@ -245,33 +245,15 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {PaperClipIcon} from '@heroicons/vue/outline'
|
||||
<script setup>
|
||||
import { PaperClipIcon } from '@heroicons/vue/outline'
|
||||
import Activity from '@/Shared/Activity'
|
||||
import Status from '@/Shared/Status'
|
||||
import VacationType from '@/Shared/VacationType'
|
||||
|
||||
export default {
|
||||
name: 'VacationRequestShow',
|
||||
components: {
|
||||
VacationType,
|
||||
Activity,
|
||||
PaperClipIcon,
|
||||
Status,
|
||||
},
|
||||
props: {
|
||||
request: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
can: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
activities: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
}
|
||||
defineProps({
|
||||
request: Object,
|
||||
can: Object,
|
||||
activities: Object,
|
||||
})
|
||||
</script>
|
||||
|
Reference in New Issue
Block a user