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

feat: add new event datetime was clicked #184

Merged
merged 21 commits into from
Jun 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fb64c83
feat: add styles for dark mode
tomosterlund Jun 16, 2023
5597b25
test: add visual regression tests for dark mode
tomosterlund Jun 17, 2023
4e84d88
feat: create function for calculating time based on clickOffset and w…
tomosterlund Jun 19, 2023
0140fc2
test: add test cases for getTimeFromClick
tomosterlund Jun 19, 2023
b96317c
refactor: implement time.doubleDigit
tomosterlund Jun 20, 2023
db2d371
test: add tests to Qalendar.test.ts
tomosterlund Jun 20, 2023
1058004
test: add more tests to Qalendar.test.ts
tomosterlund Jun 20, 2023
2517902
feat: make datetime-was-clicked compatible with flexible day boundaries
tomosterlund Jun 20, 2023
626ba5b
feat: deprecate day-was-clicked and add date-was-clicked for month view
tomosterlund Jun 22, 2023
99c5334
docs: add documentation for datetime-was-clicked and date-was-clicked
tomosterlund Jun 22, 2023
5e99aa6
test: add unit tests for Month.test.ts
tomosterlund Jun 22, 2023
a8d1868
test: add more tests to Month.test.ts
tomosterlund Jun 22, 2023
dc05b4b
test: add unit tests for language function
tomosterlund Jun 23, 2023
be83085
test: add unit tests for language function
tomosterlund Jun 23, 2023
ae1f24b
fix: implicit type any
tomosterlund Jun 24, 2023
ccdc276
test: add unit tests for Errors.ts
tomosterlund Jun 24, 2023
befc260
test: add unit tests for EventFlyoutPosition.ts
tomosterlund Jun 24, 2023
1ce38c9
test: add unit tests for month/Day.vue
tomosterlund Jun 24, 2023
8e6162a
test: add unit tests for Week.vue and DatePicker.vue
tomosterlund Jun 24, 2023
c5841f6
test: add unit tests for DatePicker.vue
tomosterlund Jun 26, 2023
cddc9d2
refactor: remove unnecessary watcher in DatePicker.vue
tomosterlund Jun 28, 2023
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
8 changes: 5 additions & 3 deletions development/QalendarView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
@edit-event="editEvent"
@delete-event="deleteEvent"
@day-was-clicked="reactToEvent"
@date-was-clicked="reactToEvent"
@datetime-was-clicked="reactToEvent"
@event-was-dragged="handleEventWasDragged"
@interval-was-clicked="handleIntervalWasClicked"
>
Expand Down Expand Up @@ -147,16 +149,16 @@ export default defineComponent({
},
},
},
defaultMode: 'month',
// defaultMode: 'day',
showCurrentTime: true,
isSilent: true,
dayIntervals: {
height: 50,
length: 30,
},
dayBoundaries: {
start: 4,
end: 4,
start: 5,
end: 5,
},
eventDialog: {
isDisabled: false,
Expand Down
2 changes: 1 addition & 1 deletion development/data/seeded-events.ts

Large diffs are not rendered by default.

26 changes: 15 additions & 11 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ prevent this by wrapping it in an element with the inline style `style="color-sc
Qalendar takes a `config` prop, which contains all the most crucial options for configuring its
behavior. `config` is passed as an object, which could look like this:

## Basic configuration

```js
data()
{
Expand Down Expand Up @@ -186,17 +188,19 @@ Please note, however, that you cannot mix these two types of time formats for an

Qalendar emits the following events that can be listened to:

| Event name | Purpose |
|:----------------------:|:--------------------------------------------------------------------------:|
| `event-was-clicked` | |
| `event-was-dragged` | emits the updated event, after an event was dragged |
| `event-was-resized` | emits the updated event, after an event was resized |
| `interval-was-clicked` | [see section on intervals](#intervals) |
| `day-was-clicked` | Emits a the date that a user clicked, e.g. `2022-11-16` |
| `updated-period` | emits the value with the new period selected in the date picker |
| `updated-mode` | emits the new selected mode and the period, when the user changes the mode |
| `edit-event` | is triggered, when a user clicks the edit-icon of an event |
| `delete-event` | is triggered, when a user clicks the delete-icon of an event |
| Event name | Purpose |
|:----------------------:|:-----------------------------------------------------------------------------------------------------------------------------------------------------------:|
| `event-was-clicked` | |
| `event-was-dragged` | emits the updated event, after an event was dragged |
| `event-was-resized` | emits the updated event, after an event was resized |
| `interval-was-clicked` | [see section on intervals](#intervals) |
| `updated-period` | emits the value with the new period selected in the date picker |
| `updated-mode` | emits the new selected mode and the period, when the user changes the mode |
| `edit-event` | is triggered, when a user clicks the edit-icon of an event |
| `delete-event` | is triggered, when a user clicks the delete-icon of an event |
| `datetime-was-clicked` | Emits a the datetime string from where the clicks in week & day modes, e.g. `2022-11-16 00:10` |
| `date-was-clicked` | In month mode, this emits a the date that the user clicked, e.g. `2022-11-16` |
| ~~day-was-clicked~~ | Emits a the date that a user clicked, e.g. `2022-11-16`. **Deprecated**. Will be removed with v4. Use `datetime-was-clicked` and `date-was-clicked` instead |

## Drag and drop

Expand Down
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Qalendar</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
Expand Down
Binary file removed public/favicon.ico
Binary file not shown.
3 changes: 2 additions & 1 deletion renovate.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"config:base"
"config:base",
":disableDependencyDashboard"
],
"packageRules": [
{
Expand Down
12 changes: 10 additions & 2 deletions src/Qalendar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
@delete-event="$emit('delete-event', $event)"
@interval-was-clicked="$emit('interval-was-clicked', $event)"
@day-was-clicked="$emit('day-was-clicked', $event)"
@datetime-was-clicked="$emit('datetime-was-clicked', $event)"
>
<template #weekDayEvent="p">
<slot
Expand Down Expand Up @@ -72,7 +73,7 @@
:config="enhancedConfig"
:period="period"
@event-was-clicked="$emit('event-was-clicked', $event)"
@day-was-clicked="$emit('day-was-clicked', $event)"
@date-was-clicked="handleDateWasClicked"
@event-was-dragged="handleEventWasUpdated($event, 'dragged')"
@updated-period="handleUpdatedPeriod($event, true)"
@edit-event="$emit('edit-event', $event)"
Expand Down Expand Up @@ -152,7 +153,9 @@ export default defineComponent({
'edit-event',
'delete-event',
'interval-was-clicked',
'day-was-clicked',
'day-was-clicked', // TODO: remove with v4. day-was-clicked is deprecated
'date-was-clicked',
'datetime-was-clicked',
],

data() {
Expand Down Expand Up @@ -328,6 +331,11 @@ export default defineComponent({
setTimePointsFromDayBoundary(boundary: number) {
return Time.getTimePointsFromHour(boundary);
},

handleDateWasClicked(payload: string) {
this.$emit('day-was-clicked', payload); // TODO: remove with v4. day-was-clicked is deprecated
this.$emit('date-was-clicked', payload);
}
},
});
</script>
Expand Down
26 changes: 7 additions & 19 deletions src/components/header/DatePicker.vue
Original file line number Diff line number Diff line change
Expand Up @@ -219,18 +219,6 @@ export default defineComponent({
},
},

watch: {
period: {
deep: true,
handler() {
if (this.selectedDate.getTime() === this.period.selectedDate.getTime())
return;

this.hydrateDatePicker();
},
},
},

mounted() {
this.hydrateDatePicker(true);
},
Expand Down Expand Up @@ -355,6 +343,7 @@ export default defineComponent({
},

toggleDatePickerMode() {
// toggle to year
if (this.datePickerMode === 'month') {
this.monthPickerDates = this.time.getCalendarYearMonths(
this.datePickerCurrentDate.getFullYear()
Expand All @@ -363,14 +352,13 @@ export default defineComponent({
return (this.datePickerMode = 'year');
}

if (this.datePickerMode === 'year') {
this.weekPickerDates = this.time.getCalendarMonthSplitInWeeks(
this.datePickerCurrentDate.getFullYear(),
this.datePickerCurrentDate.getMonth()
);
// toggle to month
this.weekPickerDates = this.time.getCalendarMonthSplitInWeeks(
this.datePickerCurrentDate.getFullYear(),
this.datePickerCurrentDate.getMonth()
);

return (this.datePickerMode = 'month');
}
this.datePickerMode = 'month';
},

getLocale() {
Expand Down
4 changes: 2 additions & 2 deletions src/components/month/Day.vue
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export default defineComponent({
'event-was-clicked',
'event-was-dragged',
'updated-period',
'day-was-clicked',
'date-was-clicked',
'day-was-selected',
],

Expand Down Expand Up @@ -190,7 +190,7 @@ export default defineComponent({
},

emitDayWasClicked() {
this.$emit('day-was-clicked', this.time.dateStringFrom(this.day.dateTimeString));
this.$emit('date-was-clicked', this.time.dateStringFrom(this.day.dateTimeString));
if (this.config.isSmall) this.$emit('day-was-selected', this.day);
},
},
Expand Down
8 changes: 2 additions & 6 deletions src/components/month/Month.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
:is-selected="selectedDay?.dateTimeString === day.dateTimeString"
@event-was-clicked="handleClickOnEvent"
@event-was-dragged="handleEventWasDragged"
@day-was-clicked="onDayWasClicked"
@date-was-clicked="$emit('date-was-clicked', $event)"
@day-was-selected="selectedDay = $event"
@updated-period="$emit('updated-period', $event)"
>
Expand Down Expand Up @@ -135,7 +135,7 @@ export default defineComponent({
'updated-period',
'event-was-clicked',
'event-was-dragged',
'day-was-clicked',
'date-was-clicked',
],

data() {
Expand All @@ -156,10 +156,6 @@ export default defineComponent({
},

methods: {
onDayWasClicked(day: dayInterface) {
this.$emit('day-was-clicked', day)
},

initScrollbar(elapsedMs = 0) {
const el = document.querySelector('.calendar-month');
if (elapsedMs > 3000) return;
Expand Down
32 changes: 31 additions & 1 deletion src/components/week/Day.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div
class="calendar-week__day"
@click.self="$emit('day-was-clicked', time.dateStringFrom(day.dateTimeString))"
@click.self="handleClickOnDay"
>
<DayEvent
v-for="(event, eventIndex) in events"
Expand Down Expand Up @@ -88,6 +88,10 @@ export default defineComponent({
type: Object as PropType<dayIntervalsType>,
required: true,
},
weekHeight: {
type: Number,
required: true,
},
},

emits: [
Expand All @@ -96,6 +100,7 @@ export default defineComponent({
'event-was-dragged',
'interval-was-clicked',
'day-was-clicked',
'datetime-was-clicked',
'drag-start',
'drag-end',
],
Expand Down Expand Up @@ -150,6 +155,31 @@ export default defineComponent({
this.time.HOURS_PER_DAY,
).getIntervals()
},

handleClickOnDay(event: MouseEvent) {
const timeClicked = this.time.getTimeFromClick(event.offsetY, this.weekHeight);
let dateString = this.time.dateStringFrom(this.day.dateTimeString);
const isFlexibleDay = this.time.DAY_END <= this.time.DAY_START;
if (isFlexibleDay) dateString = this.getDateStringForFlexibleDayBoundaries(dateString, timeClicked);
const dateTimeString = `${dateString} ${timeClicked}`;

this.$emit('day-was-clicked', dateString);
this.$emit('datetime-was-clicked', dateTimeString);
},

getDateStringForFlexibleDayBoundaries(dateString: string, timeClickedHHMM: string) {
const hourTwoDigits = this.time.doubleDigit(this.time.DAY_START / 100);
const dayStartTimeHHMM = `${hourTwoDigits}:00`
const isClickOnNextDay = timeClickedHHMM < dayStartTimeHHMM;

if (isClickOnNextDay) {
dateString = this.time.dateStringFrom(
this.time.addDaysToDateTimeString(1, dateString)
)
}

return dateString;
}
},
});
</script>
Expand Down
3 changes: 3 additions & 0 deletions src/components/week/Week.vue
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,15 @@
:day-info="{ daysTotalN: days.length, thisDayIndex: dayIndex, dateTimeString: day.dateTimeString }"
:mode="mode"
:day-intervals="dayIntervals"
:week-height="+weekHeight.replace('px', '')"
@event-was-clicked="handleClickOnEvent"
@event-was-resized="$emit('event-was-resized', $event)"
@event-was-dragged="handleEventWasDragged"
@interval-was-clicked="$emit('interval-was-clicked', $event)"
@day-was-clicked="$emit('day-was-clicked', $event)"
@drag-start="destroyScrollbarAndHideOverflow"
@drag-end="initScrollbar"
@datetime-was-clicked="$emit('datetime-was-clicked', $event)"
>
<template #weekDayEvent="p">
<slot
Expand Down Expand Up @@ -146,6 +148,7 @@ export default defineComponent({
'delete-event',
'interval-was-clicked',
'day-was-clicked',
'datetime-was-clicked',
],

data() {
Expand Down
66 changes: 26 additions & 40 deletions src/helpers/Errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,60 +2,46 @@ import { type eventInterface } from "../typings/interfaces/event.interface";
import {DATE_TIME_STRING_FULL_DAY_PATTERN, DATE_TIME_STRING_PATTERN} from "../constants";
import { type configInterface } from "../typings/config.interface";

type RecursivePartial<T> = {
[P in keyof T]?: RecursivePartial<T[P]>;
};

export default class Errors {
public static PREFIX = "[Qalendar warning]";
// public static SUFFIX = 'This is a development warning, which will never be displayed in production environments'
public static SUFFIX = "";

static checkEventProperties(event: eventInterface) {
public static readonly MISSING_ID_WARNING = `${this.PREFIX} required event property 'id' is missing \n${this.SUFFIX}`;

public static readonly MISSING_TITLE_WARNING = `${this.PREFIX} required event property 'title' is missing \n${this.SUFFIX}`;

public static readonly MISSING_TIME_WARNING = `${this.PREFIX} required event property 'time' is missing \n${this.SUFFIX}`;

public static readonly MISSING_TIME_START_WARNING = `${this.PREFIX} required event property 'time.start' is missing \n${this.SUFFIX}`;

public static readonly MISSING_TIME_END_WARNING = `${this.PREFIX} required event property 'time.end' is missing \n${this.SUFFIX}`;

static checkEventProperties(event: RecursivePartial<eventInterface>) {
// Warn if required property is missing
if (!event.id)
console.warn(
`${this.PREFIX} required event property 'id' is missing \n${this.SUFFIX}`
);
if (!event.title)
console.warn(
`${this.PREFIX} required event property 'title' is missing \n${this.SUFFIX}`
);
if (!event.time)
console.warn(
`${this.PREFIX} required event property 'time' is missing \n${this.SUFFIX}`
);
if (!event.time.start)
console.warn(
`${this.PREFIX} required event property 'time.start' is missing \n${this.SUFFIX}`
);
if (!event.time.end)
console.warn(
`${this.PREFIX} required event property 'time.end' is missing \n${this.SUFFIX}`
);
if (!event.id) console.warn(this.MISSING_ID_WARNING);
if (!event.title) console.warn(this.MISSING_TITLE_WARNING);
if (!event.time) console.warn(this.MISSING_TIME_WARNING);
if (!event?.time?.start) console.warn(this.MISSING_TIME_START_WARNING);
if (!event?.time?.end) console.warn(this.MISSING_TIME_END_WARNING);

// Warn if property type is faulty
if (!["number", "string"].includes(typeof event.id))
console.warn(
`${
this.PREFIX
} event property 'id' expects a string or a number, received ${typeof event.id} \n${
this.SUFFIX
}`
);
if (typeof event.title !== 'string')
console.warn(
`${
this.PREFIX
} event property 'title' expects a string, received ${typeof event.title} \n${
this.SUFFIX
}`
);
if (
!DATE_TIME_STRING_PATTERN.test(event.time.start)
event.time?.start
&& event.time?.end
&& !DATE_TIME_STRING_PATTERN.test(event.time.start)
&& !DATE_TIME_STRING_FULL_DAY_PATTERN.test(event.time.start)
)
console.warn(
`${this.PREFIX} event property 'time.start' expects a string formatted like 'YYYY-MM-DD hh:mm', or 'YYYY-MM-DD', received ${event.time.start} \n${this.SUFFIX}`
);
if (
!DATE_TIME_STRING_PATTERN.test(event.time.end)
event.time?.start
&& event.time?.end
&& !DATE_TIME_STRING_PATTERN.test(event.time.end)
&& !DATE_TIME_STRING_FULL_DAY_PATTERN.test(event.time.end)
)
console.warn(
Expand Down
Loading