Skip to content

Commit

Permalink
Merge pull request #23 from delyriand/feature/multiple-shipping-slot-…
Browse files Browse the repository at this point in the history
…by-method

Multiple shipping slot by method
  • Loading branch information
maximehuran authored Mar 18, 2024
2 parents 37ba81b + 96f1db1 commit 646f3d2
Show file tree
Hide file tree
Showing 36 changed files with 649 additions and 67 deletions.
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,15 @@ use Sylius\Component\Shipping\Model\ShippingMethodTranslationInterface;
-class ShippingMethod extends BaseShippingMethod
+class ShippingMethod extends BaseShippingMethod implements MonsieurBizShippingMethodInterface
{
+ use ShippingMethodTrait;
+ use ShippingMethodTrait {
+ ShippingMethodTrait::__construct as private shippingMethodTraitConstruct;
+ }
+
+ public function __construct()
+ {
+ parent::__construct();
+ $this->shippingMethodTraitConstruct();
+ }
+
protected function createTranslation(): ShippingMethodTranslationInterface
{
Expand All @@ -163,6 +171,13 @@ use Sylius\Component\Shipping\Model\ShippingMethodTranslationInterface;
bin/console doctrine:migrations:migrate
```

6. Generate the migration and update your database schema:

```bash
bin/console doctrine:migrations:diff
bin/console doctrine:migrations:migrate
```

## Sponsors


Expand Down
16 changes: 16 additions & 0 deletions UPGRADE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# UPGRADE FROM 1.0.0 TO 1.1.0

- Add `form` in the events in the override template of the `/templates/bundles/SyliusShopBundle/Checkout/SelectShipping/_choice.html.twig`:

```diff
-{{ sylius_template_event('sylius.shop.checkout.select_shipping.before_method', {'method': method}) }}
+{{ sylius_template_event('sylius.shop.checkout.select_shipping.before_method', {'method': method, 'form': form}) }}
```

```diff
-{{ sylius_template_event('sylius.shop.checkout.select_shipping.after_method', {'method': method}) }}
+{{ sylius_template_event('sylius.shop.checkout.select_shipping.after_method', {'method': method, 'form': form}) }}
```

- The `shippingSlotConfig` class parameter in the `MonsieurBiz\SyliusShippingSlotPlugin\Entity\ShippingMethodTrait` trait is deprecated and will be removed in the next version. Use the `shippingSlotConfigs` class parameter instead to manage multiple shipping slot configs by shipping method.
- The methods `getShippingSlotConfig` and `setShippingSlotConfig` in `MonsieurBiz\SyliusShippingSlotPlugin\Entity\ShippingMethodInterface` interface are deprecated and will be removed in the next version. Use the methods `getShippingSlotConfigs` and `setShippingSlotConfigs` instead.
76 changes: 63 additions & 13 deletions assets/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ global.MonsieurBizShippingSlotManager = class {
listSlotsUrl,
saveSlotUrl,
resetSlotUrl,
slotSelectError
slotSelectError,
shippingSlotConfigSelects,
) {
this.shippingMethodInputs = shippingMethodInputs;
this.nextStepButtons = nextStepButtons;
Expand All @@ -33,6 +34,7 @@ global.MonsieurBizShippingSlotManager = class {
this.saveSlotUrl = saveSlotUrl;
this.resetSlotUrl = resetSlotUrl;
this.slotSelectError = slotSelectError;
this.shippingSlotConfigSelects = shippingSlotConfigSelects;
this.previousSlot = null;
this.initShippingMethodInputs();
}
Expand All @@ -41,10 +43,25 @@ global.MonsieurBizShippingSlotManager = class {
for (let shippingMethodInput of this.shippingMethodInputs) {
// On the page load, display load slots for selected method
if (shippingMethodInput.checked) {
this.displayInputSlots(shippingMethodInput, true);
let shippingSlotConfigSelect = this.getShippingSlotConfigSelect(shippingMethodInput.value);
this.displayInputSlots(shippingMethodInput, true, shippingSlotConfigSelect);
}
this.initShippingMethodInput(shippingMethodInput);
}

this.shippingSlotConfigSelects.forEach(shippingSlotConfigSelect => {
shippingSlotConfigSelect.addEventListener("change", function () {
let checkedShippingMethodInput = Array.from(this.shippingMethodInputs).find(shippingMethodInput => shippingMethodInput.checked);
if (checkedShippingMethodInput !== null) {
this.displayInputSlots(checkedShippingMethodInput, false, shippingSlotConfigSelect);
}
const event = new CustomEvent('mbiz:shipping-slot:slot-config-selected', {
element: shippingSlotConfigSelect,
shippingMethodInput: checkedShippingMethodInput
});
document.dispatchEvent(event);
}.bind(this));
}, this);
}

initShippingMethodInput(shippingMethodInput) {
Expand All @@ -56,26 +73,30 @@ global.MonsieurBizShippingSlotManager = class {

changeShippingMethod(shippingMethodInput) {
let shippingSlotManager = this;
// Find selected shipping slot config select
let shippingSlotConfigSelect = this.getShippingSlotConfigSelect(shippingMethodInput.value);

// Reset existing slot if needed
this.resetSlot(shippingMethodInput, function () {
// Display load slots for selected method
shippingSlotManager.displayInputSlots(shippingMethodInput, false);
shippingSlotManager.displayInputSlots(shippingMethodInput, false, shippingSlotConfigSelect);
});
}

displayInputSlots(shippingMethodInput, resetSlot) {
displayInputSlots(shippingMethodInput, resetSlot, shippingSlotConfigSelect = null) {
this.disableButtons();
let shippingSlotManager = this;
this.initCalendarForAMethod(shippingMethodInput.value, function () {
this.initCalendarForAMethod(shippingMethodInput.value, shippingSlotConfigSelect, function () {
if (this.status !== 200) {
shippingSlotManager.enableButtons();
return;
}

let data = JSON.parse(this.responseText);

// Hide calendars
// Hide calendars and shipping slot config selects
shippingSlotManager.hideCalendars();
shippingSlotManager.hideShippingSlotConfigSelects();

// Authorize user to go to next step if no slot needed
if (typeof data.events === "undefined") {
Expand All @@ -96,7 +117,8 @@ global.MonsieurBizShippingSlotManager = class {
calendarContainer,
data.events,
data.timezone,
shippingMethodInput.value
shippingMethodInput.value,
shippingSlotConfigSelect
);
}
}
Expand All @@ -119,29 +141,34 @@ global.MonsieurBizShippingSlotManager = class {
}
}

initCalendarForAMethod(shippingMethodCode, callback) {
initCalendarForAMethod(shippingMethodCode, shippingSlotConfigSelect, callback) {
let req = new XMLHttpRequest();
req.onload = callback;
let url = this.initUrl;
req.open("get", url.replace("__CODE__", shippingMethodCode), true);
let url = this.initUrl
.replace("__CODE__", shippingMethodCode)
.replace("__CONFIG__", shippingSlotConfigSelect !== null ? shippingSlotConfigSelect.value : "")
;
req.open("get", url, true);
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
req.send();
}

listSlots(shippingMethodCode, from, to, callback) {
listSlots(shippingMethodCode, from, to, shippingSlotConfigSelect, callback) {
let req = new XMLHttpRequest();
req.onload = callback;
let url = this.listSlotsUrl
.replace("__CODE__", shippingMethodCode)
.replace("__FROM__", from)
.replace("__TO__", to)
.replace("__CONFIG__", shippingSlotConfigSelect !== null ? shippingSlotConfigSelect.value : "")
;
req.open("get", url, true);
req.setRequestHeader("X-Requested-With", "XMLHttpRequest");
req.send();
}

saveSlot(slot, shippingMethodInput, callback) {
let shippingSlotConfigSelect = this.getShippingSlotConfigSelect(shippingMethodInput.value);
let req = new XMLHttpRequest();
req.onload = callback;
req.open("post", this.saveSlotUrl, true);
Expand All @@ -150,6 +177,7 @@ global.MonsieurBizShippingSlotManager = class {
data.append("event", JSON.stringify(slot.event));
data.append("shippingMethod", shippingMethodInput.value);
data.append("shipmentIndex", shippingMethodInput.getAttribute("tabIndex"));
data.append("shippingSlotConfig", shippingSlotConfigSelect !== null ? shippingSlotConfigSelect.value : '');
req.send(data);
}

Expand All @@ -166,12 +194,14 @@ global.MonsieurBizShippingSlotManager = class {
disableButtons() {
for (let button of this.nextStepButtons) {
button.disabled = true;
button.form.classList.add('loading');
}
}

enableButtons() {
for (let button of this.nextStepButtons) {
button.disabled = false;
button.form.classList.remove('loading');
}
}

Expand All @@ -181,6 +211,12 @@ global.MonsieurBizShippingSlotManager = class {
}
}

hideShippingSlotConfigSelects() {
for (let shippingSlotConfigSelect of this.shippingSlotConfigSelects) {
shippingSlotConfigSelect.style.display = "none";
}
}

applySlotStyle(slot) {
if (slot.el.querySelector(".fc-event-main") !== null) {
// Timegrid view
Expand Down Expand Up @@ -217,8 +253,11 @@ global.MonsieurBizShippingSlotManager = class {
slot.el.style.display = 'none';
}

initCalendar(calendarContainer, events, timezone, shippingMethodCode) {
initCalendar(calendarContainer, events, timezone, shippingMethodCode, shippingSlotConfigSelect) {
calendarContainer.style.display = "block";
if (shippingSlotConfigSelect) {
shippingSlotConfigSelect.style.display = "block";
}
let shippingSlotManager = this;
let calendar = new Calendar(
calendarContainer,
Expand Down Expand Up @@ -275,12 +314,17 @@ global.MonsieurBizShippingSlotManager = class {
datesSet(dateInfo) {
let calendar = this;
shippingSlotManager.disableButtons();
shippingSlotManager.listSlots(shippingMethodCode, dateInfo.startStr, dateInfo.endStr, function () {
shippingSlotManager.listSlots(shippingMethodCode, dateInfo.startStr, dateInfo.endStr, shippingSlotConfigSelect, function () {
if (this.status !== 200) {
console.error('Error during slot list');
return;
}

// Remove loading class on the form
for (let button of shippingSlotManager.nextStepButtons) {
button.form.classList.remove('loading');
}

let events = JSON.parse(this.responseText);
// Use batch rendering to improve events loading
calendar.batchRendering(function() {
Expand All @@ -299,4 +343,10 @@ global.MonsieurBizShippingSlotManager = class {
);
calendar.render();
}

getShippingSlotConfigSelect(shippingMethodCode) {
return Array.from(this.shippingSlotConfigSelects).find(
shippingSlotConfigSelect => shippingSlotConfigSelect.name.includes(shippingMethodCode)
) ?? null;
}
};
10 changes: 9 additions & 1 deletion dist/src/Entity/Shipping/ShippingMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,15 @@
*/
class ShippingMethod extends SyliusShippingMethod implements ShippingMethodInterface, MonsieurBizShippingMethodInterface
{
use ShippingMethodTrait;
use ShippingMethodTrait {
ShippingMethodTrait::__construct as private shippingMethodTraitConstruct;
}

public function __construct()
{
parent::__construct();
$this->shippingMethodTraitConstruct();
}

protected function createTranslation(): ShippingMethodTranslationInterface
{
Expand Down
44 changes: 44 additions & 0 deletions dist/src/Migrations/Version20240314135057.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<?php

/*
* This file is part of Monsieur Biz' Shipping Slot plugin for Sylius.
*
* (c) Monsieur Biz <[email protected]>
*
* For the full copyright and license information, please view the LICENSE.txt
* file that was distributed with this source code.
*/

declare(strict_types=1);

namespace App\Migrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20240314135057 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}

public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE monsieurbiz_shipping_slot_shipping_method (shipping_method_id INT NOT NULL, shipping_slot_config_id INT NOT NULL, INDEX IDX_57D36B055F7D6850 (shipping_method_id), INDEX IDX_57D36B053890C4F5 (shipping_slot_config_id), PRIMARY KEY(shipping_method_id, shipping_slot_config_id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB');
$this->addSql('ALTER TABLE monsieurbiz_shipping_slot_shipping_method ADD CONSTRAINT FK_57D36B055F7D6850 FOREIGN KEY (shipping_method_id) REFERENCES sylius_shipping_method (id) ON DELETE CASCADE');
$this->addSql('ALTER TABLE monsieurbiz_shipping_slot_shipping_method ADD CONSTRAINT FK_57D36B053890C4F5 FOREIGN KEY (shipping_slot_config_id) REFERENCES monsieurbiz_shipping_slot_config (id) ON DELETE CASCADE');
}

public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE monsieurbiz_shipping_slot_shipping_method DROP FOREIGN KEY FK_57D36B055F7D6850');
$this->addSql('ALTER TABLE monsieurbiz_shipping_slot_shipping_method DROP FOREIGN KEY FK_57D36B053890C4F5');
$this->addSql('DROP TABLE monsieurbiz_shipping_slot_shipping_method');
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{% import '@SyliusShop/Common/Macro/money.html.twig' as money %}

{{ sylius_template_event('sylius.shop.checkout.select_shipping.before_method', {'method': method}) }}
{{ sylius_template_event('sylius.shop.checkout.select_shipping.before_method', {'method': method, 'form': form}) }}
<div class="item" {{ sylius_test_html_attribute('shipping-item') }}>
<div class="field">
<div class="ui radio checkbox" {{ sylius_test_html_attribute('shipping-method-checkbox') }}>
Expand All @@ -21,4 +21,4 @@
</div>
</div>
</div>
{{ sylius_template_event('sylius.shop.checkout.select_shipping.after_method', {'method': method}) }}
{{ sylius_template_event('sylius.shop.checkout.select_shipping.after_method', {'method': method, 'form': form}) }}
Loading

0 comments on commit 646f3d2

Please sign in to comment.