Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 2 additions & 5 deletions resources/js/components/field-conditions/Condition.vue
Original file line number Diff line number Diff line change
Expand Up @@ -130,15 +130,12 @@ export default {
},

fieldOptions() {
const conditions = this.conditions.map((condition) => condition.field);

return this.suggestableFields
.filter((field) => {
return !(
field.handle === this.config.handle || // Exclude the field you're adding a condition to.
this.condition.field === field.handle || // Exclude the field being used in the current condition.
conditions.includes(field.handle)
); // Exclude fields already used in other conditions.
this.condition.field === field.handle // Exclude the field being used in the current condition.
);
})
.map((field) => {
let display = field.config.display;
Expand Down
17 changes: 15 additions & 2 deletions resources/js/components/field-conditions/Converter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,32 @@ import { OPERATORS, ALIASES } from './Constants.js';

export default class {
fromBlueprint(conditions, prefix = null) {
return Object.entries(conditions).map(([field, condition]) => this.splitRhs(field, condition, prefix));
return Object.entries(conditions).flatMap(([field, condition]) =>
this.wrap(condition).map((condition) => this.splitRhs(field, condition, prefix)),
);
}

toBlueprint(conditions) {
let converted = {};

conditions.forEach((condition) => {
converted[condition.field] = this.combineRhs(condition);
const field = condition.field;
const value = this.combineRhs(condition);

if (field in converted) {
converted[field] = this.wrap(converted[field]).concat(value);
} else {
converted[field] = value;
}
});

return converted;
}

wrap(value) {
return Array.isArray(value) ? value : [value];
}

splitRhs(field, condition, prefix = null) {
return {
field: this.getScopedFieldHandle(field, prefix),
Expand Down
30 changes: 30 additions & 0 deletions resources/js/tests/FieldConditionsConverter.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,21 @@ test('it converts from blueprint format and applies prefixes', () => {
expect(converted).toEqual(expected);
});

test('it converts from blueprint format when a field has multiple conditions', () => {
let converted = FieldConditionsConverter.fromBlueprint({
status: ['published', 'archived'],
audience: 'members',
});

let expected = [
{ field: 'status', operator: 'equals', value: 'published' },
{ field: 'status', operator: 'equals', value: 'archived' },
{ field: 'audience', operator: 'equals', value: 'members' },
];

expect(converted).toEqual(expected);
});

test('it converts from blueprint format and does not apply prefix to field conditions with root syntax', () => {
let converted = FieldConditionsConverter.fromBlueprint(
{
Expand Down Expand Up @@ -103,6 +118,21 @@ test('it converts to blueprint format', () => {
expect(converted).toEqual(expected);
});

test('it converts to blueprint format when a field has multiple conditions', () => {
let converted = FieldConditionsConverter.toBlueprint([
{ field: 'status', operator: 'is', value: 'published' },
{ field: 'status', operator: 'is', value: 'archived' },
{ field: 'audience', operator: 'is', value: 'members' },
]);

let expected = {
status: ['is published', 'is archived'],
audience: 'is members',
};

expect(converted).toEqual(expected);
});

test('it converts and trims properly with empty operators', () => {
let converted = FieldConditionsConverter.toBlueprint([
{ field: 'name', operator: '', value: 'joe' },
Expand Down
15 changes: 15 additions & 0 deletions resources/js/tests/FieldConditionsValidator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,21 @@ test('it only shows when multiple conditions are met', () => {
expect(showFieldIf({ first_name: 'is San', last_name: 'is Holo', age: '> 40' })).toBe(false);
});

test('it supports multiple conditions targeting the same field', () => {
setValues({
status: 'published',
audience: 'members',
age: 22,
});

expect(Fields.showField({ if_any: { status: ['is archived', 'is published'], audience: 'is guests' } })).toBe(true);
expect(Fields.showField({ if_any: { status: ['is archived', 'is draft'], audience: 'is guests' } })).toBe(false);
expect(Fields.showField({ if: { age: ['> 18', '< 65'], audience: 'is members' } })).toBe(true);
expect(Fields.showField({ if: { age: ['> 18', '< 21'], audience: 'is members' } })).toBe(false);
expect(Fields.showField({ unless_any: { status: ['is archived', 'is draft'], audience: 'is guests' } })).toBe(true);
expect(Fields.showField({ hide_when_any: { status: ['is archived', 'is published'], audience: 'is guests' } })).toBe(false);
});

test('it shows or hides with parent key variants', () => {
setValues({
first_name: 'Rincess',
Expand Down
Loading