Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#328 - highlight and order calendar #499

Merged
merged 10 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 83 additions & 66 deletions resources/js/Pages/Calendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { router } from '@inertiajs/vue3'
import InertiaLink from '@/Shared/InertiaLink.vue'
import { useGlobalProps } from '@/Composables/useGlobalProps'
import AppLayout from '@/Shared/Layout/AppLayout.vue'
import { useStorage } from '@vueuse/core'
import Draggable from 'vuedraggable'

const props = defineProps({
users: Object,
Expand All @@ -20,7 +22,10 @@ const props = defineProps({

const { auth } = useGlobalProps()

let activeElement = ref(undefined)
const highlighted = useStorage(`calendar-highlight:${auth.value.user.id}`, [])
const order = useStorage(`calendar-order:${auth.value.user.id}`, props.users.data.map(user => user.id))

const usersInOrder = ref([...props.users.data].sort((a, b) => order.value.indexOf(a.id) > order.value.indexOf(b.id) ? 1 : -1))

const currentDate = DateTime.now()

Expand All @@ -34,6 +39,10 @@ watch(selectedMonth, (value, oldValue) => {
router.visit(`/calendar/${value.toFormat('LL-yyyy')}`)
})

watch(usersInOrder, (value) => {
order.value = value.map(item => item.id)
})

function previousMonth() {
selectedMonth.value = selectedMonth.value.minus({ month: 1 })
}
Expand All @@ -46,26 +55,23 @@ function currentMonth() {
selectedMonth.value = currentDate
}

function isActiveDay(key) {
return activeElement.value === key
}

function setActiveDay(key) {
if (activeElement.value === undefined)
activeElement.value = key
}

function unsetActiveDay() {
activeElement.value = undefined
}

function linkParameters(user, day) {
return auth.value.can.createRequestsOnBehalfOfEmployee ? { user: user.id, from_date: day.date } : { from_date: day.date }
}

function linkVacationRequest(user) {
return auth.value.user.id === user.id || auth.value.can.manageRequestsAsTechnicalApprover || auth.value.can.manageRequestsAsAdministrativeApprover
}

function toggleHighlight(id) {
if (highlighted.value.includes(id)) {
highlighted.value = highlighted.value.filter(item => item !== id)

return
}

highlighted.value.push(id)
}
</script>

<template>
Expand Down Expand Up @@ -145,7 +151,7 @@ function linkVacationRequest(user) {
<tr>
<th class="py-2 w-64 text-lg font-semibold text-gray-800 border border-gray-300">
<div class="flex justify-center items-center capitalize">
{{ selectedMonth.toLocaleString({ month: 'long', year: 'numeric' }) }}
{{ selectedMonth.toLocaleString({month: 'long', year: 'numeric'}) }}
</div>
</th>
<th
Expand All @@ -164,62 +170,73 @@ function linkVacationRequest(user) {
</th>
</tr>
</thead>
<tbody>
<tr
v-for="user in users.data"
:key="user.id"
:class="[user.isActive ? '' : 'bg-gray-100']"
>
<th class="p-2 border border-gray-300">
<UserProfileLink
:user="user"
<Draggable
v-model="usersInOrder"
tag="tbody"
ghost-class="opacity-50"
handle=".handle"
:animation="200"
:component-data="{tag: 'div', type: 'transition-group'}"
:item-key="((item) => usersInOrder.indexOf(item))"
>
<template #item="{ element }">
<tr
:class="[!element.isActive && 'bg-gray-100', element.isActive && highlighted.includes(element.id) && 'bg-green-600/5']"
>
<th
:class="['p-2 border border-gray-300 text-left', highlighted.includes(element.id) && 'bg-green-600/5']"
@click="toggleHighlight(element.id)"
>
<div class="flex justify-start items-center">
<span class="inline-flex justify-center items-center size-8 rounded-full">
<img :src="user.avatar">
</span>
<div class="ml-3">
<div class="text-sm font-medium text-gray-900 truncate">
{{ user.name }}
<UserProfileLink
class="inline-flex"
:user="element"
>
<div class="flex justify-start items-center">
<span class="inline-flex justify-center items-center size-8 rounded-full handle cursor-move">
<img :src="element.avatar">
</span>
<div class="ml-3">
<div class="text-sm font-medium text-gray-900 truncate">
{{ element.name }}
</div>
</div>
</div>
</div>
</UserProfileLink>
</th>
<td
v-for="day in calendar"
:key="day.dayOfMonth"
:class="{ 'bg-blumilk-25': day.isToday, 'bg-red-100': day.isWeekend || day.isHoliday }"
class="border border-gray-300"
@mouseleave="unsetActiveDay"
@mouseover="setActiveDay(user.id + '+' + day.date)"
>
<div
v-if="user.id in day.vacations"
class="flex justify-center items-center"
</UserProfileLink>
</th>
<td
v-for="day in calendar"
:key="day.dayOfMonth"
:class="{ 'bg-blumilk-25': day.isToday, 'bg-red-100': day.isWeekend || day.isHoliday }"
class="border border-gray-300 group"
>
<CalendarDay
:see-vacation-details="linkVacationRequest(user)"
:vacation="day.vacations[user.id]"
/>
</div>
<template
v-else-if="isActiveDay(user.id + '+' + day.date) && !day.isWeekend && !day.isHoliday && (auth.user.id === user.id || auth.can.createRequestsOnBehalfOfEmployee)"
>
<InertiaLink
:data="linkParameters(user, day)"
href="/vacation/requests/create"
<div
v-if="element.id in day.vacations"
class="flex justify-center items-center"
>
<div class="flex justify-center items-center">
<VacationTypeCalendarIcon
type="create"
/>
</div>
</InertiaLink>
</template>
</td>
</tr>
</tbody>
<CalendarDay
:see-vacation-details="linkVacationRequest(element)"
:vacation="day.vacations[element.id]"
/>
</div>
<template
v-else-if="!day.isWeekend && !day.isHoliday && (auth.user.id === element.id || auth.can.createRequestsOnBehalfOfEmployee)"
>
<InertiaLink
:data="linkParameters(element, day)"
href="/vacation/requests/create"
class="hidden group-hover:block"
>
<div class="flex justify-center items-center">
<VacationTypeCalendarIcon
type="create"
/>
</div>
</InertiaLink>
</template>
</td>
</tr>
</template>
</Draggable>
</table>
</div>
</div>
Expand Down
1 change: 1 addition & 0 deletions resources/js/Shared/UserProfileLink.vue
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const { auth } = useGlobalProps()
<InertiaLink
v-if="auth.can.manageUsers"
:href="`/users/${user.id}`"
@click.stop
>
<slot />
</InertiaLink>
Expand Down
Loading