- vue composition api (#91)
* wip * fix Co-authored-by: EwelinaLasowy <ewelina.lasowy@blumilk.pl>
This commit is contained in:
@@ -31,30 +31,16 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {computed} from 'vue'
|
||||
import {useStatusInfo} from '@/Composables/statusInfo'
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useStatusInfo } from '@/Composables/statusInfo'
|
||||
|
||||
export default {
|
||||
name: 'VacationRequestActivity',
|
||||
props: {
|
||||
activity: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
last: {
|
||||
type: Boolean,
|
||||
default: () => false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { findStatus } = useStatusInfo()
|
||||
const props = defineProps({
|
||||
activity: Object,
|
||||
last: Boolean,
|
||||
})
|
||||
|
||||
const statusInfo = computed(() => findStatus(props.activity.state))
|
||||
const { findStatus } = useStatusInfo()
|
||||
|
||||
return {
|
||||
statusInfo,
|
||||
}
|
||||
},
|
||||
}
|
||||
const statusInfo = computed(() => findStatus(props.activity.state))
|
||||
</script>
|
||||
|
@@ -1,6 +1,9 @@
|
||||
<template>
|
||||
<div class="min-h-full">
|
||||
<MainMenu />
|
||||
<MainMenu
|
||||
:auth="auth"
|
||||
:years="years"
|
||||
/>
|
||||
<main class="lg:ml-64 flex flex-col flex-1 py-8">
|
||||
<div class="px-4">
|
||||
<slot />
|
||||
@@ -9,38 +12,26 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import MainMenu from '@/Shared/MainMenu'
|
||||
import {useToast} from 'vue-toastification'
|
||||
import {watch} from 'vue'
|
||||
import { useToast } from 'vue-toastification'
|
||||
import { defineProps, watch } from 'vue'
|
||||
|
||||
export default {
|
||||
name: 'AppLayout',
|
||||
components: {
|
||||
MainMenu,
|
||||
},
|
||||
props: {
|
||||
flash: {
|
||||
type: Object,
|
||||
default: () => null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const toast = useToast()
|
||||
const props = defineProps({
|
||||
flash: Object,
|
||||
auth: Object,
|
||||
years: Object,
|
||||
})
|
||||
|
||||
watch(() => props.flash, flash => {
|
||||
if (flash.success) {
|
||||
toast.success(flash.success)
|
||||
}
|
||||
const toast = useToast()
|
||||
|
||||
if (flash.error) {
|
||||
toast.error(flash.error)
|
||||
}
|
||||
}, {immediate:true})
|
||||
watch(() => props.flash, flash => {
|
||||
if (flash.success) {
|
||||
toast.success(flash.success)
|
||||
}
|
||||
|
||||
return {
|
||||
toast,
|
||||
}
|
||||
},
|
||||
}
|
||||
if (flash.error) {
|
||||
toast.error(flash.error)
|
||||
}
|
||||
}, { immediate:true })
|
||||
</script>
|
||||
|
@@ -3,9 +3,3 @@
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'GuestLayout',
|
||||
}
|
||||
</script>
|
||||
|
@@ -91,7 +91,6 @@
|
||||
</Dialog>
|
||||
</TransitionRoot>
|
||||
|
||||
<!-- Static sidebar for desktop -->
|
||||
<div class="hidden lg:flex lg:w-64 lg:flex-col lg:fixed lg:inset-y-0">
|
||||
<div class="flex flex-col flex-grow bg-blumilk-700 pt-5 pb-4 overflow-y-auto">
|
||||
<div class="flex items-center flex-shrink-0 px-4">
|
||||
@@ -202,30 +201,23 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="ml-4 flex items-center md:ml-6">
|
||||
<!-- Profile dropdown -->
|
||||
<Menu
|
||||
as="div"
|
||||
class="ml-3 relative"
|
||||
>
|
||||
<div>
|
||||
<MenuButton
|
||||
class="max-w-xs bg-white rounded-full flex items-center text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500 lg:p-2 lg:rounded-md lg:hover:bg-gray-50"
|
||||
<MenuButton
|
||||
class="max-w-xs bg-white rounded-full flex items-center text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500 lg:p-2 lg:rounded-md lg:hover:bg-gray-50"
|
||||
>
|
||||
<img
|
||||
class="h-8 w-8 rounded-full"
|
||||
:src="auth.user.avatar"
|
||||
>
|
||||
<img
|
||||
class="h-8 w-8 rounded-full"
|
||||
:src="auth.user.avatar"
|
||||
alt="Avatar"
|
||||
>
|
||||
<span class="hidden ml-3 text-gray-700 text-sm font-medium lg:block">
|
||||
<span class="sr-only">Open user menu for </span>
|
||||
{{ auth.user.name }}
|
||||
</span>
|
||||
<ChevronDownIcon
|
||||
class="hidden flex-shrink-0 ml-1 h-5 w-5 text-gray-400 lg:block"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</MenuButton>
|
||||
</div>
|
||||
<span class="hidden ml-3 text-gray-700 text-sm font-medium lg:block">
|
||||
<span class="sr-only">Open user menu for </span>
|
||||
{{ auth.user.name }}
|
||||
</span>
|
||||
<ChevronDownIcon class="hidden flex-shrink-0 ml-1 h-5 w-5 text-gray-400 lg:block" />
|
||||
</MenuButton>
|
||||
<transition
|
||||
enter-active-class="transition ease-out duration-100"
|
||||
enter-from-class="transform opacity-0 scale-95"
|
||||
@@ -237,18 +229,14 @@
|
||||
<MenuItems
|
||||
class="origin-top-right absolute right-0 mt-2 w-48 rounded-md shadow-lg py-1 bg-white ring-1 ring-black ring-opacity-5 focus:outline-none"
|
||||
>
|
||||
<MenuItem
|
||||
v-for="item in userNavigation"
|
||||
:key="item.name"
|
||||
v-slot="{ active }"
|
||||
>
|
||||
<MenuItem v-slot="{ active }">
|
||||
<InertiaLink
|
||||
:href="item.href"
|
||||
:method="item.method"
|
||||
:as="item.as"
|
||||
href="/logout"
|
||||
method="POST"
|
||||
as="button"
|
||||
:class="[active ? 'bg-gray-100' : '', 'block w-full text-left px-4 py-2 text-sm text-gray-700']"
|
||||
>
|
||||
{{ item.name }}
|
||||
Wyloguj się
|
||||
</InertiaLink>
|
||||
</MenuItem>
|
||||
</MenuItems>
|
||||
@@ -260,8 +248,8 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {ref} from 'vue'
|
||||
<script setup>
|
||||
import { computed, ref } from 'vue'
|
||||
import {
|
||||
Dialog,
|
||||
DialogOverlay,
|
||||
@@ -273,7 +261,6 @@ import {
|
||||
TransitionRoot,
|
||||
} from '@headlessui/vue'
|
||||
import {
|
||||
BellIcon,
|
||||
HomeIcon,
|
||||
CollectionIcon,
|
||||
MenuAlt1Icon,
|
||||
@@ -283,71 +270,58 @@ import {
|
||||
StarIcon,
|
||||
CalendarIcon, DocumentTextIcon,
|
||||
} from '@heroicons/vue/outline'
|
||||
import {
|
||||
CashIcon,
|
||||
CheckCircleIcon,
|
||||
CheckIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronRightIcon,
|
||||
OfficeBuildingIcon,
|
||||
SearchIcon,
|
||||
} from '@heroicons/vue/solid'
|
||||
import {computed} from 'vue'
|
||||
import {usePage} from '@inertiajs/inertia-vue3'
|
||||
import { CheckIcon, ChevronDownIcon } from '@heroicons/vue/solid'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Dialog,
|
||||
DialogOverlay,
|
||||
Menu,
|
||||
MenuButton,
|
||||
MenuItem,
|
||||
MenuItems,
|
||||
TransitionChild,
|
||||
TransitionRoot,
|
||||
BellIcon,
|
||||
CashIcon,
|
||||
CheckCircleIcon,
|
||||
ChevronDownIcon,
|
||||
ChevronRightIcon,
|
||||
MenuAlt1Icon,
|
||||
OfficeBuildingIcon,
|
||||
SearchIcon,
|
||||
XIcon,
|
||||
StarIcon,
|
||||
HomeIcon,
|
||||
CheckIcon,
|
||||
UserGroupIcon,
|
||||
SunIcon,
|
||||
CalendarIcon,
|
||||
},
|
||||
setup() {
|
||||
const sidebarOpen = ref(false)
|
||||
const props = defineProps({
|
||||
auth: Object,
|
||||
years: Object,
|
||||
})
|
||||
|
||||
const auth = computed(() => usePage().props.value.auth)
|
||||
const years = computed(() => usePage().props.value.years)
|
||||
const sidebarOpen = ref(false)
|
||||
|
||||
const navigation = computed(() =>
|
||||
[
|
||||
{name: 'Moje wnioski', href: '/vacation-requests/me', component: 'VacationRequest/Index' , icon: DocumentTextIcon, can: true},
|
||||
{name: 'Wnioski urlopowe', href: '/vacation-requests', component: 'VacationRequest/IndexForApprovers', icon: CollectionIcon, can: auth.value.can.listAllVacationRequests},
|
||||
{name: 'Kalendarz urlopów', href: '/vacation-calendar', component: 'Calendar', icon: CalendarIcon, can: true},
|
||||
{name: 'Dni wolne', href: '/holidays', component: 'Holidays/Index', icon: StarIcon, can: true},
|
||||
{name: 'Limity urlopów', href: '/vacation-limits', component: 'VacationLimits', icon: SunIcon, can: auth.value.can.manageVacationLimits},
|
||||
{name: 'Użytkownicy', href: '/users', component: 'Users/Index', icon: UserGroupIcon, can: auth.value.can.manageUsers},
|
||||
].filter(item => item.can))
|
||||
|
||||
const userNavigation = [
|
||||
{name: 'Wyloguj się', href: '/logout', method: 'post', as: 'button'},
|
||||
]
|
||||
|
||||
return {
|
||||
auth,
|
||||
years,
|
||||
navigation,
|
||||
userNavigation,
|
||||
sidebarOpen,
|
||||
}
|
||||
},
|
||||
}
|
||||
const navigation = computed(() =>
|
||||
[
|
||||
{
|
||||
name: 'Moje wnioski',
|
||||
href: '/vacation-requests/me',
|
||||
component: 'VacationRequest/Index',
|
||||
icon: DocumentTextIcon,
|
||||
can: true,
|
||||
},
|
||||
{
|
||||
name: 'Wnioski urlopowe',
|
||||
href: '/vacation-requests',
|
||||
component: 'VacationRequest/IndexForApprovers',
|
||||
icon: CollectionIcon,
|
||||
can: props.auth.can.listAllVacationRequests,
|
||||
},
|
||||
{
|
||||
name: 'Kalendarz urlopów',
|
||||
href: '/vacation-calendar',
|
||||
component: 'Calendar',
|
||||
icon: CalendarIcon,
|
||||
can: true,
|
||||
},
|
||||
{
|
||||
name: 'Dni wolne',
|
||||
href: '/holidays',
|
||||
component: 'Holidays/Index',
|
||||
icon: StarIcon,
|
||||
can: true,
|
||||
},
|
||||
{
|
||||
name: 'Limity urlopów',
|
||||
href: '/vacation-limits',
|
||||
component: 'VacationLimits',
|
||||
icon: SunIcon,
|
||||
can: props.auth.can.manageVacationLimits,
|
||||
},
|
||||
{
|
||||
name: 'Użytkownicy',
|
||||
href: '/users',
|
||||
component: 'Users/Index',
|
||||
icon: UserGroupIcon,
|
||||
can: props.auth.can.manageUsers,
|
||||
},
|
||||
].filter(item => item.can))
|
||||
</script>
|
||||
|
61
resources/js/Shared/Pagination.vue
Normal file
61
resources/js/Shared/Pagination.vue
Normal file
@@ -0,0 +1,61 @@
|
||||
<template>
|
||||
<div
|
||||
v-if="pagination.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">
|
||||
<Component
|
||||
:is="prevLink ? 'InertiaLink': 'span'"
|
||||
:href="prevLink"
|
||||
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
|
||||
</Component>
|
||||
<Component
|
||||
:is="nextLink ? 'InertiaLink': 'span'"
|
||||
:href="nextLink"
|
||||
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">{{ pagination.from }}</span>
|
||||
od
|
||||
<span class="font-medium">{{ pagination.to }}</span>
|
||||
do
|
||||
<span class="font-medium">{{ pagination.total }}</span>
|
||||
wyników
|
||||
</div>
|
||||
<nav class="relative z-0 inline-flex space-x-1">
|
||||
<template
|
||||
v-for="(link, index) in pagination.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>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
|
||||
const props = defineProps({
|
||||
pagination: Object,
|
||||
})
|
||||
|
||||
const prevLink = computed(() => props.pagination.links.at(0)?.url)
|
||||
const nextLink = computed(() => props.pagination.links.at(-1)?.url)
|
||||
|
||||
</script>
|
@@ -2,36 +2,21 @@
|
||||
<div class="flex items-center">
|
||||
<component
|
||||
:is="statusInfo.solid.icon"
|
||||
:class="[statusInfo.solid.color ,'w-5 h-5 mr-1']"
|
||||
:class="[statusInfo.solid.color, 'w-5 h-5 mr-1']"
|
||||
/>
|
||||
<span>{{ statusInfo.text }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {computed} from 'vue'
|
||||
import {useStatusInfo} from '@/Composables/statusInfo'
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import { useStatusInfo } from '@/Composables/statusInfo'
|
||||
|
||||
export default {
|
||||
name: 'VacationRequestStatus',
|
||||
props: {
|
||||
status: {
|
||||
type: String,
|
||||
default: () => null,
|
||||
},
|
||||
last: {
|
||||
type: Boolean,
|
||||
default: () => false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { findStatus } = useStatusInfo()
|
||||
const props = defineProps({
|
||||
status: String,
|
||||
})
|
||||
|
||||
const statusInfo = computed(() => findStatus(props.status))
|
||||
const { findStatus } = useStatusInfo()
|
||||
|
||||
return {
|
||||
statusInfo,
|
||||
}
|
||||
},
|
||||
}
|
||||
const statusInfo = computed(() => findStatus(props.status))
|
||||
</script>
|
||||
|
@@ -6,17 +6,13 @@
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script setup>
|
||||
import { use } from 'echarts/core'
|
||||
import { CanvasRenderer } from 'echarts/renderers'
|
||||
import { PieChart } from 'echarts/charts'
|
||||
import {
|
||||
TitleComponent,
|
||||
TooltipComponent,
|
||||
LegendComponent,
|
||||
} from 'echarts/components'
|
||||
import { TitleComponent, TooltipComponent, LegendComponent } from 'echarts/components'
|
||||
import VChart from 'vue-echarts'
|
||||
import {computed} from 'vue'
|
||||
import { computed } from 'vue'
|
||||
|
||||
use([
|
||||
CanvasRenderer,
|
||||
@@ -26,68 +22,59 @@ use([
|
||||
LegendComponent,
|
||||
])
|
||||
|
||||
export default {
|
||||
name: 'VacationChart',
|
||||
components: {
|
||||
VChart,
|
||||
const props = defineProps({
|
||||
stats: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
used: 0,
|
||||
pending: 0,
|
||||
remaining: 0,
|
||||
}),
|
||||
},
|
||||
props: {
|
||||
stats: {
|
||||
type: Object,
|
||||
default: () => ({
|
||||
used: 0,
|
||||
pending: 0,
|
||||
remaining: 0,
|
||||
}),
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const option = computed(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b} : {c} ({d}%)',
|
||||
},
|
||||
color: [
|
||||
'#2C466F',
|
||||
'#AABDDD',
|
||||
'#527ABA',
|
||||
],
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
data: ['Wykorzystane', 'Rozpatrywane', 'Pozostałe'],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Urlop wypoczynkowy',
|
||||
type: 'pie',
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inner',
|
||||
formatter: param => param.value !== 0 ? param.value : '' ,
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
color: '#FFFFFF',
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{ value: props.stats.used, name: 'Wykorzystane' },
|
||||
{ value: props.stats.pending, name: 'Rozpatrywane' },
|
||||
{ value: props.stats.remaining, name: 'Pozostałe' },
|
||||
],
|
||||
radius: ['30%', '70%'],
|
||||
},
|
||||
],
|
||||
}))
|
||||
})
|
||||
|
||||
return { option }
|
||||
const option = computed(() => ({
|
||||
tooltip: {
|
||||
trigger: 'item',
|
||||
formatter: '{a} <br/>{b} : {c} ({d}%)',
|
||||
},
|
||||
}
|
||||
color: [
|
||||
'#2C466F',
|
||||
'#AABDDD',
|
||||
'#527ABA',
|
||||
],
|
||||
legend: {
|
||||
orient: 'vertical',
|
||||
left: 'left',
|
||||
data: ['Wykorzystane', 'Rozpatrywane', 'Pozostałe'],
|
||||
},
|
||||
series: [
|
||||
{
|
||||
name: 'Urlop wypoczynkowy',
|
||||
type: 'pie',
|
||||
itemStyle: {
|
||||
borderRadius: 10,
|
||||
borderColor: '#fff',
|
||||
borderWidth: 2,
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: 'inner',
|
||||
formatter: param => param.value !== 0 ? param.value : '' ,
|
||||
fontWeight: 'bold',
|
||||
fontSize: 16,
|
||||
color: '#FFFFFF',
|
||||
labelLine: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
data: [
|
||||
{ value: props.stats.used, name: 'Wykorzystane' },
|
||||
{ value: props.stats.pending, name: 'Rozpatrywane' },
|
||||
{ value: props.stats.remaining, name: 'Pozostałe' },
|
||||
],
|
||||
radius: ['30%', '70%'],
|
||||
},
|
||||
],
|
||||
}))
|
||||
</script>
|
||||
|
@@ -9,30 +9,15 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {computed} from 'vue'
|
||||
import {useVacationTypeInfo} from '@/Composables/vacationTypeInfo'
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import useVacationTypeInfo from '@/Composables/vacationTypeInfo'
|
||||
|
||||
export default {
|
||||
name: 'VacationType',
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: () => null,
|
||||
},
|
||||
last: {
|
||||
type: Boolean,
|
||||
default: () => false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { findType } = useVacationTypeInfo()
|
||||
const props = defineProps({
|
||||
type: String,
|
||||
})
|
||||
|
||||
const vacationTypeInfo = computed(() => findType(props.type))
|
||||
const { findType } = useVacationTypeInfo()
|
||||
|
||||
return {
|
||||
vacationTypeInfo,
|
||||
}
|
||||
},
|
||||
}
|
||||
const vacationTypeInfo = computed(() => findType(props.type))
|
||||
</script>
|
||||
|
@@ -15,34 +15,16 @@
|
||||
</Popper>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {computed} from 'vue'
|
||||
import {useVacationTypeInfo} from '@/Composables/vacationTypeInfo'
|
||||
<script setup>
|
||||
import { computed } from 'vue'
|
||||
import useVacationTypeInfo from '@/Composables/vacationTypeInfo'
|
||||
import Popper from 'vue3-popper'
|
||||
|
||||
export default {
|
||||
name: 'VacationTypeCalendarIcon',
|
||||
components: {
|
||||
Popper,
|
||||
},
|
||||
props: {
|
||||
type: {
|
||||
type: String,
|
||||
default: () => null,
|
||||
},
|
||||
last: {
|
||||
type: Boolean,
|
||||
default: () => false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const { findType } = useVacationTypeInfo()
|
||||
const props = defineProps({
|
||||
type: String,
|
||||
})
|
||||
|
||||
const typeInfo = computed(() => findType(props.type))
|
||||
const { findType } = useVacationTypeInfo()
|
||||
|
||||
return {
|
||||
typeInfo,
|
||||
}
|
||||
},
|
||||
}
|
||||
const typeInfo = computed(() => findType(props.type))
|
||||
</script>
|
||||
|
42
resources/js/Shared/Widgets/AbsenceList.vue
Normal file
42
resources/js/Shared/Widgets/AbsenceList.vue
Normal file
@@ -0,0 +1,42 @@
|
||||
<template>
|
||||
<section class="bg-white shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Dzisiejsze nieobecności
|
||||
</h2>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 px-4 sm:px-6">
|
||||
<ul class="divide-y divide-gray-200">
|
||||
<li
|
||||
v-for="absence in absences"
|
||||
:key="absence.user.id"
|
||||
class="py-4 flex"
|
||||
>
|
||||
<img
|
||||
class="h-10 w-10 rounded-full"
|
||||
:src="absence.user.avatar"
|
||||
>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">
|
||||
{{ absence.user.name }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ absence.user.email }}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="! absences.length">
|
||||
<p class="py-2">
|
||||
Brak danych
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
absences: Object,
|
||||
})
|
||||
</script>
|
76
resources/js/Shared/Widgets/PendingVacationRequests.vue
Normal file
76
resources/js/Shared/Widgets/PendingVacationRequests.vue
Normal file
@@ -0,0 +1,76 @@
|
||||
<template>
|
||||
<section class="bg-white shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Wnioski oczekujące na akcje
|
||||
</h2>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 pb-5 px-4 sm:px-6">
|
||||
<div class="flow-root mt-6">
|
||||
<ul class="-my-5 divide-y divide-gray-200">
|
||||
<li
|
||||
v-for="request in requests"
|
||||
:key="request.id"
|
||||
class="py-5"
|
||||
>
|
||||
<div class="relative focus-within:ring-2 focus-within:ring-blumilk-500">
|
||||
<h3 class="text-sm font-semibold text-blumilk-600 hover:text-blumilk-500">
|
||||
<InertiaLink
|
||||
:href="`/vacation-requests/${request.id}`"
|
||||
class="hover:underline focus:outline-none"
|
||||
>
|
||||
<span class="absolute inset-0" />
|
||||
Wniosek o {{ findType(request.type).text.toLowerCase() }}
|
||||
[{{ request.name }}]
|
||||
</InertiaLink>
|
||||
</h3>
|
||||
<p class="mt-1 text-sm text-gray-600">
|
||||
{{ request.from }} - {{ request.to }}
|
||||
</p>
|
||||
<div class="mt-3 text-sm text-gray-600">
|
||||
<div class="flex">
|
||||
<img
|
||||
class="h-10 w-10 rounded-full"
|
||||
:src="request.user.avatar"
|
||||
>
|
||||
<div class="ml-3">
|
||||
<p class="text-sm font-medium text-gray-900">
|
||||
{{ request.user.name }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ request.user.email }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="! requests.length">
|
||||
<p class="py-2">
|
||||
Brak danych
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<InertiaLink
|
||||
href="/vacation-requests"
|
||||
:data="{status: 'waiting_for_action'}"
|
||||
class="w-full flex justify-center items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Zobacz wszystkie
|
||||
</InertiaLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import useVacationTypeInfo from '@/Composables/vacationTypeInfo'
|
||||
|
||||
defineProps({
|
||||
requests: Object,
|
||||
})
|
||||
|
||||
const { findType } = useVacationTypeInfo()
|
||||
</script>
|
46
resources/js/Shared/Widgets/UpcomingHolidays.vue
Normal file
46
resources/js/Shared/Widgets/UpcomingHolidays.vue
Normal file
@@ -0,0 +1,46 @@
|
||||
<template>
|
||||
<section class="bg-white shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Najbliższe dni wolne
|
||||
</h2>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 px-4 pb-5 sm:px-6">
|
||||
<ul class="divide-y divide-gray-200">
|
||||
<li
|
||||
v-for="holiday in holidays"
|
||||
:key="holiday.id.id"
|
||||
class="py-4 flex"
|
||||
>
|
||||
<div>
|
||||
<p class="text-sm font-medium text-gray-900">
|
||||
{{ holiday.name }}
|
||||
</p>
|
||||
<p class="text-sm text-gray-500">
|
||||
{{ holiday.displayDate }}
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="! holidays.length">
|
||||
<p class="py-2">
|
||||
Brak danych
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
<div>
|
||||
<InertiaLink
|
||||
href="/holidays"
|
||||
class="w-full flex justify-center items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Zobacz wszystkie
|
||||
</InertiaLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
holidays: Object,
|
||||
})
|
||||
</script>
|
62
resources/js/Shared/Widgets/UserVacationRequests.vue
Normal file
62
resources/js/Shared/Widgets/UserVacationRequests.vue
Normal file
@@ -0,0 +1,62 @@
|
||||
<template>
|
||||
<section class="bg-white shadow-md">
|
||||
<div class="p-4 sm:px-6">
|
||||
<h2 class="text-lg leading-6 font-medium text-gray-900">
|
||||
Twoje wnioski
|
||||
</h2>
|
||||
</div>
|
||||
<div class="border-t border-gray-200 pb-5 px-4 sm:px-6">
|
||||
<div class="flow-root mt-6">
|
||||
<ul class="-my-5 divide-y divide-gray-200">
|
||||
<li
|
||||
v-for="request in requests"
|
||||
:key="request.id"
|
||||
class="py-5"
|
||||
>
|
||||
<div class="relative focus-within:ring-2 focus-within:ring-blumilk-500">
|
||||
<h3 class="text-sm font-semibold text-blumilk-600 hover:text-blumilk-500">
|
||||
<InertiaLink
|
||||
:href="`/vacation-requests/${request.id}`"
|
||||
class="hover:underline focus:outline-none"
|
||||
>
|
||||
<span class="absolute inset-0" />
|
||||
Wniosek o {{ findType(request.type).text.toLowerCase() }}
|
||||
[{{ request.name }}]
|
||||
</InertiaLink>
|
||||
</h3>
|
||||
<p class="mt-1 text-sm text-gray-600">
|
||||
{{ request.from }} - {{ request.to }}
|
||||
</p>
|
||||
<p class="mt-2 text-sm text-gray-600">
|
||||
<Status :status="request.state" />
|
||||
</p>
|
||||
</div>
|
||||
</li>
|
||||
<li v-if="! requests.length">
|
||||
<p class="py-2">
|
||||
Brak danych
|
||||
</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="mt-6">
|
||||
<InertiaLink
|
||||
href="/vacation-requests/me"
|
||||
class="w-full flex justify-center items-center px-4 py-2 border border-gray-300 shadow-sm text-sm font-medium rounded-md text-gray-700 bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blumilk-500"
|
||||
>
|
||||
Zobacz wszystkie
|
||||
</InertiaLink>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import useVacationTypeInfo from '@/Composables/vacationTypeInfo'
|
||||
|
||||
defineProps({
|
||||
requests: Object,
|
||||
})
|
||||
|
||||
const { findType } = useVacationTypeInfo()
|
||||
</script>
|
74
resources/js/Shared/Widgets/VacationStats.vue
Normal file
74
resources/js/Shared/Widgets/VacationStats.vue
Normal file
@@ -0,0 +1,74 @@
|
||||
<template>
|
||||
<section class="grid grid-cols-2 gap-4">
|
||||
<div class="bg-white shadow-md p-4">
|
||||
<VacationChart :stats="stats" />
|
||||
</div>
|
||||
<div class="h-full">
|
||||
<div class="grid grid-cols-2 gap-4 h-full">
|
||||
<div class="px-4 py-5 bg-white shadow-md sm:p-6">
|
||||
<dd class="mt-1 text-4xl font-semibold text-blumilk-500">
|
||||
{{ stats.remaining }}
|
||||
</dd>
|
||||
<dt class="text-md font-medium text-gray-700 truncate">
|
||||
Pozostało
|
||||
</dt>
|
||||
<dt class="text-sm font-medium text-gray-500 mt-2">
|
||||
Dni do wykorzystania teraz.
|
||||
</dt>
|
||||
</div>
|
||||
<div class="px-4 py-5 bg-white shadow-md sm:p-6">
|
||||
<dd class="mt-1 text-4xl font-semibold text-blumilk-700">
|
||||
{{ stats.used }}
|
||||
</dd>
|
||||
<dt class="text-md font-medium text-gray-700 truncate">
|
||||
Dni wykorzystane
|
||||
</dt>
|
||||
<dt class="text-sm font-medium text-gray-500 mt-2">
|
||||
Dni, które zostały już wykorzystane na urlop wypoczynkowy.
|
||||
</dt>
|
||||
</div>
|
||||
<div class="px-4 py-5 bg-white shadow-md sm:p-6">
|
||||
<dt class="mt-1 text-4xl font-semibold text-blumilk-200">
|
||||
{{ stats.pending }}
|
||||
</dt>
|
||||
<dd class="text-md font-medium text-gray-500 truncate">
|
||||
Rozpatrywane
|
||||
</dd>
|
||||
<dt class="text-sm font-medium text-gray-500 mt-2">
|
||||
Dni czekające na akceptację przełożonych.
|
||||
</dt>
|
||||
</div>
|
||||
<div class="px-4 py-5 bg-white shadow-md sm:p-6">
|
||||
<dt class="mt-1 text-4xl font-semibold text-gray-900">
|
||||
{{ stats.limit }}
|
||||
</dt>
|
||||
<dd class="text-md font-medium text-gray-500 truncate">
|
||||
Limit urlopu
|
||||
</dd>
|
||||
<dt class="text-sm font-medium text-gray-500 mt-2">
|
||||
Twój roczny limit urlopu wypoczynkowego.
|
||||
</dt>
|
||||
</div>
|
||||
<div class="px-4 py-5 bg-white shadow-md sm:p-6 col-span-2">
|
||||
<dt class="mt-1 text-4xl font-semibold text-gray-900">
|
||||
{{ stats.other }}
|
||||
</dt>
|
||||
<dd class="text-md font-medium text-gray-500 truncate">
|
||||
Inne urlopy
|
||||
</dd>
|
||||
<dt class="text-sm font-medium text-gray-500 mt-2">
|
||||
Urlopy bezpłatne, okolicznościowe, zwolnienia lekarskie, itd., które zostały już zatwierdzone.
|
||||
</dt>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import VacationChart from '@/Shared/VacationChart'
|
||||
|
||||
defineProps({
|
||||
stats: Object,
|
||||
})
|
||||
</script>
|
35
resources/js/Shared/Widgets/Welcome.vue
Normal file
35
resources/js/Shared/Widgets/Welcome.vue
Normal file
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<section>
|
||||
<div class=" bg-white overflow-hidden shadow">
|
||||
<div class="bg-white p-6">
|
||||
<div class="sm:flex sm:items-center sm:justify-between">
|
||||
<div class="sm:flex sm:space-x-5">
|
||||
<div class="flex-shrink-0">
|
||||
<img
|
||||
class="mx-auto h-20 w-20 rounded-full"
|
||||
:src="user.avatar"
|
||||
>
|
||||
</div>
|
||||
<div class="mt-4 text-center sm:mt-0 sm:pt-1 sm:text-left">
|
||||
<p class="text-sm font-medium text-gray-600">
|
||||
Cześć,
|
||||
</p>
|
||||
<p class="text-xl font-bold text-gray-900 sm:text-2xl">
|
||||
{{ user.name }}
|
||||
</p>
|
||||
<p class="text-sm font-medium text-gray-600">
|
||||
{{ user.role }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
defineProps({
|
||||
user: Object,
|
||||
})
|
||||
</script>
|
Reference in New Issue
Block a user