Skip to content

Commit

Permalink
Handle global control to add new custom values
Browse files Browse the repository at this point in the history
  • Loading branch information
jolelievre committed Jan 3, 2024
1 parent b0be48d commit 92a8272
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import EventEmitter from '@components/event-emitter';
import Router from '@components/router';
import ConfirmModal from '@components/modal';
import ProductEventMap from '@pages/product/product-event-map';
import {isUndefined} from '@PSTypes/typeguard';

const {$} = window;

Expand All @@ -47,6 +48,10 @@ export default class FeatureValuesManager {

$featureValueSelector: JQuery;

$newCustomValuesContainers: JQuery;

$newCustomValueInputs: JQuery;

$featureValueLoader: JQuery;

$addFeatureValueButton: JQuery;
Expand All @@ -68,6 +73,8 @@ export default class FeatureValuesManager {
this.$featureSelector.select2();
this.$featureValueSelector = $(ProductMap.featureValues.featureValueSelect, this.$controlsContainer);
this.$featureValueSelector.select2();
this.$newCustomValuesContainers = $(ProductMap.featureValues.newCustomValuesContainers, this.$controlsContainer);
this.$newCustomValueInputs = $(ProductMap.featureValues.newCustomValueInputs, this.$newCustomValuesContainers);
this.$addFeatureValueButton = $(ProductMap.featureValues.addFeatureValue, this.$controlsContainer);
this.$featureValueLoader = $(ProductMap.featureValues.featureValueLoader, this.$controlsContainer);

Expand All @@ -81,6 +88,24 @@ export default class FeatureValuesManager {

private watchAddButton(): void {
this.$addFeatureValueButton.on('click', () => {
// Check feature value first, placeholder can not be added
const $selectedFeatureValue = $('option:selected', this.$featureValueSelector);
const featureValueId = <string> $selectedFeatureValue.val();

// Placeholder selected nothing to do
if (featureValueId === '0') {
return;
}

// Custom value selected but no value in inputs
if (featureValueId === '-1') {
const newCustomValues = this.getNewCustomValues();

if (newCustomValues.length === 0) {
return;
}
}

// Get selected values first
const $selectedFeature = $('option:selected', this.$featureSelector);
const featureId = <string> $selectedFeature.val();
Expand All @@ -100,9 +125,9 @@ export default class FeatureValuesManager {
this.$collectionRowsContainer.append($newFeatureRow);
$(ProductMap.featureValues.featureIdInput, $newFeatureRow).val(featureId);
$(ProductMap.featureValues.featureNameInput, $newFeatureRow).val(featureName);
this.addFeatureValueRow($newFeatureRow, featureId, featureName);
this.addFeatureValueRow($newFeatureRow, featureId, featureName, featureValueId);
} else {
this.addFeatureValueRow($featureRow, featureId, featureName);
this.addFeatureValueRow($featureRow, featureId, featureName, featureValueId);
}

// Display list that can't be empty anymore
Expand All @@ -111,7 +136,21 @@ export default class FeatureValuesManager {
});
}

private addFeatureValueRow($featureRow: JQuery, featureId: string, featureName: string): void {
private getNewCustomValues(): string[] {
const newCustomValues: string[] = [];
$('.js-locale-input', this.$newCustomValuesContainers).each((index: number, localeInputContainer: HTMLElement) => {
const localeInput = localeInputContainer.querySelector<HTMLInputElement>('input.form-control');

if (!isUndefined(localeInputContainer.dataset.langId) && localeInput && localeInput.value !== '') {
const langId = parseInt(localeInputContainer.dataset.langId, 10);
newCustomValues[langId] = localeInput.value;
}
});

return newCustomValues;
}

private addFeatureValueRow($featureRow: JQuery, featureId: string, featureName: string, featureValueId: string): void {
const rowValuePrototype = $featureRow.data('prototype');
const rowValuePrototypeName = $featureRow.data('prototypeName');
const $featureValueRows = $(ProductMap.featureValues.featureValueRowByFeatureId(featureId), this.$collectionRowsContainer);
Expand All @@ -128,7 +167,6 @@ export default class FeatureValuesManager {
}

const $selectedFeatureValue = $('option:selected', this.$featureValueSelector);
const featureValueId = <string> $selectedFeatureValue.val();
const featureValueName = <string> $selectedFeatureValue.text();

if (featureValueId !== '-1') {
Expand All @@ -143,6 +181,13 @@ export default class FeatureValuesManager {
$(ProductMap.featureValues.featureValueNamePreview, $newFeatureValueRow).text('');
$(ProductMap.featureValues.isCustomInput, $newFeatureValueRow).val(1);
$(ProductMap.featureValues.customValuesContainer, $newFeatureValueRow).show();

const newCustomValues = this.getNewCustomValues();
newCustomValues.forEach((customValue: string, langId: number) => {
const customValueInputSelector = ProductMap.featureValues.customValueByLangId(langId);
const $customValueInput = $(customValueInputSelector, $newFeatureValueRow);
$customValueInput.val(customValue);
});
}
$(ProductMap.featureValues.featureNameCell, $newFeatureValueRow).text(featureName);
}
Expand All @@ -152,6 +197,7 @@ export default class FeatureValuesManager {
this.$featureValueSelector.empty();
this.$featureValueSelector.val('').trigger('change');
this.$featureValueSelector.prop('disabled', true);
this.$newCustomValueInputs.val('');
}

private watchDeleteButtons(): void {
Expand Down Expand Up @@ -190,39 +236,53 @@ export default class FeatureValuesManager {
private watchFeatureSelectors(): void {
this.$featureSelector.on('change', () => {
this.$addFeatureValueButton.prop('disabled', true);
const idFeature = Number(this.$featureSelector.val());
this.renderFeatureValueChoices(idFeature);
const featureId = Number(this.$featureSelector.val());
this.renderFeatureValueChoices(featureId);
});

this.$featureValueSelector.on('change', () => {
const idFeature = Number(this.$featureSelector.val());
const idFeatureValue = Number(this.$featureValueSelector.val());
this.$addFeatureValueButton.prop('disabled', idFeature === 0 || idFeatureValue === 0);
});
this.$featureValueSelector.on('change', () => this.updateAddButtonState());
this.$newCustomValueInputs.on('change keyup', () => this.updateAddButtonState());
}

private updateAddButtonState(): void {
const featureId = Number(this.$featureSelector.val());
const featureValueId = Number(this.$featureValueSelector.val());
const newCustomValues = this.getNewCustomValues();

this.$newCustomValuesContainers.toggleClass('d-none', featureId === 0 || featureValueId !== -1);

if (featureValueId !== -1) {
this.$newCustomValueInputs.val('');
}
this.$addFeatureValueButton.prop('disabled',
featureId === 0
|| featureValueId === 0
|| (featureValueId === -1 && newCustomValues.length === 0),
);
}

private renderFeatureValueChoices(idFeature: number): void {
private renderFeatureValueChoices(featureId: number): void {
this.$featureValueSelector.val('');
this.$featureValueSelector.trigger('change');
this.$featureValueSelector.prop('disabled', true);

if (!idFeature) {
if (!featureId) {
return;
}

if (this.featureValues[idFeature]) {
this.doRenderFeatureValueChoices(this.featureValues[idFeature]);
if (this.featureValues[featureId]) {
this.doRenderFeatureValueChoices(this.featureValues[featureId]);
} else {
// Hide select2 and display loader
const $featureSelect2Container = $(`#select2-${this.$featureValueSelector.prop('id')}-container`);
const $featureSelect2 = $featureSelect2Container.parents('.select2-container');
this.$featureValueLoader.removeClass('d-none');
$featureSelect2.addClass('d-none');

$.get(this.router.generate('admin_feature_get_feature_values', {idFeature}))
$.get(this.router.generate('admin_feature_get_feature_values', {featureId}))
.then((featureValuesData: FeatureValue[]) => {
this.featureValues[idFeature] = featureValuesData;
this.doRenderFeatureValueChoices(this.featureValues[idFeature]);
this.featureValues[featureId] = featureValuesData;
this.doRenderFeatureValueChoices(this.featureValues[featureId]);
this.$featureValueLoader.addClass('d-none');
$featureSelect2.removeClass('d-none');
});
Expand All @@ -233,7 +293,11 @@ export default class FeatureValuesManager {
this.$featureValueSelector.empty();
if (featureValuesData.length) {
const selectedFeatureValues = this.getFeatureValueIds();
// First add placeholder and custom value options
this.addFeatureValue(this.$featureValueSelector.data('placeholderLabel'), 0);
this.addFeatureValue(this.$featureValueSelector.data('customValueLabel'), -1);

// Then loop through the pre-defined feature values
$.each(featureValuesData, (index, featureValue) => {
if (featureValue.id !== 0 && !selectedFeatureValues.includes(featureValue.id)) {
this.addFeatureValue(featureValue.value, featureValue.id);
Expand All @@ -242,7 +306,7 @@ export default class FeatureValuesManager {
}

this.$featureValueSelector.prop('disabled', featureValuesData.length === 0);
this.$featureValueSelector.val(-1).trigger('change');
this.$featureValueSelector.val(0).trigger('change');
this.$featureValueSelector.select2();
}

Expand Down
3 changes: 3 additions & 0 deletions admin-dev/themes/new-theme/js/pages/product/product-map.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ export default {
collectionRowsContainer: '.feature-values-table-collection > tbody',
featureSelect: 'select.feature-selector',
featureValueSelect: 'select.feature-value-selector',
newCustomValuesContainers: '.new-custom-values',
newCustomValueInputs: 'input.form-control',
featureRow: 'tr.product-feature-collection',
featureRowByFeatureId: (featureId: string): string => `tr.product-feature-collection[feature-id=${featureId}]`,
featureValueRow: 'tr.product-feature-value',
Expand All @@ -109,6 +111,7 @@ export default {
featureValueNamePreview: '.feature-value-preview .text-preview-value',
isCustomInput: 'input.is-custom-feature-value',
customValuesContainer: '.custom-values-form-group',
customValueByLangId: (langId: number): string => `.js-locale-input[data-lang-id="${langId}"] input.form-control`,
deleteFeatureValue: 'button.delete-feature-value',
addFeatureValue: '.feature-value-add-button',
featureValueLoader: '.feature-value-spinner',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,14 @@ $product-page-padding-bottom: 80px !default;
}
}

.new-custom-values {
&.d-none {
// stylelint-disable-next-line
display: none !important;
}

max-width: 350px;
}

.feature-value-add-button {
padding: 0.4rem 1rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,6 @@ public function buildForm(FormBuilderInterface $builder, array $options)
'row_attr' => [
'class' => 'custom-values-form-group',
],
'attr' => [
'class' => 'custom-values',
],
'constraints' => [
new DefaultLanguage([
'message' => $this->trans(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@

use PrestaShop\PrestaShop\Adapter\Form\ChoiceProvider\FeaturesChoiceProvider;
use PrestaShopBundle\Form\Admin\Type\IconButtonType;
use PrestaShopBundle\Form\Admin\Type\TranslatableType;
use PrestaShopBundle\Form\Admin\Type\TranslatorAwareType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
Expand Down Expand Up @@ -85,15 +87,23 @@ public function buildForm(FormBuilderInterface $builder, array $options)
])
->add('feature_value_id', ChoiceType::class, [
'empty_data' => 0,
'placeholder' => $this->trans('Choose a value', 'Admin.Catalog.Feature'),
'label' => $this->trans('Pre-defined value', 'Admin.Catalog.Feature'),
'invalid_message' => $this->trans('Choose a value or provide a customized one', 'Admin.Catalog.Feature'),
'placeholder' => $this->trans('Choose a value or provide a customized one', 'Admin.Catalog.Feature'),
'label' => false,
'disabled' => true,
'attr' => [
'data-placeholder-label' => $this->trans('Choose a value or provide a customized one', 'Admin.Catalog.Feature'),
'data-custom-value-label' => $this->trans('Add a customized value', 'Admin.Catalog.Feature'),
'class' => 'feature-value-selector',
],
])
->add('custom_value', TranslatableType::class, [
'label' => false,
'required' => false,
'type' => TextType::class,
'attr' => [
'class' => 'new-custom-values d-none',
],
])
->add('add_feature', IconButtonType::class, [
'label' => $this->trans('Add a feature', 'Admin.Catalog.Feature'),
'icon' => 'add_circle',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
{{ 'Loading feature values...'|trans({}, 'Admin.Catalog.Feature') }}
</div>
{{ form_widget(form.feature_value_id) }}
{{ form_widget(form.custom_value) }}
{{ form_widget(form.add_feature) }}
</div>
{# Manually add the external link block because we don't use form_row and this way it's under the whole block #}
Expand Down

0 comments on commit 92a8272

Please sign in to comment.