Skip to content

Commit 118c7fc

Browse files
authored
#328 - highlight and order calendar (#499)
* #431 - bump everything * cs fix * fix * fix * #328 - highlight in calendar * #328 - highlight and order calendar * cr fix * fix * fix
1 parent 8f89f09 commit 118c7fc

File tree

2 files changed

+84
-66
lines changed

2 files changed

+84
-66
lines changed

resources/js/Pages/Calendar.vue

Lines changed: 83 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import { router } from '@inertiajs/vue3'
1010
import InertiaLink from '@/Shared/InertiaLink.vue'
1111
import { useGlobalProps } from '@/Composables/useGlobalProps'
1212
import AppLayout from '@/Shared/Layout/AppLayout.vue'
13+
import { useStorage } from '@vueuse/core'
14+
import Draggable from 'vuedraggable'
1315
1416
const props = defineProps({
1517
users: Object,
@@ -20,7 +22,10 @@ const props = defineProps({
2022
2123
const { auth } = useGlobalProps()
2224
23-
let activeElement = ref(undefined)
25+
const highlighted = useStorage(`calendar-highlight:${auth.value.user.id}`, [])
26+
const order = useStorage(`calendar-order:${auth.value.user.id}`, props.users.data.map(user => user.id))
27+
28+
const usersInOrder = ref([...props.users.data].sort((a, b) => order.value.indexOf(a.id) > order.value.indexOf(b.id) ? 1 : -1))
2429
2530
const currentDate = DateTime.now()
2631
@@ -34,6 +39,10 @@ watch(selectedMonth, (value, oldValue) => {
3439
router.visit(`/calendar/${value.toFormat('LL-yyyy')}`)
3540
})
3641
42+
watch(usersInOrder, (value) => {
43+
order.value = value.map(item => item.id)
44+
})
45+
3746
function previousMonth() {
3847
selectedMonth.value = selectedMonth.value.minus({ month: 1 })
3948
}
@@ -46,26 +55,23 @@ function currentMonth() {
4655
selectedMonth.value = currentDate
4756
}
4857
49-
function isActiveDay(key) {
50-
return activeElement.value === key
51-
}
52-
53-
function setActiveDay(key) {
54-
if (activeElement.value === undefined)
55-
activeElement.value = key
56-
}
57-
58-
function unsetActiveDay() {
59-
activeElement.value = undefined
60-
}
61-
6258
function linkParameters(user, day) {
6359
return auth.value.can.createRequestsOnBehalfOfEmployee ? { user: user.id, from_date: day.date } : { from_date: day.date }
6460
}
6561
6662
function linkVacationRequest(user) {
6763
return auth.value.user.id === user.id || auth.value.can.manageRequestsAsTechnicalApprover || auth.value.can.manageRequestsAsAdministrativeApprover
6864
}
65+
66+
function toggleHighlight(id) {
67+
if (highlighted.value.includes(id)) {
68+
highlighted.value = highlighted.value.filter(item => item !== id)
69+
70+
return
71+
}
72+
73+
highlighted.value.push(id)
74+
}
6975
</script>
7076
7177
<template>
@@ -145,7 +151,7 @@ function linkVacationRequest(user) {
145151
<tr>
146152
<th class="py-2 w-64 text-lg font-semibold text-gray-800 border border-gray-300">
147153
<div class="flex justify-center items-center capitalize">
148-
{{ selectedMonth.toLocaleString({ month: 'long', year: 'numeric' }) }}
154+
{{ selectedMonth.toLocaleString({month: 'long', year: 'numeric'}) }}
149155
</div>
150156
</th>
151157
<th
@@ -164,62 +170,73 @@ function linkVacationRequest(user) {
164170
</th>
165171
</tr>
166172
</thead>
167-
<tbody>
168-
<tr
169-
v-for="user in users.data"
170-
:key="user.id"
171-
:class="[user.isActive ? '' : 'bg-gray-100']"
172-
>
173-
<th class="p-2 border border-gray-300">
174-
<UserProfileLink
175-
:user="user"
173+
<Draggable
174+
v-model="usersInOrder"
175+
tag="tbody"
176+
ghost-class="opacity-50"
177+
handle=".handle"
178+
:animation="200"
179+
:component-data="{tag: 'div', type: 'transition-group'}"
180+
:item-key="((item) => usersInOrder.indexOf(item))"
181+
>
182+
<template #item="{ element }">
183+
<tr
184+
:class="[!element.isActive && 'bg-gray-100', element.isActive && highlighted.includes(element.id) && 'bg-green-600/5']"
185+
>
186+
<th
187+
:class="['p-2 border border-gray-300 text-left', highlighted.includes(element.id) && 'bg-green-600/5']"
188+
@click="toggleHighlight(element.id)"
176189
>
177-
<div class="flex justify-start items-center">
178-
<span class="inline-flex justify-center items-center size-8 rounded-full">
179-
<img :src="user.avatar">
180-
</span>
181-
<div class="ml-3">
182-
<div class="text-sm font-medium text-gray-900 truncate">
183-
{{ user.name }}
190+
<UserProfileLink
191+
class="inline-flex"
192+
:user="element"
193+
>
194+
<div class="flex justify-start items-center">
195+
<span class="inline-flex justify-center items-center size-8 rounded-full handle cursor-move">
196+
<img :src="element.avatar">
197+
</span>
198+
<div class="ml-3">
199+
<div class="text-sm font-medium text-gray-900 truncate">
200+
{{ element.name }}
201+
</div>
184202
</div>
185203
</div>
186-
</div>
187-
</UserProfileLink>
188-
</th>
189-
<td
190-
v-for="day in calendar"
191-
:key="day.dayOfMonth"
192-
:class="{ 'bg-blumilk-25': day.isToday, 'bg-red-100': day.isWeekend || day.isHoliday }"
193-
class="border border-gray-300"
194-
@mouseleave="unsetActiveDay"
195-
@mouseover="setActiveDay(user.id + '+' + day.date)"
196-
>
197-
<div
198-
v-if="user.id in day.vacations"
199-
class="flex justify-center items-center"
204+
</UserProfileLink>
205+
</th>
206+
<td
207+
v-for="day in calendar"
208+
:key="day.dayOfMonth"
209+
:class="{ 'bg-blumilk-25': day.isToday, 'bg-red-100': day.isWeekend || day.isHoliday }"
210+
class="border border-gray-300 group"
200211
>
201-
<CalendarDay
202-
:see-vacation-details="linkVacationRequest(user)"
203-
:vacation="day.vacations[user.id]"
204-
/>
205-
</div>
206-
<template
207-
v-else-if="isActiveDay(user.id + '+' + day.date) && !day.isWeekend && !day.isHoliday && (auth.user.id === user.id || auth.can.createRequestsOnBehalfOfEmployee)"
208-
>
209-
<InertiaLink
210-
:data="linkParameters(user, day)"
211-
href="/vacation/requests/create"
212+
<div
213+
v-if="element.id in day.vacations"
214+
class="flex justify-center items-center"
212215
>
213-
<div class="flex justify-center items-center">
214-
<VacationTypeCalendarIcon
215-
type="create"
216-
/>
217-
</div>
218-
</InertiaLink>
219-
</template>
220-
</td>
221-
</tr>
222-
</tbody>
216+
<CalendarDay
217+
:see-vacation-details="linkVacationRequest(element)"
218+
:vacation="day.vacations[element.id]"
219+
/>
220+
</div>
221+
<template
222+
v-else-if="!day.isWeekend && !day.isHoliday && (auth.user.id === element.id || auth.can.createRequestsOnBehalfOfEmployee)"
223+
>
224+
<InertiaLink
225+
:data="linkParameters(element, day)"
226+
href="/vacation/requests/create"
227+
class="hidden group-hover:block"
228+
>
229+
<div class="flex justify-center items-center">
230+
<VacationTypeCalendarIcon
231+
type="create"
232+
/>
233+
</div>
234+
</InertiaLink>
235+
</template>
236+
</td>
237+
</tr>
238+
</template>
239+
</Draggable>
223240
</table>
224241
</div>
225242
</div>

resources/js/Shared/UserProfileLink.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ const { auth } = useGlobalProps()
1313
<InertiaLink
1414
v-if="auth.can.manageUsers"
1515
:href="`/users/${user.id}`"
16+
@click.stop
1617
>
1718
<slot />
1819
</InertiaLink>

0 commit comments

Comments
 (0)