Skip to content

Commit

Permalink
Feature/holiday timeframe multiselect (#1296)
Browse files Browse the repository at this point in the history
* Frontend of multi-select timeframes
* multiselect logic
* migrated over more from experiment branch
* added tests for multi-tfs
* fixed unit tests
* fixed multi-select js (now exclusively for holidays)
* added hooks to update multi selection on dynamic selections
* added deprecation warning
* removed unused function
* fixed confusing wording
* added methods  & tests to get multiple items & locations from one tf
* more tests for timeframes with multi-assigned items / locations
* modified export to support multiply applied timeframes
* fixed caching issues for tfs with multiple assignments
* marked what needs to be done before #507
* moved upgrade function & added test (failing)
* added selection mode to tf creation in tests
* Adds also a test for the location taxonomy query
* add hook to trigger update on term deletion
* make sure, that multi-ids are always deleted for all non-holiday tfs
* added check for getLocations() with just one location
* use getter function for postID instead of magic property

---------

Co-authored-by: markus-mw <markus@mach-websites.de>
Co-authored-by: Chris <datengraben@gmx.de>
Co-authored-by: Chris <105302830+datengraben@users.noreply.github.com>
  • Loading branch information
4 people authored Feb 8, 2024
1 parent 5939e90 commit 8d98c00
Show file tree
Hide file tree
Showing 30 changed files with 1,413 additions and 156 deletions.
94 changes: 94 additions & 0 deletions assets/admin/js/admin.js
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,12 @@
const REPETITION_WEEKLY = "w";
const REPETITION_MONTHLY = "m";
const REPETITION_YEARLY = "y";
const SELECTION_MANUAL = 0;
const SELECTION_CATEGORY = 1;
const SELECTION_ALL = 2;
const timeframeRepetitionInput = $("#timeframe-repetition");
const locationSelectionInput = $("#location-select");
const itemSelectionInput = $("#item-select");
if (timeframeForm.length) {
const timeframeRepetitionInput = $("#timeframe-repetition");
const typeInput = $("#type");
Expand All @@ -251,6 +257,12 @@
const linkSendEntireTimeframeCodes = $("#email-booking-codes-list-all");
const linkSendCurrentMonth = $("#email-booking-codes-list-current");
const linkSendNextMonth = $("#email-booking-codes-list-next");
const singleLocationSelection = $(".cmb2-id-location-id");
const multiLocationSelection = $(".cmb2-id-location-id-list");
const singleItemSelection = $(".cmb2-id-item-id");
const multiItemSelection = $(".cmb2-id-item-id-list");
const categoryLocationSelection = $(".cmb2-id-location-category-ids");
const categoryItemSelection = $(".cmb2-id-item-category-ids");
const holidayField = $(".cmb2-id--cmb2-holiday");
const holidayInput = $("#timeframe_manual_date");
const manualDatePicker = $("#cmb2_multiselect_datepicker");
Expand Down Expand Up @@ -280,6 +292,28 @@
$(this).prop("checked", false);
});
};
const migrateSingleSelection = () => {
if (typeInput.val() != HOLIDAYS_ID) {
return;
}
const singleItemSelectionOption = singleItemSelection.find("option:selected");
if (singleItemSelectionOption.prop("value")) {
const multiItemSelectionOption = multiItemSelection.find(`input[value=${singleItemSelectionOption.prop("value")}]`);
if (multiItemSelectionOption) {
multiItemSelectionOption.prop("checked", true);
}
singleItemSelectionOption.prop("selected", false);
}
const singleLocationSelectionOption = singleLocationSelection.find("option:selected");
if (singleLocationSelectionOption.prop("value")) {
const multiLocationSelectionOption = multiLocationSelection.find(`input[value=${singleLocationSelectionOption.prop("value")}]`);
if (multiLocationSelectionOption) {
multiLocationSelectionOption.prop("checked", true);
}
singleLocationSelectionOption.prop("selected", false);
}
};
migrateSingleSelection();
const handleTypeSelection = function() {
const selectedType = $("option:selected", typeInput).val();
const selectedRepetition = $("option:selected", timeframeRepetitionInput).val();
Expand All @@ -296,10 +330,70 @@
holidayField.hide();
}
}
if (selectedType == HOLIDAYS_ID) {
itemSelectionInput.show();
locationSelectionInput.show();
migrateSingleSelection();
} else {
itemSelectionInput.hide();
locationSelectionInput.hide();
}
};
handleTypeSelection();
typeInput.change(function() {
handleTypeSelection();
handleItemSelection();
handleLocationSelection();
});
const handleLocationSelection = function() {
const selectedType = $("option:selected", typeInput).val();
if (selectedType == HOLIDAYS_ID) {
singleLocationSelection.hide();
const selectedOption = $("option:selected", locationSelectionInput).val();
if (selectedOption == SELECTION_MANUAL) {
multiLocationSelection.show();
categoryLocationSelection.hide();
} else if (selectedOption == SELECTION_CATEGORY) {
categoryLocationSelection.show();
multiLocationSelection.hide();
} else if (selectedOption == SELECTION_ALL) {
multiLocationSelection.hide();
categoryLocationSelection.hide();
}
} else {
singleLocationSelection.show();
multiLocationSelection.hide();
categoryLocationSelection.hide();
}
};
handleLocationSelection();
locationSelectionInput.change(function() {
handleLocationSelection();
});
const handleItemSelection = function() {
const selectedType = $("option:selected", typeInput).val();
if (selectedType == HOLIDAYS_ID) {
singleItemSelection.hide();
const selectedOption = $("option:selected", itemSelectionInput).val();
if (selectedOption == SELECTION_MANUAL) {
multiItemSelection.show();
categoryItemSelection.hide();
} else if (selectedOption == SELECTION_CATEGORY) {
categoryItemSelection.show();
multiItemSelection.hide();
} else if (selectedOption == SELECTION_ALL) {
multiItemSelection.hide();
categoryItemSelection.hide();
}
} else {
singleItemSelection.show();
multiItemSelection.hide();
categoryItemSelection.hide();
}
};
handleItemSelection();
itemSelectionInput.change(function() {
handleItemSelection();
});
const handleFullDaySelection = function() {
const selectedRep = $("option:selected", timeframeRepetitionInput).val();
Expand Down
2 changes: 1 addition & 1 deletion assets/admin/js/admin.min.js

Large diffs are not rendered by default.

128 changes: 126 additions & 2 deletions assets/admin/js/src/timeframe.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@
const REPETITION_MONTHLY = "m";
const REPETITION_YEARLY = "y";

// the assigned numbers for the location selection input
const SELECTION_MANUAL = 0;
const SELECTION_CATEGORY = 1;
const SELECTION_ALL = 2;

const timeframeRepetitionInput = $('#timeframe-repetition');
const locationSelectionInput = $('#location-select');
const itemSelectionInput = $('#item-select');

if (timeframeForm.length) {
const timeframeRepetitionInput = $('#timeframe-repetition');
const typeInput = $('#type');
Expand Down Expand Up @@ -72,14 +81,19 @@
const linkSendNextMonth = $('#email-booking-codes-list-next');


const singleLocationSelection = $('.cmb2-id-location-id');
const multiLocationSelection = $(".cmb2-id-location-id-list");
const singleItemSelection = $('.cmb2-id-item-id');
const multiItemSelection = $(".cmb2-id-item-id-list");
const categoryLocationSelection = $('.cmb2-id-location-category-ids');
const categoryItemSelection = $('.cmb2-id-item-category-ids');
const holidayField = $('.cmb2-id--cmb2-holiday');
const holidayInput = $('#timeframe_manual_date');
const manualDatePicker = $("#cmb2_multiselect_datepicker");
const manualDateField = $('.cmb2-id-timeframe-manual-date');
const maxDaysSelect = $('#timeframe-max-days');
const advanceBookingDays = $('#timeframe-advance-booking-days');
const bookingStartDayOffset = $('#booking-startday-offset');
const bookingConfigurationTitle = $('#title-bookings-config');
const bookingStartDayOffset = $('#booking-startday-offset');const bookingConfigurationTitle = $('#title-bookings-config');
const allowUserRoles = $('#allowed_user_roles');
const repSet = [repConfigTitle, fullDayInput, startTimeInput, endTimeInput, weekdaysInput, repetitionStartInput, repetitionEndInput, gridInput];
const noRepSet = [fullDayInput, startTimeInput, endTimeInput, gridInput, repetitionStartInput, repetitionEndInput];
Expand Down Expand Up @@ -116,6 +130,38 @@
});
}

/**
* "Moves" selection from single item /location selection to multiselect.
* Currently only for holidays, holidays used to only have one assignable single selection.
*/
const migrateSingleSelection = () => {

if (typeInput.val() != HOLIDAYS_ID) {
return;
}
// get single selection
const singleItemSelectionOption = singleItemSelection.find('option:selected');

// if it has a value, remove selection from single select and activate checkbox in multiselect
if(singleItemSelectionOption.prop('value')) {
const multiItemSelectionOption = multiItemSelection.find(`input[value=${singleItemSelectionOption.prop('value')}]`);
if(multiItemSelectionOption) {
multiItemSelectionOption.prop('checked', true);
}
singleItemSelectionOption.prop('selected', false);
}

const singleLocationSelectionOption = singleLocationSelection.find('option:selected');
if (singleLocationSelectionOption.prop('value')) {
const multiLocationSelectionOption = multiLocationSelection.find(`input[value=${singleLocationSelectionOption.prop('value')}]`);
if(multiLocationSelectionOption) {
multiLocationSelectionOption.prop('checked', true);
}
singleLocationSelectionOption.prop('selected', false);
}
}
migrateSingleSelection();

/**
* Shows/hides max day selection and user role restriction depending on timeframe type (for bookings).
*/
Expand All @@ -135,10 +181,88 @@
holidayField.hide();
}
}

//we migrate the single selection to the multiselect (new holiday timeframes do not have a single selection anymore)
if (selectedType == HOLIDAYS_ID) {
itemSelectionInput.show();
locationSelectionInput.show();
migrateSingleSelection();
} else {
itemSelectionInput.hide();
locationSelectionInput.hide();
}
}
handleTypeSelection();
typeInput.change(function () {
handleTypeSelection();
handleItemSelection();
handleLocationSelection();
});

/**
* Shows/hides selection options for locations
*/
const handleLocationSelection = function () {
const selectedType = $("option:selected", typeInput).val();
//disable the mass selection for all timeframes except holidays
if (selectedType == HOLIDAYS_ID) {
singleLocationSelection.hide();
//handle different selection types
const selectedOption = $("option:selected", locationSelectionInput).val();
if (selectedOption == SELECTION_MANUAL) {
multiLocationSelection.show();
categoryLocationSelection.hide();
} else if (selectedOption == SELECTION_CATEGORY){
categoryLocationSelection.show();
multiLocationSelection.hide();
}
else if (selectedOption == SELECTION_ALL) {
multiLocationSelection.hide();
categoryLocationSelection.hide();
}
}
else {
singleLocationSelection.show();
multiLocationSelection.hide();
categoryLocationSelection.hide();
}
};
handleLocationSelection();
locationSelectionInput.change(function () {
handleLocationSelection();
});

/**
* Shows/hides selection options for items
*/
const handleItemSelection = function () {
const selectedType = $("option:selected", typeInput).val();
//disable the mass selection for all timeframes except holidays (for now)
if (selectedType == HOLIDAYS_ID) {
singleItemSelection.hide();
//handle different selection types
const selectedOption = $("option:selected", itemSelectionInput).val();
if (selectedOption == SELECTION_MANUAL) {
multiItemSelection.show();
categoryItemSelection.hide();
} else if (selectedOption == SELECTION_CATEGORY){
categoryItemSelection.show();
multiItemSelection.hide();
}
else if (selectedOption == SELECTION_ALL) {
multiItemSelection.hide();
categoryItemSelection.hide();
}
}
else {
singleItemSelection.show();
multiItemSelection.hide();
categoryItemSelection.hide();
}
};
handleItemSelection();
itemSelectionInput.change(function () {
handleItemSelection();
});

/**
Expand Down
43 changes: 22 additions & 21 deletions src/Helper/Wordpress.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,15 +143,7 @@ public static function getRelatedPostsIdsForItem($postId): array {
public static function getRelatedPostsIdsForTimeframe($postId): array {
$timeframe = new Timeframe($postId);
$ids = [$postId];

if($timeframe->getItem()) {
$ids[] = $timeframe->getItem()->ID;
}
if($timeframe->getLocation()) {
$ids[] = $timeframe->getLocation()->ID;
}

return $ids;
return array_merge($ids, $timeframe->getItemIDs(), $timeframe->getLocationIDs() );
}

/**
Expand All @@ -166,10 +158,10 @@ public static function getRelatedPostsIdsForBooking($postId): array {
$ids = [$postId];

if($booking->getItem()) {
$ids[] = $booking->getItem()->ID;
$ids[] = $booking->getItemID();
}
if($booking->getLocation()) {
$ids[] = $booking->getLocation()->ID;
$ids[] = $booking->getLocationID();
}
if($booking->getBookableTimeFrame()) {
$ids[] = $booking->getBookableTimeFrame()->ID;
Expand Down Expand Up @@ -239,22 +231,31 @@ public static function getTags($posts, array $items = [], array $locations = [])

/**
* Returns an array of post ids of locations and items from posts.
* The only posts that have items / locations assinged are timeframes and bookings.
* Any other posts are skipped.
* @param $posts
*
* @return array
*/
public static function getLocationAndItemIdsFromPosts($posts): array {
public static function getLocationAndItemIdsFromPosts(array $posts): array {
$itemsAndLocations = [];
array_walk($posts, function ($timeframe) use (&$itemsAndLocations) {
$itemsAndLocations[] = get_post_meta(
$timeframe->ID,
Timeframe::META_ITEM_ID,
true
);
$itemsAndLocations[] = get_post_meta(
$timeframe->ID,
Timeframe::META_LOCATION_ID,
true
//only run for timeframe or booking
if ( ! in_array( $timeframe->post_type, [ \CommonsBooking\Wordpress\CustomPostType\Timeframe::$postType, Booking::$postType ] ) ) {
return;
}
if (! $timeframe instanceof Timeframe) {
if ( $timeframe->post_type == Booking::$postType ) {
$timeframe = new \CommonsBooking\Model\Booking( $timeframe );
}
elseif ( $timeframe->post_type == \CommonsBooking\Wordpress\CustomPostType\Timeframe::$postType ) {
$timeframe = new Timeframe( $timeframe );
}
}
$itemsAndLocations = array_merge(
$itemsAndLocations,
$timeframe->getItemIDs(),
$timeframe->getLocationIDs()
);
});
return array_map('intval', $itemsAndLocations);
Expand Down
4 changes: 2 additions & 2 deletions src/Model/Booking.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,8 +207,8 @@ public function assignBookableTimeframeFields() {
try {
$bookingCode = BookingCodes::getCode(
$timeframe,
$this->getItem()->ID,
$this->getLocation()->ID,
$this->getItemID(),
$this->getLocationID(),
date( 'Y-m-d', $this->getStartDate() )
);
} catch ( BookingCodeException $e ) {
Expand Down
4 changes: 2 additions & 2 deletions src/Model/Calendar.php
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,12 @@ public function getAvailabilitySlots(): array {

$availabilitySlot->locationId = "";
if ( $timeframe->getLocation() ) {
$availabilitySlot->locationId = $timeframe->getLocation()->ID . "";
$availabilitySlot->locationId = $timeframe->getLocationID() . "";
}

$availabilitySlot->itemId = "";
if ( $timeframe->getItem() ) {
$availabilitySlot->itemId = $timeframe->getItem()->ID . "";
$availabilitySlot->itemId = $timeframe->getItemID() . "";
}

$slotId = md5( serialize( $availabilitySlot ) );
Expand Down
2 changes: 1 addition & 1 deletion src/Model/Day.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public function getName() {
* Returns array with timeframes relevant for the Day.
* This function will only be able to run once.
* When on the first try, no Timeframes are found, it will set it to an empty array
* @return array
* @return \CommonsBooking\Model\Timeframe[]
* @throws Exception
*/
public function getTimeframes(): array {
Expand Down
Loading

0 comments on commit 8d98c00

Please sign in to comment.