vue-appointment-selector
v2.1.0
Published
A customizable component for select appointments on vue
Downloads
82
Readme
Vue Appointment Selector
A simple and customizable component for selecting appointments in Vue 3.
Installation
NPM
npm install vue-appointment-selector --save
Browser
Include the basic stylesheet
<link rel="stylesheet" href="https://unpkg.com/[email protected]/dist/basics.min.css">
Vue Appointment Selector needs the dayjs library to work, so you need to import the library before importing the component
<script src="https://unpkg.com/[email protected]/dayjs.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/appointment-selector.min.js"></script>
Usage
First, register Vue Appointment Selector in your app entry point (app.js
) .
import Vue from 'vue'
import { VueAppointmentSelector } from 'vue-appointment-selector'
Vue.use(VueAppointmentSelector)
...
Or directly in your component
<script>
import VueAppointmentSelector from 'vue-appointment-selector'
export default {
components: { 'appointment-selector': VueAppointmentSelector },
...
}
</script>
Next, use it on your template
<template>
<appointment-selector v-model:selected="schedule" :intervals="intervals" @cell-clicked="cellClicked"/>
</template>
<script>
import VueAppointmentSelector from 'vue-appointment-selector'
export default {
components: { 'appointment-selector': VueAppointmentSelector },
data() {
return {
schedule: {},
intervals: [
{
from: { hour: 9, minute: 0 },
to: { hour: 12, minute: 0 }
},
{
from: { hour: 16, minute: 0 },
to: { hour: 18, minute: 0 }
},
]
}
}
methods() {
cellClicked(meeting) {
console.log(meeting.start, meeting.end)
}
}
...
}
</script>
Configuring the component
Vue Appointment Selector includes props that allows you to configure things like, work days, work intervals, appointment duration, among other.
appointments-taken
Set appointments that have already been taken in appointment object format.
type: Array
[
{
start: '2021-02-22 09:00:00',
end: '2021-02-22 09:30:00'
},
{
start: '2021-02-22 09:00:00',
end: '2021-02-22 09:30:00'
}
]
intervals
Specifies the work intervals during the day, various intervals can be set, for example to consider the time of rest.
type: Array
// Set the intervals in 24 hour format
[
{
from: { hour: 9, minute: 0 },
to: { hour: 12, minute: 0 }
},
{
from: { hour: 16, minute: 0 },
to: { hour: 18, minute: 0 }
},
]
appointment-duration
Specify the duration time in minutes of each appointment, by default it is set to 30 minutes.
type: Number
appointmentDuration: 30
non-working-days
It accepts an an index array of the days of the week that will not be enabled, by default Saturday (6) and Sunday (0) are set.
type: Array
[
0, // Sunday
1, // Monday
2, // Tuesday
3, // Wednesday
4, // Thursday
5, // Friday
6, // Saturday
]
schedule-label
Sets the label when no schedule is selected.
type: String
sheduleLabel: 'No schedule has been selected'
relation-label
Sets the label to indicate the relationship between hours and days.
type: String
relationLabel: 'Hour / Day'
min-weeks
Sets the minimum number of weeks that must be loaded at the beginning, by default only one week is loaded.
type: Number
minWeeks: 2 // The component will be created with 2 weeks
Customizing the component
Various aspects of the component can be customized using Vue scopes, the cell data will be injected into each template.
Cell content
The content of the cells can be customized with the info
slot.
<template v-slot:info="data">
<div class="custom-cell-info">
<div v-if="data.appointment !== undefined">
<span class="info-icon">ⓘ</span>
</div>
</div>
</template>
Pop Up Title
The title of the pop up can be customized with the pop-up-title
slot.
<template v-slot:pop-up-title="data">
<span>{{ `${data.appointment.start} - ${data.appointment.end}` }}</span>
</template>
Pop Up Content
There are three ways to customize the content of the pop-up windows, for the appointments that have been taken.
Single pop-up
The content will be displayed in the pop up window as plain text of the text
argument..
appointmentsTaken: [
{
start: '2021-02-23 15:00:00',
end: '2021-02-23 15:30:00',
text: 'This is a plain text'
},
...
]
HTML pop-up
The content will be displayed in the pop up window as HTML text of the html
argument.
appointmentsTaken: [
{
start: '2021-02-23 15:00:00',
end: '2021-02-23 15:30:00',
html: 'This is a <strong>HTML text<strong>'
},
...
]
Template pop-up
This form allows you to have a total control of the content that will be displayed in the pop-up window.
Any data structure can be set within the data
attribute.
appointmentsTaken: [
{
start: '2021-02-23 15:00:00',
end: '2021-02-23 15:30:00',
data: {
user: {
name: 'Christian',
lastname: 'Albán',
},
description: 'A scoped template pop up'
}
},
...
]
The object will be injected into the template in the parent component.
<template v-slot:pop-up-info="data">
<div class="custom-pop-up-info">
<span>
<strong>User: </strong>
{{ `${data.appointment.data.user.name} ${data.appointment.data.user.lastname}` }}
</span>
<p>{{ data.appointment.data.description }}</p>
</div>
</template>
Events
@cell-clicked
This event is emitted when an empty cell is clicked
<template>
<appointment-selector @cell-clicked="cellClicked"/>
</template>
<script>
import VueAppointmentSelector from 'vue-appointment-selector'
export default {
components: { 'appointment-selector': VueAppointmentSelector },
...
methods() {
cellClicked(meeting) {
console.log(meeting.start, meeting.end)
}
}
...
}
</script>
Vue Appointment Selector allows you to customize various components, here is an example stylesheet of all available classes.
/*
* Appointment styles
*/
.appointment-selector {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
.schedule-header {
margin-top: 15px;
margin-bottom: 15px;
}
.selected-schedule-label {
font-style: italic;
}
.schedule {
background-color: white;
border: 1px solid #0071c0;
border-radius: 15px;
box-shadow: 0px 4px 19px 0px #4d4747;
}
.header-label {
background-color: white;
font-size: 15px;
text-align: center;
}
.relation-label {
color: #0071c0;
}
.week-day-label {
font-weight: normal;
}
.cell {
border: 1px solid #797979;
}
.cell-time {
background-color: #d9d9db;
}
.cell-available {
background-color: transparent;
transition: background-color .3s ease;
}
.cell-available:hover {
background-color: #0071c0;
}
.cell-disabled {
background-color: #9b9b9b;
}
.cell-selected {
background-color: #40b0ff;
}
.info-icon {
color: white;
}
/*
* Pop up styles
*/
.container:hover .pop-up, .persist{
max-width: 500px !important;
max-height: 500px !important;
border: 1px solid #0071c0;
animation: show-info .3s ease;
}
.pop-up {
max-width: 0px;
max-height: 0px;
overflow: hidden;
border-radius: 5px;
background-color: white;
box-shadow: 0px 0px 19px -2px #4d4747;
transition: .3s ease;
text-align: start;
}
.pop-up-title {
width: max-content;
padding: 5px 15px;
}
.pop-up-content {
width: max-content;
height: max-content;
padding: 15px;
}
@keyframes show-info {
from {
max-width: 0px;
max-height: 0px;
transform: translateX(-10px);
}
to {
max-width: 500px;
max-height: 500px;
transform: translateX(0);
}
}
/*
* Custom user styles
*/
.custom-pop-up-info span {
display: block;
}
.custom-cell-info {
text-align: end;
}
.custom-cell-info span{
margin-right: .3rem;
}