diff --git a/addon/components/utils/account-banner.hbs b/addon/components/utils/account-banner.hbs
index a16d497b..d3792283 100644
--- a/addon/components/utils/account-banner.hbs
+++ b/addon/components/utils/account-banner.hbs
@@ -21,44 +21,58 @@
{{/if}}
{{#if (or @subtitle (has-block "custom-subtitle"))}}
-
- {{#if @subtitle}}
-
- {{@subtitle}}
-
- {{else if (has-block "custom-subtitle")}}
- {{yield to="custom-subtitle"}}
- {{/if}}
-
- {{#if this.canSelectItem}}
-
+ {{#if @subtitle}}
+
- {{/if}}
-
+ {{#if this.feedbackMessage}}
+
+ {{this.feedbackMessage.value}}
+
+ {{/if}}
+
+ {{else if (has-block "custom-subtitle")}}
+ {{yield to="custom-subtitle"}}
+ {{/if}}
{{/if}}
diff --git a/addon/components/utils/account-banner.ts b/addon/components/utils/account-banner.ts
index ffc9caf7..4872b9d8 100644
--- a/addon/components/utils/account-banner.ts
+++ b/addon/components/utils/account-banner.ts
@@ -3,6 +3,8 @@ import { isBlank } from '@ember/utils';
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
+import { type FeedbackMessage } from '@upfluence/oss-components/components/o-s-s/input-container';
+
type SkinType = 'success' | 'error' | 'warning';
export type Alert = {
@@ -27,11 +29,21 @@ interface UtilsAccountBannerArgs {
canSelectItem?: boolean;
selectableItems?: any[];
+ feedbackMessage?: FeedbackMessage;
+ required?: boolean;
}
export default class extends Component {
@tracked displaySelectableItems: boolean = false;
+ get feedbackMessage(): FeedbackMessage | undefined {
+ return this.args.feedbackMessage;
+ }
+
+ get isErrored(): boolean {
+ return this.feedbackMessage?.type === 'error';
+ }
+
get disabledClass(): string {
return this.args.disabled ? 'account-banner--disabled' : '';
}
@@ -41,6 +53,7 @@ export default class extends Component {
}
get borderColorClass(): string {
+ if (this.isErrored) return 'account-banner--error';
if (this.args.skin) return `account-banner--${this.args.skin}`;
return '';
}
diff --git a/tests/integration/components/utils/account-banner-test.ts b/tests/integration/components/utils/account-banner-test.ts
index 4396846f..63ac852a 100644
--- a/tests/integration/components/utils/account-banner-test.ts
+++ b/tests/integration/components/utils/account-banner-test.ts
@@ -10,6 +10,20 @@ module('Integration | Component | utils/account-banner', function (hooks) {
setupRenderingTest(hooks);
setupIntl(hooks);
+ module('rendering', function () {
+ test('it renders', async function (assert) {
+ await render(hbs``);
+
+ assert.dom('.account-banner').exists();
+ });
+
+ test('it forwards HTML attributes', async function (assert) {
+ await render(hbs``);
+
+ assert.dom('.account-banner[data-test="banner"]').exists();
+ });
+ });
+
module('modifier classes', function () {
test('it renders with no modifier classes by default', async function (assert) {
await render(hbs``);
@@ -57,6 +71,27 @@ module('Integration | Component | utils/account-banner', function (hooks) {
});
});
+ module('icon / image', function () {
+ test('it renders @icon', async function (assert) {
+ await render(hbs``);
+
+ assert.dom('.upf-badge').exists();
+ });
+
+ test('it renders @image as a badge', async function (assert) {
+ await render(hbs``);
+
+ assert.dom('.icon-in-badge').exists();
+ });
+
+ test('@icon takes precedence over @image', async function (assert) {
+ await render(hbs``);
+
+ assert.dom('.upf-badge').exists();
+ assert.dom('.icon-in-badge').doesNotExist();
+ });
+ });
+
module('title', function () {
test('it renders @title', async function (assert) {
await render(hbs``);
@@ -89,7 +124,7 @@ module('Integration | Component | utils/account-banner', function (hooks) {
test('it renders @subtitle', async function (assert) {
await render(hbs``);
- assert.dom('[data-control-name="account-banner-selected-item-label"]').hasText('subtitle');
+ assert.dom('[data-control-name="account-banner-selected-item-label"]').containsText('subtitle');
});
test('it renders custom-subtitle block', async function (assert) {
@@ -113,30 +148,36 @@ module('Integration | Component | utils/account-banner', function (hooks) {
assert.dom('.custom-sub').doesNotExist();
});
+ test('it marks subtitle as required when @required is true', async function (assert) {
+ await render(hbs``);
+
+ assert.dom('[data-control-name="account-banner-selected-item-label"]').hasText('subtitle *');
+ });
+
+ test('it does not mark subtitle as required when @required is not set', async function (assert) {
+ await render(hbs``);
+
+ assert.dom('[data-control-name="account-banner-selected-item-label"]').hasText('subtitle');
+ });
+
test('account-banner__selection is not rendered without subtitle or custom-subtitle', async function (assert) {
await render(hbs``);
assert.dom('.account-banner__selection').doesNotExist();
});
- });
- module('actions block', function () {
- test('it renders the actions block', async function (assert) {
- await render(hbs`
-
- <:actions>action
-
- `);
+ test('unique-account class is applied when canSelectItem is false', async function (assert) {
+ await render(hbs``);
- assert.dom('.action').exists();
+ assert.dom('.account-banner__selection--unique-account').exists();
});
});
- module('dropdown', function () {
+ module('selection dropdown', function () {
test('chevron is not rendered without canSelectItem', async function (assert) {
await render(hbs``);
- assert.dom('.fa-chevron-down').doesNotExist();
+ assert.dom('.fa-chevron-down, [data-icon="chevron-down"]').doesNotExist();
});
test('chevron is not rendered with only 1 item', async function (assert) {
@@ -149,10 +190,12 @@ module('Integration | Component | utils/account-banner', function (hooks) {
/>
`);
- assert.dom('[data-icon="chevron-down"]').doesNotExist();
+ assert.dom('.fa-chevron-down, [data-icon="chevron-down"]').doesNotExist();
});
test('chevron is rendered with canSelectItem and multiple items', async function (assert) {
+ this.set('items', SELECTABLE_ITEMS);
+
await render(hbs`
`);
- this.set('items', SELECTABLE_ITEMS);
assert.dom('.fa-chevron-down, [data-icon="chevron-down"]').exists();
});
@@ -286,11 +328,45 @@ module('Integration | Component | utils/account-banner', function (hooks) {
assert.strictEqual(findAll('.item').length, SELECTABLE_ITEMS.length);
});
+ });
- test('unique-account class applied when canSelectItem is false', async function (assert) {
+ module('feedback message', function () {
+ test('it does not render any feedback message by default', async function (assert) {
await render(hbs``);
- assert.dom('.account-banner__selection--unique-account').exists();
+ assert.dom('.account-banner__selection + span').doesNotExist();
+ });
+
+ test('it renders an error feedback message', async function (assert) {
+ this.set('feedback', { type: 'error', value: 'Required field' });
+ await render(hbs``);
+
+ assert.dom('.account-banner__selection + span').exists();
+ assert.dom('.account-banner__selection + span').hasClass('font-color-error-500');
+ assert.dom('.account-banner__selection + span').hasText('Required field');
+ });
+
+ test('it renders a warning feedback message', async function (assert) {
+ this.set('feedback', { type: 'warning', value: 'Be careful' });
+ await render(hbs``);
+
+ assert.dom('.account-banner__selection + span').exists();
+ assert.dom('.account-banner__selection + span').hasClass('font-color-warning-500');
+ assert.dom('.account-banner__selection + span').hasText('Be careful');
+ });
+
+ test('it applies error border class when feedbackMessage type is error', async function (assert) {
+ this.set('feedback', { type: 'error', value: 'Required field' });
+ await render(hbs``);
+
+ assert.dom('.account-banner').hasClass('account-banner--error');
+ });
+
+ test('it does not apply error border class when feedbackMessage type is warning', async function (assert) {
+ this.set('feedback', { type: 'warning', value: 'Be careful' });
+ await render(hbs``);
+
+ assert.dom('.account-banner').hasNoClass('account-banner--error');
});
});
@@ -328,17 +404,15 @@ module('Integration | Component | utils/account-banner', function (hooks) {
});
});
- module('image / icon', function () {
- test('it renders @image as a badge', async function (assert) {
- await render(hbs``);
-
- assert.dom('.icon-in-badge').exists();
- });
-
- test('it renders @icon', async function (assert) {
- await render(hbs``);
+ module('actions block', function () {
+ test('it renders the actions block', async function (assert) {
+ await render(hbs`
+
+ <:actions>action
+
+ `);
- assert.dom('.upf-badge').exists();
+ assert.dom('.action').exists();
});
});
});