Ghost/ghost/admin/app/components/gh-member-settings-form.hbs

557 lines
38 KiB
Handlebars
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<div class="gh-member-settings" ...attributes {{did-insert this.setup}}>
<section class="gh-main-section columns-3">
<GhMemberDetails @member={{@member}} />
<div class="gh-main-section-block span-2 mt6">
<div class="gh-main-section-content grey">
<div>
<div class="gh-cp-member-email-name">
<GhFormGroup @errors={{this.member.errors}} @hasValidated={{this.member.hasValidated}} @property="name" @classNames="max-width">
<label for="member-name">Name</label>
<GhTextInput
@id="member-name"
@name="name"
@value={{this.scratchMember.name}}
@tabindex="1"
@shouldFocus="{{if this.member.isNew true}}"
@focus-out={{fn this.setProperty "name" this.scratchMember.name}}
data-test-input="member-name"
/>
<GhErrorMessage @errors={{this.member.errors}} @property="name" />
</GhFormGroup>
<GhFormGroup @errors={{this.member.errors}} @hasValidated={{this.member.hasValidated}} @property="email" @classNames="max-width">
<label for="member-email">Email</label>
<GhTextInput
@value={{this.scratchMember.email}}
@id="member-email"
@name="email"
@tabindex="2"
@autocapitalize="off"
@autocorrect="off"
@autocomplete="off"
@focus-out={{fn this.setProperty "email" this.scratchMember.email}}
data-test-input="member-email"
/>
<GhErrorMessage @errors={{this.member.errors}} @property="email" />
</GhFormGroup>
</div>
<GhFormGroup @classNames="gh-member-labels">
<label for="label-input">Labels</label>
<GhMemberLabelInput
@onChange={{this.setLabels}}
@allowEdit={{true}}
@onLabelEdit={{@onLabelEdit}}
@labels={{this.member.labels}}
@triggerId="label-input"
data-test-input=""
/>
</GhFormGroup>
<GhFormGroup @errors={{this.member.errors}} @hasValidated={{this.member.hasValidated}} @property="note" @classNames="mb0 gh-member-note">
<label for="member-note">Note <span class="midgrey-d1 fw4">(not visible to member)</span></label>
<GhTextarea
@id="member-note"
@name="note"
@class="gh-member-details-textarea"
@tabindex="3"
@value={{this.scratchMember.note}}
@focus-out={{fn this.setProperty "note" this.scratchMember.note}}
data-test-input="member-note"
/>
<GhErrorMessage @errors={{this.member.errors}} @property="note" />
<p> Maximum: <b>500</b> characters. Youve used
{{gh-count-down-characters this.scratchMember.note 500}}</p>
</GhFormGroup>
{{#if this.hasSingleNewsletter}}
{{#if (not-eq this.settings.editorDefaultEmailRecipients "disabled")}}
<GhFormGroup @classNames="gh-members-subscribed-checkbox mb0">
<div class="flex justify-between items-center">
<div>
<h4 class="gh-setting-title m">Subscribed to newsletter</h4>
<p class="gh-setting-desc">If disabled, member will <em>not</em> receive newsletter emails</p>
</div>
<div class="for-switch">
<label class="switch" for="subscribed-checkbox">
<Input
@checked={{this.member.subscribed}}
@type="checkbox"
id="subscribed-checkbox"
name="subscribed"
{{on "click" this.updateNewsletterPreference}}
data-test-checkbox="member-subscribed"
/>
<span class="input-toggle-component"></span>
</label>
</div>
</div>
</GhFormGroup>
{{/if}}
{{/if}}
</div>
</div>
{{#if this.hasMultipleNewsletters}}
<Member::NewsletterPreference
@member={{this.member}}
@newsletters={{this.newslettersList}}
@setMemberNewsletters={{this.setMemberNewsletters}}
/>
{{/if}}
{{#if this.membersUtils.paidMembersEnabled}}
<h4 class="gh-main-section-header small bn">Subscriptions</h4>
{{#unless this.tiers}}
<div class="gh-main-section-content grey">
<div class="gh-cp-membertier-notier">
{{#unless this.isCreatingComplimentary}}
<div class="gh-members-no-data gh-members-no-subs">
<span class="lightgrey">{{svg-jar "no-data-subscription"}}</span>
<h4>No subscriptions</h4>
</div>
{{/unless}}
{{#if this.isAddComplimentaryAllowed}}
{{#if this.isCreatingComplimentary}}
<GhLoadingSpinner />
{{else}}
<button
type="button"
class="gh-btn gh-btn-text green gh-btn-icon gh-btn-addtier"
{{on "click" (toggle-action "showMemberTierModal" this)}}
data-test-button="add-complimentary"
>
<span>{{svg-jar "plus"}} Add complimentary subscription</span>
</button>
{{/if}}
{{/if}}
</div>
</div>
{{/unless}}
{{#each this.tiers as |tier|}}
<div class="gh-main-section-content grey gh-member-tier-container" data-test-tier={{tier.id}}>
{{#if (feature "sourceAttribution")}}
<div class="gh-main-content-card gh-cp-membertier gh-cp-membertier-attribution gh-membertier-subscription {{if (gt tier.subscriptions.length 1) "multiple-subs" ""}}">
{{#each tier.subscriptions as |sub index|}}
<div class="gh-tier-card-header flex items-center">
<div class="gh-tier-card-price">
<div class="flex items-start">
<span class="currency-symbol">{{sub.price.currencySymbol}}</span>
<span class="amount">{{sub.price.nonDecimalAmount}}</span>
</div>
<div class="period">{{if (eq sub.price.interval "year") "yearly" "monthly"}}</div>
</div>
<div style="margin-left: 16px; flex-grow: 1;">
<h3 class="gh-membertier-name" data-test-text="tier-name" style="align-items:center !important; justify-content:flex-start !important;">
{{tier.name}}
{{#if (eq sub.status "canceled")}}
<span class="gh-badge archived" data-test-text="member-subscription-status">Cancelled</span>
{{else if sub.cancel_at_period_end}}
<span class="gh-badge archived" data-test-text="member-subscription-status">Cancelled</span>
{{else if sub.compExpiry}}
<span class="gh-badge active" data-test-text="member-subscription-status">Active</span>
{{else if sub.trialUntil}}
<span class="gh-badge active" data-test-text="member-subscription-status">Active</span>
{{else}}
<span class="gh-badge active" data-test-text="member-subscription-status">Active</span>
{{/if}}
{{#if (gt tier.subscriptions.length 1)}}
<span class="gh-membertier-subcount">{{tier.subscriptions.length}} subscriptions</span>
{{/if}}
</h3>
<div>
{{#if sub.trialUntil}}
<span class="gh-cp-membertier-pricelabel">Free trial </span>
{{else}}
{{#if (or (eq sub.price.nickname "Monthly") (eq sub.price.nickname "Yearly"))}}
{{else}}
<span class="gh-cp-membertier-pricelabel">{{sub.price.nickname}}</span><span class="gh-cp-membertier-renewal"> &ndash;</span>
{{/if}}
{{/if}}
{{#if (eq sub.status "canceled")}}
<span class="gh-cp-membertier-renewal">Ended {{sub.validUntil}}</span>
{{else if sub.cancel_at_period_end}}
<span class="gh-cp-membertier-renewal">Has access until {{sub.validUntil}}</span>
{{else if sub.compExpiry}}
<span class="gh-cp-membertier-renewal">Expires {{sub.compExpiry}}</span>
{{else if sub.trialUntil}}
<span class="gh-cp-membertier-renewal">Ends {{sub.trialUntil}}</span>
{{else}}
<span class="gh-cp-membertier-renewal">Renews {{sub.validUntil}}</span>
{{/if}}
</div>
<div class="flex flex-row gh-cp-membertier-details" {{on "click" (fn this.toggleSubscriptionExpanded sub.id)}}>
Details {{svg-jar "arrow-right-stroke"}}
</div>
<div class="gh-membertier-advanced {{if (not sub.showDetails) "hide"}}" data-test-subscription={{index}}>
<div class="gh-membertier-details-container">
{{#if sub.cancellationReason}}
<div class="mb4">
<h4>Cancellation reason</h4>
<div class="gh-membertier-cancelreason">{{sub.cancellationReason}}</div>
</div>
{{/if}}
{{#if sub.offer}}
{{#if (eq sub.offer.type "trial")}}
<div class="mb4">
<h4>Offer</h4>
<span class="gh-cp-membertier-pricelabel"> {{sub.offer.name}} </span>
&ndash; {{sub.offer.amount}} days free
</div>
{{else}}
<div class="mb4">
<h4>Offer</h4>
<span class="gh-cp-membertier-pricelabel"> {{sub.offer.name}} </span>
{{#if (eq sub.offer.type 'fixed')}}
&ndash; {{currency-symbol sub.offer.currency}}{{gh-price-amount sub.offer.amount}} off
{{else}}
&ndash; {{sub.offer.amount}}% off
{{/if}}
</div>
{{/if}}
{{/if}}
<div class="gh-membertier-details">
<div class="gh-membertier-detail">
<h4>Subscription Source</h4>
<p><span class="fw6">{{sub.attribution.referrerSource}} / {{sub.attribution.referrerMedium}}</span></p>
</div>
{{#if (and sub.attribution sub.attribution.url sub.attribution.title)}}
<div class="gh-membertier-detail">
<h4>Subscription page</h4>
<a href="{{sub.attribution.url}}" target="_blank" rel="noopener noreferrer">{{ sub.attribution.title }}</a>
</div>
{{/if}}
<p class="gh-membertier-detail-timestamp">Created on {{sub.startDate}}</p>
</div>
</div>
</div>
</div>
{{#if sub.isComplimentary}}
<span class="action-menu">
<GhDropdownButton
@dropdownName="subscription-menu-complimentary"
@classNames="gh-btn gh-btn-outline gh-btn-icon fill gh-btn-subscription-action icon-only"
@title="Actions"
data-test-button="subscription-actions"
>
<span>
{{svg-jar "dotdotdot"}}
<span class="hidden">Subscription menu</span>
</span>
</GhDropdownButton>
<GhDropdown
@name="subscription-menu-complimentary"
@tagName="ul"
@classNames="tier-actions-menu dropdown-menu dropdown-align-right"
>
<li>
<button
type="button"
{{on "click" (fn this.removeComplimentary (or tier.id tier.tier_id))}}
data-test-button="remove-complimentary"
>
<span class="red">Remove complimentary subscription</span>
</button>
</li>
</GhDropdown>
</span>
{{else}}
<span class="action-menu">
<GhDropdownButton @dropdownName="subscription-menu-{{sub.id}}" @classNames="gh-btn gh-btn-outline gh-btn-icon fill gh-btn-subscription-action icon-only" @title="Actions">
<span>
{{svg-jar "dotdotdot"}}
<span class="hidden">Subscription menu</span>
</span>
</GhDropdownButton>
<GhDropdown @name="subscription-menu-{{sub.id}}" @tagName="ul" @classNames="tier-actions-menu dropdown-menu dropdown-align-right">
<li>
<a href="https://dashboard.stripe.com/customers/{{sub.customer.id}}" target="_blank" rel="noopener noreferrer">
View Stripe customer
</a>
</li>
<li class="divider"></li>
<li>
<a href="https://dashboard.stripe.com/subscriptions/{{sub.id}}" target="_blank" rel="noopener noreferrer">
View Stripe subscription
</a>
</li>
<li>
{{#if (not-eq sub.status "canceled")}}
{{#if sub.cancel_at_period_end}}
<button type="button" {{on "click" (fn this.continueSubscription sub.id)}}>
<span>Continue subscription</span>
</button>
{{else}}
<button type="button" {{on "click" (fn this.cancelSubscription sub.id)}}>
<span class="red">Cancel subscription</span>
</button>
{{/if}}
{{/if}}
</li>
</GhDropdown>
</span>
{{/if}}
</div>
{{/each}}
{{#if (eq tier.subscriptions.length 0)}}
<div class="gh-membertier-subscription">
<div>
<div>
<span class="gh-cp-membertier-pricelabel">Complimentary</span>
<span class="gh-badge active">Active</span>
</div>
<div class="gh-membertier-created">Created on</div>
</div>
<div class="flex items-center">
<div class="gh-tier-card-price">
<div class="flex items-start">
<span class="currency-symbol">$</span>
<span class="amount">0</span>
</div>
<div class="period">yearly</div>
</div>
<span class="action-menu">
<GhDropdownButton @dropdownName="subscription-menu-complimentary" @classNames="gh-btn gh-btn-outline gh-btn-icon fill gh-btn-subscription-action icon-only" @title="Actions">
<span>
{{svg-jar "dotdotdot"}}
<span class="hidden">Subscription menu</span>
</span>
</GhDropdownButton>
<GhDropdown @name="subscription-menu-complimentary" @tagName="ul" @classNames="tier-actions-menu dropdown-menu dropdown-align-right">
<li>
<button type="button" {{on "click" (fn this.removeComplimentary tier.id)}}>
<span class="red">Remove complimentary subscription</span>
</button>
</li>
</GhDropdown>
</span>
</div>
</div>
{{/if}}
</div>
{{else}}
<div class="gh-main-content-card gh-cp-membertier {{if (gt tier.subscriptions.length 1) "multiple-subs" ""}}">
<h3 class="gh-membertier-name" data-test-text="tier-name">
{{tier.name}}
{{#if (gt tier.subscriptions.length 1)}}
<span class="gh-membertier-subcount">{{tier.subscriptions.length}} subscriptions</span>
{{/if}}
</h3>
{{#each tier.subscriptions as |sub index|}}
<div class="gh-membertier-subscription" data-test-subscription={{index}}>
<div class="gh-membertier-details-container">
<div>
{{#if sub.trialUntil}}
<span class="gh-cp-membertier-pricelabel">Free trial</span>
{{else}}
<span class="gh-cp-membertier-pricelabel">{{sub.price.nickname}}</span>
{{/if}}
&ndash;
{{#if (eq sub.status "canceled")}}
<span class="gh-cp-membertier-renewal">Ended {{sub.validUntil}}</span>
<span class="gh-badge archived" data-test-text="member-subscription-status">Cancelled</span>
{{else if sub.cancel_at_period_end}}
<span class="gh-cp-membertier-renewal">Has access until {{sub.validUntil}}</span>
<span class="gh-badge archived" data-test-text="member-subscription-status">Cancelled</span>
{{else if sub.compExpiry}}
<span class="gh-cp-membertier-renewal">Expires {{sub.compExpiry}}</span>
<span class="gh-badge active" data-test-text="member-subscription-status">Active</span>
{{else if sub.trialUntil}}
<span class="gh-cp-membertier-renewal">Ends {{sub.trialUntil}}</span>
<span class="gh-badge active" data-test-text="member-subscription-status">Active</span>
{{else}}
<span class="gh-cp-membertier-renewal">Renews {{sub.validUntil}}</span>
<span class="gh-badge active" data-test-text="member-subscription-status">Active</span>
{{/if}}
</div>
{{#if sub.cancellationReason}}
<div class="gh-membertier-cancelreason"><span class="fw6">Cancellation reason:</span> {{sub.cancellationReason}}</div>
{{/if}}
{{#if sub.offer}}
{{#if (eq sub.offer.type "trial")}}
<div>
<span class="gh-cp-membertier-pricelabel"> {{sub.offer.name}} </span>
offer
({{sub.offer.amount}} days free)
</div>
{{else}}
<div>
<span class="gh-cp-membertier-pricelabel"> {{sub.offer.name}} </span>
offer
{{#if (eq sub.offer.type 'fixed')}}
({{currency-symbol sub.offer.currency}}{{gh-price-amount sub.offer.amount}} off)
{{else}}
({{sub.offer.amount}}% off)
{{/if}}
applied to subscription
</div>
{{/if}}
{{/if}}
<div class="gh-membertier-details">
<span class="gh-membertier-created">Created on {{sub.startDate}}</span>
{{#if (and sub.attribution sub.attribution.url sub.attribution.title) }}
<span class="gh-membertier-separator">·</span>
<span class="gh-membertier-started">Subscribed on <a href="{{sub.attribution.url}}" target="_blank" rel="noopener noreferrer">{{ sub.attribution.title }}</a></span>
{{/if}}
</div>
</div>
<div class="gh-membertier-price-container">
<div class="gh-tier-card-price">
<div class="flex items-start">
<span class="currency-symbol">{{sub.price.currencySymbol}}</span>
<span class="amount">{{sub.price.nonDecimalAmount}}</span>
</div>
<div class="period">{{if (eq sub.price.interval "year") "yearly" "monthly"}}</div>
</div>
{{#if sub.isComplimentary}}
<span class="action-menu">
<GhDropdownButton
@dropdownName="subscription-menu-complimentary"
@classNames="gh-btn gh-btn-outline gh-btn-icon fill gh-btn-subscription-action icon-only"
@title="Actions"
data-test-button="subscription-actions"
>
<span>
{{svg-jar "dotdotdot"}}
<span class="hidden">Subscription menu</span>
</span>
</GhDropdownButton>
<GhDropdown
@name="subscription-menu-complimentary"
@tagName="ul"
@classNames="tier-actions-menu dropdown-menu dropdown-align-right"
>
<li>
<button
type="button"
{{on "click" (fn this.removeComplimentary (or tier.id tier.tier_id))}}
data-test-button="remove-complimentary"
>
<span class="red">Remove complimentary subscription</span>
</button>
</li>
</GhDropdown>
</span>
{{else}}
<span class="action-menu">
<GhDropdownButton @dropdownName="subscription-menu-{{sub.id}}" @classNames="gh-btn gh-btn-outline gh-btn-icon fill gh-btn-subscription-action icon-only" @title="Actions">
<span>
{{svg-jar "dotdotdot"}}
<span class="hidden">Subscription menu</span>
</span>
</GhDropdownButton>
<GhDropdown @name="subscription-menu-{{sub.id}}" @tagName="ul" @classNames="tier-actions-menu dropdown-menu dropdown-align-right">
<li>
<a href="https://dashboard.stripe.com/customers/{{sub.customer.id}}" target="_blank" rel="noopener noreferrer">
View Stripe customer
</a>
</li>
<li class="divider"></li>
<li>
<a href="https://dashboard.stripe.com/subscriptions/{{sub.id}}" target="_blank" rel="noopener noreferrer">
View Stripe subscription
</a>
</li>
<li>
{{#if (not-eq sub.status "canceled")}}
{{#if sub.cancel_at_period_end}}
<button type="button" {{on "click" (fn this.continueSubscription sub.id)}}>
<span>Continue subscription</span>
</button>
{{else}}
<button type="button" {{on "click" (fn this.cancelSubscription sub.id)}}>
<span class="red">Cancel subscription</span>
</button>
{{/if}}
{{/if}}
</li>
</GhDropdown>
</span>
{{/if}}
</div>
</div>
{{/each}}
{{#if (eq tier.subscriptions.length 0)}}
<div class="gh-membertier-subscription">
<div>
<div>
<span class="gh-cp-membertier-pricelabel">Complimentary</span>
<span class="gh-badge active">Active</span>
</div>
<div class="gh-membertier-created">Created on</div>
</div>
<div class="flex items-center">
<div class="gh-tier-card-price">
<div class="flex items-start">
<span class="currency-symbol">$</span>
<span class="amount">0</span>
</div>
<div class="period">yearly</div>
</div>
<span class="action-menu">
<GhDropdownButton @dropdownName="subscription-menu-complimentary" @classNames="gh-btn gh-btn-outline gh-btn-icon fill gh-btn-subscription-action icon-only" @title="Actions">
<span>
{{svg-jar "dotdotdot"}}
<span class="hidden">Subscription menu</span>
</span>
</GhDropdownButton>
<GhDropdown @name="subscription-menu-complimentary" @tagName="ul" @classNames="tier-actions-menu dropdown-menu dropdown-align-right">
<li>
<button type="button" {{on "click" (fn this.removeComplimentary tier.id)}}>
<span class="red">Remove complimentary subscription</span>
</button>
</li>
</GhDropdown>
</span>
</div>
</div>
{{/if}}
</div>
{{/if}}
</div>
{{/each}}
{{#if (and this.tiers this.isAddComplimentaryAllowed)}}
<div class="gh-membertier-list-footer {{if this.isCreatingComplimentary "min-height" ""}}">
{{#if this.isCreatingComplimentary}}
<GhLoadingSpinner />
{{else}}
<button
type="button"
class="gh-btn gh-btn-text green gh-btn-icon gh-btn-addtier"
{{on "click" (toggle-action "showMemberTierModal" this)}}
data-test-button="add-complimentary"
>
<span>{{svg-jar "plus"}} Add complimentary subscription</span>
</button>
{{/if}}
</div>
{{/if}}
{{/if}}
<Member::ActivityFeed @member={{this.member}} />
</div>
</section>
</div>
{{#if this.showMemberTierModal}}
<GhFullscreenModal @modifier="action wide member-tier">
<ModalMemberTier
@model={{this.member}}
@confirm={{this.addTier}}
@closeModal={{this.closeMemberTierModal}} />
</GhFullscreenModal>
{{/if}}