Skip to content

Commit

Permalink
Merge pull request #199 from Foxy/beta
Browse files Browse the repository at this point in the history
chore: release 1.38.0
  • Loading branch information
brettflorio authored Feb 6, 2025
2 parents f587538 + 363958d commit 36495c7
Show file tree
Hide file tree
Showing 51 changed files with 1,098 additions and 393 deletions.
34 changes: 27 additions & 7 deletions src/elements/internal/InternalForm/InternalForm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,25 +88,45 @@ describe('InternalForm', () => {
});

it('when loaded, renders a configurable subtitle in the optional header', async () => {
customElements.define(
'test-internal-form',
class extends InternalForm<any> {
get headerSubtitleKey() {
return 'foo';
}

get headerSubtitleOptions() {
return { baz: 'qux' };
}

get headerSubtitleBadges() {
return [{ key: 'abc' }, { key: 'def' }];
}
}
);

const root = document.createElement('div');
const element = await fixture<InternalForm<any>>(
html`<foxy-internal-form></foxy-internal-form>`
html`<test-internal-form></test-internal-form>`
);

render(element.renderHeader(), root);

let subtitle = root.querySelector(
`foxy-i18n[infer="header"][key="${element.headerSubtitleKey}"]`
);

let subtitle = root.querySelector(`foxy-i18n[infer="header"][key="foo"]`);
expect(subtitle).to.not.exist;

element.data = await getTestData<any>('./hapi/customers/0');
render(element.renderHeader(), root);

subtitle = root.querySelector(`foxy-i18n[infer="header"][key="${element.headerSubtitleKey}"]`);
subtitle = root.querySelector(`foxy-i18n[infer="header"][key="foo"]`);
expect(subtitle).to.exist;
expect(subtitle).to.have.deep.property('options', element.headerSubtitleOptions);
expect(subtitle).to.have.deep.property('options', { baz: 'qux' });

const abcBadge = root.querySelector(`foxy-i18n[infer="header badges"][key="abc"]`);
expect(abcBadge).to.exist;

const defBadge = root.querySelector(`foxy-i18n[infer="header badges"][key="def"]`);
expect(defBadge).to.exist;
});

it('when loaded, renders a Copy ID button in the optional header', async () => {
Expand Down
30 changes: 23 additions & 7 deletions src/elements/internal/InternalForm/InternalForm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,11 @@ export class InternalForm<TData extends HALJSONResource> extends Base<TData> {
return this.data ?? {};
}

/** Getter that returns a list of the optional badges to put into the subtitle. The badges are shown only if subtitle is visible. */
get headerSubtitleBadges(): { key: string }[] {
return [];
}

/** ID that will be written to clipboard when Copy ID button in header is clicked. */
get headerCopyIdValue(): string | number {
return this.data ? getResourceId(this.data._links.self.href) ?? '' : '';
Expand Down Expand Up @@ -131,13 +136,24 @@ export class InternalForm<TData extends HALJSONResource> extends Base<TData> {
</span>
${data
? html`
<foxy-i18n
infer="header"
class="text-m text-secondary"
key=${this.headerSubtitleKey}
.options=${this.headerSubtitleOptions}
>
</foxy-i18n>
<div class="flex items-center gap-s text-secondary leading-s">
${this.headerSubtitleBadges.map(badge => {
return html`
<foxy-i18n
class="border border-contrast-60 font-medium uppercase tracking-wider block rounded-s px-xs text-xs"
infer="header badges"
key=${badge.key}
>
</foxy-i18n>
`;
})}
<foxy-i18n
infer="header"
key=${this.headerSubtitleKey}
.options=${this.headerSubtitleOptions}
>
</foxy-i18n>
</div>
${actions ? html`<div class="mt-xs flex gap-m">${actions}</div>` : ''}
`
: ''}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ export class InternalSummaryControl extends InternalEditableControl {
return [
...super.styles,
css`
::slotted(*) {
min-width: 100%;
}
:host(:not([layout='section'])) slot::slotted(*) {
background-color: var(--lumo-contrast-5pct);
padding: calc(0.625em + (var(--lumo-border-radius) / 4) - 1px);
Expand Down
148 changes: 112 additions & 36 deletions src/elements/public/AdminSubscriptionForm/AdminSubscriptionForm.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,8 @@ describe('AdminSubscriptionForm', () => {
expect(customElements.get('foxy-transaction')).to.exist;
});

it('imports and defines foxy-internal-admin-subscription-form-load-in-cart-action', () => {
expect(customElements.get('foxy-internal-admin-subscription-form-load-in-cart-action')).to
.exist;
it('imports and defines foxy-internal-admin-subscription-form-link-control', () => {
expect(customElements.get('foxy-internal-admin-subscription-form-link-control')).to.exist;
});

it('imports and defines foxy-internal-admin-subscription-form-error', () => {
Expand All @@ -74,6 +73,13 @@ describe('AdminSubscriptionForm', () => {
expect(new Form()).to.have.property('ns', 'admin-subscription-form');
});

it('has a reactive property "uoeSettingsPage" that defaults to null', () => {
expect(new Form()).to.have.property('uoeSettingsPage', null);
expect(Form.properties).to.have.deep.property('uoeSettingsPage', {
attribute: 'uoe-settings-page',
});
});

it('always hides built-in Delete button because subscriptions cannot be deleted', () => {
expect(new Form().hiddenSelector.matches('delete', true)).to.be.true;
});
Expand Down Expand Up @@ -112,39 +118,6 @@ describe('AdminSubscriptionForm', () => {
expect(form.headerSubtitleOptions).to.deep.equal({ context: 'inactive' });
});

it('renders load in cart action for viewing the subscription in cart', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
<foxy-admin-subscription-form
href="https://demo.api/hapi/subscriptions/0?zoom=transaction_template"
@fetch=${(evt: FetchEvent) => router.handleEvent(evt)}
>
</foxy-admin-subscription-form>
`);

await waitUntil(() => !!form.data, '', { timeout: 5000 });
await form.requestUpdate();
const action = form.renderRoot.querySelector('[infer="view-action"]');
expect(action?.localName).to.equal('foxy-internal-admin-subscription-form-load-in-cart-action');
});

it('renders load in cart action for cancelling the subscription', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
<foxy-admin-subscription-form
href="https://demo.api/hapi/subscriptions/0?zoom=transaction_template"
@fetch=${(evt: FetchEvent) => router.handleEvent(evt)}
>
</foxy-admin-subscription-form>
`);

await waitUntil(() => !!form.data, '', { timeout: 5000 });
await form.requestUpdate();
const action = form.renderRoot.querySelector('[infer="cancel-action"]');
expect(action?.localName).to.equal('foxy-internal-admin-subscription-form-load-in-cart-action');
expect(action?.getAttribute('action')).to.equal('cancel');
});

it('renders error message control', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
Expand Down Expand Up @@ -307,6 +280,109 @@ describe('AdminSubscriptionForm', () => {
expect(slot).to.exist;
});

it('renders summary control with self-service links', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
<foxy-admin-subscription-form
href="https://demo.api/hapi/subscriptions/0"
@fetch=${(evt: FetchEvent) => router.handleEvent(evt)}
>
</foxy-admin-subscription-form>
`);

await waitUntil(() => !!form.data, '', { timeout: 5000 });
const control = form.renderRoot.querySelector('[infer="self-service-links"]');
expect(control?.localName).to.equal('foxy-internal-summary-control');
});

it('renders internal link control for loading subscription in cart inside of the self-service links summary control', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
<foxy-admin-subscription-form
href="https://demo.api/hapi/subscriptions/0"
@fetch=${(evt: FetchEvent) => router.handleEvent(evt)}
>
</foxy-admin-subscription-form>
`);

await waitUntil(() => !!form.data, '', { timeout: 5000 });
const summary = form.renderRoot.querySelector('[infer="self-service-links"]');
const control = summary?.querySelector('[infer="load-in-cart"]');

expect(control?.localName).to.equal('foxy-internal-admin-subscription-form-link-control');
expect(control).to.not.have.attribute('search');
});

it('renders internal link control for loading subscription on checkout inside of the self-service links summary control', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
<foxy-admin-subscription-form
href="https://demo.api/hapi/subscriptions/0"
@fetch=${(evt: FetchEvent) => router.handleEvent(evt)}
>
</foxy-admin-subscription-form>
`);

await waitUntil(() => !!form.data, '', { timeout: 5000 });
const summary = form.renderRoot.querySelector('[infer="self-service-links"]');
const control = summary?.querySelector('[infer="load-on-checkout"]');

expect(control?.localName).to.equal('foxy-internal-admin-subscription-form-link-control');
expect(control).to.have.attribute('search', 'cart=checkout');
});

it('renders internal link control for canceling subscription at the end of the billing period inside of the self-service links summary control', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
<foxy-admin-subscription-form
href="https://demo.api/hapi/subscriptions/0"
@fetch=${(evt: FetchEvent) => router.handleEvent(evt)}
>
</foxy-admin-subscription-form>
`);

await waitUntil(() => !!form.data, '', { timeout: 5000 });
const summary = form.renderRoot.querySelector('[infer="self-service-links"]');
const control = summary?.querySelector('[infer="cancel-at-end-of-billing-period"]');

expect(control?.localName).to.equal('foxy-internal-admin-subscription-form-link-control');
expect(control).to.have.attribute('search', 'sub_cancel=next_transaction_date');
});

it('renders internal link control for canceling subscription on the next day inside of the self-service links summary control', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
<foxy-admin-subscription-form
href="https://demo.api/hapi/subscriptions/0"
@fetch=${(evt: FetchEvent) => router.handleEvent(evt)}
>
</foxy-admin-subscription-form>
`);

await waitUntil(() => !!form.data, '', { timeout: 5000 });
const summary = form.renderRoot.querySelector('[infer="self-service-links"]');
const control = summary?.querySelector('[infer="cancel-next-day"]');

expect(control?.localName).to.equal('foxy-internal-admin-subscription-form-link-control');
expect(control).to.have.attribute('search', 'sub_cancel=true');
});

it('renders link to UOE settings page when uoeSettingsPage is set', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
<foxy-admin-subscription-form
uoe-settings-page="https://example.com"
href="https://demo.api/hapi/subscriptions/0"
@fetch=${(evt: FetchEvent) => router.handleEvent(evt)}
>
</foxy-admin-subscription-form>
`);

await waitUntil(() => !!form.data, '', { timeout: 5000 });
const summary = form.renderRoot.querySelector('[infer="self-service-links"]');
expect(summary?.querySelector('a')).to.have.attribute('href', 'https://example.com');
});

it('renders async list control for attributes', async () => {
const router = createRouter();
const form = await fixture<Form>(html`
Expand Down
70 changes: 56 additions & 14 deletions src/elements/public/AdminSubscriptionForm/AdminSubscriptionForm.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
import type { PropertyDeclarations } from 'lit-element';
import type { TemplateResult } from 'lit-html';
import type { Data } from './types';

import { TranslatableMixin } from '../../../mixins/translatable';
import { BooleanSelector } from '@foxy.io/sdk/core';
import { InternalForm } from '../../internal/InternalForm/InternalForm';
import { ifDefined } from 'lit-html/directives/if-defined';
import { html } from 'lit-html';
import { html, svg } from 'lit-html';

const NS = 'admin-subscription-form';
const Base = TranslatableMixin(InternalForm, NS);

export class AdminSubscriptionForm extends Base<Data> {
static get properties(): PropertyDeclarations {
return {
...super.properties,
uoeSettingsPage: { attribute: 'uoe-settings-page' },
};
}

/** URL of the UOE settings page in the admin. If set, displays a link to that page in the self-service links section. */
uoeSettingsPage: string | null = null;

get hiddenSelector(): BooleanSelector {
const alwaysMatch = ['delete', super.hiddenSelector.toString()];
if (!this.data?.error_message) alwaysMatch.unshift('error-message');
Expand All @@ -22,19 +33,6 @@ export class AdminSubscriptionForm extends Base<Data> {
return { context: this.data?.is_active ? 'active' : 'inactive' };
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
renderHeaderActions(data: Data): TemplateResult {
return html`
<foxy-internal-admin-subscription-form-load-in-cart-action infer="view-action">
</foxy-internal-admin-subscription-form-load-in-cart-action>
<foxy-internal-admin-subscription-form-load-in-cart-action
action="cancel"
infer="cancel-action"
>
</foxy-internal-admin-subscription-form-load-in-cart-action>
`;
}

renderBody(): TemplateResult {
let transactionsHref: string | undefined;

Expand Down Expand Up @@ -77,6 +75,50 @@ export class AdminSubscriptionForm extends Base<Data> {
</foxy-internal-number-control>
</foxy-internal-summary-control>
<foxy-internal-summary-control infer="self-service-links">
<foxy-internal-admin-subscription-form-link-control infer="load-in-cart">
</foxy-internal-admin-subscription-form-link-control>
<foxy-internal-admin-subscription-form-link-control
search="cart=checkout"
infer="load-on-checkout"
>
</foxy-internal-admin-subscription-form-link-control>
<foxy-internal-admin-subscription-form-link-control
search="sub_cancel=next_transaction_date"
infer="cancel-at-end-of-billing-period"
>
</foxy-internal-admin-subscription-form-link-control>
<foxy-internal-admin-subscription-form-link-control
search="sub_cancel=true"
infer="cancel-next-day"
>
</foxy-internal-admin-subscription-form-link-control>
<div
class="flex items-start leading-xs text-xs text-secondary"
style="gap: calc(0.625em + (var(--lumo-border-radius) / 4) - 1px)"
>
${svg`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true" class="flex-shrink-0" style="width: 1.25em"><path fill-rule="evenodd" d="M15 8A7 7 0 1 1 1 8a7 7 0 0 1 14 0ZM9 5a1 1 0 1 1-2 0 1 1 0 0 1 2 0ZM6.75 8a.75.75 0 0 0 0 1.5h.75v1.75a.75.75 0 0 0 1.5 0v-2.5A.75.75 0 0 0 8.25 8h-1.5Z" clip-rule="evenodd" /></svg>`}
<p>
<foxy-i18n infer="" key="uoe_hint_text"></foxy-i18n>
${this.uoeSettingsPage
? html`
<a
target="_blank"
class="inline-block rounded font-medium text-body cursor-pointer hover-underline focus-outline-none focus-ring-2 focus-ring-primary-50"
href=${this.uoeSettingsPage}
>
<foxy-i18n infer="" key="uoe_link_text"></foxy-i18n>
</a>
`
: ''}
</p>
</div>
</foxy-internal-summary-control>
${this.renderTemplateOrSlot()}
<foxy-internal-async-list-control
Expand Down
2 changes: 1 addition & 1 deletion src/elements/public/AdminSubscriptionForm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import '../AttributeCard/index';
import '../AttributeForm/index';
import '../Transaction/index';

import './internal/InternalAdminSubscriptionFormLoadInCartAction/index';
import './internal/InternalAdminSubscriptionFormLinkControl/index';
import './internal/InternalAdminSubscriptionFormError/index';

import { AdminSubscriptionForm } from './AdminSubscriptionForm';
Expand Down
Loading

0 comments on commit 36495c7

Please sign in to comment.